././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853070.4466803 meson-1.3.2/0000755000175000017500000000000014562742416013043 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/COPYING0000644000175000017500000002613613716006331014073 0ustar00jpakkanejpakkane 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. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665806.0 meson-1.3.2/MANIFEST.in0000644000175000017500000000052414253672216014577 0ustar00jpakkanejpakkanegraft test?cases graft manual?tests graft cross graft data graft graphics graft man graft tools graft packaging graft unittests include contributing.md 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 meson.py ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853070.4466803 meson-1.3.2/PKG-INFO0000644000175000017500000000301714562742416014141 0ustar00jpakkanejpakkaneMetadata-Version: 2.1 Name: meson Version: 1.3.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 Project-URL: Source, https://github.com/mesonbuild/meson Keywords: meson,mesonbuild,build system,cmake 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.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Topic :: Software Development :: Build Tools Requires-Python: >=3.7 Provides-Extra: ninja Provides-Extra: progress Provides-Extra: typing License-File: COPYING 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. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1695979640.0 meson-1.3.2/README.md0000644000175000017500000000641314505514170014315 0ustar00jpakkanejpakkane

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) [![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) #### Dependencies - [Python](https://python.org) (version 3.7 or newer) - [Ninja](https://ninja-build.org) (version 1.8.2 or newer) Latest Meson version supporting previous Python versions: - Python 3.6: **0.61.5** - Python 3.5: **0.56.2** - Python 3.4: **0.45.1** #### Installing from source Meson is available on [PyPi](https://pypi.python.org/pypi/meson), so it can be installed with `pip3 install meson`. The exact command to type to install with `pip` can vary between systems, be sure to use the Python 3 version of `pip`. If you wish you can install it locally with the standard Python command: ```console python3 -m pip install meson ``` For builds using Ninja, Ninja can be downloaded directly from Ninja [GitHub release page](https://github.com/ninja-build/ninja/releases) or via [PyPi](https://pypi.python.org/pypi/ninja) ```console python3 -m pip install ninja ``` More on Installing Meson build can be found at the [getting meson page](https://mesonbuild.com/Getting-meson.html). #### Creating a standalone script Meson can be run as a [Python zip app](https://docs.python.org/3/library/zipapp.html). To generate the executable run the following command: ./packaging/create_zipapp.py --outfile meson.pyz --interpreter '/usr/bin/env python3' #### 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 setup ` 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: ```console cd meson setup builddir ``` To compile, cd into your build directory and type `ninja`. To run unit tests, type `ninja test`. More on running Meson build system commands can be found at the [running meson page](https://mesonbuild.com/Running-Meson.html) or by typing `meson --help`. #### Contributing We love code contributions. See the [contribution page](https://mesonbuild.com/Contributing.html) on the website for details. #### IRC The channel to use is `#mesonbuild` either via Matrix ([web interface][matrix_web]) or [OFTC IRC][oftc_irc]. [matrix_web]: https://app.element.io/#/room/#mesonbuild:matrix.org [oftc_irc]: https://www.oftc.net/ #### 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***. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/contributing.md0000644000175000017500000000050513716006331016061 0ustar00jpakkanejpakkane## Contributing to the Meson build system Thank you for your interest in participating to the development! A large fraction of Meson is contributed by people outside the core team and we are *excited* to see what you do. **Contribution instructions can be found on the website** @ https://mesonbuild.com/Contributing.html ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.458635 meson-1.3.2/cross/0000755000175000017500000000000014562742413014171 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1660380518.0 meson-1.3.2/cross/arm64cl.txt0000644000175000017500000000057214275662546016217 0ustar00jpakkanejpakkane[binaries] c = 'cl' cpp = 'cl' fc = 'false' ar = 'lib' windres = 'rc' [built-in options] c_args = ['-DWINAPI_FAMILY=WINAPI_FAMILY_APP'] c_link_args = ['-APPCONTAINER', 'WindowsApp.lib'] cpp_args = ['-DWINAPI_FAMILY=WINAPI_FAMILY_APP'] cpp_link_args = ['-APPCONTAINER', 'WindowsApp.lib'] [host_machine] system = 'windows' cpu_family = 'aarch64' cpu = 'armv8' endian = 'little' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/cross/armcc.txt0000644000175000017500000000113214031433465016007 0ustar00jpakkanejpakkane# 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' [built-in options] # 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' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691448864.0 meson-1.3.2/cross/armclang-linux.txt0000644000175000017500000000235214464273040017651 0ustar00jpakkanejpakkane# 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', '--target=aarch64-arm-none-eabi'] #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' #pkg-config = '/usr/bin/arm-linux-gnueabihf-pkg-config' [host_machine] system = 'baremetal' cpu_family = 'arm' cpu = 'armv7' # Not sure if correct. endian = 'little' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/cross/armclang.txt0000644000175000017500000000125514433154642016517 0ustar00jpakkanejpakkane# 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', '--target=arm-arm-none-eabi'] cpp = ['armclang', '--target=arm-arm-none-eabi'] ar = 'armar' strip = 'armar' [built-in options] # The '--target', '-mcpu' options with the appropriate values should be mentioned # to cross compile c/c++ code with armclang. c_args = ['-mcpu=cortex-m0plus'] cpp_args = ['-mcpu=cortex-m0plus'] [host_machine] system = 'bare metal' # Update with your system name - bare metal/OS. cpu_family = 'arm' cpu = 'Cortex-M0+' endian = 'little' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/cross/c2000.txt0000644000175000017500000000102214031433465015444 0ustar00jpakkanejpakkane# This file assumes that path to the Texas Instruments C20000 toolchain is added # to the environment(PATH) variable, so that Meson can find # cl2000 and ar2000 while building. [binaries] c = 'cl2000' ar = 'ar2000' strip = 'cl2000' [host_machine] system = 'bare metal' cpu_family = 'c2000' cpu = 'c28x' endian = 'little' [built-in options] c_args = [ '-v28', '-ml', '-mt'] c_link_args = [ '-z', '--rom_model', '\f28004x_flash.cmd'] cpp_args = [] cpp_link_args = [] [properties] needs_exe_wrapper = true ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/cross/ccomp-armv7a.txt0000644000175000017500000000041614433154642017225 0ustar00jpakkanejpakkane[binaries] c = ['ccomp', '-target', 'armv7a-eabi'] ar = 'ccomp' strip = 'strip' [built-in options] c_args = ['-fall'] [host_machine] system = 'bare metal' # Update with your system name - bare metal/OS. cpu_family = 'arm' cpu = 'Cortex-A9' endian = 'little' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/cross/ccrx.txt0000644000175000017500000000104114031433465015660 0ustar00jpakkanejpakkane# 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' [built-in options] # 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' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1687963700.0 meson-1.3.2/cross/iphone.txt0000644000175000017500000000256414447044064016222 0ustar00jpakkanejpakkane# 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 googles and xcrun. [binaries] c = ['clang', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk'] cpp = ['clang++', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk'] objc = ['clang', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk'] objcpp = ['clang++', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk'] ar = 'ar' strip = 'strip' [built-in options] c_args = ['-miphoneos-version-min=11.0'] cpp_args = ['-miphoneos-version-min=11.0'] c_link_args = ['-miphoneos-version-min=11.0'] cpp_link_args = ['-miphoneos-version-min=11.0'] objc_args = ['-miphoneos-version-min=11.0'] objcpp_args = ['-miphoneos-version-min=11.0'] [properties] root = '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer' has_function_printf = true has_function_hfkerhisadf = false [host_machine] system = 'darwin' subsystem = 'ios' kernel = 'xnu' cpu_family = 'aarch64' cpu = 'aarch64' endian = 'little' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/cross/linux-mingw-w64-32bit.json0000644000175000017500000000031014031433465020666 0ustar00jpakkanejpakkane{ "file": "linux-mingw-w64-32bit.txt", "tests": ["common", "cmake"], "env": { "WINEPATH": "/usr/lib/gcc/i686-w64-mingw32/9.2-posix;/usr/i686-w64-mingw32/bin;/usr/i686-w64-mingw32/lib" } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691448864.0 meson-1.3.2/cross/linux-mingw-w64-32bit.txt0000644000175000017500000000162614464273040020550 0ustar00jpakkanejpakkane[binaries] c = '/usr/bin/i686-w64-mingw32-gcc' cpp = '/usr/bin/i686-w64-mingw32-g++' objc = '/usr/bin/i686-w64-mingw32-gcc' ar = '/usr/bin/i686-w64-mingw32-ar' strip = '/usr/bin/i686-w64-mingw32-strip' pkg-config = '/usr/bin/i686-w64-mingw32-pkg-config' windres = '/usr/bin/i686-w64-mingw32-windres' exe_wrapper = 'wine' ld = '/usr/bin/i686-w64-mingw32-ld' cmake = '/usr/bin/cmake' [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' [cmake] CMAKE_BUILD_WITH_INSTALL_RPATH = 'ON' CMAKE_FIND_ROOT_PATH_MODE_PROGRAM = 'NEVER' CMAKE_FIND_ROOT_PATH_MODE_LIBRARY = 'ONLY' CMAKE_FIND_ROOT_PATH_MODE_INCLUDE = 'ONLY' CMAKE_FIND_ROOT_PATH_MODE_PACKAGE = 'ONLY' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/cross/linux-mingw-w64-64bit.json0000644000175000017500000000031614031433465020701 0ustar00jpakkanejpakkane{ "file": "linux-mingw-w64-64bit.txt", "tests": ["common", "cmake"], "env": { "WINEPATH": "/usr/lib/gcc/x86_64-w64-mingw32/9.2-posix;/usr/x86_64-w64-mingw32/bin;/usr/x86_64-w64-mingw32/lib" } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691448864.0 meson-1.3.2/cross/linux-mingw-w64-64bit.txt0000644000175000017500000000161114464273040020547 0ustar00jpakkanejpakkane[binaries] c = '/usr/bin/x86_64-w64-mingw32-gcc' cpp = '/usr/bin/x86_64-w64-mingw32-g++' objc = '/usr/bin/x86_64-w64-mingw32-gcc' ar = '/usr/bin/x86_64-w64-mingw32-ar' strip = '/usr/bin/x86_64-w64-mingw32-strip' pkg-config = '/usr/bin/x86_64-w64-mingw32-pkg-config' windres = '/usr/bin/x86_64-w64-mingw32-windres' exe_wrapper = 'wine' cmake = '/usr/bin/cmake' [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' [cmake] CMAKE_BUILD_WITH_INSTALL_RPATH = 'ON' CMAKE_FIND_ROOT_PATH_MODE_PROGRAM = 'NEVER' CMAKE_FIND_ROOT_PATH_MODE_LIBRARY = 'ONLY' CMAKE_FIND_ROOT_PATH_MODE_INCLUDE = 'ONLY' CMAKE_FIND_ROOT_PATH_MODE_PACKAGE = 'ONLY' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336264.0 meson-1.3.2/cross/metrowerks-arm.txt0000644000175000017500000000111614516507010017677 0ustar00jpakkanejpakkane# This file assumes that the path to your Metrowerks Embedded ARM # toolchain is added to the environment(PATH) variable, so that # Meson can find the binaries while building. [binaries] c = 'mwccarm' c_ld = 'mwldarm' cpp = 'mwccarm' cpp_ld = 'mwldarm' ar = 'mwldarm' as = 'mwasmarm' [built-in options] c_args = ['-lang', 'c99', '-D_NITRO', '-nosyspath'] c_link_args = '@DIRNAME@' / 'metrowerks.lcf' cpp_args = ['-lang', 'c++', '-D_NITRO', '-nosyspath'] cpp_link_args = '@DIRNAME@' / 'metrowerks.lcf' [host_machine] system = 'bare metal' cpu = 'arm' cpu_family = 'arm' endian = 'little' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336264.0 meson-1.3.2/cross/metrowerks-eppc.txt0000644000175000017500000000107114516507010020047 0ustar00jpakkanejpakkane# This file assumes that the path to your Metrowerks toolchain # of choice is added to the environment(PATH) variable, so that # Meson can find the binaries while building. [binaries] c = 'mwcceppc' c_ld = 'mwldeppc' cpp = 'mwcceppc' cpp_ld = 'mwldeppc' ar = 'mwldeppc' as = 'mwasmeppc' [built-in options] c_args = ['-lang', 'c99', '-nosyspath'] c_link_args = '@DIRNAME@' / 'metrowerks.lcf' cpp_args = ['-lang', 'c++', '-nosyspath'] cpp_link_args = '@DIRNAME@' / 'metrowerks.lcf' [host_machine] system = 'bare metal' cpu = 'ppc' cpu_family = 'ppc' endian = 'little' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1685461376.0 meson-1.3.2/cross/metrowerks.lcf0000644000175000017500000000063314435414600017054 0ustar00jpakkanejpakkane# General-purpose linker script for Metrowerks toolchains. # This script will link a blank application. Its only purpose # is to allow the toolchains to run Meson tests. To link an # actual application, you need to write your own fine-tuned lcf. MEMORY { TEST (RWX) : ORIGIN=0, LENGTH=0 } SECTIONS { .TEST:{ * (.text) * (.data) * (.rodata) * (.bss) __startup=.; } > TEST }././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665806.0 meson-1.3.2/cross/msp430.txt0000644000175000017500000000077714253672216015773 0ustar00jpakkanejpakkane# This file assumes that path to the Texas Instruments MSP430 toolchain is added # to the environment(PATH) variable, so that Meson can find # cl430 and ar430 while building. [binaries] c = cl430 ar = ar430 strip = strip430 [host_machine] system = 'baremetal' cpu_family = 'msp430' endian = 'little' [built-in options] c_args = [ '-vmsp', '--printf_support=minimal'] c_link_args = [ '--rom_model', '-llibc.a',] cpp_args = [] cpp_link_args = [] [properties] needs_exe_wrapper = true ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691448864.0 meson-1.3.2/cross/none.txt0000644000175000017500000000046514464273040015672 0ustar00jpakkanejpakkane# native file used to make the build machine compiler unusable [host_machine] system = 'none' cpu_family = 'none' cpu = 'none' endian = 'little' [properties] [binaries] c = ['false'] cpp = ['false'] fc = ['false'] objc = ['false'] objcpp = ['false'] ar = ['false'] pkg-config = ['false'] cmake = ['false'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/cross/ownstdlib.txt0000644000175000017500000000041714031433465016734 0ustar00jpakkanejpakkane# 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' # Subproject name ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1687963700.0 meson-1.3.2/cross/tvos.txt0000644000175000017500000000173714447044064015734 0ustar00jpakkanejpakkane# 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 googles and xcrun. [binaries] c = ['clang', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS.sdk'] cpp = ['clang++', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS.sdk'] ar = 'ar' strip = 'strip' [built-in options] c_args = ['-mtvos-version-min=12.0'] cpp_args = ['-mtvos-version-min=12.0'] c_link_args = ['-mtvos-version-min=12.0'] cpp_link_args = ['-mtvos-version-min=12.0'] [properties] root = '/Applications/Xcode.app/Contents/Developer/Platforms/AppleTVOS.platform/Developer' has_function_printf = true has_function_hfkerhisadf = false [host_machine] system = 'darwin' subsystem = 'tvos' kernel = 'xnu' cpu_family = 'arm' cpu = 'arm64' endian = 'little' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/cross/ubuntu-armhf.json0000644000175000017500000000010514031433465017470 0ustar00jpakkanejpakkane{ "file": "ubuntu-armhf.txt", "tests": ["common"], "env": {} } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691448864.0 meson-1.3.2/cross/ubuntu-armhf.txt0000644000175000017500000000157014464273040017346 0ustar00jpakkanejpakkane[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' pkg-config = '/usr/bin/arm-linux-gnueabihf-pkg-config' ld = '/usr/bin/arm-linux/gnueabihf-ld' [built-in options] # Used in unit test '140 get define' c_args = ['-DMESON_TEST_ISSUE_1665=1'] cpp_args = '-DMESON_TEST_ISSUE_1665=1' [properties] root = '/usr/arm-linux-gnueabihf' has_function_printf = true has_function_hfkerhisadf = false skip_sanity_check = true [host_machine] system = 'linux' cpu_family = 'arm' cpu = 'armv7' # Not sure if correct. endian = 'little' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/cross/ubuntu-faketarget.txt0000644000175000017500000000061713716006331020363 0ustar00jpakkanejpakkane# 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' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336264.0 meson-1.3.2/cross/wasm.txt0000644000175000017500000000037714516507010015677 0ustar00jpakkanejpakkane[binaries] c = 'emcc' cpp = 'em++' ar = 'emar' [built-in options] c_args = [] c_link_args = ['-sEXPORT_ALL=1'] cpp_args = [] cpp_link_args = ['-sEXPORT_ALL=1'] [host_machine] system = 'emscripten' cpu_family = 'wasm32' cpu = 'wasm32' endian = 'little' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/cross/xc16.txt0000644000175000017500000000103714031433465015507 0ustar00jpakkanejpakkane# This file assumes that path to the Microchip xc16 toolchain is added # to the environment(PATH) variable, so that Meson can find # xc16-gcc and xc16-ar while building. [binaries] c = 'xc16-gcc' ar = 'xc16-ar' strip = 'xc16-gcc' [host_machine] system = 'bare metal' cpu_family = 'dspic' cpu = '33ep64mc203' endian = 'little' [properties] needs_exe_wrapper = true [built-in options] c_args = [ '-c', '-mcpu=33EP64MC203', '-omf=elf'] c_link_args = [ '-mcpu=33EP64MC203', '-omf=elf', '-Wl,--script=p33EP64MC203.gld,'] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.4706354 meson-1.3.2/data/0000755000175000017500000000000014562742413013751 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/data/.coveragerc.in0000644000175000017500000000065614107166547016511 0ustar00jpakkanejpakkane[run] branch = True parallel = True concurrency = multiprocessing data_file = @ROOT@/.coverage/coverage source = @ROOT@/mesonbuild/ [report] exclude_lines = if T.TYPE_CHECKING: [paths] mesonbuild = mesonbuild/ __w/meson/meson/mesonbuild/ @ROOT@/mesonbuild/ [html] directory = @ROOT@/.coverage/html [xml] output = @ROOT@/.coverage/coverage.xml [json] output = @ROOT@/.coverage/coverage.json ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/data/com.mesonbuild.install.policy0000644000175000017500000000160013716006331021542 0ustar00jpakkanejpakkane 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1670690299.0 meson-1.3.2/data/macros.meson0000644000175000017500000000235414345132773016305 0ustar00jpakkanejpakkane%__meson %{_bindir}/meson %__meson_wrap_mode nodownload %__meson_auto_features enabled %meson \ %set_build_flags \ %{shrink:%{__meson} setup \ --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 \ %{shrink:%{__meson} compile \ -C %{_vpath_builddir} \ -j %{_smp_build_ncpus} \ --verbose \ %{nil}} %meson_install \ %{shrink:DESTDIR=%{buildroot} %{__meson} install \ -C %{_vpath_builddir} \ --no-rebuild \ %{nil}} %meson_test \ %{shrink:%{__meson} test \ -C %{_vpath_builddir} \ --num-processes %{_smp_build_ncpus} \ --print-errorlogs \ %{nil}} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/data/schema.xsd0000644000175000017500000001054113716006331015722 0ustar00jpakkanejpakkane ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853066.726624 meson-1.3.2/data/shell-completions/0000755000175000017500000000000014562742413017412 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.4706354 meson-1.3.2/data/shell-completions/bash/0000755000175000017500000000000014562742413020327 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0 meson-1.3.2/data/shell-completions/bash/meson0000644000175000017500000006463714562742373021420 0ustar00jpakkanejpakkane# shellcheck shell=bash _get_subprojects_dir() { # TODO: meson-info/intro-projectinfo.json has the info for the subproject # directory, but we can't know what the build directory is in these contexts. # Let's default to subprojects. # Get subprojects directory. All subprojects subcommands support --sourcedir, # so if that argument was passed, use it to find subprojects. subprojects_dir="subprojects" for (( i=${#COMP_WORDS[@]} - 1; i >= 0; i-- )); do # Exit early if we have made our way back to the command if [[ "${COMP_WORDS[$i]}" = "subprojects" ]]; then break fi prev=$((i - 1)) if [[ $prev -gt 0 ]] && [[ "${COMP_WORDS[$prev]}" = "--sourcedir" ]]; then subprojects_dir="${COMP_WORDS[$i]}" break fi done echo "$subprojects_dir" } _subprojects() { subprojects_dir=$(_get_subprojects_dir) pushd "$subprojects_dir" &>/dev/null || return local COMPREPLY=() _filedir # _filedir for whatever reason can't reason about symlinks, so -d will them. # Filter out wrap files with this expresion. IFS=$'\n' echo "${COMPREPLY[*]}" | grep -vE '\.wrap$' | xargs popd &>/dev/null } _wraps() { subprojects_dir=$(_get_subprojects_dir) db="$subprojects_dir/wrapdb.json" if [[ ! -f "$db" ]]; then return fi document=$(cat "$db") wraps=($(python3 -c 'import sys, json for wrap in json.load(sys.stdin).keys(): print(wrap) ' <<< "$document")) echo "${wraps[@]}" } _meson() { command="${COMP_WORDS[1]}" subcommands=( setup configure dist install introspect init test wrap subprojects help rewrite compile devenv env2mfile ) if [[ " ${subcommands[*]} " =~ " ${command} " ]]; then "_meson-$command" "${COMP_WORDS[@]:1}" else _meson-setup "${COMP_WORDS[@]}" fi } && 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 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) elif option["type"] == "feature": choices.append("auto") choices.append("enabled") choices.append("disabled") 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 |\ bindir |\ datadir |\ includedir |\ infodir |\ libdir |\ licensedir |\ libexecdir |\ localedir |\ localstatedir |\ mandir |\ sbindir |\ sharedstatedir |\ sysconfdir |\ python.platlibdir |\ python.purelibdir |\ pkg-config-path |\ build.pkg-config-path |\ cmake-prefix-path |\ build.cmake-prefix-path) _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)) ;; native-file) _filedir COMPREPLY+=($(_filedir_in "$XDG_DATA_DIRS"/meson/native)) COMPREPLY+=($(_filedir_in /usr/local/share/meson/native)) COMPREPLY+=($(_filedir_in /usr/share/meson/native)) COMPREPLY+=($(_filedir_in "$XDG_DATA_HOME"/meson/native)) COMPREPLY+=($(_filedir_in ~/.local/share/meson/native)) ;; *) return 1;; esac return 0 } _meson_compgen_options() { local -r cur=$1 if [[ ${cur:0:2} == -- ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}' -- "${cur:2}")) elif [[ ${cur:0:1} == - ]]; then if [[ ${#cur} == 1 ]]; then # Only add longopts if cur not "-something" COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}' -- "")) fi COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}' -- "${cur:1}")) else return 1 fi return 0 } _meson_common_setup_configure_longopts=( help prefix bindir datadir includedir infodir libdir licensedir libexecdir localedir localstatedir mandir sbindir sharedstatedir sysconfdir auto-features backend genvslite buildtype debug default-library errorlogs install-umask layout optimization prefer-static stdsplit strip unity unity-size warnlevel werror wrap-mode force-fallback-for vsenv pkgconfig.relocatable python.bytecompile python.install-env python.platlibdir python.purelibdir python.allow-limited-api pkg-config-path build.pkg-config-path cmake-prefix-path build.cmake-prefix-path clearcache ) _meson-setup() { shortopts=( h D v ) longopts=( ${_meson_common_setup_configure_longopts[@]} native-file cross-file version fatal-meson-warnings reconfigure wipe ) local cur prev if _get_comp_words_by_ref cur prev &>/dev/null; then if [[ ${prev:0:2} == -- ]] && _meson_complete_option "${prev:2}" "$cur"; then return elif [[ ${prev:0:1} == - ]] && [[ ${prev:1:2} != - ]] && _meson_complete_option "${prev:1}"; then return fi fi 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 ! _meson_compgen_options "$cur"; then _filedir -d if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi if [[ $COMP_CWORD == 1 ]]; then COMPREPLY+=($(compgen -W '${subcommands[*]}' -- "$cur")) fi fi } _meson-configure() { shortopts=( h D ) longopts=( ${_meson_common_setup_configure_longopts[@]} no-pager ) 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 ! _meson_compgen_options "$cur"; then 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-dist() { shortopts=( h C ) longopts=( allow-dirty help formats include-subprojects no-tests ) local cur prev if _get_comp_words_by_ref -n ':' cur prev &>/dev/null; then case $prev in -C) _filedir -d return ;; --formats) formats=( xztar gztar zip ) COMPREPLY+=($(compgen -W '${formats[*]}' -- "$cur")) return ;; esac else cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi } _meson-install() { shortopts=( h n C ) longopts=( help no-rebuild only-changed quiet destdir dry-run skip-subprojects tags strip ) local cur prev if _get_comp_words_by_ref -n ':' cur prev &>/dev/null; then for i in "${!COMP_WORDS[@]}"; do opt="${COMP_WORDS[i]}" dir="${COMP_WORDS[i+1]}" case "$opt" in -C) break ;; esac dir=. done case $prev in -C | --destdir) _filedir -d return ;; --tags) tags=$(meson introspect "$dir" --install-plan | python3 -c 'import sys, json targets = json.load(sys.stdin)["targets"] for target, attributes in targets.items(): print(attributes["tag"]) ' 2> /dev/null) if [[ $? == 0 ]]; then COMPREPLY+=($(compgen -W '${tags[*]}' -- "$cur")) fi return ;; esac else cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi } _meson-introspect() { shortopts=( h a i f ) longopts=( ast benchmarks buildoptions buildsystem-files dependencies scan-dependencies installed install-plan projectinfo targets tests backend all indent force-object-output ) local cur prev if ! _get_comp_words_by_ref cur prev &>/dev/null; then cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then 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-init() { shortopts=( h C n e d l b f ) longopts=( help name executable deps language build builddir force type version ) if ! _meson_compgen_options "$cur"; then if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi } _meson-test() { shortopts=( h j q v t C ) longopts=( help maxfail repeat no-rebuild gdb gdb-path list wrapper suite no-suite no-stdsplit print-errorlogs benchmark logbase num-processes verbose quiet timeout-multiplier setup test-args ) local cur prev if _get_comp_words_by_ref -n ':' cur prev &>/dev/null; then case $prev in --maxfail | --repeat) # number, can't be completed return ;; --wrapper) _command_offset "$COMP_CWORD" return ;; --gdb-path) _filedir 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=$(meson introspect "$dir" --tests | python3 -c 'import sys, json; for test in json.load(sys.stdin): for suite in test["suite"]: print(suite) ' 2> /dev/null) if [[ $? == 0 ]]; then COMPREPLY+=($(compgen -W '${suites[*]}' -- "$cur")) __ltrim_colon_completions "$cur" fi return ;; --logbase) # free string, can't be completed return ;; -j | --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 ! _meson_compgen_options "$cur"; then 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=$(meson introspect "$dir" --tests | python3 -c 'import sys, json; for test in json.load(sys.stdin): print(test["name"]) ' 2> /dev/null) if [[ $? == 0 ]]; then COMPREPLY+=($(compgen -W '${tests[*]}' -- "$cur")) fi if [ -z "$cur" ]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}' -- "${cur:2}")) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}' -- "${cur:1}")) fi fi } _meson-wrap() { shortopts=( h ) longopts=( help ) subcommands=( info install list promote search status update update-db ) for i in "$@"; do if [[ " ${subcommands[*]} " =~ " $i " ]]; then "_meson-wrap-$i" "${COMP_WORDS[i]:1}" return fi done local cur prev if ! _get_comp_words_by_ref cur prev &>/dev/null; then cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then COMPREPLY+=($(compgen -W '${subcommands[*]}' -- "$cur")) if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi } _meson-wrap-info() { shortopts=( h ) longopts=( allow-insecure help ) local cur prev if ! _get_comp_words_by_ref cur prev &>/dev/null; then cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi read -ra wraps < <(_wraps) COMPREPLY+=($(compgen -W '${wraps[*]}' -- "$cur")) } _meson-wrap-install() { shortopts=( h ) longopts=( allow-insecure help ) local cur prev if ! _get_comp_words_by_ref cur prev &>/dev/null; then cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi read -ra wraps < <(_wraps) COMPREPLY+=($(compgen -W '${wraps[*]}' -- "$cur")) } _meson-wrap-list() { shortopts=( h ) longopts=( allow-insecure help ) local cur prev if ! _get_comp_words_by_ref cur prev &>/dev/null; then cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi } _meson-wrap-promote() { shortopts=( h ) longopts=( help ) local cur prev if ! _get_comp_words_by_ref cur prev &>/dev/null; then cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then if [[ -z $cur ]]; then _filedir COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi } _meson-wrap-search() { shortopts=( h ) longopts=( allow-insecure help ) local cur prev if ! _get_comp_words_by_ref cur prev &>/dev/null; then cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi read -ra wraps < <(_wraps) COMPREPLY+=($(compgen -W '${wraps[*]}' -- "$cur")) } _meson-wrap-status() { shortopts=( h ) longopts=( allow-insecure help ) local cur prev if ! _get_comp_words_by_ref cur prev &>/dev/null; then cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi } _meson-wrap-update() { shortopts=( h ) longopts=( allow-insecure force help sourcedir types ) local cur prev if _get_comp_words_by_ref cur prev &>/dev/null; then case $prev in --sourcedir) _filedir -d return ;; --types) types=( file git hg svn ) COMPREPLY+=($(compgen -W '${types[*]}' -- "$cur")) return ;; -j | --num-processes) # number, can't be completed return ;; esac else cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi COMPREPLY+=($(_subprojects)) } _meson-wrap-update-db() { shortopts=( h ) longopts=( allow-insecure help ) local cur prev if ! _get_comp_words_by_ref cur prev &>/dev/null; then cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi } _meson-subprojects() { shortopts=( h ) longopts=( help ) subcommands=( checkout download foreach packagefiles purge update ) for i in "$@"; do if [[ " ${subcommands[*]} " =~ " $i " ]]; then "_meson-subprojects-$i" "${COMP_WORDS[i]:1}" return fi done local cur prev if ! _get_comp_words_by_ref cur prev &>/dev/null; then cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then COMPREPLY+=($(compgen -W '${subcommands[*]}' -- "$cur")) if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi } _meson-subprojects-checkout() { shortopts=( b h j ) longopts=( allow-insecure help num-processes sourcedir types ) local cur prev if _get_comp_words_by_ref cur prev &>/dev/null; then case $prev in --sourcedir) _filedir -d return ;; --types) types=( file git hg svn ) COMPREPLY+=($(compgen -W '${types[*]}' -- "$cur")) return ;; -j | --num-processes) # number, can't be completed return ;; esac else cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi COMPREPLY+=($(_subprojects)) } _meson-subprojects-download() { shortopts=( h j ) longopts=( allow-insecure help num-processes sourcedir types ) local cur prev if _get_comp_words_by_ref cur prev &>/dev/null; then case $prev in --sourcedir) _filedir -d return ;; --types) types=( file git hg svn ) COMPREPLY+=($(compgen -W '${types[*]}' -- "$cur")) return ;; -j | --num-processes) # number, can't be completed return ;; esac else cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi COMPREPLY+=($(_subprojects)) } _meson-subprojects-foreach() { shortopts=( h j ) longopts=( allow-insecure help num-processes sourcedir types ) local cur prev if _get_comp_words_by_ref cur prev &>/dev/null; then case $prev in --sourcedir) _filedir -d return ;; --types) types=( file git hg svn ) COMPREPLY+=($(compgen -W '${types[*]}' -- "$cur")) return ;; -j | --num-processes) # number, can't be completed return ;; esac else cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi COMPREPLY+=($(_subprojects)) } _meson-subprojects-packagefiles() { shortopts=( h j ) longopts=( allow-insecure apply help num-processes save sourcedir types ) local cur prev if _get_comp_words_by_ref cur prev &>/dev/null; then case $prev in --sourcedir) _filedir -d return ;; --types) types=( file git hg svn ) COMPREPLY+=($(compgen -W '${types[*]}' -- "$cur")) return ;; -j | --num-processes) # number, can't be completed return ;; --apply | --save) return ;; esac else cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi COMPREPLY+=($(_subprojects)) } _meson-subprojects-purge() { shortopts=( h j ) longopts=( allow-insecure confirm help include-cache num-processes sourcedir types ) local cur prev if _get_comp_words_by_ref cur prev &>/dev/null; then case $prev in --sourcedir) _filedir -d return ;; --types) types=( file git hg svn ) COMPREPLY+=($(compgen -W '${types[*]}' -- "$cur")) return ;; -j | --num-processes) # number, can't be completed return ;; --apply | --save) return ;; esac else cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi COMPREPLY+=($(_subprojects)) } _meson-subprojects-update() { shortopts=( h j ) longopts=( allow-insecure help num-processes rebase reset sourcedir types ) local cur prev if _get_comp_words_by_ref cur prev &>/dev/null; then case $prev in --sourcedir) _filedir -d return ;; --types) types=( file git hg svn ) COMPREPLY+=($(compgen -W '${types[*]}' -- "$cur")) return ;; -j | --num-processes) # number, can't be completed return ;; --rebase | --reset) return ;; esac else cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi COMPREPLY+=($(_subprojects)) } _meson-help() { longopts=( setup configure dist install introspect init test wrap subprojects rewrite compile devenv env2mfile ) local cur prev if _get_comp_words_by_ref cur prev &>/dev/null; then COMPREPLY+=($(compgen -W '${longopts[*]}' -- "$cur")) fi } _meson-rewrite() { : TODO } _meson-compile() { shortopts=( h C j l v ) longopts=( help clean jobs load-average verbose ninja-args vs-args xcode-args ) local cur prev if _get_comp_words_by_ref cur prev &>/dev/null; then if [[ ${prev:0:2} == -- ]] && _meson_complete_option "${prev:2}" "$cur"; then return elif [[ ${prev:0:1} == - ]] && [[ ${prev:1:2} != - ]] && _meson_complete_option "${prev:1}"; then return fi else cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then _filedir -d if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi } _meson-devenv() { shortopts=( h w ) longopts=( dump dump-format help workdir ) local cur prev if _get_comp_words_by_ref -n ':' cur prev &>/dev/null; then case $prev in -C | -w | --workdir) _filedir -d return ;; --dump) _filedir return ;; --dump-format) dump_formats=( sh export vscode ) COMPREPLY+=($(compgen -W '${dump_formats[*]}' -- "$cur")) return ;; esac else cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi } _meson-env2mfile() { shortopts=( h o ) longopts=( cpu cpu-family cross debarch endian gccsuffix help kernel native subsystem system ) local cur prev if _get_comp_words_by_ref -n ':' cur prev &>/dev/null; then case $prev in --endian) endianness=( big little ) COMPREPLY+=($(compgen -W '${endianness[*]}' -- "$cur")) return ;; -o) _filedir return ;; esac else cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.4706354 meson-1.3.2/data/shell-completions/zsh/0000755000175000017500000000000014562742413020216 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/data/shell-completions/zsh/_meson0000644000175000017500000004020414433154642021417 0ustar00jpakkanejpakkane#compdef meson # 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 __meson_dist_formats=("xztar" "gztar" "zip") local __meson_cd='-C[change into this directory before running]:target dir:_directories' local -a __meson_common=( '--prefix=[installation prefix]: :_directories' '--bindir=[executable directory]: :_directories' '--datadir=[data file directory]: :_directories' '--includedir=[header file directory]: :_directories' '--infodir=[info page directory]: :_directories' '--libdir=[library directory]: :_directories' '--libexecdir=[library executable directory]: :_directories' '--localedir=[locale data directory]: :_directories' '--localstatedir=[local state data directory]: :_directories' '--mandir=[manual page directory]: :_directories' '--sbindir=[system executable directory]: :_directories' '--sharedstatedir=[arch-independent data directory]: :_directories' '--sysconfdir=[system configuration directory]: :_directories' '--auto-features=[default value for auto features]:auto features types:(auto disabled enabled)' '--backend=[backend to use]:Meson backend:'"$__meson_backends" '--buildtype=[build type to use]:Meson build type:'"$__meson_build_types" '--debug[turn on building with debug]' '--default-library=[default library type]:default library type:(shared static both)' '--errorlogs[prints the logs from failing tests]' '--install-umask=[default umask for permissions of all installed files]' '--layout=[build directory layout]:build directory layout:(flat mirror)' '--optimization=[optimization level for compiled targets]:optimization:(0 g 1 2 3 s)' '--stdsplit=[split stdout and stderr in test logs]' '--strip[strip targets on install]' '--unity=[unity builds on/off]:whether to do unity builds:(on off subprojects)' '--warnlevel=[compiler warning level]:compiler warning level:warning level:(1 2 3)' '--werror[treat warnings as errors]' '--wrap-mode=[special wrap mode]:wrap mode:'"$__meson_wrap_modes" '--force-fallback-for=[force fallback for listed subprojects]' '--pkg-config-path=[extra paths for HOST pkg-config to search]:paths:_dir_list -s ,' '--build.pkg-config-path=[extra paths for BUILD pkg-config to search]:paths:_dir_list -s ,' '--cmake-prefix-path=[extra prefixes for HOST cmake to search]:paths:_dir_list -s ,' '--build.cmake-prefix-path=[extra prefix for BUILD cmake to search]:paths:_dir_list -s ,' ) local -a meson_commands=( 'configure:configure a project' 'dist:generate release archive' 'init:create a new project' 'install:install one or more targets' 'introspect:query project properties' 'setup:set up a build directory' 'test:run tests' 'wrap:manage source dependencies' 'subprojects:manage subprojects' 'compile:Build the project' ) (( $+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_wrap_names] )) || __meson_wrap_names() { local rwraps rwraps="$(_call_program meson meson wrap list)" local -a wraps=(${(@f)rwraps}) _describe -t wraps "Meson wraps" wraps } (( $+functions[__meson_installed_wraps] )) || __meson_installed_wraps() { local rwraps if rwraps="$(ls subprojects/ | grep '\.wrap$' | cut -d . -f 1)"; then local -a wraps=(${(@f)rwraps}) _describe -t wraps "Meson wraps" wraps 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' \ '--cross-file=[cross-compilation environment description]:cross file:_files' \ '--native-file=[build machine compilation environment description]:native file:_files' \ '--clearcache[clear cached state]' \ '--fatal-meson-warnings=[exit when any meson warnings are encountered]' \ '(-v --version)'{'-v','--version'}'[print the meson version and exit]' \ '--reconfigure=[re-run build configuration]' \ '--wipe=[delete saved state and restart using saved command line options]' \ ":$firstd directory:_directories" \ "::$secondd directory:_directories" \ "${(@)__meson_common}" } (( $+functions[_meson-configure] )) || _meson-configure() { local curcontext="$curcontext" # TODO: implement 'mesonconf @file' local -a specs=( '*-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}" \ "${(@)__meson_common}" } (( $+functions[_meson-test] )) || _meson-test() { local curcontext="$curcontext" # TODO: complete test suites local -a specs=( '--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]' '--gdb-path=[program to run for gdb (can be wrapper or compatible program)]:program:_path_commands' '--list[list available tests]' '(--wrapper --wrap)'{'--wrapper=','--wrap='}'[wrapper to run tests with]:wrapper program:_path_commands' "$__meson_cd" '(--suite)--no-suite[do not run tests from this suite]:test suite: ' '(--no-suite)--suite[only 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: ' '(--verbose -v)'{'--verbose','-v'}'[do not redirect stdout and stderr]' '(--quiet -q)'{'--quiet','-q'}'[produce less output to the terminal]' '(--timeout-multiplier -t)'{'--timeout-multiplier','-t'}'[a multiplier for test timeouts]:Python floating-point number: ' '--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-install] )) || _meson-install() { local curcontext="$curcontext" local -a specs=( "$__meson_cd" '--no-rebuild[Do not rebuild before installing]' '--only-changed[Do not overwrite files that are older than the copied file]' '--quiet[Do not print every file that was installed]' ) _arguments \ '(: -)'{'--help','-h'}'[show a help message and quit]' \ "${(@)specs}" } (( $+functions[_meson-introspect] )) || _meson-introspect() { local curcontext="$curcontext" local -a specs=( '--ast[dump the ASK of the meson file]' '--benchmarks[list all benchmarks]' '--buildoptions[list all build options]' '--buildsystem-files[list files that belong to the build system]' '--dependencies[list external dependencies]' '--installed[list all installed files and directories]' '--projectinfo[show project information]' '--targets[list top level targets]' '--tests[list all unit tests]' '--backend=[backend to use]:Meson backend:'"$__meson_backends" '::build directory:_directories' ) _arguments \ '(: -)'{'--help','-h'}'[show a help message and quit]' \ "${(@)specs}" } (( $+functions[_meson-init] )) || _meson-init() { local curcontext="$curcontext" local -a specs=( "$__meson_cd" '(-n --name)'{'-n','--name'}'=[the name of the project (defaults to directory name)]' '(-e --executable)'{'-e','--executable'}'=[the name of the executable target to create (defaults to project name)]' '(-d --deps)'{'-d','--deps'}'=[comma separated list of dependencies]' '(-l --language)'{'-l','--language'}'=[comma separated list of languages (autodetected based on sources if unset)]:languages:_values , (c cpp cs cuda d fortran java objc objcpp rust)' '(-b --build)'{'-b','--build'}'[build the project immediately after generation]' '--builddir=[directory for building]:directory:_directories' '(-f --force)'{'-f','--force'}'[overwrite any existing files and directories]' '(-t --type)'{'-t','--type'}'=[project type, defaults to executable]:type:(executable library)' '(-v --version)'{'-v','--version'}'[print the meson version and exit]' ) _arguments \ '(: -)'{'--help','-h'}'[show a help message and quit]' \ "${(@)specs}" } (( $+functions[_meson-wrap] )) || _meson-wrap() { local -a commands=( 'list:list all available wraps' 'search:search the db by name' 'install:install the specified project' 'update:Update a project to its newest available version' 'info:Show info about a wrap' 'status:Show the status of your subprojects' ) if (( CURRENT == 2 )); then _describe -t commands "Meson wrap subcommands" commands else local curcontext="$curcontext" cmd="${${commands[(r)$words[2]:*]%%:*}}" if (( $#cmd )); then if [[ $cmd == status ]]; then _message "no options" elif [[ $cmd == "list" ]]; then _arguments '*:meson wraps' elif [[ $cmd == "search" ]]; then _arguments '*:meson wraps' elif [[ $cmd == "install" ]]; then _arguments '*:meson wraps:__meson_wrap_names' elif [[ $cmd == "update" ]]; then _arguments '*:meson wraps:__meson_installed_wraps' elif [[ $cmd == "info" ]]; then _arguments '*:meson wraps:__meson_wrap_name' elif [[ $cmd == "status" ]]; then _arguments '*:' elif [[ $cmd == "promote" ]]; then # TODO: how do you figure out what wraps are provided by subprojects if # they haven't been fetched yet? _arguments '*:' fi else _message "unknown meson wrap command: $words[2]" fi fi } (( $+functions[_meson-dist] )) || _meson-dist() { local curcontext="$curcontext" local -a specs=( '--allow-dirty[Allow even when repository contains uncommitted changes]' '--formats=[comma separated list of archive types to create]:archive formats:_values -s , format '"$__meson_dist_formats" '--include-subprojects[Include source code of subprojects that have been used for the build]' '--no-tests[Do not build and test generated packages]' "$__meson_cd" ) _arguments \ '(: -)'{'--help','-h'}'[show a help message and quit]' \ "${(@)specs}" } (( $+functions[_meson-subprojects-update] )) || _meson-subprojects-update() { local curcontext="$curcontext" local -a specs=( "--rebase[rebase your branch on top of wrap's revision (git only)]" '--sourcedir=[path to source directory]:_directories' '*:subprojects:__meson_installed_wraps' ) _arguments \ '(: -)'{'--help','-h'}'[show a help message and quit]' \ "${(@)specs}" } (( $+functions[_meson-subprojects-checkout] )) || _meson-subprojects-checkout() { local curcontext="$curcontext" local -a specs=( '-b[create a new branch]' '--sourcedir=[path to source directory]:_directories' # FIXME: this doesn't work exactly right, but I can't figure it out ':branch name' '*:subprojects:__meson_installed_wraps' ) _arguments \ '(: -)'{'--help','-h'}'[show a help message and quit]' \ "${(@)specs}" } (( $+functions[_meson-subprojects-download] )) || _meson-subprojects-download() { local curcontext="$curcontext" local -a specs=( '--sourcedir=[path to source directory]:_directories' ) _arguments \ '(: -)'{'--help','-h'}'[show a help message and quit]' \ "${(@)specs}" } (( $+functions[_meson-subprojects-foreach] )) || _meson-subprojects-foreach() { local curcontext="$curcontext" local -a specs=( '--sourcedir=[path to source directory]:_directories' '*:command:_command_names -e' ) _arguments \ '(: -)'{'--help','-h'}'[show a help message and quit]' \ "${(@)specs}" } (( $+functions[_meson-subprojects] )) || _meson-subprojects() { local -a commands=( 'update:update all subprojects from wrap files' 'checkout:checkout a branch (git only)' 'download:ensure subprojects are fetched, even if not in use. Already downloaded subprojects are not modified.' 'foreach:execute a command in each subproject directory' ) if (( CURRENT == 2 )); then _describe -t commands "Meson subproject subcommands" commands else local curcontext="$curcontext" cmd="${${commands[(r)$words[2]:*]%%:*}}" if (( $#cmd )); then if [[ $cmd == status ]]; then _message "no options" else _meson-subprojects-$cmd fi else _message "unknown meson subproject command: $words[2]" fi fi } (( $+functions[_meson-compile] )) || _meson-compile() { local curcontext="$curcontext" local -a specs=( "$__meson_cd" '--clean[Clean the build directory]' '(-j --jobs)'{'-j','--jobs'}'=[the number fo work jobs to run (if supported)]:_guard "[0-9]#" "number of jobs"' '(-l --load-average)'{'-l','--load-average'}'=[the system load average to try to maintain (if supported)]:_guard "[0-9]#" "load average"' '(-v --verbose)'{'-v','--verbose'}'[Show more output]' '--ninja-args=[Arguments to pass to ninja (only when using ninja)]' '--vs-args=[Arguments to pass to vs (only when using msbuild)]' ) _arguments \ '(: -)'{'--help','-h'}'[show a help message and quit]' \ "${(@)specs}" } 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 ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853066.730624 meson-1.3.2/data/syntax-highlighting/0000755000175000017500000000000014562742413017742 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.4706354 meson-1.3.2/data/syntax-highlighting/vim/0000755000175000017500000000000014562742413020535 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/data/syntax-highlighting/vim/README0000644000175000017500000000020513716006331021402 0ustar00jpakkanejpakkaneftdetect sets the filetype ftplugin sets Meson indentation rules indent does Meson indentation syntax does Meson syntax highlighting ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.4746354 meson-1.3.2/data/syntax-highlighting/vim/ftdetect/0000755000175000017500000000000014562742413022337 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/data/syntax-highlighting/vim/ftdetect/meson.vim0000644000175000017500000000033014433154642024167 0ustar00jpakkanejpakkaneau BufNewFile,BufRead meson.build set filetype=meson au BufNewFile,BufRead meson.options set filetype=meson au BufNewFile,BufRead meson_options.txt set filetype=meson au BufNewFile,BufRead *.wrap set filetype=dosini ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.4746354 meson-1.3.2/data/syntax-highlighting/vim/ftplugin/0000755000175000017500000000000014562742413022365 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/data/syntax-highlighting/vim/ftplugin/meson.vim0000644000175000017500000000217214140314117024211 0ustar00jpakkanejpakkane" Vim filetype plugin file " Language: meson " License: VIM License " Maintainer: Liam Beguin " 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 formatoptions+=croql formatoptions-=t let b:undo_ftplugin = "setl com< cms< fo<" if get(g:, "meson_recommended_style", 1) setlocal expandtab setlocal shiftwidth=2 setlocal softtabstop=2 let b:undo_ftplugin .= " | setl et< sts< sw<" endif if exists("loaded_matchit") && !exists("b:match_words") let b:match_words = '\:\:\:\,' . \ '\:\:\:\' let b:undo_ftplugin .= " | unlet! b:match_words" endif if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter") let b:browsefilter = "Meson Build Files (meson.build)\tmeson.build\n" . \ "All Files (*.*)\t*.*\n" let b:undo_ftplugin .= " | unlet! b:browsefilter" endif let &cpo = s:keepcpo unlet s:keepcpo ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.4786353 meson-1.3.2/data/syntax-highlighting/vim/indent/0000755000175000017500000000000014562742413022016 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/data/syntax-highlighting/vim/indent/meson.vim0000644000175000017500000001230714140314117023643 0ustar00jpakkanejpakkane" Vim indent file " Language: Meson " License: VIM License " Maintainer: Nirbheek Chauhan " Liam Beguin " 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) let b:undo_indent = "setl ai< inde< indk< lisp<" " Only define the function once. if exists("*GetMesonIndent") finish endif let s:keepcpo= &cpo set 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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.4786353 meson-1.3.2/data/syntax-highlighting/vim/syntax/0000755000175000017500000000000014562742413022063 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336264.0 meson-1.3.2/data/syntax-highlighting/vim/syntax/meson.vim0000644000175000017500000000767614516507010023730 0ustar00jpakkanejpakkane" Vim syntax file " Language: Meson " License: VIM License " Maintainer: Nirbheek Chauhan " Liam Beguin " Last Change: 2023 Aug 27 " 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 " if 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 in syn keyword mesonStatement continue break 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\+\>" syn match mesonNumber "\<0x\x\+\>" syn match mesonNumber "\<0o\o\+\>" " booleans syn keyword mesonBoolean false true " Built-in functions syn keyword mesonBuiltin \ build_machine \ host_machine \ meson \ option \ target_machine \ add_global_arguments \ add_global_link_arguments \ add_languages \ add_project_arguments \ add_project_dependencies \ add_project_link_arguments \ add_test_setup \ alias_target \ assert \ benchmark \ both_libraries \ build_target \ configuration_data \ configure_file \ custom_target \ debug \ declare_dependency \ dependency \ disabler \ environment \ error \ executable \ files \ find_program \ generator \ get_option \ get_variable \ import \ include_directories \ install_data \ install_emptydir \ install_headers \ install_man \ install_subdir \ install_symlink \ is_disabler \ is_variable \ jar \ join_paths \ library \ message \ project \ range \ run_command \ run_target \ set_variable \ shared_library \ shared_module \ static_library \ structured_sources \ subdir \ subdir_done \ subproject \ summary \ test \ unset_variable \ 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 " The default highlight links. Can be overridden later. hi def link mesonStatement Statement hi def link mesonConditional Conditional hi def link mesonRepeat Repeat hi def link mesonOperator Operator hi def link mesonComment Comment hi def link mesonTodo Todo hi def link mesonString String hi def link mesonEscape Special hi def link mesonNumber Number hi def link mesonBuiltin Function hi def link mesonBoolean Boolean if exists("meson_space_error_highlight") hi def link mesonSpaceError Error endif let b:current_syntax = "meson" let &cpo = s:cpo_save unlet s:cpo_save " vim:set sw=2 sts=2 ts=8 noet: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336264.0 meson-1.3.2/data/test.schema.json0000644000175000017500000000767614516507010017071 0ustar00jpakkanejpakkane{ "type": "object", "additionalProperties": false, "properties": { "env": { "type": "object", "additionalProperties": { "type": "string" } }, "installed": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "file": { "type": "string" }, "type": { "type": "string", "enum": [ "file", "python_file", "dir", "exe", "shared_lib", "python_lib", "python_limited_lib", "python_bytecode", "pdb", "implib", "py_implib", "py_limited_implib", "implibempty", "expr", "link" ] }, "platform": { "type": "string", "enum": [ "msvc", "gcc", "cygwin", "!cygwin" ] }, "version": { "type": "string" }, "language": { "type": "string" } }, "required": [ "file", "type" ] } }, "matrix": { "type": "object", "properties": { "options": { "additionalProperties": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "val": { "type": ["string", "boolean", "null", "array"], "items": { "type": "string" } }, "compilers": { "type": "object", "additionalProperties": { "type": "string" } }, "skip_on_env": { "type": "array", "items": { "type": "string" } }, "skip_on_jobname": { "type": "array", "items": { "type": "string" } }, "skip_on_os": { "type": "array", "items": { "type": "string" } } }, "required": [ "val" ] } }, "exclude": { "type": "array", "items": { "type": "object", "additionalProperties": { "type": ["string", "boolean", "array"], "items": { "type": "string" } } } } } } }, "do_not_set_opts": { "type": "array", "items": { "type": "string", "enum": [ "libdir", "prefix" ] } }, "tools": { "type": "object" }, "stdout": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "line": { "type": "string" }, "match": { "type": "string", "enum": [ "literal", "re" ] }, "count": { "type": "integer" }, "comment": { "type": "string" } }, "required": [ "line" ] } }, "skip_on_env": { "type": "array", "items": { "type": "string" } }, "skip_on_jobname": { "type": "array", "items": { "type": "string" } }, "skip_on_os": { "type": "array", "items": { "type": "string" } } } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.4826355 meson-1.3.2/graphics/0000755000175000017500000000000014562742413014640 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336264.0 meson-1.3.2/graphics/meson_logo.svg0000644000175000017500000013432514516507010017521 0ustar00jpakkanejpakkane image/svg+xml The official color of the logo is PANTONE 2105 C.The sRGB substitute is (57, 32, 124). ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/graphics/meson_logo_big.png0000644000175000017500000005260113716006331020324 0ustar00jpakkanejpakkane‰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`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/graphics/wrap_logo.svg0000644000175000017500000001056213716006331017346 0ustar00jpakkanejpakkane image/svg+xml ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.4866354 meson-1.3.2/man/0000755000175000017500000000000014562742413013613 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0 meson-1.3.2/man/meson.10000644000175000017500000001235714562742373015033 0ustar00jpakkanejpakkane.TH MESON "1" "February 2024" "meson 1.3.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, 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/ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7426243 meson-1.3.2/manual tests/0000755000175000017500000000000014562742413015440 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.4866354 meson-1.3.2/manual tests/1 wrap/0000755000175000017500000000000014562742413016532 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/1 wrap/main.c0000644000175000017500000000034113716006331017610 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/1 wrap/meson.build0000644000175000017500000000042113716006331020661 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.4866354 meson-1.3.2/manual tests/1 wrap/subprojects/0000755000175000017500000000000014562742413021075 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/1 wrap/subprojects/sqlite.wrap0000644000175000017500000000070313716006331023261 0ustar00jpakkanejpakkane[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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.4866354 meson-1.3.2/manual tests/10 svn wrap/0000755000175000017500000000000014562742413017401 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/10 svn wrap/meson.build0000644000175000017500000000035513716006331021536 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/10 svn wrap/prog.c0000644000175000017500000000011613716006331020502 0ustar00jpakkanejpakkane#include"subproj.h" int main(void) { subproj_function(); return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.4866354 meson-1.3.2/manual tests/10 svn wrap/subprojects/0000755000175000017500000000000014562742413021744 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/10 svn wrap/subprojects/samplesubproject.wrap0000644000175000017500000000015513716006331026212 0ustar00jpakkanejpakkane[wrap-svn] directory=samplesubproject url=https://svn.code.sf.net/p/mesonsubproject/code/trunk revision=head ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.4866354 meson-1.3.2/manual tests/11 wrap imposter/0000755000175000017500000000000014562742413020436 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/11 wrap imposter/meson.build0000644000175000017500000000040413716006331022566 0ustar00jpakkanejpakkaneproject('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')././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.4946356 meson-1.3.2/manual tests/11 wrap imposter/subprojects/0000755000175000017500000000000014562742413023001 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/11 wrap imposter/subprojects/zlib.wrap0000644000175000017500000000062313716006331024625 0ustar00jpakkanejpakkane[wrap-file] directory = zlib-1.2.8 source_url = https://zlib.net/zlib-1.2.11.tar.gz source_filename = zlib-1.2.11.tar.gz source_hash = c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1 patch_url = https://wrapdb.mesonbuild.com.invalid/v1/projects/zlib/1.2.11/4/get_zip patch_filename = zlib-1.2.11-4-wrap.zip patch_hash = 886b67480dbe73b406ad83a1dd6d9596f93089d90c220ccfc91944c95f1c68c4././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.4986358 meson-1.3.2/manual tests/12 wrap mirror/0000755000175000017500000000000014562742413020107 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/manual tests/12 wrap mirror/meson.build0000644000175000017500000000017614433154642022253 0ustar00jpakkanejpakkaneproject('downloader') # this test will timeout, showing that a subdomain isn't caught as masquerading url subproject('zlib') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.4986358 meson-1.3.2/manual tests/12 wrap mirror/subprojects/0000755000175000017500000000000014562742413022452 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/12 wrap mirror/subprojects/zlib.wrap0000644000175000017500000000062313716006331024276 0ustar00jpakkanejpakkane[wrap-file] directory = zlib-1.2.8 source_url = https://zlib.net/zlib-1.2.11.tar.gz source_filename = zlib-1.2.11.tar.gz source_hash = c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1 patch_url = https://mirror1.wrapdb.mesonbuild.com/v1/projects/zlib/1.2.11/4/get_zip patch_filename = zlib-1.2.11-4-wrap.zip patch_hash = 886b67480dbe73b406ad83a1dd6d9596f93089d90c220ccfc91944c95f1c68c4././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.506636 meson-1.3.2/manual tests/13 builddir upgrade/0000755000175000017500000000000014562742414021053 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.506636 meson-1.3.2/manual tests/13 builddir upgrade/data/0000755000175000017500000000000014562742414021764 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/manual tests/13 builddir upgrade/data/foo.dat0000644000175000017500000000000014316400150023210 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/manual tests/13 builddir upgrade/foo.10000644000175000017500000000000014316400150021667 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/manual tests/13 builddir upgrade/foo.c0000644000175000017500000000011714316400150021762 0ustar00jpakkanejpakkane#include int main() { printf("Hello world!\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/manual tests/13 builddir upgrade/lib.c0000644000175000017500000000023414316400150021745 0ustar00jpakkanejpakkane#if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllexport) #else #define DLL_PUBLIC #endif int DLL_PUBLIC foo(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/manual tests/13 builddir upgrade/meson.build0000644000175000017500000000111514316400150023174 0ustar00jpakkanejpakkaneproject('check old builddirs in a stable release', 'c') lib = both_libraries('lib', 'lib.c') exe = executable('foo', 'foo.c', link_with: lib, install: true) test('exe', exe) install_data('data/foo.dat', install_dir: get_option('datadir') / 'foo') install_man('foo.1') py = import('python').find_installation() py.install_sources('mod.py', subdir: 'foo') install_subdir('data', install_dir: py.get_install_dir()) custom_target( input: 'mod.py', output: 'hello.dat', command: [py, '@INPUT@'], capture: true, install: true, install_dir: get_option('localstatedir') / 'foo', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/manual tests/13 builddir upgrade/mod.py0000644000175000017500000000002614316400150022163 0ustar00jpakkanejpakkaneprint('Hello world!') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.5106359 meson-1.3.2/manual tests/2 multiwrap/0000755000175000017500000000000014562742414017607 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/2 multiwrap/meson.build0000644000175000017500000000051613716006331021742 0ustar00jpakkanejpakkaneproject('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]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/2 multiwrap/prog.c0000644000175000017500000000273713716006331020722 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.514636 meson-1.3.2/manual tests/2 multiwrap/subprojects/0000755000175000017500000000000014562742414022152 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/2 multiwrap/subprojects/libpng.wrap0000644000175000017500000000066713716006331024320 0ustar00jpakkanejpakkane[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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/2 multiwrap/subprojects/lua.wrap0000644000175000017500000000061213716006331023614 0ustar00jpakkanejpakkane[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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/2 multiwrap/subprojects/zlib.wrap0000644000175000017500000000061713716006331024000 0ustar00jpakkanejpakkane[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 ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.514636 meson-1.3.2/manual tests/3 git wrap/0000755000175000017500000000000014562742414017301 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/manual tests/3 git wrap/meson.build0000644000175000017500000000034614433154642021443 0ustar00jpakkanejpakkaneproject('git 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/3 git wrap/prog.c0000644000175000017500000000011613716006331020401 0ustar00jpakkanejpakkane#include"subproj.h" int main(void) { subproj_function(); return 0; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.514636 meson-1.3.2/manual tests/3 git wrap/subprojects/0000755000175000017500000000000014562742414021644 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/3 git wrap/subprojects/samplesubproject.wrap0000644000175000017500000000015113716006331026105 0ustar00jpakkanejpakkane[wrap-git] directory=samplesubproject url=https://github.com/jpakkane/samplesubproject.git revision=head ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.5346363 meson-1.3.2/manual tests/4 standalone binaries/0000755000175000017500000000000014562742414021472 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/4 standalone binaries/Info.plist0000644000175000017500000000141613716006331023433 0ustar00jpakkanejpakkane 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/4 standalone binaries/build_linux_package.sh0000755000175000017500000000044113716006331026010 0ustar00jpakkanejpakkane#!/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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/4 standalone binaries/build_osx_package.sh0000755000175000017500000000121713716006331025464 0ustar00jpakkanejpakkane#!/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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/4 standalone binaries/build_windows_package.py0000755000175000017500000000206713716006331026367 0ustar00jpakkanejpakkane#!/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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/4 standalone binaries/linux_bundler.sh0000755000175000017500000000030713716006331024672 0ustar00jpakkanejpakkane#!/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"* ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/4 standalone binaries/meson.build0000644000175000017500000000173213716006331023626 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/4 standalone binaries/myapp.cpp0000644000175000017500000000204713716006331023316 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/4 standalone binaries/myapp.icns0000644000175000017500000000344713716006331023475 0ustar00jpakkanejpakkaneicns'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`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/4 standalone binaries/myapp.iss0000644000175000017500000000054213716006331023330 0ustar00jpakkanejpakkane; 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" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/4 standalone binaries/myapp.sh0000755000175000017500000000020513716006331023143 0ustar00jpakkanejpakkane#!/bin/bash cd "${0%/*}" if [ `uname` == 'Darwin' ]; then ./myapp else export LD_LIBRARY_PATH="`pwd`/lib" bin/myapp fi ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/4 standalone binaries/osx_bundler.sh0000755000175000017500000000050513716006331024344 0ustar00jpakkanejpakkane#!/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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/manual tests/4 standalone binaries/readme.txt0000644000175000017500000000073314433154642023470 0ustar00jpakkanejpakkaneThis directory shows how you can build redistributable binaries. On OSX this means 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). ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/4 standalone binaries/template.dmg.gz0000644000175000017500000011067713716006331024420 0ustar00jpakkanejpakkane‹…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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.5466363 meson-1.3.2/manual tests/5 rpm/0000755000175000017500000000000014562742414016364 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/5 rpm/lib.c0000644000175000017500000000010713716006331017263 0ustar00jpakkanejpakkane#include"lib.h" char *meson_print(void) { return "Hello, world!"; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/5 rpm/lib.h0000644000175000017500000000003113716006331017264 0ustar00jpakkanejpakkanechar *meson_print(void); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/5 rpm/main.c0000644000175000017500000000015713716006331017446 0ustar00jpakkanejpakkane#include #include int main(void) { char *t = meson_print(); printf("%s", t); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/5 rpm/meson.build0000644000175000017500000000060613716006331020517 0ustar00jpakkanejpakkaneproject('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() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.5506365 meson-1.3.2/manual tests/6 hg wrap/0000755000175000017500000000000014562742414017117 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/manual tests/6 hg wrap/meson.build0000644000175000017500000000035414433154642021260 0ustar00jpakkanejpakkaneproject('Mercurial 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/6 hg wrap/prog.c0000644000175000017500000000011613716006331020217 0ustar00jpakkanejpakkane#include"subproj.h" int main(void) { subproj_function(); return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.5546365 meson-1.3.2/manual tests/6 hg wrap/subprojects/0000755000175000017500000000000014562742414021462 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/6 hg wrap/subprojects/samplesubproject.wrap0000644000175000017500000000014613716006331025727 0ustar00jpakkanejpakkane[wrap-hg] directory=samplesubproject url=https://bitbucket.org/jpakkane/samplesubproject revision=tip ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.5586367 meson-1.3.2/manual tests/8 timeout/0000755000175000017500000000000014562742414017257 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/8 timeout/meson.build0000644000175000017500000000041313716006331021406 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/manual tests/8 timeout/sleepprog.c0000644000175000017500000000010613716006331021407 0ustar00jpakkanejpakkane#include int main(void) { sleep(1000); return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.5586367 meson-1.3.2/meson.egg-info/0000755000175000017500000000000014562742414015654 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853066.0 meson-1.3.2/meson.egg-info/PKG-INFO0000644000175000017500000000301714562742412016750 0ustar00jpakkanejpakkaneMetadata-Version: 2.1 Name: meson Version: 1.3.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 Project-URL: Source, https://github.com/mesonbuild/meson Keywords: meson,mesonbuild,build system,cmake 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.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Topic :: Software Development :: Build Tools Requires-Python: >=3.7 Provides-Extra: ninja Provides-Extra: progress Provides-Extra: typing License-File: COPYING 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. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853066.0 meson-1.3.2/meson.egg-info/SOURCES.txt0000644000175000017500000066232514562742412017554 0ustar00jpakkanejpakkaneCOPYING MANIFEST.in README.md contributing.md 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/arm64cl.txt cross/armcc.txt cross/armclang-linux.txt cross/armclang.txt cross/c2000.txt cross/ccomp-armv7a.txt cross/ccrx.txt cross/iphone.txt cross/linux-mingw-w64-32bit.json cross/linux-mingw-w64-32bit.txt cross/linux-mingw-w64-64bit.json cross/linux-mingw-w64-64bit.txt cross/metrowerks-arm.txt cross/metrowerks-eppc.txt cross/metrowerks.lcf cross/msp430.txt cross/none.txt cross/ownstdlib.txt cross/tvos.txt cross/ubuntu-armhf.json cross/ubuntu-armhf.txt cross/ubuntu-faketarget.txt cross/wasm.txt cross/xc16.txt data/.coveragerc.in data/com.mesonbuild.install.policy data/macros.meson data/schema.xsd data/test.schema.json data/shell-completions/bash/meson data/shell-completions/zsh/_meson 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/13 builddir upgrade/foo.1 manual tests/13 builddir upgrade/foo.c manual tests/13 builddir upgrade/lib.c manual tests/13 builddir upgrade/meson.build manual tests/13 builddir upgrade/mod.py manual tests/13 builddir upgrade/data/foo.dat 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/8 timeout/meson.build manual tests/8 timeout/sleepprog.c 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/_pathlib.py mesonbuild/_typing.py mesonbuild/arglist.py mesonbuild/build.py mesonbuild/coredata.py mesonbuild/depfile.py mesonbuild/envconfig.py mesonbuild/environment.py mesonbuild/mcompile.py mesonbuild/mconf.py mesonbuild/mdevenv.py mesonbuild/mdist.py mesonbuild/mesondata.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/programs.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/nonebackend.py mesonbuild/backend/vs2010backend.py mesonbuild/backend/vs2012backend.py mesonbuild/backend/vs2013backend.py mesonbuild/backend/vs2015backend.py mesonbuild/backend/vs2017backend.py mesonbuild/backend/vs2019backend.py mesonbuild/backend/vs2022backend.py mesonbuild/backend/xcodebackend.py mesonbuild/cargo/__init__.py mesonbuild/cargo/builder.py mesonbuild/cargo/cfg.py mesonbuild/cargo/interpreter.py mesonbuild/cargo/manifest.py mesonbuild/cargo/version.py mesonbuild/cmake/__init__.py mesonbuild/cmake/common.py mesonbuild/cmake/executor.py mesonbuild/cmake/fileapi.py mesonbuild/cmake/generator.py mesonbuild/cmake/interpreter.py mesonbuild/cmake/toolchain.py mesonbuild/cmake/traceparser.py mesonbuild/cmake/tracetargets.py mesonbuild/cmake/data/__init__.py mesonbuild/cmake/data/preload.cmake mesonbuild/compilers/__init__.py mesonbuild/compilers/asm.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/cython.py mesonbuild/compilers/d.py mesonbuild/compilers/detect.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/compcert.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/metrowerks.py mesonbuild/compilers/mixins/pgi.py mesonbuild/compilers/mixins/ti.py mesonbuild/compilers/mixins/visualstudio.py mesonbuild/compilers/mixins/xc16.py mesonbuild/dependencies/__init__.py mesonbuild/dependencies/base.py mesonbuild/dependencies/boost.py mesonbuild/dependencies/cmake.py mesonbuild/dependencies/coarrays.py mesonbuild/dependencies/configtool.py mesonbuild/dependencies/cuda.py mesonbuild/dependencies/detect.py mesonbuild/dependencies/dev.py mesonbuild/dependencies/dub.py mesonbuild/dependencies/factory.py mesonbuild/dependencies/framework.py mesonbuild/dependencies/hdf5.py mesonbuild/dependencies/misc.py mesonbuild/dependencies/mpi.py mesonbuild/dependencies/pkgconfig.py mesonbuild/dependencies/platform.py mesonbuild/dependencies/python.py mesonbuild/dependencies/qt.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/dependencies/data/__init__.py mesonbuild/interpreter/__init__.py mesonbuild/interpreter/compiler.py mesonbuild/interpreter/dependencyfallbacks.py mesonbuild/interpreter/interpreter.py mesonbuild/interpreter/interpreterobjects.py mesonbuild/interpreter/kwargs.py mesonbuild/interpreter/mesonmain.py mesonbuild/interpreter/type_checking.py mesonbuild/interpreter/primitives/__init__.py mesonbuild/interpreter/primitives/array.py mesonbuild/interpreter/primitives/boolean.py mesonbuild/interpreter/primitives/dict.py mesonbuild/interpreter/primitives/integer.py mesonbuild/interpreter/primitives/range.py mesonbuild/interpreter/primitives/string.py mesonbuild/interpreterbase/__init__.py mesonbuild/interpreterbase/_unholder.py mesonbuild/interpreterbase/baseobjects.py mesonbuild/interpreterbase/decorators.py mesonbuild/interpreterbase/disabler.py mesonbuild/interpreterbase/exceptions.py mesonbuild/interpreterbase/helpers.py mesonbuild/interpreterbase/interpreterbase.py mesonbuild/interpreterbase/operator.py mesonbuild/linkers/__init__.py mesonbuild/linkers/base.py mesonbuild/linkers/detect.py mesonbuild/linkers/linkers.py mesonbuild/modules/__init__.py mesonbuild/modules/cmake.py mesonbuild/modules/cuda.py mesonbuild/modules/dlang.py mesonbuild/modules/external_project.py mesonbuild/modules/fs.py mesonbuild/modules/gnome.py mesonbuild/modules/hotdoc.py mesonbuild/modules/i18n.py mesonbuild/modules/icestorm.py mesonbuild/modules/java.py mesonbuild/modules/keyval.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/qt6.py mesonbuild/modules/rust.py mesonbuild/modules/simd.py mesonbuild/modules/sourceset.py mesonbuild/modules/wayland.py mesonbuild/modules/windows.py mesonbuild/scripts/__init__.py mesonbuild/scripts/clangformat.py mesonbuild/scripts/clangtidy.py mesonbuild/scripts/cleantrees.py mesonbuild/scripts/cmake_run_ctgt.py mesonbuild/scripts/cmd_or_ps.ps1 mesonbuild/scripts/copy.py mesonbuild/scripts/coverage.py mesonbuild/scripts/delwithsuffix.py mesonbuild/scripts/depfixer.py mesonbuild/scripts/depscan.py mesonbuild/scripts/dirchanger.py mesonbuild/scripts/env2mfile.py mesonbuild/scripts/externalproject.py mesonbuild/scripts/gettext.py mesonbuild/scripts/gtkdochelper.py mesonbuild/scripts/hotdochelper.py mesonbuild/scripts/itstool.py mesonbuild/scripts/meson_exe.py mesonbuild/scripts/msgfmthelper.py mesonbuild/scripts/pycompile.py mesonbuild/scripts/python_info.py mesonbuild/scripts/regen_checker.py mesonbuild/scripts/run_tool.py mesonbuild/scripts/scanbuild.py mesonbuild/scripts/symbolextractor.py mesonbuild/scripts/tags.py mesonbuild/scripts/test_loaded_modules.py mesonbuild/scripts/uninstall.py mesonbuild/scripts/vcstagger.py mesonbuild/scripts/yasm.py mesonbuild/templates/__init__.py mesonbuild/templates/cpptemplates.py mesonbuild/templates/cstemplates.py mesonbuild/templates/ctemplates.py mesonbuild/templates/cudatemplates.py mesonbuild/templates/dlangtemplates.py mesonbuild/templates/fortrantemplates.py mesonbuild/templates/javatemplates.py mesonbuild/templates/mesontemplates.py mesonbuild/templates/objcpptemplates.py mesonbuild/templates/objctemplates.py mesonbuild/templates/rusttemplates.py mesonbuild/templates/samplefactory.py mesonbuild/templates/sampleimpl.py mesonbuild/templates/valatemplates.py mesonbuild/utils/__init__.py mesonbuild/utils/core.py mesonbuild/utils/platform.py mesonbuild/utils/posix.py mesonbuild/utils/universal.py mesonbuild/utils/vsenv.py mesonbuild/utils/win32.py mesonbuild/wrap/__init__.py mesonbuild/wrap/wrap.py mesonbuild/wrap/wraptool.py packaging/License.rtf packaging/create_zipapp.py packaging/createmsi.py packaging/createpkg.py packaging/hook-mesonbuild.py packaging/macpages/English.lproj/conclusion.html packaging/macpages/English.lproj/license.html packaging/macpages/English.lproj/welcome.html 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/1 basic/subprojects/cmMod/cpp_pch.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/11 cmake_module_path/subprojects/cmMod/CMakeLists.txt test cases/cmake/11 cmake_module_path/subprojects/cmMod/gen.py test cases/cmake/12 generator expressions/main.cpp test cases/cmake/12 generator expressions/meson.build test cases/cmake/12 generator expressions/test.json 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.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/17 include path order/main.cpp test cases/cmake/17 include path order/meson.build test cases/cmake/17 include path order/subprojects/cmMod/CMakeLists.txt test cases/cmake/17 include path order/subprojects/cmMod/cmMod.cpp test cases/cmake/17 include path order/subprojects/cmMod/incA/cmMod.hpp test cases/cmake/17 include path order/subprojects/cmMod/incB/cmMod.hpp test cases/cmake/17 include path order/subprojects/cmMod/incC/cmMod.hpp test cases/cmake/17 include path order/subprojects/cmMod/incD/cmMod.hpp test cases/cmake/17 include path order/subprojects/cmMod/incE/cmMod.hpp test cases/cmake/17 include path order/subprojects/cmMod/incF/cmMod.hpp test cases/cmake/17 include path order/subprojects/cmMod/incG/cmMod.hpp test cases/cmake/17 include path order/subprojects/cmMod/incH/cmMod.hpp test cases/cmake/17 include path order/subprojects/cmMod/incI/cmMod.hpp test cases/cmake/17 include path order/subprojects/cmMod/incJ/cmMod.hpp test cases/cmake/17 include path order/subprojects/cmMod/incL/cmMod.hpp test cases/cmake/17 include path order/subprojects/cmMod/incM/cmMod.hpp test cases/cmake/17 include path order/subprojects/cmMod/incN/cmMod.hpp test cases/cmake/17 include path order/subprojects/cmMod/incO/cmMod.hpp test cases/cmake/17 include path order/subprojects/cmMod/incP/cmMod.hpp test cases/cmake/18 skip include files/main.cpp test cases/cmake/18 skip include files/meson.build test cases/cmake/18 skip include files/subprojects/cmMod/CMakeLists.txt test cases/cmake/18 skip include files/subprojects/cmMod/cmMod.cpp test cases/cmake/18 skip include files/subprojects/cmMod/cmMod.hpp test cases/cmake/18 skip include files/subprojects/cmMod/fakeInc/CMakeLists.txt test cases/cmake/18 skip include files/subprojects/cmMod/fakeInc/cmModInc1.cpp test cases/cmake/18 skip include files/subprojects/cmMod/fakeInc/cmModInc2.cpp test cases/cmake/18 skip include files/subprojects/cmMod/fakeInc/cmModInc3.cpp test cases/cmake/18 skip include files/subprojects/cmMod/fakeInc/cmModInc4.cpp test cases/cmake/19 advanced options/main.cpp test cases/cmake/19 advanced options/meson.build test cases/cmake/19 advanced options/test.json test cases/cmake/19 advanced options/subprojects/cmOpts/CMakeLists.txt test cases/cmake/19 advanced options/subprojects/cmOpts/cmMod.cpp test cases/cmake/19 advanced options/subprojects/cmOpts/cmMod.hpp test cases/cmake/19 advanced options/subprojects/cmOpts/cmTest.cpp test cases/cmake/19 advanced options/subprojects/cmOpts/cmTest.hpp test cases/cmake/19 advanced options/subprojects/cmOpts/main.cpp test cases/cmake/2 advanced/main.cpp test cases/cmake/2 advanced/meson.build test cases/cmake/2 advanced/test.json 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/20 cmake file/foolib.cmake.in test cases/cmake/20 cmake file/meson.build test cases/cmake/20 cmake file/test.json test cases/cmake/21 shared module/meson.build test cases/cmake/21 shared module/prog.c test cases/cmake/21 shared module/runtime.c test cases/cmake/21 shared module/subprojects/cmMod/CMakeLists.txt test cases/cmake/21 shared module/subprojects/cmMod/module/module.c test cases/cmake/21 shared module/subprojects/cmMod/module/module.h test cases/cmake/22 cmake module/meson.build test cases/cmake/22 cmake module/projectConfig.cmake.in test cases/cmake/22 cmake module/test.json test cases/cmake/22 cmake module/cmake_project/CMakeLists.txt test cases/cmake/23 cmake toolchain/CMakeToolchain.cmake test cases/cmake/23 cmake toolchain/meson.build test cases/cmake/23 cmake toolchain/nativefile.ini.in test cases/cmake/23 cmake toolchain/subprojects/cmMod/CMakeLists.txt test cases/cmake/23 cmake toolchain/subprojects/cmModFortran/CMakeLists.txt test cases/cmake/24 mixing languages/main.c test cases/cmake/24 mixing languages/meson.build test cases/cmake/24 mixing languages/subprojects/cmTest/CMakeLists.txt test cases/cmake/24 mixing languages/subprojects/cmTest/cmTest.c test cases/cmake/24 mixing languages/subprojects/cmTest/cmTest.h test cases/cmake/24 mixing languages/subprojects/cmTest/cmTest.m test cases/cmake/25 assembler/main.c test cases/cmake/25 assembler/meson.build test cases/cmake/25 assembler/subprojects/cmTest/CMakeLists.txt test cases/cmake/25 assembler/subprojects/cmTest/cmTest.c test cases/cmake/25 assembler/subprojects/cmTest/cmTestAsm.s test cases/cmake/26 cmake package prefix dir/cmakePackagePrefixDirConfig.cmake.in test cases/cmake/26 cmake package prefix dir/meson.build test cases/cmake/26 cmake package prefix dir/test.json test cases/cmake/27 dependency fallback/main.cpp test cases/cmake/27 dependency fallback/meson.build test cases/cmake/27 dependency fallback/subprojects/broken_method.wrap test cases/cmake/27 dependency fallback/subprojects/cmMod.wrap test cases/cmake/27 dependency fallback/subprojects/force_cmake.wrap test cases/cmake/27 dependency fallback/subprojects/meson_method.wrap test cases/cmake/27 dependency fallback/subprojects/cmMod/CMakeLists.txt test cases/cmake/27 dependency fallback/subprojects/cmMod/cmMod.cpp test cases/cmake/27 dependency fallback/subprojects/cmMod/cmMod.hpp test cases/cmake/27 dependency fallback/subprojects/cmMod/cpp_pch.hpp test cases/cmake/27 dependency fallback/subprojects/cmake_subp/CMakeLists.txt test cases/cmake/27 dependency fallback/subprojects/force_cmake/CMakeLists.txt test cases/cmake/27 dependency fallback/subprojects/force_cmake/meson.build test cases/cmake/27 dependency fallback/subprojects/meson_subp/meson.build 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/test.json 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/test.json 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/cpyInc.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/genMain.cpp test cases/cmake/8 custom command/subprojects/cmMod/macro_name.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/8 custom command/subprojects/cmMod/cpyTest/cpyTest5.hpp test cases/cmake/8 custom command/subprojects/cmMod/mycpy/.gitkeep 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/foo.fr.1 test cases/common/10 man install/meson.build test cases/common/10 man install/test.json 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 postconf with args/meson.build test cases/common/100 postconf with args/postconf.py test cases/common/100 postconf with args/prog.c test cases/common/100 postconf with args/raw.dat test cases/common/101 testframework options/meson.build test cases/common/101 testframework options/meson_options.txt test cases/common/101 testframework options/test.json test cases/common/102 extract same name/lib.c test cases/common/102 extract same name/main.c test cases/common/102 extract same name/meson.build test cases/common/102 extract same name/src/lib.c test cases/common/103 has header symbol/meson.build test cases/common/104 has arg/meson.build test cases/common/105 generatorcustom/catter.py test cases/common/105 generatorcustom/gen-resx.py test cases/common/105 generatorcustom/gen.c test cases/common/105 generatorcustom/gen.py test cases/common/105 generatorcustom/host.c test cases/common/105 generatorcustom/main.c test cases/common/105 generatorcustom/meson.build test cases/common/105 generatorcustom/res1.txt test cases/common/105 generatorcustom/res2.txt test cases/common/106 multiple dir configure file/meson.build test cases/common/106 multiple dir configure file/subdir/foo.txt test cases/common/106 multiple dir configure file/subdir/meson.build test cases/common/106 multiple dir configure file/subdir/someinput.in test cases/common/107 spaces backslash/comparer-end-notstring.c test cases/common/107 spaces backslash/comparer-end.c test cases/common/107 spaces backslash/comparer.c test cases/common/107 spaces backslash/meson.build test cases/common/107 spaces backslash/asm output/meson.build test cases/common/107 spaces backslash/include/comparer.h test cases/common/108 ternary/meson.build test cases/common/109 custom target capture/data_source.txt test cases/common/109 custom target capture/meson.build test cases/common/109 custom target capture/my_compiler.py test cases/common/109 custom target capture/test.json 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 allgenerate/converter.py test cases/common/110 allgenerate/foobar.cpp.in test cases/common/110 allgenerate/meson.build test cases/common/111 pathjoin/meson.build test cases/common/112 subdir subproject/meson.build test cases/common/112 subdir subproject/prog/meson.build test cases/common/112 subdir subproject/prog/prog.c test cases/common/112 subdir subproject/subprojects/sub/meson.build test cases/common/112 subdir subproject/subprojects/sub/sub.c test cases/common/112 subdir subproject/subprojects/sub/sub.h test cases/common/113 interpreter copy mutable var on assignment/meson.build test cases/common/114 skip/meson.build test cases/common/115 subproject project arguments/exe.c test cases/common/115 subproject project arguments/exe.cpp test cases/common/115 subproject project arguments/meson.build test cases/common/115 subproject project arguments/subprojects/subexe/meson.build test cases/common/115 subproject project arguments/subprojects/subexe/subexe.c test cases/common/116 test skip/meson.build test cases/common/116 test skip/test_skip.c test cases/common/117 shared module/meson.build test cases/common/117 shared module/module.c test cases/common/117 shared module/nosyms.c test cases/common/117 shared module/prog.c test cases/common/117 shared module/runtime.c test cases/common/117 shared module/test.json test cases/common/118 llvm ir and assembly/main.c test cases/common/118 llvm ir and assembly/main.cpp test cases/common/118 llvm ir and assembly/meson.build test cases/common/118 llvm ir and assembly/square-aarch64.S test cases/common/118 llvm ir and assembly/square-arm.S test cases/common/118 llvm ir and assembly/square-x86.S test cases/common/118 llvm ir and assembly/square-x86_64.S test cases/common/118 llvm ir and assembly/square.ll test cases/common/118 llvm ir and assembly/symbol-underscore.h test cases/common/119 cpp and asm/meson.build test cases/common/119 cpp and asm/retval-arm.S test cases/common/119 cpp and asm/retval-x86.S test cases/common/119 cpp and asm/retval-x86_64.S test cases/common/119 cpp and asm/symbol-underscore.h test cases/common/119 cpp and asm/trivial.cc 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/meson.build test cases/common/12 data/runscript.sh test cases/common/12 data/somefile.txt test cases/common/12 data/test.json 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/subdir/data.txt test cases/common/12 data/subprojects/moredata/data.txt test cases/common/12 data/subprojects/moredata/meson.build 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 extract all shared library/extractor.h test cases/common/120 extract all shared library/four.c test cases/common/120 extract all shared library/func1234.def test cases/common/120 extract all shared library/meson.build test cases/common/120 extract all shared library/one.c test cases/common/120 extract all shared library/prog.c test cases/common/120 extract all shared library/three.c test cases/common/120 extract all shared library/two.c test cases/common/121 object only target/meson.build test cases/common/121 object only target/obj_generator.py test cases/common/121 object only target/prog.c test cases/common/121 object only target/source.c test cases/common/121 object only target/source2.c test cases/common/121 object only target/source2.def test cases/common/121 object only target/source3.c test cases/common/121 object only target/test.json test cases/common/121 object only target/objdir/meson.build test cases/common/121 object only target/objdir/source4.c test cases/common/121 object only target/objdir/source5.c test cases/common/121 object only target/objdir/source6.c test cases/common/122 no buildincdir/meson.build test cases/common/122 no buildincdir/prog.c test cases/common/122 no buildincdir/include/header.h test cases/common/123 custom target directory install/docgen.py test cases/common/123 custom target directory install/meson.build test cases/common/123 custom target directory install/test.json test cases/common/124 dependency file generation/main .c test cases/common/124 dependency file generation/meson.build test cases/common/125 configure file in generator/meson.build test cases/common/125 configure file in generator/inc/confdata.in test cases/common/125 configure file in generator/inc/meson.build test cases/common/125 configure file in generator/src/gen.py test cases/common/125 configure file in generator/src/main.c test cases/common/125 configure file in generator/src/meson.build test cases/common/125 configure file in generator/src/source test cases/common/126 generated llvm ir/copyfile.py test cases/common/126 generated llvm ir/main.c test cases/common/126 generated llvm ir/meson.build test cases/common/126 generated llvm ir/square.ll.in test cases/common/127 generated assembly/copyfile.py test cases/common/127 generated assembly/empty.c test cases/common/127 generated assembly/main.c test cases/common/127 generated assembly/meson.build test cases/common/127 generated assembly/square-arm.S.in test cases/common/127 generated assembly/square-x86.S.in test cases/common/127 generated assembly/square-x86_64.S.in test cases/common/127 generated assembly/square.def test cases/common/127 generated assembly/symbol-underscore.h test cases/common/128 build by default targets in tests/main.c test cases/common/128 build by default targets in tests/meson.build test cases/common/128 build by default targets in tests/write_file.py test cases/common/129 build by default/checkexists.py test cases/common/129 build by default/foo.c test cases/common/129 build by default/meson.build test cases/common/129 build by default/mygen.py test cases/common/129 build by default/source.txt 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/linkwhole/lib1.c test cases/common/13 pch/linkwhole/lib2.c test cases/common/13 pch/linkwhole/main.c test cases/common/13 pch/linkwhole/meson.build test cases/common/13 pch/linkwhole/pch1/pch_one.h test cases/common/13 pch/linkwhole/pch2/pch_two.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/13 pch/withIncludeFile/meson.build test cases/common/13 pch/withIncludeFile/prog.c test cases/common/13 pch/withIncludeFile/pch/prog.h test cases/common/130 include order/meson.build test cases/common/130 include order/ordertest.c test cases/common/130 include order/ctsub/copyfile.py test cases/common/130 include order/ctsub/emptyfile.c test cases/common/130 include order/ctsub/main.h test cases/common/130 include order/ctsub/meson.build test cases/common/130 include order/inc1/hdr.h test cases/common/130 include order/inc2/hdr.h test cases/common/130 include order/inc3/meson.build test cases/common/130 include order/inc3/prefer-build-dir-over-src-dir.h test cases/common/130 include order/sub1/main.h test cases/common/130 include order/sub1/meson.build test cases/common/130 include order/sub1/some.c test cases/common/130 include order/sub1/some.h test cases/common/130 include order/sub2/main.h test cases/common/130 include order/sub2/meson.build test cases/common/130 include order/sub3/main.h test cases/common/130 include order/sub3/meson.build test cases/common/130 include order/sub4/main.c test cases/common/130 include order/sub4/main.h test cases/common/130 include order/sub4/meson.build test cases/common/131 override options/four.c test cases/common/131 override options/meson.build test cases/common/131 override options/one.c test cases/common/131 override options/three.c test cases/common/131 override options/two.c test cases/common/132 get define/concat.h test cases/common/132 get define/meson.build test cases/common/132 get define/meson_options.txt test cases/common/132 get define/test.json test cases/common/133 c cpp and asm/main.c test cases/common/133 c cpp and asm/main.cpp test cases/common/133 c cpp and asm/meson.build test cases/common/133 c cpp and asm/retval-arm.S test cases/common/133 c cpp and asm/retval-x86.S test cases/common/133 c cpp and asm/retval-x86_64.S test cases/common/133 c cpp and asm/somelib.c test cases/common/133 c cpp and asm/symbol-underscore.h test cases/common/134 compute int/config.h.in test cases/common/134 compute int/foobar.h test cases/common/134 compute int/meson.build test cases/common/134 compute int/prog.c.in test cases/common/135 custom target object output/meson.build test cases/common/135 custom target object output/obj_generator.py test cases/common/135 custom target object output/objdir/meson.build test cases/common/135 custom target object output/objdir/source.c test cases/common/135 custom target object output/progdir/meson.build test cases/common/135 custom target object output/progdir/prog.c test cases/common/136 empty build file/meson.build test cases/common/136 empty build file/subdir/meson.build test cases/common/137 whole archive/func1.c test cases/common/137 whole archive/func2.c test cases/common/137 whole archive/meson.build test cases/common/137 whole archive/mylib.h test cases/common/137 whole archive/prog.c test cases/common/137 whole archive/exe/meson.build test cases/common/137 whole archive/exe2/meson.build test cases/common/137 whole archive/exe3/meson.build test cases/common/137 whole archive/exe4/meson.build test cases/common/137 whole archive/sh_func2_dep_func1/meson.build test cases/common/137 whole archive/sh_func2_linked_func1/meson.build test cases/common/137 whole archive/sh_func2_transdep_func1/meson.build test cases/common/137 whole archive/sh_only_link_whole/meson.build test cases/common/137 whole archive/st_func1/meson.build test cases/common/137 whole archive/st_func2/meson.build test cases/common/138 C and CPP link/dummy.c test cases/common/138 C and CPP link/foo.c test cases/common/138 C and CPP link/foo.cpp test cases/common/138 C and CPP link/foo.h test cases/common/138 C and CPP link/foo.hpp test cases/common/138 C and CPP link/foobar.c test cases/common/138 C and CPP link/foobar.h test cases/common/138 C and CPP link/meson.build test cases/common/138 C and CPP link/sub.c test cases/common/138 C and CPP link/sub.h test cases/common/139 mesonintrospect from scripts/check_env.py test cases/common/139 mesonintrospect from scripts/check_introspection.py test cases/common/139 mesonintrospect from scripts/meson.build 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/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.json 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 custom target multiple outputs/generator.py test cases/common/140 custom target multiple outputs/meson.build test cases/common/140 custom target multiple outputs/test.json test cases/common/141 special characters/.editorconfig test cases/common/141 special characters/arg-char-test.c test cases/common/141 special characters/arg-string-test.c test cases/common/141 special characters/arg-unquoted-test.c test cases/common/141 special characters/check_quoting.py test cases/common/141 special characters/meson.build test cases/common/141 special characters/test.json test cases/common/142 nested links/meson.build test cases/common/142 nested links/xephyr.c test cases/common/143 list of file sources/foo test cases/common/143 list of file sources/gen.py test cases/common/143 list of file sources/meson.build test cases/common/144 link depends custom target/foo.c test cases/common/144 link depends custom target/make_file.py test cases/common/144 link depends custom target/meson.build test cases/common/145 recursive linking/lib.h test cases/common/145 recursive linking/main.c test cases/common/145 recursive linking/meson.build test cases/common/145 recursive linking/3rdorderdeps/lib.c.in test cases/common/145 recursive linking/3rdorderdeps/main.c.in test cases/common/145 recursive linking/3rdorderdeps/meson.build test cases/common/145 recursive linking/circular/lib1.c test cases/common/145 recursive linking/circular/lib2.c test cases/common/145 recursive linking/circular/lib3.c test cases/common/145 recursive linking/circular/main.c test cases/common/145 recursive linking/circular/meson.build test cases/common/145 recursive linking/circular/prop1.c test cases/common/145 recursive linking/circular/prop2.c test cases/common/145 recursive linking/circular/prop3.c test cases/common/145 recursive linking/edge-cases/libsto.c test cases/common/145 recursive linking/edge-cases/meson.build test cases/common/145 recursive linking/edge-cases/shstmain.c test cases/common/145 recursive linking/edge-cases/stobuilt.c test cases/common/145 recursive linking/edge-cases/stomain.c test cases/common/145 recursive linking/shnodep/lib.c test cases/common/145 recursive linking/shnodep/meson.build test cases/common/145 recursive linking/shshdep/lib.c test cases/common/145 recursive linking/shshdep/meson.build test cases/common/145 recursive linking/shstdep/lib.c test cases/common/145 recursive linking/shstdep/meson.build test cases/common/145 recursive linking/stnodep/lib.c test cases/common/145 recursive linking/stnodep/meson.build test cases/common/145 recursive linking/stshdep/lib.c test cases/common/145 recursive linking/stshdep/meson.build test cases/common/145 recursive linking/ststdep/lib.c test cases/common/145 recursive linking/ststdep/meson.build test cases/common/146 library at root/lib.c test cases/common/146 library at root/meson.build test cases/common/146 library at root/main/main.c test cases/common/146 library at root/main/meson.build test cases/common/147 simd/fallback.c test cases/common/147 simd/meson.build test cases/common/147 simd/simd_avx.c test cases/common/147 simd/simd_avx2.c test cases/common/147 simd/simd_mmx.c test cases/common/147 simd/simd_neon.c test cases/common/147 simd/simd_sse.c test cases/common/147 simd/simd_sse2.c test cases/common/147 simd/simd_sse3.c test cases/common/147 simd/simd_sse41.c test cases/common/147 simd/simd_sse42.c test cases/common/147 simd/simd_ssse3.c test cases/common/147 simd/simdchecker.c test cases/common/147 simd/simdfuncs.h test cases/common/147 simd/include/simdheader.h test cases/common/148 shared module resolving symbol in executable/meson.build test cases/common/148 shared module resolving symbol in executable/module.c test cases/common/148 shared module resolving symbol in executable/prog.c test cases/common/149 dotinclude/dotproc.c test cases/common/149 dotinclude/meson.build test cases/common/149 dotinclude/stdio.h test cases/common/15 if/meson.build test cases/common/15 if/prog.c test cases/common/150 reserved targets/meson.build test cases/common/150 reserved targets/test.c test cases/common/150 reserved targets/all/meson.build test cases/common/150 reserved targets/benchmark/meson.build test cases/common/150 reserved targets/clean/meson.build test cases/common/150 reserved targets/clean-ctlist/meson.build test cases/common/150 reserved targets/clean-gcda/meson.build test cases/common/150 reserved targets/clean-gcno/meson.build test cases/common/150 reserved targets/coverage/meson.build test cases/common/150 reserved targets/coverage-html/meson.build test cases/common/150 reserved targets/coverage-sonarqube/meson.build test cases/common/150 reserved targets/coverage-text/meson.build test cases/common/150 reserved targets/coverage-xml/meson.build test cases/common/150 reserved targets/dist/meson.build test cases/common/150 reserved targets/distcheck/meson.build test cases/common/150 reserved targets/install/meson.build test cases/common/150 reserved targets/phony/meson.build test cases/common/150 reserved targets/reconfigure/meson.build test cases/common/150 reserved targets/runtarget/echo.py test cases/common/150 reserved targets/runtarget/meson.build test cases/common/150 reserved targets/scan-build/meson.build test cases/common/150 reserved targets/test/meson.build test cases/common/150 reserved targets/uninstall/meson.build test cases/common/151 duplicate source names/meson.build test cases/common/151 duplicate source names/dir1/file.c test cases/common/151 duplicate source names/dir1/meson.build test cases/common/151 duplicate source names/dir2/file.c test cases/common/151 duplicate source names/dir2/meson.build test cases/common/151 duplicate source names/dir2/dir1/file.c test cases/common/151 duplicate source names/dir3/file.c test cases/common/151 duplicate source names/dir3/meson.build test cases/common/151 duplicate source names/dir3/dir1/file.c test cases/common/152 index customtarget/check_args.py test cases/common/152 index customtarget/gen_sources.py test cases/common/152 index customtarget/lib.c test cases/common/152 index customtarget/meson.build test cases/common/152 index customtarget/subdir/foo.c test cases/common/152 index customtarget/subdir/meson.build test cases/common/153 wrap file should not failed/meson.build test cases/common/153 wrap file should not failed/src/meson.build test cases/common/153 wrap file should not failed/src/test.c test cases/common/153 wrap file should not failed/src/subprojects/prog.c test cases/common/153 wrap file should not failed/src/subprojects/foo/prog2.c test cases/common/153 wrap file should not failed/subprojects/.gitignore test cases/common/153 wrap file should not failed/subprojects/bar.wrap test cases/common/153 wrap file should not failed/subprojects/foo.wrap test cases/common/153 wrap file should not failed/subprojects/patchdir.wrap test cases/common/153 wrap file should not failed/subprojects/patchfile.wrap test cases/common/153 wrap file should not failed/subprojects/zlib.wrap test cases/common/153 wrap file should not failed/subprojects/bar-1.0/bar.c test cases/common/153 wrap file should not failed/subprojects/bar-1.0/meson.build test cases/common/153 wrap file should not failed/subprojects/foo-1.0/foo.c test cases/common/153 wrap file should not failed/subprojects/foo-1.0/meson.build test cases/common/153 wrap file should not failed/subprojects/foo-1.0-patchdir/foo.c test cases/common/153 wrap file should not failed/subprojects/foo-1.0-patchdir/meson.build test cases/common/153 wrap file should not failed/subprojects/packagecache/foo-1.0-patch.tar.xz test cases/common/153 wrap file should not failed/subprojects/packagecache/foo-1.0.tar.xz test cases/common/153 wrap file should not failed/subprojects/packagecache/zlib-1.2.8-8-wrap.zip test cases/common/153 wrap file should not failed/subprojects/packagecache/zlib-1.2.8.tar.gz test cases/common/153 wrap file should not failed/subprojects/packagefiles/bar-1.0-patch.tar.xz test cases/common/153 wrap file should not failed/subprojects/packagefiles/bar-1.0.tar.xz test cases/common/153 wrap file should not failed/subprojects/packagefiles/foo-1.0/meson.build test cases/common/153 wrap file should not failed/subprojects/packagefiles/patchfile/0001-Change-foo-to-executable.patch test cases/common/153 wrap file should not failed/subprojects/packagefiles/patchfile/0001-Change-return-value-to-43.patch test cases/common/153 wrap file should not failed/subprojects/packagefiles/patchfile/0002-Change-return-value-to-44.patch test cases/common/153 wrap file should not failed/subprojects/zlib-1.2.8/foo.c test cases/common/153 wrap file should not failed/subprojects/zlib-1.2.8/meson.build test cases/common/154 includedir subproj/meson.build test cases/common/154 includedir subproj/prog.c test cases/common/154 includedir subproj/subprojects/inctest/meson.build test cases/common/154 includedir subproj/subprojects/inctest/include/incfile.h test cases/common/155 subproject dir name collision/a.c test cases/common/155 subproject dir name collision/meson.build test cases/common/155 subproject dir name collision/custom_subproject_dir/B/b.c test cases/common/155 subproject dir name collision/custom_subproject_dir/B/meson.build test cases/common/155 subproject dir name collision/custom_subproject_dir/C/c.c test cases/common/155 subproject dir name collision/custom_subproject_dir/C/meson.build test cases/common/155 subproject dir name collision/other_subdir/meson.build test cases/common/155 subproject dir name collision/other_subdir/custom_subproject_dir/other.c test cases/common/156 config tool variable/meson.build test cases/common/157 custom target subdir depend files/copyfile.py test cases/common/157 custom target subdir depend files/meson.build test cases/common/157 custom target subdir depend files/subdir/dep.dat test cases/common/157 custom target subdir depend files/subdir/foo.c.in test cases/common/157 custom target subdir depend files/subdir/meson.build test cases/common/158 disabler/meson.build test cases/common/159 array option/meson.build test cases/common/159 array option/meson_options.txt test cases/common/16 comparison/meson.build test cases/common/16 comparison/prog.c test cases/common/160 custom target template substitution/checkcopy.py test cases/common/160 custom target template substitution/foo.c.in test cases/common/160 custom target template substitution/meson.build test cases/common/161 not-found dependency/meson.build test cases/common/161 not-found dependency/testlib.c test cases/common/161 not-found dependency/sub/meson.build test cases/common/161 not-found dependency/subprojects/trivial/meson.build test cases/common/161 not-found dependency/subprojects/trivial/trivial.c test cases/common/162 subdir if_found/meson.build test cases/common/162 subdir if_found/subdir/meson.build test cases/common/163 default options prefix dependent defaults/meson.build test cases/common/164 dependency factory/meson.build test cases/common/165 get project license/bar.c test cases/common/165 get project license/meson.build test cases/common/166 yield/meson.build test cases/common/166 yield/meson_options.txt test cases/common/166 yield/subprojects/sub/meson.build test cases/common/166 yield/subprojects/sub/meson_options.txt test cases/common/167 subproject nested subproject dirs/meson.build test cases/common/167 subproject nested subproject dirs/prog.c test cases/common/167 subproject nested subproject dirs/contrib/subprojects/alpha/a.c test cases/common/167 subproject nested subproject dirs/contrib/subprojects/alpha/meson.build test cases/common/167 subproject nested subproject dirs/contrib/subprojects/alpha/var/subprojects/wrap_files_might_be_here test cases/common/167 subproject nested subproject dirs/contrib/subprojects/beta/b.c test cases/common/167 subproject nested subproject dirs/contrib/subprojects/beta/meson.build test cases/common/168 preserve gendir/base.inp test cases/common/168 preserve gendir/genprog.py test cases/common/168 preserve gendir/meson.build test cases/common/168 preserve gendir/testprog.c test cases/common/168 preserve gendir/com/mesonbuild/subbie.inp test cases/common/169 source in dep/bar.cpp test cases/common/169 source in dep/foo.c test cases/common/169 source in dep/meson.build test cases/common/169 source in dep/generated/funname test cases/common/169 source in dep/generated/genheader.py test cases/common/169 source in dep/generated/main.c test cases/common/169 source in dep/generated/meson.build test cases/common/17 array/func.c test cases/common/17 array/meson.build test cases/common/17 array/prog.c test cases/common/170 generator link whole/export.h test cases/common/170 generator link whole/generator.py test cases/common/170 generator link whole/main.c test cases/common/170 generator link whole/meson.build test cases/common/170 generator link whole/meson_test_function.tmpl test cases/common/170 generator link whole/pull_meson_test_function.c test cases/common/171 initial c_args/meson.build test cases/common/171 initial c_args/test.json test cases/common/172 identical target name in subproject flat layout/foo.c test cases/common/172 identical target name in subproject flat layout/main.c test cases/common/172 identical target name in subproject flat layout/meson.build test cases/common/172 identical target name in subproject flat layout/subprojects/subproj/foo.c test cases/common/172 identical target name in subproject flat layout/subprojects/subproj/meson.build test cases/common/173 as-needed/config.h test cases/common/173 as-needed/libA.cpp test cases/common/173 as-needed/libA.h test cases/common/173 as-needed/libB.cpp test cases/common/173 as-needed/main.cpp test cases/common/173 as-needed/meson.build test cases/common/174 ndebug if-release enabled/main.c test cases/common/174 ndebug if-release enabled/meson.build test cases/common/175 ndebug if-release disabled/main.c test cases/common/175 ndebug if-release disabled/meson.build test cases/common/176 subproject version/meson.build test cases/common/176 subproject version/subprojects/a/meson.build test cases/common/177 subdir_done/meson.build test cases/common/178 bothlibraries/dummy.py test cases/common/178 bothlibraries/foo.cpp test cases/common/178 bothlibraries/libfile.c test cases/common/178 bothlibraries/main.c test cases/common/178 bothlibraries/main2.c test cases/common/178 bothlibraries/meson.build test cases/common/178 bothlibraries/mylib.h test cases/common/179 escape and unicode/file.c.in test cases/common/179 escape and unicode/file.py test cases/common/179 escape and unicode/find.py test cases/common/179 escape and unicode/fun.c test cases/common/179 escape and unicode/main.c test cases/common/179 escape and unicode/meson.build test cases/common/18 includedir/meson.build test cases/common/18 includedir/include/func.h test cases/common/18 includedir/src/func.c test cases/common/18 includedir/src/meson.build test cases/common/18 includedir/src/prog.c test cases/common/18 includedirxyz/do_not_delete test cases/common/180 has link arg/meson.build test cases/common/181 same target name flat layout/foo.c test cases/common/181 same target name flat layout/main.c test cases/common/181 same target name flat layout/meson.build test cases/common/181 same target name flat layout/subdir/foo.c test cases/common/181 same target name flat layout/subdir/meson.build test cases/common/182 find override/meson.build test cases/common/182 find override/prog-version.py test cases/common/182 find override/otherdir/main.c test cases/common/182 find override/otherdir/main2.c test cases/common/182 find override/otherdir/meson.build test cases/common/182 find override/otherdir/source.desc test cases/common/182 find override/otherdir/source2.desc test cases/common/182 find override/subdir/converter.py test cases/common/182 find override/subdir/gencodegen.py.in test cases/common/182 find override/subdir/meson.build test cases/common/182 find override/subprojects/sub.wrap test cases/common/182 find override/subprojects/sub2.wrap test cases/common/182 find override/subprojects/sub/meson.build test cases/common/182 find override/subprojects/sub2/meson.build test cases/common/182 find override/subprojects/sub2/prog-version.py test cases/common/183 partial dependency/meson.build test cases/common/183 partial dependency/declare_dependency/main.c test cases/common/183 partial dependency/declare_dependency/meson.build test cases/common/183 partial dependency/declare_dependency/other.c test cases/common/183 partial dependency/declare_dependency/headers/foo.c test cases/common/183 partial dependency/declare_dependency/headers/foo.h test cases/common/184 openmp/main.c test cases/common/184 openmp/main.cpp test cases/common/184 openmp/main.f90 test cases/common/184 openmp/meson.build test cases/common/185 same target name/file.c test cases/common/185 same target name/meson.build test cases/common/185 same target name/sub/file2.c test cases/common/185 same target name/sub/meson.build test cases/common/186 test depends/gen.py test cases/common/186 test depends/main.c test cases/common/186 test depends/meson.build test cases/common/186 test depends/test.py test cases/common/187 args flattening/meson.build test cases/common/188 dict/meson.build test cases/common/188 dict/prog.c test cases/common/189 check header/meson.build test cases/common/189 check header/ouagadougou.h test cases/common/19 header in file list/header.h test cases/common/19 header in file list/meson.build test cases/common/19 header in file list/prog.c test cases/common/190 install_mode/config.h.in test cases/common/190 install_mode/data_source.txt test cases/common/190 install_mode/foo.1 test cases/common/190 install_mode/meson.build test cases/common/190 install_mode/rootdir.h test cases/common/190 install_mode/runscript.sh test cases/common/190 install_mode/stat.c test cases/common/190 install_mode/test.json test cases/common/190 install_mode/trivial.c test cases/common/190 install_mode/sub1/second.dat test cases/common/190 install_mode/sub2/stub test cases/common/191 subproject array version/meson.build test cases/common/191 subproject array version/subprojects/foo/meson.build test cases/common/192 feature option/meson.build test cases/common/192 feature option/meson_options.txt test cases/common/193 feature option disabled/meson.build test cases/common/193 feature option disabled/meson_options.txt test cases/common/194 static threads/lib1.c test cases/common/194 static threads/lib2.c test cases/common/194 static threads/meson.build test cases/common/194 static threads/prog.c test cases/common/195 generator in subdir/meson.build test cases/common/195 generator in subdir/com/mesonbuild/meson.build test cases/common/195 generator in subdir/com/mesonbuild/subbie.inp test cases/common/195 generator in subdir/com/mesonbuild/testprog.c test cases/common/195 generator in subdir/com/mesonbuild/tooldir/genprog.py test cases/common/196 subproject with features/meson.build test cases/common/196 subproject with features/meson_options.txt test cases/common/196 subproject with features/nothing.c test cases/common/196 subproject with features/subprojects/auto_sub_with_missing_dep/meson.build test cases/common/196 subproject with features/subprojects/disabled_sub/meson.build test cases/common/196 subproject with features/subprojects/disabled_sub/lib/meson.build test cases/common/196 subproject with features/subprojects/disabled_sub/lib/sub.c test cases/common/196 subproject with features/subprojects/disabled_sub/lib/sub.h test cases/common/196 subproject with features/subprojects/sub/meson.build test cases/common/196 subproject with features/subprojects/sub/lib/meson.build test cases/common/196 subproject with features/subprojects/sub/lib/sub.c test cases/common/196 subproject with features/subprojects/sub/lib/sub.h test cases/common/197 function attributes/meson.build test cases/common/197 function attributes/meson_options.txt test cases/common/197 function attributes/test.json test cases/common/198 broken subproject/meson.build test cases/common/198 broken subproject/subprojects/broken/broken.c test cases/common/198 broken subproject/subprojects/broken/meson.build test cases/common/199 argument syntax/meson.build test cases/common/2 cpp/VERSIONFILE test cases/common/2 cpp/cpp.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 global arg/meson.build test cases/common/20 global arg/prog.c test cases/common/20 global arg/prog.cc test cases/common/200 install name_prefix name_suffix/libfile.c test cases/common/200 install name_prefix name_suffix/meson.build test cases/common/200 install name_prefix name_suffix/test.json test cases/common/201 kwarg entry/meson.build test cases/common/201 kwarg entry/prog.c test cases/common/201 kwarg entry/test.json test cases/common/201 kwarg entry/inc/prog.h test cases/common/202 custom target build by default/docgen.py test cases/common/202 custom target build by default/meson.build test cases/common/202 custom target build by default/test.json test cases/common/203 find_library and headers/foo.h test cases/common/203 find_library and headers/meson.build test cases/common/204 line continuation/meson.build test cases/common/205 native file path override/main.cpp test cases/common/205 native file path override/meson.build test cases/common/205 native file path override/nativefile.ini test cases/common/205 native file path override/test.json test cases/common/206 tap tests/cat.c test cases/common/206 tap tests/issue7515.txt test cases/common/206 tap tests/meson.build test cases/common/206 tap tests/tester.c test cases/common/207 warning level 0/main.cpp test cases/common/207 warning level 0/meson.build test cases/common/208 link custom/custom_stlib.py test cases/common/208 link custom/custom_target.c test cases/common/208 link custom/custom_target.py test cases/common/208 link custom/dummy.c test cases/common/208 link custom/lib.c test cases/common/208 link custom/meson.build test cases/common/208 link custom/outerlib.c test cases/common/208 link custom/prog.c test cases/common/209 link custom_i single from multiple/generate_conflicting_stlibs.py test cases/common/209 link custom_i single from multiple/meson.build test cases/common/209 link custom_i single from multiple/prog.c test cases/common/21 target arg/func.c test cases/common/21 target arg/func2.c test cases/common/21 target arg/meson.build test cases/common/21 target arg/prog.cc test cases/common/21 target arg/prog2.cc test cases/common/210 link custom_i multiple from multiple/generate_stlibs.py test cases/common/210 link custom_i multiple from multiple/meson.build test cases/common/210 link custom_i multiple from multiple/prog.c test cases/common/211 dependency get_variable method/meson.build test cases/common/211 dependency get_variable method/test.json test cases/common/212 source set configuration_data/a.c test cases/common/212 source set configuration_data/all.h test cases/common/212 source set configuration_data/f.c test cases/common/212 source set configuration_data/g.c test cases/common/212 source set configuration_data/meson.build test cases/common/212 source set configuration_data/nope.c test cases/common/212 source set configuration_data/subdir/b.c test cases/common/212 source set configuration_data/subdir/meson.build test cases/common/213 source set dictionary/a.c test cases/common/213 source set dictionary/all.h test cases/common/213 source set dictionary/f.c test cases/common/213 source set dictionary/g.c test cases/common/213 source set dictionary/meson.build test cases/common/213 source set dictionary/nope.c test cases/common/213 source set dictionary/subdir/b.c test cases/common/213 source set dictionary/subdir/meson.build test cases/common/214 source set custom target/a.c test cases/common/214 source set custom target/all.h test cases/common/214 source set custom target/cp.py test cases/common/214 source set custom target/f.c test cases/common/214 source set custom target/g.c test cases/common/214 source set custom target/meson.build test cases/common/215 source set realistic example/common.h test cases/common/215 source set realistic example/dummy.cpp test cases/common/215 source set realistic example/main.cc test cases/common/215 source set realistic example/meson.build test cases/common/215 source set realistic example/not-found.cc test cases/common/215 source set realistic example/was-found.cc test cases/common/215 source set realistic example/zlib.cc test cases/common/215 source set realistic example/boards/meson.build test cases/common/215 source set realistic example/boards/arm/aarch64.cc test cases/common/215 source set realistic example/boards/arm/arm.cc test cases/common/215 source set realistic example/boards/arm/arm.h test cases/common/215 source set realistic example/boards/arm/arm32.cc test cases/common/215 source set realistic example/boards/arm/versatilepb.cc test cases/common/215 source set realistic example/boards/arm/virt.cc test cases/common/215 source set realistic example/boards/arm/xlnx_zcu102.cc test cases/common/215 source set realistic example/boards/x86/pc.cc test cases/common/215 source set realistic example/config/aarch64 test cases/common/215 source set realistic example/config/arm test cases/common/215 source set realistic example/config/x86 test cases/common/215 source set realistic example/devices/meson.build test cases/common/215 source set realistic example/devices/virtio-mmio.cc test cases/common/215 source set realistic example/devices/virtio-pci.cc test cases/common/215 source set realistic example/devices/virtio.cc test cases/common/215 source set realistic example/devices/virtio.h test cases/common/216 custom target input extracted objects/check_object.py test cases/common/216 custom target input extracted objects/meson.build test cases/common/216 custom target input extracted objects/libdir/gen.py test cases/common/216 custom target input extracted objects/libdir/meson.build test cases/common/216 custom target input extracted objects/libdir/source.c test cases/common/217 test priorities/meson.build test cases/common/217 test priorities/testprog.py test cases/common/218 include_dir dot/meson.build test cases/common/218 include_dir dot/rone.h test cases/common/218 include_dir dot/src/main.c test cases/common/218 include_dir dot/src/meson.build test cases/common/218 include_dir dot/src/rone.c test cases/common/219 include_type dependency/main.cpp test cases/common/219 include_type dependency/meson.build test cases/common/219 include_type dependency/pch/test.hpp test cases/common/219 include_type dependency/subprojects/subDep/meson.build test cases/common/22 object extraction/check-obj.py test cases/common/22 object extraction/create-source.py test cases/common/22 object extraction/header.h test cases/common/22 object extraction/lib.c test cases/common/22 object extraction/lib2.c test cases/common/22 object extraction/main.c test cases/common/22 object extraction/meson.build test cases/common/22 object extraction/src/lib.c test cases/common/220 fs module/meson.build test cases/common/220 fs module/subdir/btgt.c test cases/common/220 fs module/subdir/meson.build test cases/common/220 fs module/subdir/subdirfile.txt test cases/common/220 fs module/subprojects/subbie/meson.build test cases/common/220 fs module/subprojects/subbie/subprojectfile.txt test cases/common/220 fs module/subprojects/subbie/subsub/meson.build test cases/common/220 fs module/subprojects/subbie/subsub/subsubfile.txt test cases/common/221 zlib/meson.build test cases/common/222 native prop/crossfile.ini test cases/common/222 native prop/meson.build test cases/common/222 native prop/nativefile.ini test cases/common/223 persubproject options/foo.c test cases/common/223 persubproject options/main.cpp test cases/common/223 persubproject options/meson.build test cases/common/223 persubproject options/test.json test cases/common/223 persubproject options/subprojects/sub1/foo.c test cases/common/223 persubproject options/subprojects/sub1/meson.build test cases/common/223 persubproject options/subprojects/sub2/foo.c test cases/common/223 persubproject options/subprojects/sub2/foo.cpp test cases/common/223 persubproject options/subprojects/sub2/meson.build test cases/common/224 arithmetic operators/meson.build test cases/common/225 link language/c_linkage.cpp test cases/common/225 link language/c_linkage.h test cases/common/225 link language/lib.cpp test cases/common/225 link language/main.c test cases/common/225 link language/meson.build test cases/common/226 link depends indexed custom target/check_arch.py test cases/common/226 link depends indexed custom target/foo.c test cases/common/226 link depends indexed custom target/make_file.py test cases/common/226 link depends indexed custom target/meson.build test cases/common/227 very long command line/codegen.py test cases/common/227 very long command line/main.c test cases/common/227 very long command line/meson.build test cases/common/227 very long command line/name_gen.py test cases/common/228 custom_target source/a test cases/common/228 custom_target source/meson.build test cases/common/228 custom_target source/x.py test cases/common/229 disabler array addition/meson.build test cases/common/229 disabler array addition/test.c test cases/common/23 endian/meson.build test cases/common/23 endian/prog.c test cases/common/230 external project/app.c test cases/common/230 external project/func.c test cases/common/230 external project/func.h test cases/common/230 external project/meson.build test cases/common/230 external project/test.json test cases/common/230 external project/libfoo/configure test cases/common/230 external project/libfoo/libfoo.c test cases/common/230 external project/libfoo/libfoo.h test cases/common/230 external project/libfoo/meson.build test cases/common/231 subdir files/meson.build test cases/common/231 subdir files/subdir/meson.build test cases/common/231 subdir files/subdir/prog.c test cases/common/232 dependency allow_fallback/meson.build test cases/common/232 dependency allow_fallback/subprojects/foob/meson.build test cases/common/232 dependency allow_fallback/subprojects/foob3/meson.build test cases/common/233 wrap case/meson.build test cases/common/233 wrap case/prog.c test cases/common/233 wrap case/subprojects/up_down.wrap test cases/common/233 wrap case/subprojects/up_down/meson.build test cases/common/233 wrap case/subprojects/up_down/up_down.h test cases/common/234 get_file_contents/.gitattributes test cases/common/234 get_file_contents/VERSION test cases/common/234 get_file_contents/meson.build test cases/common/234 get_file_contents/utf-16-text test cases/common/234 get_file_contents/other/meson.build test cases/common/235 invalid standard overridden to valid/main.c test cases/common/235 invalid standard overridden to valid/meson.build test cases/common/235 invalid standard overridden to valid/test.json test cases/common/236 proper args splitting/main.c test cases/common/236 proper args splitting/meson.build test cases/common/236 proper args splitting/test.json test cases/common/237 fstrings/meson.build test cases/common/238 dependency include_type inconsistency/meson.build test cases/common/238 dependency include_type inconsistency/bar/meson.build test cases/common/238 dependency include_type inconsistency/subprojects/baz.wrap test cases/common/238 dependency include_type inconsistency/subprojects/foo.wrap test cases/common/238 dependency include_type inconsistency/subprojects/baz/meson.build test cases/common/238 dependency include_type inconsistency/subprojects/foo/meson.build test cases/common/239 includedir violation/meson.build test cases/common/239 includedir violation/test.json test cases/common/239 includedir violation/subprojects/sub/meson.build test cases/common/239 includedir violation/subprojects/sub/include/placeholder.h test cases/common/24 library versions/lib.c test cases/common/24 library versions/meson.build test cases/common/24 library versions/test.json test cases/common/24 library versions/subdir/meson.build test cases/common/240 dependency native host == build/meson.build test cases/common/240 dependency native host == build/test.json test cases/common/241 set and get variable/meson.build test cases/common/241 set and get variable/test1.txt test cases/common/241 set and get variable/test2.txt test cases/common/242 custom target feed/data_source.txt test cases/common/242 custom target feed/meson.build test cases/common/242 custom target feed/my_compiler.py test cases/common/242 custom target feed/test.json test cases/common/243 escape++/meson.build test cases/common/243 escape++/test.c test cases/common/244 variable scope/meson.build test cases/common/245 custom target index source/code_source.c test cases/common/245 custom target index source/copyfile.py test cases/common/245 custom target index source/copyfile2.py test cases/common/245 custom target index source/header_source.h test cases/common/245 custom target index source/main.c test cases/common/245 custom target index source/meson.build test cases/common/246 dependency fallbacks/meson.build test cases/common/246 dependency fallbacks/subprojects/png/meson.build test cases/common/247 deprecated option/meson.build test cases/common/247 deprecated option/meson_options.txt test cases/common/247 deprecated option/test.json test cases/common/248 install_emptydir/meson.build test cases/common/248 install_emptydir/test.json test cases/common/249 install_symlink/datafile.dat test cases/common/249 install_symlink/meson.build test cases/common/249 install_symlink/test.json test cases/common/25 config subdir/meson.build test cases/common/25 config subdir/include/config.h.in test cases/common/25 config subdir/include/meson.build test cases/common/25 config subdir/src/meson.build test cases/common/25 config subdir/src/prog.c test cases/common/250 system include dir/main.cpp test cases/common/250 system include dir/meson.build test cases/common/250 system include dir/lib/lib.hpp test cases/common/251 add_project_dependencies/lib.c test cases/common/251 add_project_dependencies/main.c test cases/common/251 add_project_dependencies/meson.build test cases/common/251 add_project_dependencies/inc/lib.h test cases/common/252 install data structured/meson.build test cases/common/252 install data structured/test.json test cases/common/252 install data structured/dir1/bad test cases/common/252 install data structured/dir1/file1 test cases/common/252 install data structured/dir1/file2 test cases/common/252 install data structured/dir1/file3 test cases/common/252 install data structured/dir2/bad test cases/common/252 install data structured/dir2/file1 test cases/common/252 install data structured/dir2/file2 test cases/common/252 install data structured/dir2/file3 test cases/common/252 install data structured/dir3/bad test cases/common/252 install data structured/dir3/file1 test cases/common/252 install data structured/dir3/file2 test cases/common/252 install data structured/dir3/file3 test cases/common/252 install data structured/pysrc/__init__.py test cases/common/252 install data structured/pysrc/bad.py test cases/common/252 install data structured/pysrc/bar.py test cases/common/252 install data structured/pysrc/foo.py test cases/common/252 install data structured/pysrc/meson.build test cases/common/252 install data structured/pysrc/submod/__init__.py test cases/common/252 install data structured/pysrc/submod/bad.py test cases/common/252 install data structured/pysrc/submod/baz.py test cases/common/253 subproject dependency variables/meson.build test cases/common/253 subproject dependency variables/test.json test cases/common/253 subproject dependency variables/subprojects/subfiles/foo.c test cases/common/253 subproject dependency variables/subprojects/subfiles/meson.build test cases/common/253 subproject dependency variables/subprojects/subfiles/subdir/foo.c test cases/common/253 subproject dependency variables/subprojects/subfiles/subdir2/foo.c test cases/common/254 long output/dumper.c test cases/common/254 long output/meson.build test cases/common/255 module warnings/meson.build test cases/common/255 module warnings/test.json test cases/common/256 subproject extracted objects/foo.c test cases/common/256 subproject extracted objects/meson.build test cases/common/256 subproject extracted objects/test.json test cases/common/256 subproject extracted objects/subprojects/myobjects/cpplib.cpp test cases/common/256 subproject extracted objects/subprojects/myobjects/cpplib.h test cases/common/256 subproject extracted objects/subprojects/myobjects/meson.build test cases/common/257 generated header dep/foo.c test cases/common/257 generated header dep/meson.build test cases/common/258 subsubproject inplace/meson.build test cases/common/258 subsubproject inplace/subprojects/sub/meson.build test cases/common/258 subsubproject inplace/subprojects/sub/subprojects/subsub.wrap test cases/common/258 subsubproject inplace/subprojects/sub/subprojects/subsub-1.0/meson.build test cases/common/259 preprocess/bar.c test cases/common/259 preprocess/foo.c test cases/common/259 preprocess/foo.h test cases/common/259 preprocess/math.c test cases/common/259 preprocess/meson.build test cases/common/259 preprocess/src/file.map.in test cases/common/259 preprocess/src/meson.build test cases/common/26 find program/meson.build test cases/common/26 find program/print-version-with-prefix.py test cases/common/26 find program/print-version.py test cases/common/26 find program/source.in test cases/common/26 find program/scripts/test_subdir.py test cases/common/260 declare_dependency objects/bar.c test cases/common/260 declare_dependency objects/foo.c test cases/common/260 declare_dependency objects/meson.build test cases/common/260 declare_dependency objects/prog.c test cases/common/261 testcase clause/meson.build test cases/common/261 testcase clause/test.json test cases/common/262 generator chain/data.txt test cases/common/262 generator chain/meson.build test cases/common/262 generator chain/stage1.py test cases/common/262 generator chain/stage2.py test cases/common/263 internal dependency includes in checks/meson.build test cases/common/263 internal dependency includes in checks/include/test_262_header.h test cases/common/264 required keyword in has functions/meson.build test cases/common/264 required keyword in has functions/meson_options.txt test cases/common/265 default_options dict/lib.c test cases/common/265 default_options dict/meson.build test cases/common/265 default_options dict/meson_options.txt test cases/common/266 format string/meson.build test cases/common/266 format string/meson_options.txt test cases/common/266 format string/test.json test cases/common/267 default_options in find_program/meson.build test cases/common/267 default_options in find_program/subprojects/dummy.wrap test cases/common/267 default_options in find_program/subprojects/dummy/dummy.c test cases/common/267 default_options in find_program/subprojects/dummy/meson.build test cases/common/267 default_options in find_program/subprojects/dummy/meson_options.txt test cases/common/268 install functions and follow symlinks/meson.build test cases/common/268 install functions and follow symlinks/test.json test cases/common/268 install functions and follow symlinks/foo/file1 test cases/common/269 configure file output format/compare.py test cases/common/269 configure file output format/meson.build test cases/common/269 configure file output format/expected/config.h test cases/common/269 configure file output format/expected/config.json test cases/common/269 configure file output format/expected/config.mg test cases/common/269 configure file output format/expected/config.nasm test cases/common/27 multiline string/meson.build test cases/common/270 int_to_str_fill/meson.build test cases/common/271 env in generator.process/generate_main.py test cases/common/271 env in generator.process/main.template test cases/common/271 env in generator.process/meson.build test cases/common/272 unity/meson.build test cases/common/272 unity/slib.c test cases/common/272 unity/slib1.c test cases/common/272 unity/slib2.c test cases/common/272 unity/test.json test cases/common/28 try compile/foo.h.in test cases/common/28 try compile/invalid.c test cases/common/28 try compile/meson.build test cases/common/28 try compile/valid.c test cases/common/29 compiler id/meson.build test cases/common/3 static/lib3.c 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 sizeof/config.h.in test cases/common/30 sizeof/meson.build test cases/common/30 sizeof/prog.c.in test cases/common/31 define10/config.h.in test cases/common/31 define10/meson.build test cases/common/31 define10/prog.c test cases/common/32 has header/meson.build test cases/common/32 has header/ouagadougou.h test cases/common/33 run program/check-env.py test cases/common/33 run program/get-version.py test cases/common/33 run program/meson.build test cases/common/33 run program/test.json test cases/common/33 run program/scripts/hello.bat test cases/common/33 run program/scripts/hello.sh test cases/common/34 logic ops/meson.build test cases/common/35 string operations/meson.build test cases/common/36 has function/meson.build test cases/common/37 has member/meson.build test cases/common/38 alignment/meson.build test cases/common/39 library chain/main.c test cases/common/39 library chain/meson.build test cases/common/39 library chain/test.json test cases/common/39 library chain/subdir/lib1.c test cases/common/39 library chain/subdir/meson.build test cases/common/39 library chain/subdir/subdir2/lib2.c test cases/common/39 library chain/subdir/subdir2/meson.build test cases/common/39 library chain/subdir/subdir3/lib3.c test cases/common/39 library chain/subdir/subdir3/meson.build test cases/common/4 shared/libfile.c test cases/common/4 shared/libfile2.c test cases/common/4 shared/meson.build test cases/common/40 options/meson.build test cases/common/40 options/meson_options.txt test cases/common/40 options/test.json test cases/common/41 test args/cmd_args.c test cases/common/41 test args/copyfile.py test cases/common/41 test args/env2vars.c test cases/common/41 test args/envvars.c test cases/common/41 test args/meson.build test cases/common/41 test args/tester.c test cases/common/41 test args/tester.py test cases/common/41 test args/testfile.txt test cases/common/42 subproject/meson.build test cases/common/42 subproject/mylicense.txt test cases/common/42 subproject/test.json test cases/common/42 subproject/user.c test cases/common/42 subproject/subprojects/sublib/meson.build test cases/common/42 subproject/subprojects/sublib/simpletest.c test cases/common/42 subproject/subprojects/sublib/sublib.c test cases/common/42 subproject/subprojects/sublib/sublicense1.txt test cases/common/42 subproject/subprojects/sublib/sublicense2.txt test cases/common/42 subproject/subprojects/sublib/include/subdefs.h test cases/common/43 subproject options/meson.build test cases/common/43 subproject options/meson_options.txt test cases/common/43 subproject options/subprojects/subproject/meson.build test cases/common/43 subproject options/subprojects/subproject/meson_options.txt test cases/common/44 pkgconfig-gen/answer.c test cases/common/44 pkgconfig-gen/foo.c test cases/common/44 pkgconfig-gen/meson.build test cases/common/44 pkgconfig-gen/simple.c test cases/common/44 pkgconfig-gen/simple.h test cases/common/44 pkgconfig-gen/simple5.c test cases/common/44 pkgconfig-gen/test.json test cases/common/44 pkgconfig-gen/dependencies/custom.c test cases/common/44 pkgconfig-gen/dependencies/dummy.c test cases/common/44 pkgconfig-gen/dependencies/exposed.c test cases/common/44 pkgconfig-gen/dependencies/internal.c test cases/common/44 pkgconfig-gen/dependencies/main.c test cases/common/44 pkgconfig-gen/dependencies/meson.build test cases/common/44 pkgconfig-gen/dependencies/test2.c test cases/common/44 pkgconfig-gen/inc1/inc1.h test cases/common/44 pkgconfig-gen/inc2/inc2.h test cases/common/45 custom install dirs/datafile.cat test cases/common/45 custom install dirs/meson.build test cases/common/45 custom install dirs/prog.1 test cases/common/45 custom install dirs/prog.c test cases/common/45 custom install dirs/sample.h test cases/common/45 custom install dirs/test.json test cases/common/45 custom install dirs/subdir/datafile.dog test cases/common/46 subproject subproject/meson.build test cases/common/46 subproject subproject/prog.c test cases/common/46 subproject subproject/subprojects/a/a.c test cases/common/46 subproject subproject/subprojects/a/meson.build test cases/common/46 subproject subproject/subprojects/b/b.c test cases/common/46 subproject subproject/subprojects/b/meson.build test cases/common/46 subproject subproject/subprojects/c/meson.build test cases/common/47 same file name/meson.build test cases/common/47 same file name/prog.c test cases/common/47 same file name/d1/file.c test cases/common/47 same file name/d2/file.c test cases/common/48 file grabber/a.c test cases/common/48 file grabber/b.c test cases/common/48 file grabber/c.c test cases/common/48 file grabber/grabber.bat test cases/common/48 file grabber/grabber.sh test cases/common/48 file grabber/grabber2.bat test cases/common/48 file grabber/meson.build test cases/common/48 file grabber/prog.c test cases/common/48 file grabber/subdir/meson.build test cases/common/48 file grabber/subdir/suba.c test cases/common/48 file grabber/subdir/subb.c test cases/common/48 file grabber/subdir/subc.c test cases/common/48 file grabber/subdir/subprog.c test cases/common/49 custom target/data_source.txt test cases/common/49 custom target/meson.build test cases/common/49 custom target/my_compiler.py test cases/common/49 custom target/test.json test cases/common/49 custom target/depfile/dep.py test cases/common/49 custom target/depfile/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 custom target chain/data_source.txt test cases/common/50 custom target chain/meson.build test cases/common/50 custom target chain/my_compiler.py test cases/common/50 custom target chain/my_compiler2.py test cases/common/50 custom target chain/test.json test cases/common/50 custom target chain/usetarget/meson.build test cases/common/50 custom target chain/usetarget/myexe.c test cases/common/50 custom target chain/usetarget/subcomp.py test cases/common/51 run target/.clang-format test cases/common/51 run target/.clang-tidy test cases/common/51 run target/check-env.py test cases/common/51 run target/check_exists.py test cases/common/51 run target/configure.in test cases/common/51 run target/converter.py test cases/common/51 run target/fakeburner.py test cases/common/51 run target/helloprinter.c test cases/common/51 run target/meson.build test cases/common/51 run target/subdir/textprinter.py test cases/common/52 object generator/meson.build test cases/common/52 object generator/obj_generator.py test cases/common/52 object generator/prog.c test cases/common/52 object generator/source.c test cases/common/52 object generator/source2.c test cases/common/52 object generator/source3.c test cases/common/52 object generator/source4.c test cases/common/53 install script/customtarget.py test cases/common/53 install script/meson.build test cases/common/53 install script/myinstall.py test cases/common/53 install script/prog.c test cases/common/53 install script/test.json test cases/common/53 install script/src/a file.txt test cases/common/53 install script/src/foo.c test cases/common/53 install script/src/meson.build test cases/common/53 install script/src/myinstall.py test cases/common/54 custom target source output/generator.py test cases/common/54 custom target source output/main.c test cases/common/54 custom target source output/meson.build test cases/common/55 exe static shared/meson.build test cases/common/55 exe static shared/prog.c test cases/common/55 exe static shared/shlib2.c test cases/common/55 exe static shared/stat.c test cases/common/55 exe static shared/stat2.c test cases/common/55 exe static shared/subdir/exports.h test cases/common/55 exe static shared/subdir/meson.build test cases/common/55 exe static shared/subdir/shlib.c test cases/common/56 array methods/a.txt test cases/common/56 array methods/b.txt test cases/common/56 array methods/c.txt test cases/common/56 array methods/meson.build test cases/common/57 custom header generator/input.def test cases/common/57 custom header generator/makeheader.py test cases/common/57 custom header generator/meson.build test cases/common/57 custom header generator/prog.c test cases/common/57 custom header generator/somefile.txt test cases/common/58 multiple generators/data2.dat test cases/common/58 multiple generators/main.cpp test cases/common/58 multiple generators/meson.build test cases/common/58 multiple generators/mygen.py test cases/common/58 multiple generators/subdir/data.dat test cases/common/58 multiple generators/subdir/meson.build test cases/common/59 install subdir/meson.build test cases/common/59 install subdir/test.json test cases/common/59 install subdir/nested_elided/sub/eighth.dat test cases/common/59 install subdir/nested_elided/sub/dircheck/ninth.dat test cases/common/59 install subdir/sub/sub1/third.dat test cases/common/59 install subdir/sub1/second.dat test cases/common/59 install subdir/sub2/excluded-three.dat test cases/common/59 install subdir/sub2/one.dat test cases/common/59 install subdir/sub2/dircheck/excluded-three.dat test cases/common/59 install subdir/sub2/excluded/two.dat test cases/common/59 install subdir/sub3/data/data.txt test cases/common/59 install subdir/sub3/data/excluded.txt test cases/common/59 install subdir/sub3/data/excluded/excluded.txt test cases/common/59 install subdir/sub_elided/fourth.dat test cases/common/59 install subdir/sub_elided/dircheck/fifth.dat test cases/common/59 install subdir/subdir/meson.build test cases/common/59 install subdir/subdir/sub1/data1.dat test cases/common/59 install subdir/subdir/sub1/sub2/data2.dat test cases/common/59 install subdir/subdir/sub_elided/sixth.dat test cases/common/59 install subdir/subdir/sub_elided/dircheck/seventh.dat test cases/common/6 linkshared/cpplib.cpp test cases/common/6 linkshared/cpplib.h test cases/common/6 linkshared/cppmain.cpp test cases/common/6 linkshared/libfile.c test cases/common/6 linkshared/main.c test cases/common/6 linkshared/meson.build test cases/common/6 linkshared/test.json test cases/common/60 foreach/meson.build test cases/common/60 foreach/prog1.c test cases/common/60 foreach/prog2.c test cases/common/60 foreach/prog3.c test cases/common/60 foreach/test.json test cases/common/61 number arithmetic/meson.build test cases/common/62 string arithmetic/meson.build test cases/common/62 string arithmetic/test.json test cases/common/63 array arithmetic/meson.build test cases/common/64 arithmetic bidmas/meson.build test cases/common/65 build always/main.c test cases/common/65 build always/meson.build test cases/common/65 build always/version.c.in test cases/common/65 build always/version.h test cases/common/65 build always/version_gen.py test cases/common/66 vcstag/meson.build test cases/common/66 vcstag/tagprog.c test cases/common/66 vcstag/vcstag.c.in test cases/common/66 vcstag/version.py test cases/common/67 modules/meson.build test cases/common/67 modules/meson_options.txt test cases/common/68 should fail/failing.c test cases/common/68 should fail/meson.build test cases/common/69 configure file in custom target/meson.build test cases/common/69 configure file in custom target/inc/confdata.in test cases/common/69 configure file in custom target/inc/meson.build test cases/common/69 configure file in custom target/src/meson.build test cases/common/69 configure file in custom target/src/mycompiler.py 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 external test program/meson.build test cases/common/70 external test program/mytest.py test cases/common/71 ctarget dependency/gen1.py test cases/common/71 ctarget dependency/gen2.py test cases/common/71 ctarget dependency/input.dat test cases/common/71 ctarget dependency/meson.build test cases/common/72 shared subproject/a.c test cases/common/72 shared subproject/meson.build test cases/common/72 shared subproject/subprojects/B/b.c test cases/common/72 shared subproject/subprojects/B/meson.build test cases/common/72 shared subproject/subprojects/C/c.c test cases/common/72 shared subproject/subprojects/C/meson.build test cases/common/73 shared subproject 2/a.c test cases/common/73 shared subproject 2/meson.build test cases/common/73 shared subproject 2/subprojects/B/b.c test cases/common/73 shared subproject 2/subprojects/B/meson.build test cases/common/73 shared subproject 2/subprojects/C/c.c test cases/common/73 shared subproject 2/subprojects/C/meson.build test cases/common/74 file object/lib.c test cases/common/74 file object/meson.build test cases/common/74 file object/prog.c test cases/common/74 file object/subdir1/lib.c test cases/common/74 file object/subdir1/meson.build test cases/common/74 file object/subdir1/prog.c test cases/common/74 file object/subdir2/lib.c test cases/common/74 file object/subdir2/meson.build test cases/common/74 file object/subdir2/prog.c test cases/common/75 custom subproject dir/a.c test cases/common/75 custom subproject dir/meson.build test cases/common/75 custom subproject dir/custom_subproject_dir/B/b.c test cases/common/75 custom subproject dir/custom_subproject_dir/B/meson.build test cases/common/75 custom subproject dir/custom_subproject_dir/C/c.c test cases/common/75 custom subproject dir/custom_subproject_dir/C/meson.build test cases/common/76 has type/meson.build test cases/common/77 extract from nested subdir/meson.build test cases/common/77 extract from nested subdir/src/meson.build test cases/common/77 extract from nested subdir/src/first/lib_first.c test cases/common/77 extract from nested subdir/src/first/meson.build test cases/common/77 extract from nested subdir/tst/meson.build test cases/common/77 extract from nested subdir/tst/first/exe_first.c test cases/common/77 extract from nested subdir/tst/first/meson.build test cases/common/78 internal dependency/meson.build test cases/common/78 internal dependency/proj1/meson.build test cases/common/78 internal dependency/proj1/proj1f1.c test cases/common/78 internal dependency/proj1/proj1f2.c test cases/common/78 internal dependency/proj1/proj1f3.c test cases/common/78 internal dependency/proj1/include/proj1.h test cases/common/78 internal dependency/src/main.c test cases/common/78 internal dependency/src/meson.build test cases/common/79 same basename/exe1.c test cases/common/79 same basename/exe2.c test cases/common/79 same basename/lib.c test cases/common/79 same basename/meson.build test cases/common/79 same basename/sharedsub/meson.build test cases/common/79 same basename/staticsub/meson.build test cases/common/8 install/gendir.py test cases/common/8 install/meson.build test cases/common/8 install/prog.c test cases/common/8 install/stat.c test cases/common/8 install/test.json test cases/common/80 declare dep/main.c test cases/common/80 declare dep/meson.build test cases/common/80 declare dep/entity/entity.h test cases/common/80 declare dep/entity/entity1.c test cases/common/80 declare dep/entity/entity2.c test cases/common/80 declare dep/entity/meson.build test cases/common/81 extract all/extractor.h test cases/common/81 extract all/four.c test cases/common/81 extract all/meson.build test cases/common/81 extract all/one.c test cases/common/81 extract all/prog.c test cases/common/81 extract all/three.c test cases/common/81 extract all/two.c test cases/common/82 add language/meson.build test cases/common/82 add language/prog.c test cases/common/82 add language/prog.cc test cases/common/83 identical target name in subproject/bar.c test cases/common/83 identical target name in subproject/meson.build test cases/common/83 identical target name in subproject/true.py test cases/common/83 identical target name in subproject/subprojects/foo/bar.c test cases/common/83 identical target name in subproject/subprojects/foo/meson.build test cases/common/83 identical target name in subproject/subprojects/foo/true.py test cases/common/84 plusassign/meson.build test cases/common/85 skip subdir/meson.build test cases/common/85 skip subdir/subdir1/meson.build test cases/common/85 skip subdir/subdir1/subdir2/meson.build test cases/common/86 private include/meson.build test cases/common/86 private include/stlib/compiler.py test cases/common/86 private include/stlib/foo1.def test cases/common/86 private include/stlib/foo2.def test cases/common/86 private include/stlib/meson.build test cases/common/86 private include/user/libuser.c test cases/common/86 private include/user/meson.build test cases/common/87 default options/meson.build test cases/common/87 default options/subprojects/sub1/meson.build test cases/common/87 default options/subprojects/sub1/meson_options.txt test cases/common/88 dep fallback/gensrc.py test cases/common/88 dep fallback/meson.build test cases/common/88 dep fallback/tester.c test cases/common/88 dep fallback/subprojects/boblib/bob.c test cases/common/88 dep fallback/subprojects/boblib/bob.h test cases/common/88 dep fallback/subprojects/boblib/genbob.py test cases/common/88 dep fallback/subprojects/boblib/meson.build test cases/common/88 dep fallback/subprojects/dummylib/meson.build test cases/common/89 default library/ef.cpp test cases/common/89 default library/ef.h test cases/common/89 default library/eftest.cpp test cases/common/89 default library/meson.build 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/test.json test cases/common/9 header install/child/childdir.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 gen extra/meson.build test cases/common/90 gen extra/name.dat test cases/common/90 gen extra/name.l test cases/common/90 gen extra/plain.c test cases/common/90 gen extra/srcgen.py test cases/common/90 gen extra/srcgen2.py test cases/common/90 gen extra/srcgen3.py test cases/common/90 gen extra/upper.c test cases/common/91 benchmark/delayer.c test cases/common/91 benchmark/meson.build test cases/common/92 test workdir/meson.build test cases/common/92 test workdir/opener.c test cases/common/92 test workdir/subdir/checker.py test cases/common/92 test workdir/subdir/meson.build test cases/common/93 suites/exe1.c test cases/common/93 suites/exe2.c test cases/common/93 suites/meson.build test cases/common/93 suites/subprojects/sub/meson.build test cases/common/93 suites/subprojects/sub/sub1.c test cases/common/93 suites/subprojects/sub/sub2.c test cases/common/94 threads/meson.build test cases/common/94 threads/threadprog.c test cases/common/94 threads/threadprog.cpp test cases/common/95 manygen/depuser.c test cases/common/95 manygen/meson.build test cases/common/95 manygen/subdir/funcinfo.def test cases/common/95 manygen/subdir/manygen.py test cases/common/95 manygen/subdir/meson.build test cases/common/96 stringdef/meson.build test cases/common/96 stringdef/stringdef.c test cases/common/97 find program path/meson.build test cases/common/97 find program path/program.py test cases/common/98 subproject subdir/meson.build test cases/common/98 subproject subdir/prog.c test cases/common/98 subproject subdir/test.json test cases/common/98 subproject subdir/subprojects/sub_implicit.wrap test cases/common/98 subproject subdir/subprojects/sub/meson.build test cases/common/98 subproject subdir/subprojects/sub/lib/meson.build test cases/common/98 subproject subdir/subprojects/sub/lib/sub.c test cases/common/98 subproject subdir/subprojects/sub/lib/sub.h test cases/common/98 subproject subdir/subprojects/sub_implicit/meson.build test cases/common/98 subproject subdir/subprojects/sub_implicit/meson_options.txt test cases/common/98 subproject subdir/subprojects/sub_implicit/subprojects/subsub/foo.h test cases/common/98 subproject subdir/subprojects/sub_implicit/subprojects/subsub/meson.build test cases/common/98 subproject subdir/subprojects/sub_implicit/subprojects/subsub/subprojects/subsubsub.wrap test cases/common/98 subproject subdir/subprojects/sub_implicit/subprojects/subsub/subprojects/packagefiles/subsubsub-1.0.zip test cases/common/98 subproject subdir/subprojects/sub_novar/meson.build test cases/common/98 subproject subdir/subprojects/sub_static/meson.build test cases/common/99 postconf/meson.build test cases/common/99 postconf/postconf.py test cases/common/99 postconf/prog.c test cases/common/99 postconf/raw.dat test cases/csharp/1 basic/meson.build test cases/csharp/1 basic/prog.cs test cases/csharp/1 basic/test.json test cases/csharp/1 basic/text.cs test cases/csharp/2 library/helper.cs test cases/csharp/2 library/meson.build test cases/csharp/2 library/prog.cs test cases/csharp/2 library/test.json 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/meson.build test cases/csharp/4 external dep/prog.cs test cases/csharp/4 external dep/test.json 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/13 cuda compiler setting/meson.build test cases/cuda/13 cuda compiler setting/nativefile.ini test cases/cuda/13 cuda compiler setting/prog.cu test cases/cuda/14 cuda has header symbol/meson.build test cases/cuda/15 sanitizer/meson.build test cases/cuda/15 sanitizer/prog.cu test cases/cuda/16 multistd/lib.cu test cases/cuda/16 multistd/main.cu test cases/cuda/16 multistd/meson.build 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/cython/1 basic/cytest.py test cases/cython/1 basic/meson.build test cases/cython/1 basic/test.json test cases/cython/1 basic/libdir/cstorer.pxd test cases/cython/1 basic/libdir/meson.build test cases/cython/1 basic/libdir/storer.c test cases/cython/1 basic/libdir/storer.h test cases/cython/1 basic/libdir/storer.pyx test cases/cython/2 generated sources/configure.pyx.in test cases/cython/2 generated sources/g.in test cases/cython/2 generated sources/gen.py test cases/cython/2 generated sources/generator.py test cases/cython/2 generated sources/includestuff.pyx test cases/cython/2 generated sources/meson.build test cases/cython/2 generated sources/simpleinclude.pyx test cases/cython/2 generated sources/simplestuff.pxi test cases/cython/2 generated sources/stuff.pxi.in test cases/cython/2 generated sources/test.py test cases/cython/2 generated sources/libdir/gen.py test cases/cython/2 generated sources/libdir/meson.build test cases/cython/3 cython_args/cythonargs.pyx test cases/cython/3 cython_args/meson.build test cases/cython/3 cython_args/test.py test cases/d/1 simple/app.d test cases/d/1 simple/meson.build test cases/d/1 simple/test.json 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/.gitignore test cases/d/11 dub/meson.build test cases/d/11 dub/test.d test cases/d/12 root include directory/meson.build test cases/d/12 root include directory/some/meson.build test cases/d/12 root include directory/some/dlang/code.d test cases/d/12 root include directory/some/dlang/meson.build test cases/d/13 declare dep/meson.build test cases/d/13 declare dep/test.d test cases/d/13 declare dep/views/test.txt test cases/d/14 dub with deps/meson.build test cases/d/14 dub with deps/test.d test cases/d/15 compiler run checks/meson.build test cases/d/15 compiler run checks/test_sizeof.d test cases/d/16 code generation/exe.d test cases/d/16 code generation/generator.d test cases/d/16 code generation/input.txt test cases/d/16 code generation/meson.build test cases/d/2 static library/app.d test cases/d/2 static library/libstuff.d test cases/d/2 static library/meson.build test cases/d/2 static library/test.json test cases/d/3 shared library/app.d test cases/d/3 shared library/libstuff.d test cases/d/3 shared library/libstuff.di test cases/d/3 shared library/lld-test.py test cases/d/3 shared library/meson.build test cases/d/3 shared library/test.json test cases/d/3 shared library/sub/libstuff.d test cases/d/3 shared library/sub/meson.build test cases/d/4 library versions/lib.d test cases/d/4 library versions/meson.build test cases/d/4 library versions/test.json test cases/d/5 mixed/app.d test cases/d/5 mixed/libstuff.c test cases/d/5 mixed/meson.build test cases/d/5 mixed/test.json test cases/d/6 unittest/app.d test cases/d/6 unittest/meson.build test cases/d/6 unittest/second_unit.d test cases/d/6 unittest/test.json test cases/d/7 multilib/app.d 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/7 multilib/test.json 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/test.json 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 build/5 failed pickled/false.py test cases/failing build/5 failed pickled/meson.build 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/5 tap tests/tester_with_status.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/1 project not first/test.json test cases/failing/10 out of bounds/meson.build test cases/failing/10 out of bounds/test.json test cases/failing/100 bool in combo/meson.build test cases/failing/100 bool in combo/meson_options.txt test cases/failing/100 bool in combo/nativefile.ini test cases/failing/100 bool in combo/test.json test cases/failing/101 compiler no lang/meson.build test cases/failing/101 compiler no lang/test.json test cases/failing/102 no fallback/meson.build test cases/failing/102 no fallback/test.json test cases/failing/102 no fallback/subprojects/foob/meson.build test cases/failing/103 feature require/meson.build test cases/failing/103 feature require/meson_options.txt test cases/failing/103 feature require/test.json test cases/failing/104 feature require.bis/meson.build test cases/failing/104 feature require.bis/meson_options.txt test cases/failing/104 feature require.bis/test.json test cases/failing/105 no build get_external_property/meson.build test cases/failing/105 no build get_external_property/test.json test cases/failing/106 enter subdir twice/meson.build test cases/failing/106 enter subdir twice/test.json test cases/failing/106 enter subdir twice/sub/meson.build test cases/failing/107 invalid fstring/meson.build test cases/failing/107 invalid fstring/test.json test cases/failing/107 invalid fstring/109 invalid fstring/meson.build test cases/failing/107 invalid fstring/109 invalid fstring/test.json test cases/failing/108 compiler argument checking/meson.build test cases/failing/108 compiler argument checking/test.json test cases/failing/109 empty fallback/meson.build test cases/failing/109 empty fallback/test.json test cases/failing/109 empty fallback/subprojects/foo/meson.build test cases/failing/11 object arithmetic/meson.build test cases/failing/11 object arithmetic/test.json test cases/failing/110 cmake executable dependency/meson.build test cases/failing/110 cmake executable dependency/test.json test cases/failing/110 cmake executable dependency/subprojects/cmlib/CMakeLists.txt test cases/failing/110 cmake executable dependency/subprojects/cmlib/main.c test cases/failing/111 allow_fallback with fallback/meson.build test cases/failing/111 allow_fallback with fallback/test.json test cases/failing/112 nonsensical bindgen/meson.build test cases/failing/112 nonsensical bindgen/test.json test cases/failing/112 nonsensical bindgen/src/header.h test cases/failing/112 nonsensical bindgen/src/source.c test cases/failing/113 run_target in test/meson.build test cases/failing/113 run_target in test/test.json test cases/failing/113 run_target in test/trivial.c test cases/failing/114 run_target in add_install_script/meson.build test cases/failing/114 run_target in add_install_script/test.json test cases/failing/114 run_target in add_install_script/trivial.c test cases/failing/115 pathsep in install_symlink/meson.build test cases/failing/115 pathsep in install_symlink/test.json test cases/failing/116 subproject version conflict/meson.build test cases/failing/116 subproject version conflict/test.json test cases/failing/116 subproject version conflict/subprojects/A/meson.build test cases/failing/116 subproject version conflict/subprojects/B/meson.build test cases/failing/117 structured source empty string/main.rs test cases/failing/117 structured source empty string/meson.build test cases/failing/117 structured source empty string/test.json test cases/failing/118 structured_sources conflicts/main.rs test cases/failing/118 structured_sources conflicts/meson.build test cases/failing/118 structured_sources conflicts/test.json test cases/failing/119 missing compiler/meson.build test cases/failing/119 missing compiler/test.json test cases/failing/119 missing compiler/subprojects/sub/main.c test cases/failing/119 missing compiler/subprojects/sub/meson.build test cases/failing/12 string arithmetic/meson.build test cases/failing/12 string arithmetic/test.json test cases/failing/120 cmake subproject error/meson.build test cases/failing/120 cmake subproject error/test.json test cases/failing/120 cmake subproject error/subprojects/cmlib/CMakeLists.txt test cases/failing/121 pkgconfig not relocatable outside prefix/meson.build test cases/failing/121 pkgconfig not relocatable outside prefix/test.json test cases/failing/122 subproject sandbox violation/meson.build test cases/failing/122 subproject sandbox violation/meson_options.txt test cases/failing/122 subproject sandbox violation/test.json test cases/failing/122 subproject sandbox violation/subprojects/subproj1/file.txt test cases/failing/122 subproject sandbox violation/subprojects/subproj1/meson.build test cases/failing/122 subproject sandbox violation/subprojects/subproj1/nested/meson.build test cases/failing/122 subproject sandbox violation/subprojects/subproj2/file.txt test cases/failing/122 subproject sandbox violation/subprojects/subproj2/meson.build test cases/failing/122 subproject sandbox violation/subprojects/subproj2/nested/meson.build test cases/failing/122 subproject sandbox violation/subprojects/subproj3/file.txt test cases/failing/122 subproject sandbox violation/subprojects/subproj3/meson.build test cases/failing/123 override and add_project_dependency/lib.c test cases/failing/123 override and add_project_dependency/meson.build test cases/failing/123 override and add_project_dependency/test.json test cases/failing/123 override and add_project_dependency/inc/lib.h test cases/failing/123 override and add_project_dependency/subprojects/a/meson.build test cases/failing/123 override and add_project_dependency/subprojects/a/prog.c test cases/failing/124 targets before add_project_dependency/lib.c test cases/failing/124 targets before add_project_dependency/meson.build test cases/failing/124 targets before add_project_dependency/test.json test cases/failing/124 targets before add_project_dependency/inc/lib.h test cases/failing/125 extract from unity/meson.build test cases/failing/125 extract from unity/src1.c test cases/failing/125 extract from unity/src2.c test cases/failing/125 extract from unity/test.json test cases/failing/126 subproject object as a dependency/main.c test cases/failing/126 subproject object as a dependency/meson.build test cases/failing/126 subproject object as a dependency/test.json test cases/failing/126 subproject object as a dependency/subprojects/sub/meson.build test cases/failing/127 generator host binary/exe.c test cases/failing/127 generator host binary/lib.in test cases/failing/127 generator host binary/meson.build test cases/failing/127 generator host binary/test.json test cases/failing/128 invalid ast/meson.build test cases/failing/128 invalid ast/test.json test cases/failing/129 invalid project function/meson.build test cases/failing/129 invalid project function/test.json test cases/failing/13 array arithmetic/meson.build test cases/failing/13 array arithmetic/test.json test cases/failing/14 invalid option name/meson.build test cases/failing/14 invalid option name/meson_options.txt test cases/failing/14 invalid option name/test.json test cases/failing/15 kwarg before arg/meson.build test cases/failing/15 kwarg before arg/prog.c test cases/failing/15 kwarg before arg/test.json 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/test.json 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/17 same target/test.json test cases/failing/18 wrong plusassign/meson.build test cases/failing/18 wrong plusassign/test.json test cases/failing/19 target clash/clash.c test cases/failing/19 target clash/meson.build test cases/failing/19 target clash/test.json test cases/failing/2 missing file/meson.build test cases/failing/2 missing file/test.json test cases/failing/20 version/meson.build test cases/failing/20 version/test.json test cases/failing/21 subver/meson.build test cases/failing/21 subver/test.json test cases/failing/21 subver/subprojects/foo/meson.build test cases/failing/22 assert/meson.build test cases/failing/22 assert/test.json test cases/failing/23 rel testdir/meson.build test cases/failing/23 rel testdir/simple.c test cases/failing/23 rel testdir/test.json test cases/failing/24 int conversion/meson.build test cases/failing/24 int conversion/test.json test cases/failing/25 badlang/meson.build test cases/failing/25 badlang/test.json test cases/failing/26 output subdir/foo.in test cases/failing/26 output subdir/meson.build test cases/failing/26 output subdir/test.json test cases/failing/26 output subdir/subdir/dummy.txt test cases/failing/27 noprog use/meson.build test cases/failing/27 noprog use/test.json test cases/failing/28 no crossprop/meson.build test cases/failing/28 no crossprop/test.json test cases/failing/29 nested ternary/meson.build test cases/failing/29 nested ternary/test.json test cases/failing/3 missing subdir/meson.build test cases/failing/3 missing subdir/test.json test cases/failing/30 invalid man extension/foo.a1 test cases/failing/30 invalid man extension/meson.build test cases/failing/30 invalid man extension/test.json test cases/failing/31 no man extension/foo test cases/failing/31 no man extension/meson.build test cases/failing/31 no man extension/test.json 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/32 exe static shared/test.json test cases/failing/33 non-root subproject/meson.build test cases/failing/33 non-root subproject/test.json test cases/failing/33 non-root subproject/some/meson.build test cases/failing/34 dependency not-required then required/meson.build test cases/failing/34 dependency not-required then required/test.json test cases/failing/35 project argument after target/exe.c test cases/failing/35 project argument after target/meson.build test cases/failing/35 project argument after target/test.json test cases/failing/36 pkgconfig dependency impossible conditions/meson.build test cases/failing/36 pkgconfig dependency impossible conditions/test.json test cases/failing/37 has function external dependency/meson.build test cases/failing/37 has function external dependency/mylib.c test cases/failing/37 has function external dependency/test.json test cases/failing/38 prefix absolute/meson.build test cases/failing/38 prefix absolute/test.json test cases/failing/39 kwarg assign/dummy.c test cases/failing/39 kwarg assign/meson.build test cases/failing/39 kwarg assign/prog.c test cases/failing/39 kwarg assign/test.json test cases/failing/4 missing meson.build/meson.build test cases/failing/4 missing meson.build/test.json test cases/failing/4 missing meson.build/subdir/dummy.txt test cases/failing/40 custom target plainname many inputs/1.txt test cases/failing/40 custom target plainname many inputs/2.txt test cases/failing/40 custom target plainname many inputs/catfiles.py test cases/failing/40 custom target plainname many inputs/meson.build test cases/failing/40 custom target plainname many inputs/test.json test cases/failing/41 custom target outputs not matching install_dirs/generator.py test cases/failing/41 custom target outputs not matching install_dirs/meson.build test cases/failing/41 custom target outputs not matching install_dirs/test.json test cases/failing/42 project name colon/meson.build test cases/failing/42 project name colon/test.json test cases/failing/43 abs subdir/meson.build test cases/failing/43 abs subdir/test.json test cases/failing/43 abs subdir/bob/meson.build test cases/failing/44 abspath to srcdir/meson.build test cases/failing/44 abspath to srcdir/test.json test cases/failing/45 pkgconfig variables reserved/meson.build test cases/failing/45 pkgconfig variables reserved/simple.c test cases/failing/45 pkgconfig variables reserved/simple.h test cases/failing/45 pkgconfig variables reserved/test.json test cases/failing/46 pkgconfig variables zero length/meson.build test cases/failing/46 pkgconfig variables zero length/simple.c test cases/failing/46 pkgconfig variables zero length/simple.h test cases/failing/46 pkgconfig variables zero length/test.json test cases/failing/47 pkgconfig variables zero length value/meson.build test cases/failing/47 pkgconfig variables zero length value/simple.c test cases/failing/47 pkgconfig variables zero length value/simple.h test cases/failing/47 pkgconfig variables zero length value/test.json test cases/failing/48 pkgconfig variables not key value/meson.build test cases/failing/48 pkgconfig variables not key value/simple.c test cases/failing/48 pkgconfig variables not key value/simple.h test cases/failing/48 pkgconfig variables not key value/test.json test cases/failing/49 executable comparison/meson.build test cases/failing/49 executable comparison/prog.c test cases/failing/49 executable comparison/test.json test cases/failing/5 misplaced option/meson.build test cases/failing/5 misplaced option/test.json test cases/failing/50 inconsistent comparison/meson.build test cases/failing/50 inconsistent comparison/test.json test cases/failing/51 slashname/meson.build test cases/failing/51 slashname/test.json test cases/failing/51 slashname/sub/meson.build test cases/failing/51 slashname/sub/prog.c test cases/failing/52 reserved meson prefix/meson.build test cases/failing/52 reserved meson prefix/test.json test cases/failing/52 reserved meson prefix/meson-foo/meson.build test cases/failing/53 or on new line/meson.build test cases/failing/53 or on new line/meson_options.txt test cases/failing/53 or on new line/test.json test cases/failing/54 link with executable/meson.build test cases/failing/54 link with executable/module.c test cases/failing/54 link with executable/prog.c test cases/failing/54 link with executable/test.json test cases/failing/55 assign custom target index/meson.build test cases/failing/55 assign custom target index/test.json test cases/failing/56 getoption prefix/meson.build test cases/failing/56 getoption prefix/test.json test cases/failing/56 getoption prefix/subprojects/abc/meson.build test cases/failing/56 getoption prefix/subprojects/abc/meson_options.txt test cases/failing/57 bad option argument/meson.build test cases/failing/57 bad option argument/meson_options.txt test cases/failing/57 bad option argument/test.json test cases/failing/58 subproj filegrab/meson.build test cases/failing/58 subproj filegrab/prog.c test cases/failing/58 subproj filegrab/test.json test cases/failing/58 subproj filegrab/subprojects/a/meson.build test cases/failing/59 grab subproj/meson.build test cases/failing/59 grab subproj/test.json test cases/failing/59 grab subproj/subprojects/foo/meson.build test cases/failing/59 grab subproj/subprojects/foo/sub.c test cases/failing/6 missing incdir/meson.build test cases/failing/6 missing incdir/test.json test cases/failing/60 grab sibling/meson.build test cases/failing/60 grab sibling/test.json test cases/failing/60 grab sibling/subprojects/a/meson.build test cases/failing/60 grab sibling/subprojects/b/meson.build test cases/failing/60 grab sibling/subprojects/b/sneaky.c test cases/failing/61 string as link target/meson.build test cases/failing/61 string as link target/prog.c test cases/failing/61 string as link target/test.json test cases/failing/62 dependency not-found and required/meson.build test cases/failing/62 dependency not-found and required/test.json test cases/failing/63 subproj different versions/main.c test cases/failing/63 subproj different versions/meson.build test cases/failing/63 subproj different versions/test.json test cases/failing/63 subproj different versions/subprojects/a/a.c test cases/failing/63 subproj different versions/subprojects/a/a.h test cases/failing/63 subproj different versions/subprojects/a/meson.build test cases/failing/63 subproj different versions/subprojects/b/b.c test cases/failing/63 subproj different versions/subprojects/b/b.h test cases/failing/63 subproj different versions/subprojects/b/meson.build test cases/failing/63 subproj different versions/subprojects/c/c.h test cases/failing/63 subproj different versions/subprojects/c/meson.build test cases/failing/64 wrong boost module/meson.build test cases/failing/64 wrong boost module/test.json test cases/failing/65 install_data rename bad size/file1.txt test cases/failing/65 install_data rename bad size/file2.txt test cases/failing/65 install_data rename bad size/meson.build test cases/failing/65 install_data rename bad size/test.json test cases/failing/66 skip only subdir/meson.build test cases/failing/66 skip only subdir/test.json test cases/failing/66 skip only subdir/subdir/meson.build test cases/failing/67 dual override/meson.build test cases/failing/67 dual override/overrides.py test cases/failing/67 dual override/test.json test cases/failing/68 override used/meson.build test cases/failing/68 override used/other.py test cases/failing/68 override used/something.py test cases/failing/68 override used/test.json test cases/failing/69 run_command unclean exit/meson.build test cases/failing/69 run_command unclean exit/returncode.py test cases/failing/69 run_command unclean exit/test.json test cases/failing/7 go to subproject/meson.build test cases/failing/7 go to subproject/test.json test cases/failing/7 go to subproject/subprojects/meson.build test cases/failing/70 int literal leading zero/meson.build test cases/failing/70 int literal leading zero/test.json test cases/failing/71 configuration immutable/input test cases/failing/71 configuration immutable/meson.build test cases/failing/71 configuration immutable/test.json test cases/failing/72 link with shared module on osx/meson.build test cases/failing/72 link with shared module on osx/module.c test cases/failing/72 link with shared module on osx/prog.c test cases/failing/72 link with shared module on osx/test.json test cases/failing/73 non-ascii in ascii encoded configure file/config9.h.in test cases/failing/73 non-ascii in ascii encoded configure file/meson.build test cases/failing/73 non-ascii in ascii encoded configure file/test.json test cases/failing/74 subproj dependency not-found and required/meson.build test cases/failing/74 subproj dependency not-found and required/test.json test cases/failing/75 unfound run/meson.build test cases/failing/75 unfound run/test.json test cases/failing/76 framework dependency with version/meson.build test cases/failing/76 framework dependency with version/test.json test cases/failing/77 override exe config/foo.c test cases/failing/77 override exe config/meson.build test cases/failing/77 override exe config/test.json test cases/failing/78 gl dependency with version/meson.build test cases/failing/78 gl dependency with version/test.json test cases/failing/79 threads dependency with version/meson.build test cases/failing/79 threads dependency with version/test.json test cases/failing/8 recursive/meson.build test cases/failing/8 recursive/test.json test cases/failing/8 recursive/subprojects/a/meson.build test cases/failing/8 recursive/subprojects/b/meson.build test cases/failing/80 gtest dependency with version/meson.build test cases/failing/80 gtest dependency with version/test.json test cases/failing/81 dub library/meson.build test cases/failing/81 dub library/test.json test cases/failing/82 dub executable/meson.build test cases/failing/82 dub executable/test.json test cases/failing/83 dub compiler/meson.build test cases/failing/83 dub compiler/test.json test cases/failing/84 subproj not-found dep/meson.build test cases/failing/84 subproj not-found dep/test.json test cases/failing/84 subproj not-found dep/subprojects/somesubproj/meson.build test cases/failing/85 invalid configure file/input test cases/failing/85 invalid configure file/meson.build test cases/failing/85 invalid configure file/test.json test cases/failing/86 kwarg dupe/meson.build test cases/failing/86 kwarg dupe/prog.c test cases/failing/86 kwarg dupe/test.json test cases/failing/87 missing pch file/meson.build test cases/failing/87 missing pch file/prog.c test cases/failing/87 missing pch file/test.json test cases/failing/88 pch source different folder/meson.build test cases/failing/88 pch source different folder/prog.c test cases/failing/88 pch source different folder/test.json test cases/failing/88 pch source different folder/include/pch.h test cases/failing/88 pch source different folder/src/pch.c test cases/failing/89 unknown config tool/meson.build test cases/failing/89 unknown config tool/test.json test cases/failing/9 missing extra file/meson.build test cases/failing/9 missing extra file/prog.c test cases/failing/9 missing extra file/test.json test cases/failing/90 custom target install data/Info.plist.cpp test cases/failing/90 custom target install data/meson.build test cases/failing/90 custom target install data/preproc.py test cases/failing/90 custom target install data/test.json test cases/failing/91 add dict non string key/meson.build test cases/failing/91 add dict non string key/test.json test cases/failing/92 add dict duplicate keys/meson.build test cases/failing/92 add dict duplicate keys/test.json test cases/failing/93 no host get_external_property/meson.build test cases/failing/93 no host get_external_property/test.json test cases/failing/94 no native compiler/main.c test cases/failing/94 no native compiler/meson.build test cases/failing/94 no native compiler/test.json test cases/failing/95 subdir parse error/meson.build test cases/failing/95 subdir parse error/test.json test cases/failing/95 subdir parse error/subdir/meson.build test cases/failing/96 invalid option file/meson.build test cases/failing/96 invalid option file/meson_options.txt test cases/failing/96 invalid option file/test.json test cases/failing/97 no lang/main.c test cases/failing/97 no lang/meson.build test cases/failing/97 no lang/test.json test cases/failing/98 no glib-compile-resources/meson.build test cases/failing/98 no glib-compile-resources/test.json test cases/failing/98 no glib-compile-resources/trivial.gresource.xml test cases/failing/99 number in combo/meson.build test cases/failing/99 number in combo/nativefile.ini test cases/failing/99 number in combo/test.json 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/meson.build test cases/fortran/15 include/timestwo.f90 test cases/fortran/15 include/subprojects/cmake_inc/CMakeLists.txt test cases/fortran/15 include/subprojects/cmake_inc/main.f90 test cases/fortran/15 include/subprojects/cmake_inc/thousand.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/main.f90 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/21 install static/main.f90 test cases/fortran/21 install static/main_lib.f90 test cases/fortran/21 install static/meson.build test cases/fortran/21 install static/test.json test cases/fortran/21 install static/subprojects/static_hello/meson.build test cases/fortran/21 install static/subprojects/static_hello/static_hello.f90 test cases/fortran/22 extract_objects/bar.f90 test cases/fortran/22 extract_objects/foo1.f90 test cases/fortran/22 extract_objects/foo2.f90 test cases/fortran/22 extract_objects/meson.build test cases/fortran/23 preprocess/main.f90 test cases/fortran/23 preprocess/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/mod3.f90 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.c 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/meson_options.txt test cases/frameworks/1 boost/nomod.cpp test cases/frameworks/1 boost/python_module.cpp test cases/frameworks/1 boost/test.json 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/foo.c test cases/frameworks/10 gtk-doc/meson.build test cases/frameworks/10 gtk-doc/test.json 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/baz.jpg test cases/frameworks/10 gtk-doc/doc/foobar1/baz.png.in test cases/frameworks/10 gtk-doc/doc/foobar1/foobar-docs.sgml test cases/frameworks/10 gtk-doc/doc/foobar1/foobar-sections.txt test cases/frameworks/10 gtk-doc/doc/foobar1/foobar.types 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/meson.build test cases/frameworks/11 gir subproject/test.json 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/meson.build test cases/frameworks/12 multiple gir/test.json 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/meson.build test cases/frameworks/13 yelp/test.json 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/index2.page test cases/frameworks/13 yelp/help/C/index3.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/meson.build test cases/frameworks/14 doxygen/test.json 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/meson_options.txt test cases/frameworks/15 llvm/sum.c test cases/frameworks/15 llvm/test.json test cases/frameworks/16 sdl2/meson.build test cases/frameworks/16 sdl2/meson_options.txt test cases/frameworks/16 sdl2/sdl2prog.c test cases/frameworks/16 sdl2/test.json 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/17 mpi/meson_options.txt test cases/frameworks/17 mpi/test.json test cases/frameworks/18 vulkan/meson.build test cases/frameworks/18 vulkan/test.json 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/19 pcap/test.json test cases/frameworks/2 gtest/meson.build test cases/frameworks/2 gtest/test.cc test cases/frameworks/2 gtest/test.json 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/20 cups/test.json test cases/frameworks/21 libwmf/libwmf_prog.c test cases/frameworks/21 libwmf/meson.build test cases/frameworks/21 libwmf/test.json 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/test.json 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/meson.build test cases/frameworks/23 hotdoc/test.json 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/24 libgcrypt/test.json 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/25 hdf5/meson_options.txt test cases/frameworks/25 hdf5/test.json 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/26 netcdf/test.json test cases/frameworks/27 gpgme/gpgme_prog.c test cases/frameworks/27 gpgme/meson.build test cases/frameworks/27 gpgme/test.json 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/test.json test cases/frameworks/28 gir link order 2/samelibname/dummy.c 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/29 blocks/test.json test cases/frameworks/3 gmock/gmocktest.cc test cases/frameworks/3 gmock/meson.build test cases/frameworks/3 gmock/test.json 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/test.json test cases/frameworks/30 scalapack/cmake/FindSCALAPACK.cmake test cases/frameworks/31 curses/main.c test cases/frameworks/31 curses/meson.build test cases/frameworks/31 curses/meson_options.txt test cases/frameworks/31 curses/test.json test cases/frameworks/32 boost root/meson.build test cases/frameworks/32 boost root/nativefile.ini.in test cases/frameworks/32 boost root/boost/include/boost/version.hpp test cases/frameworks/32 boost root/boost/lib/boost_regex-vc142-mt-gd-x32-0_1.lib test cases/frameworks/32 boost root/boost/lib/boost_regex-vc142-mt-gd-x64-0_1.lib test cases/frameworks/32 boost root/boost/lib/libboost_regex.so.0.1.0 test cases/frameworks/33 boost split root/meson.build test cases/frameworks/33 boost split root/nativefile.ini.in test cases/frameworks/33 boost split root/boost/extra-dir/include/boost/version.hpp test cases/frameworks/33 boost split root/boost/lib/boost_regex-vc142-mt-gd-x32-0_2.lib test cases/frameworks/33 boost split root/boost/lib/boost_regex-vc142-mt-gd-x64-0_2.lib test cases/frameworks/33 boost split root/boost/lib/libboost_regex.so.0.2.0 test cases/frameworks/34 gir static lib/meson.build test cases/frameworks/34 gir static lib/test.json test cases/frameworks/34 gir static lib/statichelper/meson-sample.c test cases/frameworks/34 gir static lib/statichelper/meson-sample.h.in test cases/frameworks/34 gir static lib/statichelper/meson.build test cases/frameworks/34 gir static lib/subdir/gir/meson-subsample.c test cases/frameworks/34 gir static lib/subdir/gir/meson-subsample.h test cases/frameworks/34 gir static lib/subdir/gir/meson.build test cases/frameworks/34 gir static lib/subdir/gir/prog.c test cases/frameworks/35 boost symlinks/meson.build test cases/frameworks/35 boost symlinks/nativefile.ini.in test cases/frameworks/35 boost symlinks/boost/Cellar/boost-python/0.3.0/lib/boost_python-vc142-mt-gd-x32-0_3.lib test cases/frameworks/35 boost symlinks/boost/Cellar/boost-python/0.3.0/lib/boost_python-vc142-mt-gd-x64-0_3.lib test cases/frameworks/35 boost symlinks/boost/Cellar/boost-python/0.3.0/lib/libboost_python.so.0.3.0 test cases/frameworks/35 boost symlinks/boost/Cellar/boost/0.3.0/include/boost/version.hpp test cases/frameworks/35 boost symlinks/boost/Cellar/boost/0.3.0/lib/boost_regex-vc142-mt-gd-x32-0_3.lib test cases/frameworks/35 boost symlinks/boost/Cellar/boost/0.3.0/lib/boost_regex-vc142-mt-gd-x64-0_3.lib test cases/frameworks/35 boost symlinks/boost/Cellar/boost/0.3.0/lib/libboost_regex.so.0.3.0 test cases/frameworks/35 boost symlinks/boost/include/boost/version.hpp test cases/frameworks/35 boost symlinks/boost/lib/boost_python-vc142-mt-gd-x32-0_3.lib test cases/frameworks/35 boost symlinks/boost/lib/boost_python-vc142-mt-gd-x64-0_3.lib test cases/frameworks/35 boost symlinks/boost/lib/boost_regex-vc142-mt-gd-x32-0_3.lib test cases/frameworks/35 boost symlinks/boost/lib/boost_regex-vc142-mt-gd-x64-0_3.lib test cases/frameworks/35 boost symlinks/boost/lib/libboost_python.so.0.3.0 test cases/frameworks/35 boost symlinks/boost/lib/libboost_regex.so.0.3.0 test cases/frameworks/36 gtkdoc cpp/foo-docs.xml test cases/frameworks/36 gtkdoc cpp/foo.cpp test cases/frameworks/36 gtkdoc cpp/foo.h test cases/frameworks/36 gtkdoc cpp/meson.build test cases/frameworks/36 gtkdoc cpp/test.json test cases/frameworks/37 gir cpp/foo.cpp test cases/frameworks/37 gir cpp/foo.h test cases/frameworks/37 gir cpp/meson.build test cases/frameworks/37 gir cpp/test.json 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/qt4_lang.qrc test cases/frameworks/4 qt/qt4core_fr.ts test cases/frameworks/4 qt/qt4embedded_fr.ts test cases/frameworks/4 qt/qt5_lang.qrc test cases/frameworks/4 qt/qt5core_fr.ts test cases/frameworks/4 qt/qt5embedded_fr.ts test cases/frameworks/4 qt/qt6_lang.qrc test cases/frameworks/4 qt/qt6core_fr.ts test cases/frameworks/4 qt/qt6embedded_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/test.json test cases/frameworks/4 qt/thing.png test cases/frameworks/4 qt/thing2.png test cases/frameworks/4 qt/mocdep/meson.build test cases/frameworks/4 qt/mocdep/mocdep.h 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/test.json 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/meson.build test cases/frameworks/6 gettext/meson_options.txt test cases/frameworks/6 gettext/test.json 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/test5.desktop.in.in test cases/frameworks/6 gettext/data/test6.desktop.in.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/data3/com.mesonbuild.test.intlprog.metainfo.xml test cases/frameworks/6 gettext/data3/meson.build test cases/frameworks/6 gettext/data3/metainfo.its test cases/frameworks/6 gettext/data3/verify.py 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/copyfile.py test cases/frameworks/7 gnome/meson.build test cases/frameworks/7 gnome/test.json 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.in test cases/frameworks/7 gnome/genmarshal/marshaller.list test cases/frameworks/7 gnome/genmarshal/meson.build test cases/frameworks/7 gnome/gir/copy.py 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/gir/dep1/dep3/dep3.c test cases/frameworks/7 gnome/gir/dep1/dep3/dep3.h test cases/frameworks/7 gnome/gir/dep1/dep3/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/mkenums/subdir/h2.h.in test cases/frameworks/7 gnome/mkenums/subdir/h3.h test cases/frameworks/7 gnome/mkenums/subdir/meson.build 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/resources/generated/meson.build 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.json test cases/frameworks/8 flex/test.txt test cases/frameworks/8 flex/testfile 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/meson.build test cases/java/1 basic/test.json test cases/java/1 basic/com/mesonbuild/Simple.java test cases/java/10 resources/meson.build test cases/java/10 resources/src/meson.build test cases/java/10 resources/src/com/mesonbuild/Resources.java test cases/java/10 resources/src/resources/resource1.txt test cases/java/10 resources/src/resources/subdir/resource2.txt 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/java/9 jni/meson.build test cases/java/9 jni/lib/com_mesonbuild_JniTest.c test cases/java/9 jni/lib/meson.build test cases/java/9 jni/lib/native.c test cases/java/9 jni/src/meson.build test cases/java/9 jni/src/com/mesonbuild/Configured.java.in test cases/java/9 jni/src/com/mesonbuild/JniTest.java test cases/java/9 jni/src/com/mesonbuild/meson.build test cases/keyval/1 basic/.config test cases/keyval/1 basic/meson.build test cases/keyval/1 basic/test.json test cases/keyval/2 subdir/.config test cases/keyval/2 subdir/meson.build test cases/keyval/2 subdir/dir/meson.build test cases/keyval/3 load_config files/meson.build test cases/keyval/3 load_config files/dir/config test cases/keyval/3 load_config files/dir/meson.build test cases/keyval/4 load_config builddir/config test cases/keyval/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/test.json test cases/linuxlike/13 cmake dependency/testFlagSet.c test cases/linuxlike/13 cmake dependency/cmake/FindImportedOldStyle.cmake 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_fake1/cmMesonTestF1Config.cmake test cases/linuxlike/13 cmake dependency/cmake_fake2/cmMesonTestF2Config.cmake test cases/linuxlike/13 cmake dependency/cmake_fake3/bin/.gitkeep test cases/linuxlike/13 cmake dependency/cmake_fake3/lib/cmake/cmMesonTestF3/cmMesonTestF3Config.cmake test cases/linuxlike/13 cmake dependency/cmake_pref_env/lib/cmake/cmMesonTestDep/cmMesonTestDepConfig.cmake test cases/linuxlike/13 cmake dependency/cmake_pref_env/lib/cmake/cmMesonVersionedTestDep/cmMesonVersionedTestDepConfig.cmake test cases/linuxlike/13 cmake dependency/cmake_pref_env/lib/cmake/cmMesonVersionedTestDep/cmMesonVersionedTestDepConfigVersion.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/fakezlib/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/lib.c test cases/linuxlike/7 library versions/meson.build test cases/linuxlike/7 library versions/test.json test cases/linuxlike/8 subproject library install/meson.build test cases/linuxlike/8 subproject library install/test.json 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/nasm/2 asm language/hello.asm test cases/nasm/2 asm language/meson.build test cases/nasm/3 nasm only/dummy.asm test cases/nasm/3 nasm only/dummy.def test cases/nasm/3 nasm only/meson.build test cases/native/1 trivial/meson.build test cases/native/1 trivial/trivial.c test cases/native/2 global arg/meson.build test cases/native/2 global arg/prog.c test cases/native/2 global arg/prog.cc test cases/native/3 pipeline/input_src.dat test cases/native/3 pipeline/meson.build test cases/native/3 pipeline/prog.c test cases/native/3 pipeline/srcgen.c test cases/native/3 pipeline/depends/copyrunner.py test cases/native/3 pipeline/depends/filecopier.c test cases/native/3 pipeline/depends/libsrc.c.in test cases/native/3 pipeline/depends/meson.build test cases/native/3 pipeline/depends/prog.c test cases/native/3 pipeline/src/input_src.dat test cases/native/3 pipeline/src/meson.build test cases/native/3 pipeline/src/prog.c test cases/native/3 pipeline/src/srcgen.c test cases/native/4 tryrun/error.c test cases/native/4 tryrun/meson.build test cases/native/4 tryrun/no_compile.c test cases/native/4 tryrun/ok.c test cases/native/5 install script/file.txt test cases/native/5 install script/meson.build test cases/native/5 install script/test.json test cases/native/5 install script/wrap.py test cases/native/5 install script/src/exe.c test cases/native/5 install script/src/meson.build test cases/native/6 add language/meson.build test cases/native/6 add language/prog.cc test cases/native/7 selfbuilt custom/checkarg.cpp test cases/native/7 selfbuilt custom/data.dat test cases/native/7 selfbuilt custom/mainprog.cpp test cases/native/7 selfbuilt custom/meson.build test cases/native/7 selfbuilt custom/tool.cpp test cases/native/8 external program shebang parsing/input.txt test cases/native/8 external program shebang parsing/main.c test cases/native/8 external program shebang parsing/meson.build test cases/native/8 external program shebang parsing/script.int.in test cases/native/9 override with exe/main2.input test cases/native/9 override with exe/meson.build test cases/native/9 override with exe/subprojects/sub/foobar.c test cases/native/9 override with exe/subprojects/sub/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/lib.c test cases/osx/2 library versions/meson.build test cases/osx/2 library versions/require_pkgconfig.py test cases/osx/2 library versions/test.json test cases/osx/3 has function xcode8/meson.build 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/test.json test cases/osx/4 framework/xcode-frameworks.png 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/5 extra frameworks/test.json 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/osx/9 global variable ar/libfile.c test cases/osx/9 global variable ar/libfile2.c test cases/osx/9 global variable ar/meson.build test cases/osx/9 global variable ar/nativefile.ini test cases/osx/9 global variable ar/prog.c 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/10 extmodule limited api disabled/meson.build test cases/python/10 extmodule limited api disabled/module.c test cases/python/2 extmodule/blaster.py.in test cases/python/2 extmodule/meson.build test cases/python/2 extmodule/meson_options.txt test cases/python/2 extmodule/test.json test cases/python/2 extmodule/ext/meson.build test cases/python/2 extmodule/ext/tachyon_module.c test cases/python/2 extmodule/ext/nested/meson.build test cases/python/2 extmodule/ext/wrongdir/meson.build test cases/python/2 extmodule/subinst/printer.py test cases/python/2 extmodule/subinst/submod/printer.py 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/python/6 failing subproject/meson.build test cases/python/6 failing subproject/subprojects/bar/meson.build test cases/python/7 install path/meson.build test cases/python/7 install path/test.json test cases/python/7 install path/test.py test cases/python/7 install path/structured/meson.build test cases/python/7 install path/structured/one.py test cases/python/7 install path/structured/two.py test cases/python/7 install path/structured/alpha/one.py test cases/python/7 install path/structured/alpha/three.py test cases/python/7 install path/structured/alpha/two.py test cases/python/7 install path/structured/beta/one.py test cases/python/7 install path/target/meson.build test cases/python/8 different python versions/blaster.py test cases/python/8 different python versions/meson.build test cases/python/8 different python versions/meson_options.txt test cases/python/8 different python versions/test.json test cases/python/8 different python versions/ext/meson.build test cases/python/8 different python versions/ext/tachyon_module.c test cases/python/9 extmodule limited api/limited.c test cases/python/9 extmodule limited api/meson.build test cases/python/9 extmodule limited api/not_limited.c test cases/python/9 extmodule limited api/test.json 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/rewrite/6 extra_files/addExtraFiles.json test cases/rewrite/6 extra_files/info.json test cases/rewrite/6 extra_files/meson.build test cases/rewrite/6 extra_files/rmExtraFiles.json test cases/rust/1 basic/clippy.toml test cases/rust/1 basic/meson.build test cases/rust/1 basic/prog.rs test cases/rust/1 basic/test.json test cases/rust/1 basic/subdir/meson.build test cases/rust/1 basic/subdir/prog.rs test cases/rust/10 language stds/2015.rs test cases/rust/10 language stds/2018.rs test cases/rust/10 language stds/meson.build test cases/rust/11 generated main/gen.py test cases/rust/11 generated main/generated_lib_main.rs test cases/rust/11 generated main/meson.build test cases/rust/11 generated main/sub/meson.build test cases/rust/12 bindgen/meson.build test cases/rust/12 bindgen/test.json test cases/rust/12 bindgen/dependencies/clib2.c test cases/rust/12 bindgen/dependencies/external_dep.h test cases/rust/12 bindgen/dependencies/internal_dep.h test cases/rust/12 bindgen/dependencies/internal_main.rs test cases/rust/12 bindgen/dependencies/meson.build test cases/rust/12 bindgen/include/other.h test cases/rust/12 bindgen/src/gen_header.py test cases/rust/12 bindgen/src/global-project.h test cases/rust/12 bindgen/src/global.c test cases/rust/12 bindgen/src/global.rs test cases/rust/12 bindgen/src/header.h test cases/rust/12 bindgen/src/main.rs test cases/rust/12 bindgen/src/main2.rs test cases/rust/12 bindgen/src/source.c test cases/rust/12 bindgen/sub/meson.build test cases/rust/13 external c dependencies/c_accessing_zlib.c test cases/rust/13 external c dependencies/meson.build test cases/rust/13 external c dependencies/meson_options.txt test cases/rust/13 external c dependencies/prog.rs test cases/rust/13 external c dependencies/test.json test cases/rust/14 external libm/meson.build test cases/rust/14 external libm/meson_options.txt test cases/rust/14 external libm/prog.rs test cases/rust/14 external libm/rs_math.rs test cases/rust/14 external libm/test.json test cases/rust/15 polyglot sharedlib/adder.c test cases/rust/15 polyglot sharedlib/adder.h test cases/rust/15 polyglot sharedlib/adder.rs test cases/rust/15 polyglot sharedlib/addertest.c test cases/rust/15 polyglot sharedlib/meson.build test cases/rust/15 polyglot sharedlib/zero/meson.build test cases/rust/15 polyglot sharedlib/zero/zero.c test cases/rust/15 polyglot sharedlib/zero/zero_static.c test cases/rust/16 internal c dependencies/lib.c test cases/rust/16 internal c dependencies/lib.h test cases/rust/16 internal c dependencies/main.rs test cases/rust/16 internal c dependencies/meson.build test cases/rust/16 internal c dependencies/test.py test cases/rust/17 staticlib link staticlib/branch.rs test cases/rust/17 staticlib link staticlib/leaf.rs test cases/rust/17 staticlib link staticlib/meson.build test cases/rust/17 staticlib link staticlib/prog.c test cases/rust/17 staticlib link staticlib/test.json test cases/rust/18 proc-macro/meson.build test cases/rust/18 proc-macro/proc.rs test cases/rust/18 proc-macro/use.rs test cases/rust/19 structured sources/gen.py test cases/rust/19 structured sources/main-gen-copy.rs test cases/rust/19 structured sources/meson.build test cases/rust/19 structured sources/no_copy_test.py test cases/rust/19 structured sources/priv.rs test cases/rust/19 structured sources/src/foo.rs.in test cases/rust/19 structured sources/src/main.rs test cases/rust/19 structured sources/src2/main-unique.rs test cases/rust/19 structured sources/src2/meson.build test cases/rust/19 structured sources/src2/foo/mod.rs test cases/rust/2 sharedlib/meson.build test cases/rust/2 sharedlib/prog.rs test cases/rust/2 sharedlib/stuff.rs test cases/rust/2 sharedlib/test.json test cases/rust/2 sharedlib/value.c test cases/rust/20 rust and cpp/lib.cpp test cases/rust/20 rust and cpp/lib.hpp test cases/rust/20 rust and cpp/main.rs test cases/rust/20 rust and cpp/meson.build test cases/rust/20 rust and cpp/test.json test cases/rust/21 transitive dependencies/app.rs test cases/rust/21 transitive dependencies/foo.c test cases/rust/21 transitive dependencies/foo.rs test cases/rust/21 transitive dependencies/main.rs test cases/rust/21 transitive dependencies/meson.build test cases/rust/21 transitive dependencies/proc.rs test cases/rust/21 transitive dependencies/static1.c test cases/rust/21 transitive dependencies/static2.c test cases/rust/21 transitive dependencies/test.json test cases/rust/21 transitive dependencies/diamond/func.c test cases/rust/21 transitive dependencies/diamond/main.c test cases/rust/21 transitive dependencies/diamond/meson.build test cases/rust/21 transitive dependencies/diamond/r1.rs test cases/rust/21 transitive dependencies/diamond/r2.rs test cases/rust/21 transitive dependencies/diamond/r3.rs test cases/rust/21 transitive dependencies/liba/lib.rs test cases/rust/21 transitive dependencies/liba/meson.build test cases/rust/21 transitive dependencies/libb/lib.rs test cases/rust/21 transitive dependencies/libb/meson.build test cases/rust/22 cargo subproject/main.c test cases/rust/22 cargo subproject/meson.build test cases/rust/22 cargo subproject/subprojects/bar-rs.wrap test cases/rust/22 cargo subproject/subprojects/foo-rs.wrap test cases/rust/22 cargo subproject/subprojects/bar-rs/Cargo.toml test cases/rust/22 cargo subproject/subprojects/bar-rs/src/lib.rs test cases/rust/22 cargo subproject/subprojects/foo-rs/Cargo.toml test cases/rust/22 cargo subproject/subprojects/foo-rs/src/lib.rs test cases/rust/23 crt-static/lib.c test cases/rust/23 crt-static/main.rs test cases/rust/23 crt-static/meson.build test cases/rust/23 crt-static/test.json test cases/rust/3 staticlib/meson.build test cases/rust/3 staticlib/other.rs test cases/rust/3 staticlib/prog.rs test cases/rust/3 staticlib/stuff.rs test cases/rust/3 staticlib/test.json test cases/rust/3 staticlib/value.c test cases/rust/4 polyglot/meson.build test cases/rust/4 polyglot/proc.rs test cases/rust/4 polyglot/prog.c test cases/rust/4 polyglot/stuff.rs test cases/rust/4 polyglot/test.json test cases/rust/5 polyglot static/clib.c test cases/rust/5 polyglot static/meson.build test cases/rust/5 polyglot static/overflow_size_checks.py test cases/rust/5 polyglot static/prog.c test cases/rust/5 polyglot static/stuff.rs test cases/rust/5 polyglot static/test.json 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/6 named staticlib/test.json 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/7 private crate collision/test.json 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/rust/9 unit tests/helper.rs test cases/rust/9 unit tests/meson.build test cases/rust/9 unit tests/test.rs test cases/rust/9 unit tests/test2.rs test cases/rust/9 unit tests/test3.rs test cases/swift/1 exe/main.swift test cases/swift/1 exe/meson.build 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/main.c 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/100 custom target name/file.txt.in test cases/unit/100 custom target name/meson.build test cases/unit/100 custom target name/subdir/meson.build test cases/unit/101 relative find program/foo.py test cases/unit/101 relative find program/meson.build test cases/unit/101 relative find program/subdir/meson.build test cases/unit/102 rlib linkage/lib2.rs test cases/unit/102 rlib linkage/main.rs test cases/unit/102 rlib linkage/meson.build test cases/unit/103 python without pkgconfig/meson.build test cases/unit/104 strip/lib.c test cases/unit/104 strip/meson.build test cases/unit/105 debug function/meson.build test cases/unit/106 pkgconfig relocatable with absolute path/meson.build test cases/unit/107 subproject symlink/cp.py test cases/unit/107 subproject symlink/main.c test cases/unit/107 subproject symlink/meson.build test cases/unit/107 subproject symlink/symlinked_subproject/meson.build test cases/unit/107 subproject symlink/symlinked_subproject/src.c test cases/unit/107 subproject symlink/symlinked_subproject/datadir/datafile test cases/unit/107 subproject symlink/symlinked_subproject/datadir/meson.build test cases/unit/108 new subproject on reconfigure/meson.build test cases/unit/108 new subproject on reconfigure/meson_options.txt test cases/unit/108 new subproject on reconfigure/subprojects/foo/foo.c test cases/unit/108 new subproject on reconfigure/subprojects/foo/meson.build test cases/unit/109 configure same noop/meson.build test cases/unit/109 configure same noop/meson_options.txt 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/110 freeze/freeze.c test cases/unit/110 freeze/meson.build test cases/unit/111 replace unencodable xml chars/meson.build test cases/unit/111 replace unencodable xml chars/script.py test cases/unit/112 classpath/meson.build test cases/unit/112 classpath/com/mesonbuild/Simple.java test cases/unit/113 list build options/meson.build test cases/unit/113 list build options/meson_options.txt test cases/unit/114 complex link cases/main.c test cases/unit/114 complex link cases/meson.build test cases/unit/114 complex link cases/s1.c test cases/unit/114 complex link cases/s2.c test cases/unit/114 complex link cases/s3.c test cases/unit/115 c cpp stds/meson.build test cases/unit/116 empty project/expected_mods.json test cases/unit/116 empty project/meson.build test cases/unit/117 genvslite/main.cpp test cases/unit/117 genvslite/meson.build test cases/unit/118 meson package cache dir/meson.build test cases/unit/118 meson package cache dir/cache_dir/foo.zip test cases/unit/118 meson package cache dir/cache_dir/bar/meson.build test cases/unit/118 meson package cache dir/subprojects/bar.wrap test cases/unit/118 meson package cache dir/subprojects/foo.wrap test cases/unit/119 openssl cmake bug/meson.build test cases/unit/119 openssl cmake bug/nativefile.ini 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/120 rewrite/meson.build test cases/unit/121 executable suffix/main.c test cases/unit/121 executable suffix/meson.build 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/cp.py 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/meson_options.txt test cases/unit/17 prebuilt shared/patron.c test cases/unit/17 prebuilt shared/rejected.c test cases/unit/17 prebuilt shared/rejected.h test cases/unit/17 prebuilt shared/rejected_main.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/35 dist script/subprojects/sub/dist-script.py test cases/unit/35 dist script/subprojects/sub/meson.build test cases/unit/35 dist script/subprojects/sub/meson_options.txt test cases/unit/35 dist script/subprojects/sub/prog.c 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 external, internal library rpath/built library/bar.c test cases/unit/39 external, internal library rpath/built library/foo.py test cases/unit/39 external, internal library rpath/built library/meson.build test cases/unit/39 external, internal library rpath/built library/meson_options.txt test cases/unit/39 external, internal library rpath/built library/prog.c test cases/unit/39 external, internal library rpath/external library/bar.c test cases/unit/39 external, internal library rpath/external library/faa.c test cases/unit/39 external, internal library rpath/external library/foo.c test cases/unit/39 external, internal library rpath/external library/meson.build 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 featurenew subprojects/meson.build test cases/unit/40 featurenew subprojects/subprojects/bar/meson.build test cases/unit/40 featurenew subprojects/subprojects/baz/meson.build test cases/unit/40 featurenew subprojects/subprojects/foo/meson.build test cases/unit/41 rpath order/meson.build test cases/unit/41 rpath order/myexe.c test cases/unit/41 rpath order/subprojects/sub1/lib.c test cases/unit/41 rpath order/subprojects/sub1/meson.build test cases/unit/41 rpath order/subprojects/sub2/lib.c test cases/unit/41 rpath order/subprojects/sub2/meson.build test cases/unit/42 dep order/lib1.c test cases/unit/42 dep order/lib2.c test cases/unit/42 dep order/meson.build test cases/unit/42 dep order/myexe.c test cases/unit/43 promote wrap/meson.build test cases/unit/43 promote wrap/subprojects/s1/meson.build test cases/unit/43 promote wrap/subprojects/s1/subprojects/ambiguous/meson.build test cases/unit/43 promote wrap/subprojects/s2/meson.build test cases/unit/43 promote wrap/subprojects/s2/subprojects/ambiguous.wrap test cases/unit/44 vscpp17/main.cpp test cases/unit/44 vscpp17/meson.build test cases/unit/45 native dep pkgconfig var/cross_pkgconfig.py test cases/unit/45 native dep pkgconfig var/meson.build test cases/unit/45 native dep pkgconfig var/meson_options.txt test cases/unit/45 native dep pkgconfig var/cross_pkgconfig/dep_tester.pc test cases/unit/45 native dep pkgconfig var/native_pkgconfig/dep_tester.pc test cases/unit/46 native file binary/meson.build test cases/unit/46 native file binary/meson_options.txt test cases/unit/47 reconfigure/main.c test cases/unit/47 reconfigure/meson.build test cases/unit/47 reconfigure/meson_options.txt test cases/unit/47 reconfigure/subprojects/sub1/meson.build test cases/unit/48 testsetup default/envcheck.py test cases/unit/48 testsetup default/meson.build test cases/unit/49 pkgconfig csharp library/meson.build test cases/unit/49 pkgconfig csharp library/somelib.cs 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 noncross options/meson.build test cases/unit/50 noncross options/prog.c test cases/unit/50 noncross options/ylib.pc test cases/unit/51 ldflagdedup/bob.c test cases/unit/51 ldflagdedup/meson.build test cases/unit/51 ldflagdedup/prog.c test cases/unit/52 pkgconfig static link order/dummy.c test cases/unit/52 pkgconfig static link order/meson.build test cases/unit/53 clang-format/.clang-format test cases/unit/53 clang-format/header_expected_h test cases/unit/53 clang-format/header_orig_h test cases/unit/53 clang-format/meson.build test cases/unit/53 clang-format/prog_expected_c test cases/unit/53 clang-format/prog_orig_c test cases/unit/53 clang-format/dummydir.h/dummy.dat test cases/unit/54 introspect buildoptions/subprojects/projectBad/meson.build test cases/unit/54 introspect buildoptions/subprojects/projectBad/meson_options.txt test cases/unit/55 dedup compiler libs/meson.build test cases/unit/55 dedup compiler libs/app/app.c test cases/unit/55 dedup compiler libs/app/meson.build test cases/unit/55 dedup compiler libs/liba/liba.c test cases/unit/55 dedup compiler libs/liba/liba.h test cases/unit/55 dedup compiler libs/liba/meson.build test cases/unit/55 dedup compiler libs/libb/libb.c test cases/unit/55 dedup compiler libs/libb/libb.h test cases/unit/55 dedup compiler libs/libb/meson.build test cases/unit/56 introspection/cp.py test cases/unit/56 introspection/meson.build test cases/unit/56 introspection/meson_options.txt test cases/unit/56 introspection/t1.cpp test cases/unit/56 introspection/t2.cpp test cases/unit/56 introspection/t3.cpp test cases/unit/56 introspection/sharedlib/meson.build test cases/unit/56 introspection/sharedlib/shared.cpp test cases/unit/56 introspection/sharedlib/shared.hpp test cases/unit/56 introspection/staticlib/meson.build test cases/unit/56 introspection/staticlib/static.c test cases/unit/56 introspection/staticlib/static.h test cases/unit/57 pkg_config_path option/meson.build test cases/unit/57 pkg_config_path option/build_extra_path/totally_made_up_dep.pc test cases/unit/57 pkg_config_path option/host_extra_path/totally_made_up_dep.pc test cases/unit/58 introspect buildoptions/c_compiler.py test cases/unit/58 introspect buildoptions/main.c test cases/unit/58 introspect buildoptions/meson.build test cases/unit/58 introspect buildoptions/meson_options.txt test cases/unit/58 introspect buildoptions/subprojects/evilFile.txt test cases/unit/58 introspect buildoptions/subprojects/projectA/meson.build test cases/unit/58 introspect buildoptions/subprojects/projectA/meson_options.txt test cases/unit/58 introspect buildoptions/subprojects/projectBad/meson.build test cases/unit/58 introspect buildoptions/subprojects/projectBad/meson_options.txt test cases/unit/59 native file override/crossfile test cases/unit/59 native file override/crossfile2 test cases/unit/59 native file override/meson.build test cases/unit/59 native file override/meson_options.txt test cases/unit/59 native file override/nativefile 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 identity cross/build_wrapper.py test cases/unit/60 identity cross/host_wrapper.py test cases/unit/60 identity cross/meson.build test cases/unit/60 identity cross/stuff.h test cases/unit/61 pkgconfig relative paths/pkgconfig/librelativepath.pc test cases/unit/62 cmake_prefix_path/meson.build test cases/unit/62 cmake_prefix_path/prefix/lib/cmake/mesontest/mesontest-config.cmake test cases/unit/63 cmake parser/meson.build test cases/unit/63 cmake parser/prefix/lib/cmake/mesontest/mesontest-config.cmake test cases/unit/64 alias target/main.c test cases/unit/64 alias target/meson.build test cases/unit/64 alias target/subdir/meson.build test cases/unit/65 static archive stripping/app/appA.c test cases/unit/65 static archive stripping/app/appB.c test cases/unit/65 static archive stripping/app/meson.build test cases/unit/65 static archive stripping/lib/libA.c test cases/unit/65 static archive stripping/lib/libA.h test cases/unit/65 static archive stripping/lib/libB.c test cases/unit/65 static archive stripping/lib/libB.h test cases/unit/65 static archive stripping/lib/meson.build test cases/unit/66 static link/meson.build test cases/unit/66 static link/test1.c test cases/unit/66 static link/test2.c test cases/unit/66 static link/test3.c test cases/unit/66 static link/test4.c test cases/unit/66 static link/test5.c test cases/unit/66 static link/lib/func1.c test cases/unit/66 static link/lib/func10.c test cases/unit/66 static link/lib/func11.c test cases/unit/66 static link/lib/func12.c test cases/unit/66 static link/lib/func14.c test cases/unit/66 static link/lib/func15.c test cases/unit/66 static link/lib/func16.c test cases/unit/66 static link/lib/func17.c test cases/unit/66 static link/lib/func18.c test cases/unit/66 static link/lib/func19.c test cases/unit/66 static link/lib/func2.c test cases/unit/66 static link/lib/func3.c test cases/unit/66 static link/lib/func4.c test cases/unit/66 static link/lib/func5.c test cases/unit/66 static link/lib/func6.c test cases/unit/66 static link/lib/func7.c test cases/unit/66 static link/lib/func8.c test cases/unit/66 static link/lib/func9.c test cases/unit/66 static link/lib/meson.build test cases/unit/67 test env value/meson.build test cases/unit/67 test env value/test.py test cases/unit/68 clang-tidy/.clang-tidy test cases/unit/68 clang-tidy/cttest.cpp test cases/unit/68 clang-tidy/cttest_fixed.cpp test cases/unit/68 clang-tidy/meson.build test cases/unit/68 clang-tidy/dummydir.h/dummy.dat test cases/unit/69 cross/crossfile.in test cases/unit/69 cross/meson.build test cases/unit/69 cross/meson_options.txt 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 cross test passed/exewrapper.py test cases/unit/70 cross test passed/meson.build test cases/unit/70 cross test passed/meson_options.txt test cases/unit/70 cross test passed/script.py test cases/unit/70 cross test passed/src/main.c test cases/unit/71 summary/meson.build test cases/unit/71 summary/meson_options.txt test cases/unit/71 summary/subprojects/sub/meson.build test cases/unit/71 summary/subprojects/sub2/meson.build test cases/unit/71 summary/subprojects/sub2/subprojects/subsub/meson.build test cases/unit/72 wrap file url/meson.build test cases/unit/72 wrap file url/subprojects/foo-patch.tar.xz test cases/unit/72 wrap file url/subprojects/foo.tar.xz test cases/unit/73 dep files/foo.c test cases/unit/73 dep files/meson.build test cases/unit/74 pkgconfig prefixes/client/client.c test cases/unit/74 pkgconfig prefixes/client/meson.build test cases/unit/74 pkgconfig prefixes/val1/meson.build test cases/unit/74 pkgconfig prefixes/val1/val1.c test cases/unit/74 pkgconfig prefixes/val1/val1.h test cases/unit/74 pkgconfig prefixes/val2/meson.build test cases/unit/74 pkgconfig prefixes/val2/val2.c test cases/unit/74 pkgconfig prefixes/val2/val2.h test cases/unit/75 subdir libdir/meson.build test cases/unit/75 subdir libdir/subprojects/flub/meson.build test cases/unit/76 as link whole/bar.c test cases/unit/76 as link whole/foo.c test cases/unit/76 as link whole/meson.build test cases/unit/77 nostdlib/meson.build test cases/unit/77 nostdlib/prog.c test cases/unit/77 nostdlib/subprojects/mylibc/libc.c test cases/unit/77 nostdlib/subprojects/mylibc/meson.build test cases/unit/77 nostdlib/subprojects/mylibc/stdio.h test cases/unit/77 nostdlib/subprojects/mylibc/stubstart.s test cases/unit/78 user options for subproject/.gitignore test cases/unit/78 user options for subproject/75 user options for subproject/.gitignore test cases/unit/78 user options for subproject/75 user options for subproject/meson.build test cases/unit/78 user options for subproject/subprojects/sub/meson.build test cases/unit/78 user options for subproject/subprojects/sub/meson_options.txt test cases/unit/79 global-rpath/meson.build test cases/unit/79 global-rpath/rpathified.cpp test cases/unit/79 global-rpath/yonder/meson.build test cases/unit/79 global-rpath/yonder/yonder.cpp test cases/unit/79 global-rpath/yonder/yonder.h 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/80 wrap-git/meson.build test cases/unit/80 wrap-git/subprojects/packagefiles/wrap_git_builddef/meson.build test cases/unit/80 wrap-git/subprojects/wrap_git_upstream/main.c test cases/unit/81 meson version compare/meson.build test cases/unit/81 meson version compare/subprojects/foo/meson.build test cases/unit/82 cross only introspect/meson.build test cases/unit/83 change option choices/meson.build test cases/unit/83 change option choices/meson_options.1.txt test cases/unit/83 change option choices/meson_options.2.txt test cases/unit/84 nested subproject regenerate depends/main.c test cases/unit/84 nested subproject regenerate depends/meson.build test cases/unit/84 nested subproject regenerate depends/subprojects/sub1/meson.build test cases/unit/84 nested subproject regenerate depends/subprojects/sub2/CMakeLists.txt test cases/unit/85 cpp modules/meson.build test cases/unit/85 cpp modules/gcc/main.cpp test cases/unit/85 cpp modules/gcc/meson.build test cases/unit/85 cpp modules/gcc/src0.cxx test cases/unit/85 cpp modules/gcc/src1.cxx test cases/unit/85 cpp modules/gcc/src2.cxx test cases/unit/85 cpp modules/gcc/src3.cxx test cases/unit/85 cpp modules/gcc/src4.cxx test cases/unit/85 cpp modules/gcc/src5.cxx test cases/unit/85 cpp modules/gcc/src6.cxx test cases/unit/85 cpp modules/gcc/src7.cxx test cases/unit/85 cpp modules/gcc/src8.cxx test cases/unit/85 cpp modules/gcc/src9.cxx test cases/unit/85 cpp modules/vs/main.cpp test cases/unit/85 cpp modules/vs/meson.build test cases/unit/85 cpp modules/vs/src0.ixx test cases/unit/85 cpp modules/vs/src1.ixx test cases/unit/85 cpp modules/vs/src2.ixx test cases/unit/85 cpp modules/vs/src3.ixx test cases/unit/85 cpp modules/vs/src4.ixx test cases/unit/85 cpp modules/vs/src5.ixx test cases/unit/85 cpp modules/vs/src6.ixx test cases/unit/85 cpp modules/vs/src7.ixx test cases/unit/85 cpp modules/vs/src8.ixx test cases/unit/85 cpp modules/vs/src9.ixx test cases/unit/86 prelinking/file1.c test cases/unit/86 prelinking/file2.c test cases/unit/86 prelinking/file3.c test cases/unit/86 prelinking/file4.c test cases/unit/86 prelinking/main.c test cases/unit/86 prelinking/meson.build test cases/unit/86 prelinking/private_header.h test cases/unit/86 prelinking/public_header.h test cases/unit/87 run native test/main.c test cases/unit/87 run native test/meson.build test cases/unit/88 multiple envvars/meson.build test cases/unit/88 multiple envvars/prog.c test cases/unit/88 multiple envvars/prog.cpp test cases/unit/89 pkgconfig build rpath order/dummy.pc test cases/unit/89 pkgconfig build rpath order/meson.build test cases/unit/89 pkgconfig build rpath order/prog.c test cases/unit/89 pkgconfig build rpath order/prog.cc test cases/unit/89 pkgconfig build rpath order/sub/meson.build test cases/unit/89 pkgconfig build rpath order/sub/stuff.c test cases/unit/9 d dedup/meson.build test cases/unit/9 d dedup/prog.c test cases/unit/90 devenv/main.c test cases/unit/90 devenv/meson.build test cases/unit/90 devenv/test-devenv.py test cases/unit/90 devenv/subprojects/sub/foo.c test cases/unit/90 devenv/subprojects/sub/meson.build test cases/unit/92 install skip subprojects/foo.c test cases/unit/92 install skip subprojects/foo.dat test cases/unit/92 install skip subprojects/foo.h test cases/unit/92 install skip subprojects/meson.build test cases/unit/92 install skip subprojects/foo/foofile test cases/unit/92 install skip subprojects/subprojects/bar/bar.c test cases/unit/92 install skip subprojects/subprojects/bar/bar.dat test cases/unit/92 install skip subprojects/subprojects/bar/bar.h test cases/unit/92 install skip subprojects/subprojects/bar/meson.build test cases/unit/92 install skip subprojects/subprojects/bar/bar/barfile test cases/unit/93 new subproject in configured project/meson.build test cases/unit/93 new subproject in configured project/meson_options.txt test cases/unit/93 new subproject in configured project/subprojects/sub/foo.c test cases/unit/93 new subproject in configured project/subprojects/sub/meson.build test cases/unit/94 clangformat/.clang-format test cases/unit/94 clangformat/.clang-format-ignore test cases/unit/94 clangformat/.clang-format-include test cases/unit/94 clangformat/meson.build test cases/unit/94 clangformat/not-included/badformat.cpp test cases/unit/94 clangformat/src/badformat.c test cases/unit/94 clangformat/src/badformat.cpp test cases/unit/95 custominc/helper.c test cases/unit/95 custominc/meson.build test cases/unit/95 custominc/prog.c test cases/unit/95 custominc/prog2.c test cases/unit/95 custominc/easytogrepfor/genh.py test cases/unit/95 custominc/easytogrepfor/meson.build test cases/unit/96 implicit force fallback/meson.build test cases/unit/96 implicit force fallback/subprojects/something/meson.build test cases/unit/97 compiler.links file arg/meson.build test cases/unit/97 compiler.links file arg/test.c test cases/unit/98 link full name/.gitignore test cases/unit/98 link full name/libtestprovider/meson.build test cases/unit/98 link full name/libtestprovider/provider.c test cases/unit/98 link full name/proguser/meson.build test cases/unit/98 link full name/proguser/receiver.c test cases/unit/99 install all targets/bar-custom.txt test cases/unit/99 install all targets/bar-devel.h test cases/unit/99 install all targets/bar-notag.txt test cases/unit/99 install all targets/foo.in test cases/unit/99 install all targets/foo1-devel.h test cases/unit/99 install all targets/lib.c test cases/unit/99 install all targets/main.c test cases/unit/99 install all targets/meson.build test cases/unit/99 install all targets/script.py test cases/unit/99 install all targets/custom_files/data.txt test cases/unit/99 install all targets/excludes/excluded.txt test cases/unit/99 install all targets/excludes/installed.txt test cases/unit/99 install all targets/excludes/excluded/placeholder.txt test cases/unit/99 install all targets/subdir/bar2-devel.h test cases/unit/99 install all targets/subdir/foo2.in test cases/unit/99 install all targets/subdir/foo3-devel.h test cases/unit/99 install all targets/subdir/lib.c test cases/unit/99 install all targets/subdir/main.c test cases/unit/99 install all targets/subdir/meson.build test cases/unit/99 install all targets/subdir/script.py test cases/unit/99 install all targets/subprojects/subproject/aaa.txt test cases/unit/99 install all targets/subprojects/subproject/bbb.txt test cases/unit/99 install all targets/subprojects/subproject/meson.build 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/main.vala test cases/vala/11 generated vapi/meson.build test cases/vala/11 generated vapi/test.json 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/foo.metadata 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/27 file as command line argument/meson.build test cases/vala/27 file as command line argument/my-resources.xml test cases/vala/27 file as command line argument/mywidget.ui test cases/vala/27 file as command line argument/mywidget.vala 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/meson.build test cases/vala/6 static library/mylib.vala test cases/vala/6 static library/prog.vala test cases/vala/6 static library/test.json test cases/vala/7 shared library/meson.build test cases/vala/7 shared library/test.json test cases/vala/7 shared library/lib/meson.build test cases/vala/7 shared library/lib/mylib.vala test cases/vala/7 shared library/lib/source.py test cases/vala/7 shared library/prog/meson.build test cases/vala/7 shared library/prog/prog.vala test cases/vala/8 generated sources/meson.build test cases/vala/8 generated sources/test.json 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/meson.build test cases/vala/9 gir/test.json test cases/warning/1 version for string div/meson.build test cases/warning/1 version for string div/test.json test cases/warning/1 version for string div/a/b.c test cases/warning/2 languages missing native/meson.build test cases/warning/2 languages missing native/test.json test cases/warning/3 fallback consistency/meson.build test cases/warning/3 fallback consistency/test.json test cases/warning/3 fallback consistency/subprojects/sub/meson.build test cases/warning/4 fallback consistency/meson.build test cases/warning/4 fallback consistency/test.json test cases/warning/4 fallback consistency/subprojects/sub/meson.build test cases/warning/5 fallback consistency/meson.build test cases/warning/5 fallback consistency/test.json test cases/warning/5 fallback consistency/subprojects/foo.wrap test cases/warning/5 fallback consistency/subprojects/foo/meson.build test cases/warning/6 list add/meson.build test cases/warning/6 list add/test.json test cases/warning/7 module without unstable/meson.build test cases/warning/7 module without unstable/test.json test cases/warning/8 target with no sources/meson.build test cases/warning/8 target with no sources/test.json test cases/warning/9 meson.options/meson.build test cases/warning/9 meson.options/meson.options test cases/warning/9 meson.options/test.json test cases/warning/9 meson.options/subprojects/no-warn/meson.build test cases/warning/9 meson.options/subprojects/no-warn/meson.options test cases/warning/9 meson.options/subprojects/no-warn/meson_options.txt test cases/wasm/1 basic/hello.c test cases/wasm/1 basic/hello.cpp test cases/wasm/1 basic/hello.html test cases/wasm/1 basic/meson.build test cases/wasm/2 threads/meson.build test cases/wasm/2 threads/threads.c test cases/wasm/2 threads/threads.cpp test cases/wasm/3 jslib/meson.build test cases/wasm/3 jslib/prog.c test cases/wasm/3 jslib/somefuncs.js test cases/wayland/1 client/both.c test cases/wayland/1 client/client.c test cases/wayland/1 client/local.c test cases/wayland/1 client/meson.build test cases/wayland/1 client/server.c test cases/wayland/1 client/test.xml test cases/wayland/2 core only/core.c test cases/wayland/2 core only/meson.build test cases/windows/1 basic/meson.build test cases/windows/1 basic/prog.c test cases/windows/1 basic/test.json 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/meson.build test cases/windows/11 exe implib/prog.c test cases/windows/11 exe implib/test.json 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/17 msvc ndebug/main.cpp test cases/windows/17 msvc ndebug/meson.build test cases/windows/18 msvc charset/iso-8859-1.c test cases/windows/18 msvc charset/meson.build test cases/windows/18 msvc charset/meson_options.txt test cases/windows/18 msvc charset/utf8.c test cases/windows/19 msvc cplusplus define/main.cpp test cases/windows/19 msvc cplusplus define/meson.build test cases/windows/2 winmain/meson.build test cases/windows/2 winmain/prog.c test cases/windows/20 vs install static lib with generated obj deps/both_lib_source.c test cases/windows/20 vs install static lib with generated obj deps/copyfile.py test cases/windows/20 vs install static lib with generated obj deps/generated_source.c test cases/windows/20 vs install static lib with generated obj deps/meson.build test cases/windows/20 vs install static lib with generated obj deps/static_lib_source.c test cases/windows/20 vs install static lib with generated obj deps/test.json test cases/windows/21 masm/hello.masm test cases/windows/21 masm/meson.build 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/lib.c test cases/windows/7 dll versioning/meson.build test cases/windows/7 dll versioning/test.json 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/exe.def 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/build_website.py tools/cmake2meson.py tools/copy_files.py tools/dircondenser.py tools/regenerate_docs.py tools/run_with_cov.py unittests/__init__.py unittests/allplatformstests.py unittests/baseplatformtests.py unittests/cargotests.py unittests/darwintests.py unittests/datatests.py unittests/failuretests.py unittests/helpers.py unittests/internaltests.py unittests/linuxcrosstests.py unittests/linuxliketests.py unittests/machinefiletests.py unittests/platformagnostictests.py unittests/pythontests.py unittests/rewritetests.py unittests/subprojectscommandtests.py unittests/taptests.py unittests/windowstests.py././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853066.0 meson-1.3.2/meson.egg-info/dependency_links.txt0000644000175000017500000000000114562742412021720 0ustar00jpakkanejpakkane ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853066.0 meson-1.3.2/meson.egg-info/entry_points.txt0000644000175000017500000000006414562742412021150 0ustar00jpakkanejpakkane[console_scripts] meson = mesonbuild.mesonmain:main ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853066.0 meson-1.3.2/meson.egg-info/requires.txt0000644000175000017500000000015114562742412020247 0ustar00jpakkanejpakkane [ninja] ninja>=1.8.2 [progress] tqdm [typing] mypy [typing:python_version < "3.8"] typing_extensions ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853066.0 meson-1.3.2/meson.egg-info/top_level.txt0000644000175000017500000000001314562742412020376 0ustar00jpakkanejpakkanemesonbuild ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/meson.py0000755000175000017500000000274614562742363014553 0ustar00jpakkanejpakkane#!/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 file is an entry point for all commands, including scripts. Include the # strict minimum python modules for performance reasons. import sys # Check python version before importing anything else, we might have an older # Python that would error on f-string syntax for example. if sys.version_info < (3, 7): print('Meson works correctly only with python 3.7+.') print('You have python {}.'.format(sys.version)) print('Please update your environment') sys.exit(1) 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()) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.582637 meson-1.3.2/mesonbuild/0000755000175000017500000000000014562742414015202 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1650551419.0 meson-1.3.2/mesonbuild/__init__.py0000644000175000017500000000000014230265173017273 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/_pathlib.py0000644000175000017500000000456314562742363017351 0ustar00jpakkanejpakkane# Copyright 2021 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ''' This module soly exists to work around a pathlib.resolve bug on certain Windows systems: https://github.com/mesonbuild/meson/issues/7295 https://bugs.python.org/issue31842 It should **never** be used directly. Instead, it is automatically used when `import pathlib` is used. This is achieved by messing with `sys.modules['pathlib']` in mesonmain. Additionally, the sole purpose of this module is to work around a python bug. This only bugfixes to pathlib functions and classes are allowed here. Finally, this file should be removed once all upstream python bugs are fixed and it is OK to tell our users to "just upgrade python". ''' from __future__ import annotations import pathlib import os import platform __all__ = [ 'PurePath', 'PurePosixPath', 'PureWindowsPath', 'Path', ] PurePath = pathlib.PurePath PurePosixPath = pathlib.PurePosixPath PureWindowsPath = pathlib.PureWindowsPath # Only patch on platforms where the bug occurs if platform.system().lower() in {'windows'}: # Can not directly inherit from pathlib.Path because the __new__ # operator of pathlib.Path() returns a {Posix,Windows}Path object. class Path(type(pathlib.Path())): def resolve(self, strict: bool = False) -> 'Path': ''' Work around a resolve bug on certain Windows systems: https://github.com/mesonbuild/meson/issues/7295 https://bugs.python.org/issue31842 ''' try: return super().resolve(strict=strict) except OSError: return Path(os.path.normpath(self)) else: Path = pathlib.Path PosixPath = pathlib.PosixPath WindowsPath = pathlib.WindowsPath __all__ += [ 'PosixPath', 'WindowsPath', ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/_typing.py0000644000175000017500000000454214562742363017235 0ustar00jpakkanejpakkane# SPDX-License-Identifer: Apache-2.0 # Copyright 2020 The Meson development team # Copyright Ā© 2020-2021 Intel Corporation # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Meson specific typing helpers. Holds typing helper classes, such as the ImmutableProtocol classes """ __all__ = [ 'Protocol', 'ImmutableListProtocol' ] import typing # We can change this to typing when we require python 3.8 from typing_extensions import Protocol T = typing.TypeVar('T') class StringProtocol(Protocol): def __str__(self) -> str: ... class SizedStringProtocol(Protocol, StringProtocol, typing.Sized): pass class ImmutableListProtocol(Protocol[T]): """A protocol used in cases where a list is returned, but should not be mutated. This provides all of the methods of a Sequence, as well as copy(). copy() returns a list, which allows mutation as it's a copy and that's (hopefully) safe. One particular case this is important is for cached values, since python is a pass-by-reference language. """ def __iter__(self) -> typing.Iterator[T]: ... @typing.overload def __getitem__(self, index: int) -> T: ... @typing.overload def __getitem__(self, index: slice) -> typing.List[T]: ... def __contains__(self, item: T) -> bool: ... def __reversed__(self) -> typing.Iterator[T]: ... def __len__(self) -> int: ... def __add__(self, other: typing.List[T]) -> typing.List[T]: ... def __eq__(self, other: typing.Any) -> bool: ... def __ne__(self, other: typing.Any) -> bool: ... def __le__(self, other: typing.Any) -> bool: ... def __lt__(self, other: typing.Any) -> bool: ... def __gt__(self, other: typing.Any) -> bool: ... def __ge__(self, other: typing.Any) -> bool: ... def count(self, item: T) -> int: ... def index(self, item: T) -> int: ... def copy(self) -> typing.List[T]: ... ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/arglist.py0000644000175000017500000003160614562742363017232 0ustar00jpakkanejpakkane# Copyright 2012-2020 The Meson development team # Copyright Ā© 2020 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. from __future__ import annotations from functools import lru_cache import collections import enum import os import re import typing as T if T.TYPE_CHECKING: from .linkers.linkers import StaticLinker from .compilers import Compiler # execinfo is a compiler lib on BSD UNIXY_COMPILER_INTERNAL_LIBS = ['m', 'c', 'pthread', 'dl', 'rt', 'execinfo'] class Dedup(enum.Enum): """What kind of deduplication can be done to compiler args. OVERRIDDEN - 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. UNIQUE - Arguments that once specified cannot be undone, such as `-c` or `-pipe`. New instances of these can be completely skipped. NO_DEDUP - 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. """ NO_DEDUP = 0 UNIQUE = 1 OVERRIDDEN = 2 class CompilerArgs(T.MutableSequence[str]): ''' 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'] ''' # Arg prefixes that override by prepending instead of appending prepend_prefixes: T.Tuple[str, ...] = () # Arg prefixes and args that must be de-duped by returning 2 dedup2_prefixes: T.Tuple[str, ...] = () dedup2_suffixes: T.Tuple[str, ...] = () dedup2_args: T.Tuple[str, ...] = () # 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: T.Tuple[str, ...] = () 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: T.Tuple[str, ...] = () # 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 # TODO: these should probably move too 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: T.List[str] = list(iterable) if iterable is not None else [] self.pre: T.Deque[str] = collections.deque() self.post: T.Deque[str] = collections.deque() # Flush the saved pre and post list into the _container list # # This correctly deduplicates the entries after _can_dedup definition # Note: This function is designed to work without delete operations, as deletions are worsening the performance a lot. def flush_pre_post(self) -> None: new: T.List[str] = [] pre_flush_set: T.Set[str] = set() post_flush: T.Deque[str] = collections.deque() post_flush_set: T.Set[str] = set() #The two lists are here walked from the front to the back, in order to not need removals for deduplication for a in self.pre: dedup = self._can_dedup(a) if a not in pre_flush_set: new.append(a) if dedup is Dedup.OVERRIDDEN: pre_flush_set.add(a) for a in reversed(self.post): dedup = self._can_dedup(a) if a not in post_flush_set: post_flush.appendleft(a) if dedup is Dedup.OVERRIDDEN: post_flush_set.add(a) #pre and post will overwrite every element that is in the container #only copy over args that are in _container but not in the post flush or pre flush set if pre_flush_set or post_flush_set: for a in self._container: if a not in post_flush_set and a not in pre_flush_set: new.append(a) else: new.extend(self._container) new.extend(post_flush) self._container = new self.pre.clear() self.post.clear() def __iter__(self) -> T.Iterator[str]: self.flush_pre_post() return iter(self._container) @T.overload # noqa: F811 def __getitem__(self, index: int) -> str: # noqa: F811 pass @T.overload # noqa: F811 def __getitem__(self, index: slice) -> T.MutableSequence[str]: # noqa: F811 pass def __getitem__(self, index: T.Union[int, slice]) -> T.Union[str, T.MutableSequence[str]]: # noqa: F811 self.flush_pre_post() 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.Iterable[str]) -> None: # noqa: F811 pass def __setitem__(self, index: T.Union[int, slice], value: T.Union[str, T.Iterable[str]]) -> None: # noqa: F811 self.flush_pre_post() self._container[index] = value # type: ignore # TODO: fix 'Invalid index type' and 'Incompatible types in assignment' errors def __delitem__(self, index: T.Union[int, slice]) -> None: self.flush_pre_post() del self._container[index] def __len__(self) -> int: return len(self._container) + len(self.pre) + len(self.post) def insert(self, index: int, value: str) -> None: self.flush_pre_post() self._container.insert(index, value) def copy(self) -> 'CompilerArgs': self.flush_pre_post() return type(self)(self.compiler, self._container.copy()) @classmethod @lru_cache(maxsize=None) def _can_dedup(cls, arg: str) -> Dedup: """Returns whether the argument can be safely de-duped. 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 deduping 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 Dedup.NO_DEDUP if arg in cls.dedup2_args or \ arg.startswith(cls.dedup2_prefixes) or \ arg.endswith(cls.dedup2_suffixes): return Dedup.OVERRIDDEN 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 Dedup.UNIQUE return Dedup.NO_DEDUP @classmethod @lru_cache(maxsize=None) def _should_prepend(cls, arg: str) -> bool: return arg.startswith(cls.prepend_prefixes) 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. self.flush_pre_post() if copy: new = self.copy() else: new = self 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. ''' self.flush_pre_post() 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 ''' self.flush_pre_post() 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': self.flush_pre_post() 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 ''' tmp_pre: T.Deque[str] = collections.deque() if not isinstance(args, collections.abc.Iterable): raise TypeError(f'can only concatenate Iterable[str] (not "{args}") to CompilerArgs') 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 is Dedup.UNIQUE: # Argument already exists and adding a new instance is useless if arg in self._container or arg in self.pre or arg in self.post: continue if self._should_prepend(arg): tmp_pre.appendleft(arg) else: self.post.append(arg) self.pre.extendleft(tmp_pre) #pre and post is going to be merged later before a iter call return self def __radd__(self, args: T.Iterable[str]) -> 'CompilerArgs': self.flush_pre_post() new = type(self)(self.compiler, args) new += self return new def __eq__(self, other: object) -> T.Union[bool]: self.flush_pre_post() # 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 += [arg] def extend(self, args: T.Iterable[str]) -> None: self += args def __repr__(self) -> str: self.flush_pre_post() return f'CompilerArgs({self.compiler!r}, {self._container!r})' ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.582637 meson-1.3.2/mesonbuild/ast/0000755000175000017500000000000014562742414015771 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/ast/__init__.py0000644000175000017500000000227414562742363020112 0ustar00jpakkanejpakkane# 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', 'AstJSONPrinter', '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, AstJSONPrinter ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/ast/interpreter.py0000644000175000017500000004430414562742363020716 0ustar00jpakkanejpakkane# 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 __future__ import annotations import os import sys import typing as T from .. import mparser, mesonlib from .. import environment from ..interpreterbase import ( MesonInterpreterObject, InterpreterBase, InvalidArguments, BreakRequest, ContinueRequest, Disabler, default_resolve_key, ) from ..interpreter import ( StringHolder, BooleanHolder, IntegerHolder, ArrayHolder, DictHolder, ) from ..mparser import ( ArgumentNode, ArithmeticNode, ArrayNode, AssignmentNode, BaseNode, ElementaryNode, EmptyNode, IdNode, MethodNode, NotNode, PlusAssignmentNode, TernaryNode, TestCaseClauseNode, ) if T.TYPE_CHECKING: from .visitor import AstVisitor from ..interpreter import Interpreter from ..interpreterbase import TYPE_nkwargs, TYPE_nvar from ..mparser import ( AndNode, ComparisonNode, ForeachClauseNode, IfClauseNode, IndexNode, OrNode, UMinusNode, ) class DontCareObject(MesonInterpreterObject): pass class MockExecutable(MesonInterpreterObject): pass class MockStaticLibrary(MesonInterpreterObject): pass class MockSharedLibrary(MesonInterpreterObject): pass class MockCustomTarget(MesonInterpreterObject): pass class MockRunTarget(MesonInterpreterObject): pass ADD_SOURCE = 0 REMOVE_SOURCE = 1 _T = T.TypeVar('_T') _V = T.TypeVar('_V') class AstInterpreter(InterpreterBase): def __init__(self, source_root: str, subdir: str, subproject: str, visitors: T.Optional[T.List[AstVisitor]] = None): super().__init__(source_root, subdir, subproject) self.visitors = visitors if visitors is not None else [] self.processed_buildfiles: T.Set[str] = set() self.assignments: T.Dict[str, BaseNode] = {} self.assign_vals: T.Dict[str, T.Any] = {} self.reverse_assignment: T.Dict[str, BaseNode] = {} 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, 'install_symlink': self.func_do_nothing, 'install_emptydir': 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_dependencies': 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, 'unset_variable': self.func_do_nothing, 'is_disabler': self.func_do_nothing, 'is_variable': self.func_do_nothing, 'disabler': 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, 'subdir_done': self.func_do_nothing, 'alias_target': self.func_do_nothing, 'summary': self.func_do_nothing, 'range': self.func_do_nothing, 'structured_sources': self.func_do_nothing, 'debug': self.func_do_nothing, }) def _unholder_args(self, args: _T, kwargs: _V) -> T.Tuple[_T, _V]: return args, kwargs def _holderify(self, res: _T) -> _T: return res def func_do_nothing(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> bool: return True def load_root_meson_file(self) -> None: super().load_root_meson_file() for i in self.visitors: self.ast.accept(i) def func_subdir(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> None: args = self.flatten_args(args) if len(args) != 1 or not isinstance(args[0], str): sys.stderr.write(f'Unable to evaluate subdir({args}) in AstInterpreter --> Skipping\n') 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) build_file = os.path.join(symlinkless_dir, 'meson.build') if build_file in self.processed_buildfiles: sys.stderr.write('Trying to enter {} which has already been visited --> Skipping\n'.format(args[0])) return self.processed_buildfiles.add(build_file) if not os.path.isfile(absname): sys.stderr.write(f'Unable to find build file {buildfilename} --> Skipping\n') return with open(absname, encoding='utf-8') as f: code = f.read() assert isinstance(code, str) try: codeblock = mparser.Parser(code, absname).parse() except mesonlib.MesonException as me: me.file = absname 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: BaseNode) -> bool: return True def evaluate_fstring(self, node: mparser.FormatStringNode) -> str: assert isinstance(node, mparser.FormatStringNode) return node.value def evaluate_arraystatement(self, cur: mparser.ArrayNode) -> TYPE_nvar: return self.reduce_arguments(cur.args)[0] def evaluate_arithmeticstatement(self, cur: ArithmeticNode) -> int: self.evaluate_statement(cur.left) self.evaluate_statement(cur.right) return 0 def evaluate_uminusstatement(self, cur: UMinusNode) -> int: self.evaluate_statement(cur.value) return 0 def evaluate_ternary(self, node: TernaryNode) -> None: assert isinstance(node, TernaryNode) self.evaluate_statement(node.condition) self.evaluate_statement(node.trueblock) self.evaluate_statement(node.falseblock) def evaluate_dictstatement(self, node: mparser.DictNode) -> TYPE_nkwargs: def resolve_key(node: mparser.BaseNode) -> str: if isinstance(node, mparser.BaseStringNode): return node.value return '__AST_UNKNOWN__' arguments, kwargs = self.reduce_arguments(node.args, key_resolver=resolve_key) assert not arguments self.argument_depth += 1 for key, value in kwargs.items(): if isinstance(key, BaseNode): self.evaluate_statement(key) self.argument_depth -= 1 return {} def evaluate_plusassign(self, node: PlusAssignmentNode) -> None: assert isinstance(node, PlusAssignmentNode) # Cheat by doing a reassignment self.assignments[node.var_name.value] = node.value # Save a reference to the value node if node.value.ast_id: self.reverse_assignment[node.value.ast_id] = node self.assign_vals[node.var_name.value] = self.evaluate_statement(node.value) def evaluate_indexing(self, node: IndexNode) -> int: return 0 def unknown_function_called(self, func_name: str) -> None: pass def reduce_arguments( self, args: mparser.ArgumentNode, key_resolver: T.Callable[[mparser.BaseNode], str] = default_resolve_key, duplicate_key_error: T.Optional[str] = None, ) -> T.Tuple[T.List[TYPE_nvar], TYPE_nkwargs]: if isinstance(args, ArgumentNode): kwargs: T.Dict[str, TYPE_nvar] = {} for key, val in args.kwargs.items(): kwargs[key_resolver(key)] = val if args.incorrect_order(): raise InvalidArguments('All keyword arguments must be after positional arguments.') return self.flatten_args(args.arguments), kwargs else: return self.flatten_args(args), {} def evaluate_comparison(self, node: ComparisonNode) -> bool: self.evaluate_statement(node.left) self.evaluate_statement(node.right) return False def evaluate_andstatement(self, cur: AndNode) -> bool: self.evaluate_statement(cur.left) self.evaluate_statement(cur.right) return False def evaluate_orstatement(self, cur: OrNode) -> bool: self.evaluate_statement(cur.left) self.evaluate_statement(cur.right) return False def evaluate_notstatement(self, cur: NotNode) -> bool: self.evaluate_statement(cur.value) return False def evaluate_foreach(self, node: ForeachClauseNode) -> None: try: self.evaluate_codeblock(node.block) except ContinueRequest: pass except BreakRequest: pass def evaluate_if(self, node: IfClauseNode) -> None: for i in node.ifs: self.evaluate_codeblock(i.block) if not isinstance(node.elseblock, EmptyNode): self.evaluate_codeblock(node.elseblock.block) def get_variable(self, varname: str) -> int: return 0 def assignment(self, node: AssignmentNode) -> None: assert isinstance(node, AssignmentNode) self.assignments[node.var_name.value] = node.value # Save a reference to the value node if node.value.ast_id: self.reverse_assignment[node.value.ast_id] = node self.assign_vals[node.var_name.value] = 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): assert isinstance(n.value, str) if n.value in loop_detect or n.value not in self.assignments: return [] return quick_resolve(self.assignments[n.value], 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 node.ast_id if node.ast_id in id_loop_detect: return None # Loop detected id_loop_detect += [node.ast_id] # Try to evaluate the value of the node if isinstance(node, IdNode): result = quick_resolve(node) elif isinstance(node, ElementaryNode): result = node.value elif isinstance(node, NotNode): result = self.resolve_node(node.value, include_unknown_args, id_loop_detect) if isinstance(result, bool): result = not result elif isinstance(node, ArrayNode): result = node.args.arguments.copy() elif isinstance(node, ArgumentNode): result = node.arguments.copy() elif isinstance(node, ArithmeticNode): if node.operation != 'add': return None # Only handle string and array concats l = self.resolve_node(node.left, include_unknown_args, id_loop_detect) r = self.resolve_node(node.right, include_unknown_args, id_loop_detect) 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.arguments, include_unknown_args, id_loop_detect) mkwargs: T.Dict[str, TYPE_nvar] = {} method_name = node.name.value try: if isinstance(src, str): result = StringHolder(src, T.cast('Interpreter', self)).method_call(method_name, margs, mkwargs) elif isinstance(src, bool): result = BooleanHolder(src, T.cast('Interpreter', self)).method_call(method_name, margs, mkwargs) elif isinstance(src, int): result = IntegerHolder(src, T.cast('Interpreter', self)).method_call(method_name, margs, mkwargs) elif isinstance(src, list): result = ArrayHolder(src, T.cast('Interpreter', self)).method_call(method_name, margs, mkwargs) elif isinstance(src, dict): result = DictHolder(src, T.cast('Interpreter', self)).method_call(method_name, margs, mkwargs) 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: T.List[TYPE_nvar] = [] 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_raw: T.Union[TYPE_nvar, T.Sequence[TYPE_nvar]], include_unknown_args: bool = False, id_loop_detect: T.Optional[T.List[str]] = None) -> T.List[TYPE_nvar]: # Make sure we are always dealing with lists if isinstance(args_raw, list): args = args_raw else: args = [args_raw] flattened_args: T.List[TYPE_nvar] = [] # 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] flattened_args += resolved elif isinstance(i, (str, bool, int, float)) or include_unknown_args: flattened_args += [i] return flattened_args def flatten_kwargs(self, kwargs: T.Dict[str, TYPE_nvar], include_unknown_args: bool = False) -> T.Dict[str, TYPE_nvar]: flattened_kwargs = {} for key, val in kwargs.items(): if isinstance(val, BaseNode): resolved = self.resolve_node(val, include_unknown_args) if resolved is not None: flattened_kwargs[key] = resolved elif isinstance(val, (str, bool, int, float)) or include_unknown_args: flattened_kwargs[key] = val return flattened_kwargs def evaluate_testcase(self, node: TestCaseClauseNode) -> Disabler | None: return Disabler(subproject=self.subproject) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/ast/introspection.py0000644000175000017500000004273514562742363021261 0ustar00jpakkanejpakkane# 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 __future__ import annotations import argparse import copy import os import typing as T from .. import compilers, environment, mesonlib, optinterpreter from .. import coredata as cdata from ..build import Executable, Jar, SharedLibrary, SharedModule, StaticLibrary from ..compilers import detect_compiler_for from ..interpreterbase import InvalidArguments from ..mesonlib import MachineChoice, OptionKey from ..mparser import BaseNode, ArithmeticNode, ArrayNode, ElementaryNode, IdNode, FunctionNode, BaseStringNode from .interpreter import AstInterpreter if T.TYPE_CHECKING: from ..build import BuildTarget from ..interpreterbase import TYPE_nvar from .visitor import AstVisitor # TODO: it would be nice to not have to duplicate this BUILD_TARGET_FUNCTIONS = [ 'executable', 'jar', 'library', 'shared_library', 'shared_module', 'static_library', 'both_libraries' ] class IntrospectionHelper(argparse.Namespace): # mimic an argparse namespace def __init__(self, cross_file: str): super().__init__() self.cross_file = cross_file self.native_file: str = None self.cmd_line_options: T.Dict[str, str] = {} def __eq__(self, other: object) -> bool: return NotImplemented 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: str, subdir: str, backend: str, visitors: T.Optional[T.List[AstVisitor]] = None, cross_file: T.Optional[str] = None, subproject: str = '', subproject_dir: str = 'subprojects', env: T.Optional[environment.Environment] = None): visitors = visitors if visitors is not None else [] super().__init__(source_root, subdir, subproject, 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_dir = subproject_dir self.coredata = self.environment.get_coredata() self.backend = backend self.default_options = {OptionKey('backend'): self.backend} self.project_data: T.Dict[str, T.Any] = {} self.targets: T.List[T.Dict[str, T.Any]] = [] self.dependencies: T.List[T.Dict[str, T.Any]] = [] self.project_node: BaseNode = 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: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> None: 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} optfile = os.path.join(self.source_root, self.subdir, 'meson.options') if not os.path.exists(optfile): optfile = os.path.join(self.source_root, self.subdir, 'meson_options.txt') if os.path.exists(optfile): oi = optinterpreter.OptionInterpreter(self.subproject) oi.process(optfile) self.coredata.update_project_options(oi.options) def_opts = self.flatten_args(kwargs.get('default_options', [])) _project_default_options = mesonlib.stringlistify(def_opts) self.project_default_options = cdata.create_options_dict(_project_default_options, self.subproject) 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, BaseStringNode): assert isinstance(spdirname.value, str) 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.options.items() if k.is_backend()} self.coredata.set_options(options) self._add_languages(proj_langs, True, MachineChoice.HOST) self._add_languages(proj_langs, True, MachineChoice.BUILD) def do_subproject(self, dirname: str) -> None: 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: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> None: kwargs = self.flatten_kwargs(kwargs) required = kwargs.get('required', True) if isinstance(required, cdata.UserFeatureOption): required = required.is_enabled() if 'native' in kwargs: native = kwargs.get('native', False) self._add_languages(args, required, MachineChoice.BUILD if native else MachineChoice.HOST) else: for for_machine in [MachineChoice.BUILD, MachineChoice.HOST]: self._add_languages(args, required, for_machine) def _add_languages(self, raw_langs: T.List[TYPE_nvar], required: bool, for_machine: MachineChoice) -> None: langs: T.List[str] = [] for l in self.flatten_args(raw_langs): if isinstance(l, str): langs.append(l) elif isinstance(l, BaseStringNode): langs.append(l.value) for lang in sorted(langs, key=compilers.sort_clink): lang = lang.lower() if lang not in self.coredata.compilers[for_machine]: try: comp = detect_compiler_for(self.environment, lang, for_machine, True) except mesonlib.MesonException: # do we even care about introspecting this language? if required: raise else: continue if self.subproject: options = {} for k in comp.get_options(): v = copy.copy(self.coredata.options[k]) k = k.evolve(subproject=self.subproject) options[k] = v self.coredata.add_compiler_options(options, lang, for_machine, self.environment) def func_dependency(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> None: 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] 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': node.condition_level > 0, 'node': node }] def build_target(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs_raw: T.Dict[str, TYPE_nvar], targetclass: T.Type[BuildTarget]) -> T.Optional[T.Dict[str, T.Any]]: args = self.flatten_args(args) if not args or not isinstance(args[0], str): return None name = args[0] srcqueue = [node] extra_queue = [] # Process the sources BEFORE flattening the kwargs, to preserve the original nodes if 'sources' in kwargs_raw: srcqueue += mesonlib.listify(kwargs_raw['sources']) if 'extra_files' in kwargs_raw: extra_queue += mesonlib.listify(kwargs_raw['extra_files']) kwargs = self.flatten_kwargs(kwargs_raw, True) def traverse_nodes(inqueue: T.List[BaseNode]) -> T.List[BaseNode]: res: T.List[BaseNode] = [] while inqueue: curr = inqueue.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 assert isinstance(curr.value, str) var_name = curr.value if var_name in self.assignments: tmp_node = self.assignments[var_name] if isinstance(tmp_node, (ArrayNode, IdNode, FunctionNode)): inqueue += [tmp_node] elif isinstance(curr, ArithmeticNode): inqueue += [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.value in BUILD_TARGET_FUNCTIONS: arg_nodes.pop(0) elementary_nodes = [x for x in arg_nodes if isinstance(x, (str, BaseStringNode))] inqueue += [x for x in arg_nodes if isinstance(x, (FunctionNode, ArrayNode, IdNode, ArithmeticNode))] if elementary_nodes: res += [curr] return res source_nodes = traverse_nodes(srcqueue) extraf_nodes = traverse_nodes(extra_queue) # 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: T.List[T.Any] = [] empty_sources: T.List[T.Any] = [] # Passing the unresolved sources list causes errors kwargs_reduced['_allow_no_sources'] = True target = targetclass(name, self.subdir, self.subproject, for_machine, empty_sources, [], objects, self.environment, self.coredata.compilers[for_machine], kwargs_reduced) target.process_compilers_late() 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, 'extra_files': extraf_nodes, 'kwargs': kwargs, 'node': node, } self.targets += [new_target] return new_target def build_library(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> T.Optional[T.Dict[str, T.Any]]: default_library = self.coredata.get_option(OptionKey('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) return None def func_executable(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> T.Optional[T.Dict[str, T.Any]]: return self.build_target(node, args, kwargs, Executable) def func_static_lib(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> T.Optional[T.Dict[str, T.Any]]: return self.build_target(node, args, kwargs, StaticLibrary) def func_shared_lib(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> T.Optional[T.Dict[str, T.Any]]: return self.build_target(node, args, kwargs, SharedLibrary) def func_both_lib(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> T.Optional[T.Dict[str, T.Any]]: return self.build_target(node, args, kwargs, SharedLibrary) def func_shared_module(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> T.Optional[T.Dict[str, T.Any]]: return self.build_target(node, args, kwargs, SharedModule) def func_library(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> T.Optional[T.Dict[str, T.Any]]: return self.build_library(node, args, kwargs) def func_jar(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> T.Optional[T.Dict[str, T.Any]]: return self.build_target(node, args, kwargs, Jar) def func_build_target(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> T.Optional[T.Dict[str, T.Any]]: if 'target_type' not in kwargs: return None 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) return None def is_subproject(self) -> bool: return self.subproject != '' def analyze(self) -> None: self.load_root_meson_file() self.sanity_check_ast() self.parse_project() self.run() def extract_subproject_dir(self) -> T.Optional[str]: '''Fast path to extract subproject_dir kwarg. This is faster than self.parse_project() which also initialize options and also calls parse_project() on every subproject. ''' if not self.ast.lines: return project = self.ast.lines[0] # first line is always project() if not isinstance(project, FunctionNode): return for kw, val in project.args.kwargs.items(): assert isinstance(kw, IdNode), 'for mypy' if kw.value == 'subproject_dir': # mypy does not understand "and isinstance" if isinstance(val, BaseStringNode): return val.value return None ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/ast/postprocess.py0000644000175000017500000000757614562742363020751 0ustar00jpakkanejpakkane# 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 __future__ import annotations from .visitor import AstVisitor import typing as T if T.TYPE_CHECKING: from .. import mparser class AstIndentationGenerator(AstVisitor): def __init__(self) -> None: self.level = 0 def visit_default_func(self, node: mparser.BaseNode) -> None: # Store the current level in the node node.level = self.level def visit_ArrayNode(self, node: mparser.ArrayNode) -> None: self.visit_default_func(node) self.level += 1 node.args.accept(self) self.level -= 1 def visit_DictNode(self, node: mparser.DictNode) -> None: self.visit_default_func(node) self.level += 1 node.args.accept(self) self.level -= 1 def visit_MethodNode(self, node: mparser.MethodNode) -> None: 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) -> None: self.visit_default_func(node) self.level += 1 node.args.accept(self) self.level -= 1 def visit_ForeachClauseNode(self, node: mparser.ForeachClauseNode) -> None: 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) -> None: 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) -> None: 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) -> None: self.counter: T.Dict[str, int] = {} def visit_default_func(self, node: mparser.BaseNode) -> None: 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) -> None: self.condition_level = 0 def visit_default_func(self, node: mparser.BaseNode) -> None: node.condition_level = self.condition_level def visit_ForeachClauseNode(self, node: mparser.ForeachClauseNode) -> None: 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) -> None: 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) -> None: self.visit_default_func(node) self.condition_level += 1 node.condition.accept(self) node.block.accept(self) self.condition_level -= 1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/ast/printer.py0000644000175000017500000005445214562742363020043 0ustar00jpakkanejpakkane# 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 __future__ import annotations from .. import mparser from .visitor import AstVisitor from itertools import zip_longest import re import typing as T arithmic_map = { 'add': '+', 'sub': '-', 'mod': '%', 'mul': '*', 'div': '/' } class AstPrinter(AstVisitor): def __init__(self, indent: int = 2, arg_newline_cutoff: int = 5, update_ast_line_nos: bool = False): self.result = '' self.indent = indent self.arg_newline_cutoff = arg_newline_cutoff self.ci = '' self.is_newline = True self.last_level = 0 self.curr_line = 1 if update_ast_line_nos else None def post_process(self) -> None: self.result = re.sub(r'\s+\n', '\n', self.result) def append(self, data: str, node: mparser.BaseNode) -> None: self.last_level = node.level if self.is_newline: self.result += ' ' * (node.level * self.indent) self.result += data self.is_newline = False def append_padded(self, data: str, node: mparser.BaseNode) -> None: if self.result and self.result[-1] not in [' ', '\n']: data = ' ' + data self.append(data + ' ', node) def newline(self) -> None: self.result += '\n' self.is_newline = True if self.curr_line is not None: self.curr_line += 1 def visit_BooleanNode(self, node: mparser.BooleanNode) -> None: self.append('true' if node.value else 'false', node) node.lineno = self.curr_line or node.lineno def visit_IdNode(self, node: mparser.IdNode) -> None: assert isinstance(node.value, str) self.append(node.value, node) node.lineno = self.curr_line or node.lineno def visit_NumberNode(self, node: mparser.NumberNode) -> None: self.append(str(node.value), node) node.lineno = self.curr_line or node.lineno def escape(self, val: str) -> str: return val.translate(str.maketrans({'\'': '\\\'', '\\': '\\\\'})) def visit_StringNode(self, node: mparser.StringNode) -> None: assert isinstance(node.value, str) self.append("'" + self.escape(node.value) + "'", node) node.lineno = self.curr_line or node.lineno def visit_FormatStringNode(self, node: mparser.FormatStringNode) -> None: assert isinstance(node.value, str) self.append("f'" + self.escape(node.value) + "'", node) node.lineno = self.curr_line or node.lineno def visit_MultilineStringNode(self, node: mparser.StringNode) -> None: assert isinstance(node.value, str) self.append("'''" + node.value + "'''", node) node.lineno = self.curr_line or node.lineno def visit_FormatMultilineStringNode(self, node: mparser.FormatStringNode) -> None: assert isinstance(node.value, str) self.append("f'''" + node.value + "'''", node) node.lineno = self.curr_line or node.lineno def visit_ContinueNode(self, node: mparser.ContinueNode) -> None: self.append('continue', node) node.lineno = self.curr_line or node.lineno def visit_BreakNode(self, node: mparser.BreakNode) -> None: self.append('break', node) node.lineno = self.curr_line or node.lineno def visit_ArrayNode(self, node: mparser.ArrayNode) -> None: node.lineno = self.curr_line or node.lineno self.append('[', node) node.args.accept(self) self.append(']', node) def visit_DictNode(self, node: mparser.DictNode) -> None: node.lineno = self.curr_line or node.lineno self.append('{', node) node.args.accept(self) self.append('}', node) def visit_OrNode(self, node: mparser.OrNode) -> None: node.left.accept(self) self.append_padded('or', node) node.lineno = self.curr_line or node.lineno node.right.accept(self) def visit_AndNode(self, node: mparser.AndNode) -> None: node.left.accept(self) self.append_padded('and', node) node.lineno = self.curr_line or node.lineno node.right.accept(self) def visit_ComparisonNode(self, node: mparser.ComparisonNode) -> None: node.left.accept(self) self.append_padded(node.ctype, node) node.lineno = self.curr_line or node.lineno node.right.accept(self) def visit_ArithmeticNode(self, node: mparser.ArithmeticNode) -> None: node.left.accept(self) self.append_padded(arithmic_map[node.operation], node) node.lineno = self.curr_line or node.lineno node.right.accept(self) def visit_NotNode(self, node: mparser.NotNode) -> None: node.lineno = self.curr_line or node.lineno self.append_padded('not', node) node.value.accept(self) def visit_CodeBlockNode(self, node: mparser.CodeBlockNode) -> None: node.lineno = self.curr_line or node.lineno for i in node.lines: i.accept(self) self.newline() def visit_IndexNode(self, node: mparser.IndexNode) -> None: node.iobject.accept(self) node.lineno = self.curr_line or node.lineno self.append('[', node) node.index.accept(self) self.append(']', node) def visit_MethodNode(self, node: mparser.MethodNode) -> None: node.lineno = self.curr_line or node.lineno node.source_object.accept(self) self.append('.' + node.name.value + '(', node) node.args.accept(self) self.append(')', node) def visit_FunctionNode(self, node: mparser.FunctionNode) -> None: node.lineno = self.curr_line or node.lineno self.append(node.func_name.value + '(', node) node.args.accept(self) self.append(')', node) def visit_AssignmentNode(self, node: mparser.AssignmentNode) -> None: node.lineno = self.curr_line or node.lineno self.append(node.var_name.value + ' = ', node) node.value.accept(self) def visit_PlusAssignmentNode(self, node: mparser.PlusAssignmentNode) -> None: node.lineno = self.curr_line or node.lineno self.append(node.var_name.value + ' += ', node) node.value.accept(self) def visit_ForeachClauseNode(self, node: mparser.ForeachClauseNode) -> None: node.lineno = self.curr_line or node.lineno self.append_padded('foreach', node) self.append_padded(', '.join(varname.value for varname in node.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) -> None: node.lineno = self.curr_line or node.lineno prefix = '' for i in node.ifs: self.append_padded(prefix + 'if', node) prefix = 'el' i.accept(self) if not isinstance(node.elseblock, mparser.EmptyNode): self.append('else', node) node.elseblock.accept(self) self.append('endif', node) def visit_UMinusNode(self, node: mparser.UMinusNode) -> None: node.lineno = self.curr_line or node.lineno self.append_padded('-', node) node.value.accept(self) def visit_IfNode(self, node: mparser.IfNode) -> None: node.lineno = self.curr_line or node.lineno node.condition.accept(self) self.newline() node.block.accept(self) def visit_TernaryNode(self, node: mparser.TernaryNode) -> None: node.lineno = self.curr_line or node.lineno 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) -> None: node.lineno = self.curr_line or node.lineno 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(): 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) class RawPrinter(AstVisitor): def __init__(self): self.result = '' def visit_default_func(self, node: mparser.BaseNode): self.result += node.value if node.whitespaces: node.whitespaces.accept(self) def visit_unary_operator(self, node: mparser.UnaryOperatorNode): node.operator.accept(self) node.value.accept(self) if node.whitespaces: node.whitespaces.accept(self) def visit_binary_operator(self, node: mparser.BinaryOperatorNode): node.left.accept(self) node.operator.accept(self) node.right.accept(self) if node.whitespaces: node.whitespaces.accept(self) def visit_BooleanNode(self, node: mparser.BooleanNode) -> None: self.result += 'true' if node.value else 'false' if node.whitespaces: node.whitespaces.accept(self) def visit_NumberNode(self, node: mparser.NumberNode) -> None: self.result += node.raw_value if node.whitespaces: node.whitespaces.accept(self) def visit_StringNode(self, node: mparser.StringNode) -> None: self.result += f"'{node.raw_value}'" if node.whitespaces: node.whitespaces.accept(self) def visit_MultilineStringNode(self, node: mparser.MultilineStringNode) -> None: self.result += f"'''{node.value}'''" if node.whitespaces: node.whitespaces.accept(self) def visit_FormatStringNode(self, node: mparser.FormatStringNode) -> None: self.result += 'f' self.visit_StringNode(node) def visit_MultilineFormatStringNode(self, node: mparser.MultilineFormatStringNode) -> None: self.result += 'f' self.visit_MultilineStringNode(node) def visit_ContinueNode(self, node: mparser.ContinueNode) -> None: self.result += 'continue' if node.whitespaces: node.whitespaces.accept(self) def visit_BreakNode(self, node: mparser.BreakNode) -> None: self.result += 'break' if node.whitespaces: node.whitespaces.accept(self) def visit_ArrayNode(self, node: mparser.ArrayNode) -> None: node.lbracket.accept(self) node.args.accept(self) node.rbracket.accept(self) if node.whitespaces: node.whitespaces.accept(self) def visit_DictNode(self, node: mparser.DictNode) -> None: node.lcurl.accept(self) node.args.accept(self) node.rcurl.accept(self) if node.whitespaces: node.whitespaces.accept(self) def visit_ParenthesizedNode(self, node: mparser.ParenthesizedNode) -> None: node.lpar.accept(self) node.inner.accept(self) node.rpar.accept(self) if node.whitespaces: node.whitespaces.accept(self) def visit_OrNode(self, node: mparser.OrNode) -> None: self.visit_binary_operator(node) def visit_AndNode(self, node: mparser.AndNode) -> None: self.visit_binary_operator(node) def visit_ComparisonNode(self, node: mparser.ComparisonNode) -> None: self.visit_binary_operator(node) def visit_ArithmeticNode(self, node: mparser.ArithmeticNode) -> None: self.visit_binary_operator(node) def visit_NotNode(self, node: mparser.NotNode) -> None: self.visit_unary_operator(node) def visit_CodeBlockNode(self, node: mparser.CodeBlockNode) -> None: if node.pre_whitespaces: node.pre_whitespaces.accept(self) for i in node.lines: i.accept(self) if node.whitespaces: node.whitespaces.accept(self) def visit_IndexNode(self, node: mparser.IndexNode) -> None: node.iobject.accept(self) node.lbracket.accept(self) node.index.accept(self) node.rbracket.accept(self) if node.whitespaces: node.whitespaces.accept(self) def visit_MethodNode(self, node: mparser.MethodNode) -> None: node.source_object.accept(self) node.dot.accept(self) node.name.accept(self) node.lpar.accept(self) node.args.accept(self) node.rpar.accept(self) if node.whitespaces: node.whitespaces.accept(self) def visit_FunctionNode(self, node: mparser.FunctionNode) -> None: node.func_name.accept(self) node.lpar.accept(self) node.args.accept(self) node.rpar.accept(self) if node.whitespaces: node.whitespaces.accept(self) def visit_AssignmentNode(self, node: mparser.AssignmentNode) -> None: node.var_name.accept(self) node.operator.accept(self) node.value.accept(self) if node.whitespaces: node.whitespaces.accept(self) def visit_PlusAssignmentNode(self, node: mparser.PlusAssignmentNode) -> None: node.var_name.accept(self) node.operator.accept(self) node.value.accept(self) if node.whitespaces: node.whitespaces.accept(self) def visit_ForeachClauseNode(self, node: mparser.ForeachClauseNode) -> None: node.foreach_.accept(self) for varname, comma in zip_longest(node.varnames, node.commas): varname.accept(self) if comma is not None: comma.accept(self) node.column.accept(self) node.items.accept(self) node.block.accept(self) node.endforeach.accept(self) if node.whitespaces: node.whitespaces.accept(self) def visit_IfClauseNode(self, node: mparser.IfClauseNode) -> None: for i in node.ifs: i.accept(self) if not isinstance(node.elseblock, mparser.EmptyNode): node.elseblock.accept(self) node.endif.accept(self) if node.whitespaces: node.whitespaces.accept(self) def visit_UMinusNode(self, node: mparser.UMinusNode) -> None: self.visit_unary_operator(node) def visit_IfNode(self, node: mparser.IfNode) -> None: node.if_.accept(self) node.condition.accept(self) node.block.accept(self) if node.whitespaces: node.whitespaces.accept(self) def visit_ElseNode(self, node: mparser.ElseNode) -> None: node.else_.accept(self) node.block.accept(self) if node.whitespaces: node.whitespaces.accept(self) def visit_TernaryNode(self, node: mparser.TernaryNode) -> None: node.condition.accept(self) node.questionmark.accept(self) node.trueblock.accept(self) node.column.accept(self) node.falseblock.accept(self) if node.whitespaces: node.whitespaces.accept(self) def visit_ArgumentNode(self, node: mparser.ArgumentNode) -> None: commas_iter = iter(node.commas) for arg in node.arguments: arg.accept(self) try: comma = next(commas_iter) comma.accept(self) except StopIteration: pass assert len(node.columns) == len(node.kwargs) for (key, val), column in zip(node.kwargs.items(), node.columns): key.accept(self) column.accept(self) val.accept(self) try: comma = next(commas_iter) comma.accept(self) except StopIteration: pass if node.whitespaces: node.whitespaces.accept(self) class AstJSONPrinter(AstVisitor): def __init__(self) -> None: self.result: T.Dict[str, T.Any] = {} self.current = self.result def _accept(self, key: str, node: mparser.BaseNode) -> None: old = self.current data: T.Dict[str, T.Any] = {} self.current = data node.accept(self) self.current = old self.current[key] = data def _accept_list(self, key: str, nodes: T.Sequence[mparser.BaseNode]) -> None: old = self.current datalist: T.List[T.Dict[str, T.Any]] = [] for i in nodes: self.current = {} i.accept(self) datalist += [self.current] self.current = old self.current[key] = datalist def _raw_accept(self, node: mparser.BaseNode, data: T.Dict[str, T.Any]) -> None: old = self.current self.current = data node.accept(self) self.current = old def setbase(self, node: mparser.BaseNode) -> None: self.current['node'] = type(node).__name__ self.current['lineno'] = node.lineno self.current['colno'] = node.colno self.current['end_lineno'] = node.end_lineno self.current['end_colno'] = node.end_colno def visit_default_func(self, node: mparser.BaseNode) -> None: self.setbase(node) def gen_ElementaryNode(self, node: mparser.ElementaryNode) -> None: self.current['value'] = node.value self.setbase(node) def visit_BooleanNode(self, node: mparser.BooleanNode) -> None: self.gen_ElementaryNode(node) def visit_IdNode(self, node: mparser.IdNode) -> None: self.gen_ElementaryNode(node) def visit_NumberNode(self, node: mparser.NumberNode) -> None: self.gen_ElementaryNode(node) def visit_StringNode(self, node: mparser.StringNode) -> None: self.gen_ElementaryNode(node) def visit_FormatStringNode(self, node: mparser.FormatStringNode) -> None: self.gen_ElementaryNode(node) def visit_ArrayNode(self, node: mparser.ArrayNode) -> None: self._accept('args', node.args) self.setbase(node) def visit_DictNode(self, node: mparser.DictNode) -> None: self._accept('args', node.args) self.setbase(node) def visit_OrNode(self, node: mparser.OrNode) -> None: self._accept('left', node.left) self._accept('right', node.right) self.setbase(node) def visit_AndNode(self, node: mparser.AndNode) -> None: self._accept('left', node.left) self._accept('right', node.right) self.setbase(node) def visit_ComparisonNode(self, node: mparser.ComparisonNode) -> None: self._accept('left', node.left) self._accept('right', node.right) self.current['ctype'] = node.ctype self.setbase(node) def visit_ArithmeticNode(self, node: mparser.ArithmeticNode) -> None: self._accept('left', node.left) self._accept('right', node.right) self.current['op'] = arithmic_map[node.operation] self.setbase(node) def visit_NotNode(self, node: mparser.NotNode) -> None: self._accept('right', node.value) self.setbase(node) def visit_CodeBlockNode(self, node: mparser.CodeBlockNode) -> None: self._accept_list('lines', node.lines) self.setbase(node) def visit_IndexNode(self, node: mparser.IndexNode) -> None: self._accept('object', node.iobject) self._accept('index', node.index) self.setbase(node) def visit_MethodNode(self, node: mparser.MethodNode) -> None: self._accept('object', node.source_object) self._accept('args', node.args) self.current['name'] = node.name.value self.setbase(node) def visit_FunctionNode(self, node: mparser.FunctionNode) -> None: self._accept('args', node.args) self.current['name'] = node.func_name.value self.setbase(node) def visit_AssignmentNode(self, node: mparser.AssignmentNode) -> None: self._accept('value', node.value) self.current['var_name'] = node.var_name.value self.setbase(node) def visit_PlusAssignmentNode(self, node: mparser.PlusAssignmentNode) -> None: self._accept('value', node.value) self.current['var_name'] = node.var_name.value self.setbase(node) def visit_ForeachClauseNode(self, node: mparser.ForeachClauseNode) -> None: self._accept('items', node.items) self._accept('block', node.block) self.current['varnames'] = [varname.value for varname in node.varnames] self.setbase(node) def visit_IfClauseNode(self, node: mparser.IfClauseNode) -> None: self._accept_list('ifs', node.ifs) self._accept('else', node.elseblock) self.setbase(node) def visit_UMinusNode(self, node: mparser.UMinusNode) -> None: self._accept('right', node.value) self.setbase(node) def visit_IfNode(self, node: mparser.IfNode) -> None: self._accept('condition', node.condition) self._accept('block', node.block) self.setbase(node) def visit_TernaryNode(self, node: mparser.TernaryNode) -> None: self._accept('condition', node.condition) self._accept('true', node.trueblock) self._accept('false', node.falseblock) self.setbase(node) def visit_ArgumentNode(self, node: mparser.ArgumentNode) -> None: self._accept_list('positional', node.arguments) kwargs_list: T.List[T.Dict[str, T.Dict[str, T.Any]]] = [] for key, val in node.kwargs.items(): key_res: T.Dict[str, T.Any] = {} val_res: T.Dict[str, T.Any] = {} self._raw_accept(key, key_res) self._raw_accept(val, val_res) kwargs_list += [{'key': key_res, 'val': val_res}] self.current['kwargs'] = kwargs_list self.setbase(node) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/ast/visitor.py0000644000175000017500000001345114562742363020051 0ustar00jpakkanejpakkane# 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 __future__ import annotations import typing as T if T.TYPE_CHECKING: from .. import mparser class AstVisitor: def __init__(self) -> None: pass def visit_default_func(self, node: mparser.BaseNode) -> None: pass def visit_BooleanNode(self, node: mparser.BooleanNode) -> None: self.visit_default_func(node) def visit_IdNode(self, node: mparser.IdNode) -> None: self.visit_default_func(node) def visit_NumberNode(self, node: mparser.NumberNode) -> None: self.visit_default_func(node) def visit_StringNode(self, node: mparser.StringNode) -> None: self.visit_default_func(node) def visit_FormatStringNode(self, node: mparser.FormatStringNode) -> None: self.visit_default_func(node) def visit_MultilineStringNode(self, node: mparser.StringNode) -> None: self.visit_default_func(node) def visit_FormatMultilineStringNode(self, node: mparser.FormatStringNode) -> None: self.visit_default_func(node) def visit_ContinueNode(self, node: mparser.ContinueNode) -> None: self.visit_default_func(node) def visit_BreakNode(self, node: mparser.BreakNode) -> None: self.visit_default_func(node) def visit_SymbolNode(self, node: mparser.SymbolNode) -> None: self.visit_default_func(node) def visit_WhitespaceNode(self, node: mparser.WhitespaceNode) -> None: self.visit_default_func(node) def visit_ArrayNode(self, node: mparser.ArrayNode) -> None: self.visit_default_func(node) node.args.accept(self) def visit_DictNode(self, node: mparser.DictNode) -> None: self.visit_default_func(node) node.args.accept(self) def visit_EmptyNode(self, node: mparser.EmptyNode) -> None: self.visit_default_func(node) def visit_OrNode(self, node: mparser.OrNode) -> None: self.visit_default_func(node) node.left.accept(self) node.right.accept(self) def visit_AndNode(self, node: mparser.AndNode) -> None: self.visit_default_func(node) node.left.accept(self) node.right.accept(self) def visit_ComparisonNode(self, node: mparser.ComparisonNode) -> None: self.visit_default_func(node) node.left.accept(self) node.right.accept(self) def visit_ArithmeticNode(self, node: mparser.ArithmeticNode) -> None: self.visit_default_func(node) node.left.accept(self) node.right.accept(self) def visit_NotNode(self, node: mparser.NotNode) -> None: self.visit_default_func(node) node.value.accept(self) def visit_CodeBlockNode(self, node: mparser.CodeBlockNode) -> None: self.visit_default_func(node) for i in node.lines: i.accept(self) def visit_IndexNode(self, node: mparser.IndexNode) -> None: self.visit_default_func(node) node.iobject.accept(self) node.index.accept(self) def visit_MethodNode(self, node: mparser.MethodNode) -> None: self.visit_default_func(node) node.source_object.accept(self) node.name.accept(self) node.args.accept(self) def visit_FunctionNode(self, node: mparser.FunctionNode) -> None: self.visit_default_func(node) node.func_name.accept(self) node.args.accept(self) def visit_AssignmentNode(self, node: mparser.AssignmentNode) -> None: self.visit_default_func(node) node.var_name.accept(self) node.value.accept(self) def visit_PlusAssignmentNode(self, node: mparser.PlusAssignmentNode) -> None: self.visit_default_func(node) node.var_name.accept(self) node.value.accept(self) def visit_ForeachClauseNode(self, node: mparser.ForeachClauseNode) -> None: self.visit_default_func(node) for varname in node.varnames: varname.accept(self) node.items.accept(self) node.block.accept(self) def visit_IfClauseNode(self, node: mparser.IfClauseNode) -> None: self.visit_default_func(node) for i in node.ifs: i.accept(self) node.elseblock.accept(self) def visit_UMinusNode(self, node: mparser.UMinusNode) -> None: self.visit_default_func(node) node.value.accept(self) def visit_IfNode(self, node: mparser.IfNode) -> None: self.visit_default_func(node) node.condition.accept(self) node.block.accept(self) def visit_ElseNode(self, node: mparser.IfNode) -> None: self.visit_default_func(node) node.block.accept(self) def visit_TernaryNode(self, node: mparser.TernaryNode) -> None: self.visit_default_func(node) node.condition.accept(self) node.trueblock.accept(self) node.falseblock.accept(self) def visit_ArgumentNode(self, node: mparser.ArgumentNode) -> None: self.visit_default_func(node) for i in node.arguments: i.accept(self) for key, val in node.kwargs.items(): key.accept(self) val.accept(self) def visit_ParenthesizedNode(self, node: mparser.ParenthesizedNode) -> None: self.visit_default_func(node) node.inner.accept(self) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.5986373 meson-1.3.2/mesonbuild/backend/0000755000175000017500000000000014562742414016571 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1650551419.0 meson-1.3.2/mesonbuild/backend/__init__.py0000644000175000017500000000000014230265173020662 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0 meson-1.3.2/mesonbuild/backend/backends.py0000644000175000017500000030356714562742373020737 0ustar00jpakkanejpakkane# 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. from __future__ import annotations from collections import OrderedDict from dataclasses import dataclass, InitVar from functools import lru_cache from itertools import chain from pathlib import Path import copy import enum import json import os import pickle import re import shutil import typing as T import hashlib from .. import build from .. import dependencies from .. import programs from .. import mesonlib from .. import mlog from ..compilers import LANGUAGES_USING_LDFLAGS, detect from ..mesonlib import ( File, MachineChoice, MesonException, OrderedSet, classify_unity_sources, OptionKey, join_args, ExecutableSerialisation ) if T.TYPE_CHECKING: from .._typing import ImmutableListProtocol from ..arglist import CompilerArgs from ..compilers import Compiler from ..environment import Environment from ..interpreter import Interpreter, Test from ..linkers.linkers import StaticLinker from ..mesonlib import FileMode, FileOrString from typing_extensions import TypedDict _ALL_SOURCES_TYPE = T.List[T.Union[File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList]] class TargetIntrospectionData(TypedDict): language: str compiler: T.List[str] parameters: T.List[str] sources: T.List[str] generated_sources: T.List[str] # Languages that can mix with C or C++ but don't support unity builds yet # because the syntax we use for unity builds is specific to C/++/ObjC/++. # Assembly files cannot be unitified and neither can LLVM IR files LANGS_CANT_UNITY = ('d', 'fortran', 'vala') @dataclass(eq=False) class RegenInfo: source_dir: str build_dir: str depfiles: T.List[str] class TestProtocol(enum.Enum): EXITCODE = 0 TAP = 1 GTEST = 2 RUST = 3 @classmethod def from_str(cls, string: str) -> 'TestProtocol': if string == 'exitcode': return cls.EXITCODE elif string == 'tap': return cls.TAP elif string == 'gtest': return cls.GTEST elif string == 'rust': return cls.RUST raise MesonException(f'unknown test format {string}') def __str__(self) -> str: cls = type(self) if self is cls.EXITCODE: return 'exitcode' elif self is cls.GTEST: return 'gtest' elif self is cls.RUST: return 'rust' return 'tap' @dataclass(eq=False) class CleanTrees: ''' Directories outputted by custom targets that have to be manually cleaned because on Linux `ninja clean` only deletes empty directories. ''' build_dir: str trees: T.List[str] @dataclass(eq=False) class InstallData: source_dir: str build_dir: str prefix: str libdir: str strip_bin: T.List[str] # TODO: in python 3.8 or with typing_Extensions this could be: # `T.Union[T.Literal['preserve'], int]`, which would be more accurate. install_umask: T.Union[str, int] mesonintrospect: T.List[str] version: str def __post_init__(self) -> None: self.targets: T.List[TargetInstallData] = [] self.headers: T.List[InstallDataBase] = [] self.man: T.List[InstallDataBase] = [] self.emptydir: T.List[InstallEmptyDir] = [] self.data: T.List[InstallDataBase] = [] self.symlinks: T.List[InstallSymlinkData] = [] self.install_scripts: T.List[ExecutableSerialisation] = [] self.install_subdirs: T.List[SubdirInstallData] = [] @dataclass(eq=False) class TargetInstallData: fname: str outdir: str outdir_name: InitVar[T.Optional[str]] strip: bool install_name_mappings: T.Mapping[str, str] rpath_dirs_to_remove: T.Set[bytes] install_rpath: str # TODO: install_mode should just always be a FileMode object install_mode: T.Optional['FileMode'] subproject: str optional: bool = False tag: T.Optional[str] = None can_strip: bool = False def __post_init__(self, outdir_name: T.Optional[str]) -> None: if outdir_name is None: outdir_name = os.path.join('{prefix}', self.outdir) self.out_name = os.path.join(outdir_name, os.path.basename(self.fname)) @dataclass(eq=False) class InstallEmptyDir: path: str install_mode: 'FileMode' subproject: str tag: T.Optional[str] = None @dataclass(eq=False) class InstallDataBase: path: str install_path: str install_path_name: str install_mode: 'FileMode' subproject: str tag: T.Optional[str] = None data_type: T.Optional[str] = None follow_symlinks: T.Optional[bool] = None @dataclass(eq=False) class InstallSymlinkData: target: str name: str install_path: str subproject: str tag: T.Optional[str] = None allow_missing: bool = False # cannot use dataclass here because "exclude" is out of order class SubdirInstallData(InstallDataBase): def __init__(self, path: str, install_path: str, install_path_name: str, install_mode: 'FileMode', exclude: T.Tuple[T.Set[str], T.Set[str]], subproject: str, tag: T.Optional[str] = None, data_type: T.Optional[str] = None, follow_symlinks: T.Optional[bool] = None): super().__init__(path, install_path, install_path_name, install_mode, subproject, tag, data_type, follow_symlinks) self.exclude = exclude @dataclass(eq=False) class TestSerialisation: name: str project_name: str suite: T.List[str] fname: T.List[str] is_cross_built: bool exe_wrapper: T.Optional[programs.ExternalProgram] needs_exe_wrapper: bool is_parallel: bool cmd_args: T.List[str] env: mesonlib.EnvironmentVariables should_fail: bool timeout: T.Optional[int] workdir: T.Optional[str] extra_paths: T.List[str] protocol: TestProtocol priority: int cmd_is_built: bool cmd_is_exe: bool depends: T.List[str] version: str verbose: bool def __post_init__(self) -> None: if self.exe_wrapper is not None: assert isinstance(self.exe_wrapper, programs.ExternalProgram) def get_backend_from_name(backend: str, build: T.Optional[build.Build] = None, interpreter: T.Optional['Interpreter'] = None) -> T.Optional['Backend']: if backend == 'ninja': from . import ninjabackend return ninjabackend.NinjaBackend(build, interpreter) elif backend == 'vs': from . import vs2010backend return vs2010backend.autodetect_vs_version(build, interpreter) elif backend == 'vs2010': from . import vs2010backend return vs2010backend.Vs2010Backend(build, interpreter) elif backend == 'vs2012': from . import vs2012backend return vs2012backend.Vs2012Backend(build, interpreter) elif backend == 'vs2013': from . import vs2013backend return vs2013backend.Vs2013Backend(build, interpreter) elif backend == 'vs2015': from . import vs2015backend return vs2015backend.Vs2015Backend(build, interpreter) elif backend == 'vs2017': from . import vs2017backend return vs2017backend.Vs2017Backend(build, interpreter) elif backend == 'vs2019': from . import vs2019backend return vs2019backend.Vs2019Backend(build, interpreter) elif backend == 'vs2022': from . import vs2022backend return vs2022backend.Vs2022Backend(build, interpreter) elif backend == 'xcode': from . import xcodebackend return xcodebackend.XCodeBackend(build, interpreter) elif backend == 'none': from . import nonebackend return nonebackend.NoneBackend(build, interpreter) return None def get_genvslite_backend(genvsname: str, build: T.Optional[build.Build] = None, interpreter: T.Optional['Interpreter'] = None) -> T.Optional['Backend']: if genvsname == 'vs2022': from . import vs2022backend return vs2022backend.Vs2022Backend(build, interpreter, gen_lite = True) 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: environment: T.Optional['Environment'] name = '' def __init__(self, build: T.Optional[build.Build], interpreter: T.Optional['Interpreter']): # 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.interpreter = interpreter self.environment = build.environment self.processed_targets: T.Set[str] = set() 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()) self.src_to_build = mesonlib.relpath(self.environment.get_build_dir(), self.environment.get_source_dir()) # If requested via 'capture = True', returns captured compile args per # target (e.g. captured_args[target]) that can be used later, for example, # to populate things like intellisense fields in generated visual studio # projects (as is the case when using '--genvslite'). # # 'vslite_ctx' is only provided when # we expect this backend setup/generation to make use of previously captured # compile args (as is the case when using '--genvslite'). def generate(self, capture: bool = False, vslite_ctx: dict = None) -> T.Optional[dict]: raise RuntimeError(f'generate is not implemented in {type(self).__name__}') def get_target_filename(self, t: T.Union[build.Target, build.CustomTargetIndex], *, warn_multi_output: bool = True) -> str: if isinstance(t, build.CustomTarget): if warn_multi_output and len(t.get_outputs()) != 1: mlog.warning(f'custom_target {t.name!r} has more than one output! ' f'Using the first one. Consider using `{t.name}[0]`.') filename = t.get_outputs()[0] elif isinstance(t, build.CustomTargetIndex): filename = t.get_outputs()[0] else: assert isinstance(t, build.BuildTarget), t filename = t.get_filename() return os.path.join(self.get_target_dir(t), filename) def get_target_filename_abs(self, target: T.Union[build.Target, build.CustomTargetIndex]) -> str: return os.path.join(self.environment.get_build_dir(), self.get_target_filename(target)) def get_target_debug_filename(self, target: build.BuildTarget) -> T.Optional[str]: assert isinstance(target, build.BuildTarget), target if target.get_debug_filename(): debug_filename = target.get_debug_filename() return os.path.join(self.get_target_dir(target), debug_filename) else: return None def get_target_debug_filename_abs(self, target: build.BuildTarget) -> T.Optional[str]: assert isinstance(target, build.BuildTarget), target if not target.get_debug_filename(): return None return os.path.join(self.environment.get_build_dir(), self.get_target_debug_filename(target)) def get_source_dir_include_args(self, target: build.BuildTarget, compiler: 'Compiler', *, absolute_path: bool = False) -> T.List[str]: curdir = target.get_subdir() if absolute_path: lead = self.source_dir else: lead = self.build_to_src tmppath = os.path.normpath(os.path.join(lead, curdir)) return compiler.get_include_args(tmppath, False) def get_build_dir_include_args(self, target: build.BuildTarget, compiler: 'Compiler', *, absolute_path: bool = False) -> T.List[str]: if absolute_path: curdir = os.path.join(self.build_dir, target.get_subdir()) else: curdir = target.get_subdir() if curdir == '': curdir = '.' return compiler.get_include_args(curdir, False) def get_target_filename_for_linking(self, target: T.Union[build.Target, build.CustomTargetIndex]) -> T.Optional[str]: # 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() # In AIX, if we archive .so, the blibpath must link to archived shared library otherwise to the .so file. if mesonlib.is_aix() and target.aix_so_archive: link_lib = re.sub('[.][a]([.]?([0-9]+))*([.]?([a-z]+))*', '.a', link_lib.replace('.so', '.a')) return Path(self.get_target_dir(target), link_lib).as_posix() elif isinstance(target, build.StaticLibrary): return Path(self.get_target_dir(target), target.get_filename()).as_posix() elif isinstance(target, (build.CustomTarget, build.CustomTargetIndex)): if not target.is_linkable_target(): raise MesonException(f'Tried to link against custom target "{target.name}", which is not linkable.') return Path(self.get_target_dir(target), target.get_filename()).as_posix() elif isinstance(target, build.Executable): if target.import_filename: return Path(self.get_target_dir(target), target.get_import_filename()).as_posix() else: return None raise AssertionError(f'BUG: Tried to link to {target!r} which is not linkable') @lru_cache(maxsize=None) def get_target_dir(self, target: T.Union[build.Target, build.CustomTargetIndex]) -> str: if isinstance(target, build.RunTarget): # this produces no output, only a dummy top-level name dirname = '' elif self.environment.coredata.get_option(OptionKey('layout')) == 'mirror': dirname = target.get_subdir() else: dirname = 'meson-out' return dirname def get_target_dir_relative_to(self, t: build.Target, o: build.Target) -> str: '''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: build.Target) -> str: # 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: T.Union[build.BuildTarget, build.CustomTarget, build.CustomTargetIndex]) -> str: return os.path.join(self.get_target_filename(target, warn_multi_output=False) + '.p') def get_target_private_dir_abs(self, target: T.Union[build.BuildTarget, build.CustomTarget, build.CustomTargetIndex]) -> str: 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: T.Union[build.BuildTarget, build.CustomTarget, build.CustomTargetIndex], gensrc: T.Union[build.CustomTarget, build.CustomTargetIndex, build.GeneratedList], src: str) -> str: """ 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: T.Union[build.BuildTarget, build.CustomTarget, build.CustomTargetIndex], suffix: str, number: int) -> mesonlib.File: # 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 = f'{target.name}-unity{number}.{suffix}' return mesonlib.File.from_built_file(self.get_target_private_dir(target), osrc) def generate_unity_files(self, target: build.BuildTarget, unity_src: str) -> T.List[mesonlib.File]: abs_files: T.List[str] = [] result: T.List[mesonlib.File] = [] compsrcs = classify_unity_sources(target.compilers.values(), unity_src) unity_size = target.get_option(OptionKey('unity_size')) assert isinstance(unity_size, int), 'for mypy' def init_language_file(suffix: str, unity_file_number: int) -> T.TextIO: unity_src = self.get_unity_source_file(target, suffix, unity_file_number) 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', encoding='utf-8') # For each language, generate unity source files and return the list for comp, srcs in compsrcs.items(): files_in_current = unity_size + 1 unity_file_number = 0 # TODO: this could be simplified with an algorithm that pre-sorts # the sources into the size of chunks we want ofile = None for src in srcs: if files_in_current >= unity_size: if ofile: ofile.close() ofile = init_language_file(comp.get_default_suffix(), unity_file_number) unity_file_number += 1 files_in_current = 0 ofile.write(f'#include<{src}>\n') files_in_current += 1 if ofile: ofile.close() for x in abs_files: mesonlib.replace_if_different(x, x + '.tmp') return result @staticmethod def relpath(todir: str, fromdir: str) -> str: return os.path.relpath(os.path.join('dummyprefixdir', todir), os.path.join('dummyprefixdir', fromdir)) def flatten_object_list(self, target: build.BuildTarget, proj_dir_to_build_root: str = '' ) -> T.Tuple[T.List[str], T.List[build.BuildTargetTypes]]: obj_list, deps = self._flatten_object_list(target, target.get_objects(), proj_dir_to_build_root) return list(dict.fromkeys(obj_list)), deps def determine_ext_objs(self, objects: build.ExtractedObjects, proj_dir_to_build_root: str = '') -> T.List[str]: obj_list, _ = self._flatten_object_list(objects.target, [objects], proj_dir_to_build_root) return list(dict.fromkeys(obj_list)) def _flatten_object_list(self, target: build.BuildTarget, objects: T.Sequence[T.Union[str, 'File', build.ExtractedObjects]], proj_dir_to_build_root: str) -> T.Tuple[T.List[str], T.List[build.BuildTargetTypes]]: obj_list: T.List[str] = [] deps: T.List[build.BuildTargetTypes] = [] 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): if obj.is_built: o = os.path.join(proj_dir_to_build_root, obj.rel_to_builddir(self.build_to_src)) obj_list.append(o) else: o = os.path.join(proj_dir_to_build_root, self.build_to_src) obj_list.append(obj.rel_to_builddir(o)) elif isinstance(obj, build.ExtractedObjects): if obj.recursive: objs, d = self._flatten_object_list(obj.target, obj.objlist, proj_dir_to_build_root) obj_list.extend(objs) deps.extend(d) obj_list.extend(self._determine_ext_objs(obj, proj_dir_to_build_root)) deps.append(obj.target) else: raise MesonException('Unknown data type in object list.') return obj_list, deps @staticmethod def is_swift_target(target: build.BuildTarget) -> bool: for s in target.sources: if s.endswith('swift'): return True return False def determine_swift_dep_dirs(self, target: build.BuildTarget) -> T.List[str]: result: T.List[str] = [] for l in target.link_targets: result.append(self.get_target_private_dir_abs(l)) return result def get_executable_serialisation( self, cmd: T.Sequence[T.Union[programs.ExternalProgram, build.BuildTarget, build.CustomTarget, File, str]], workdir: T.Optional[str] = None, extra_bdeps: T.Optional[T.List[build.BuildTarget]] = None, capture: T.Optional[str] = None, feed: T.Optional[str] = None, env: T.Optional[mesonlib.EnvironmentVariables] = None, tag: T.Optional[str] = None, verbose: bool = False, installdir_map: T.Optional[T.Dict[str, str]] = None) -> 'ExecutableSerialisation': # XXX: cmd_args either need to be lowered to strings, or need to be checked for non-string arguments, right? exe, *raw_cmd_args = cmd if isinstance(exe, programs.ExternalProgram): exe_cmd = exe.get_command() exe_for_machine = exe.for_machine elif isinstance(exe, build.BuildTarget): exe_cmd = [self.get_target_filename_abs(exe)] exe_for_machine = exe.for_machine elif isinstance(exe, build.CustomTarget): # The output of a custom target can either be directly runnable # or not, that is, a script, a native binary or a cross compiled # binary when exe wrapper is available and when it is not. # This implementation is not exhaustive but it works in the # common cases. exe_cmd = [self.get_target_filename_abs(exe)] exe_for_machine = MachineChoice.BUILD elif isinstance(exe, mesonlib.File): exe_cmd = [exe.rel_to_builddir(self.environment.source_dir)] exe_for_machine = MachineChoice.BUILD else: exe_cmd = [exe] exe_for_machine = MachineChoice.BUILD cmd_args: T.List[str] = [] for c in raw_cmd_args: if isinstance(c, programs.ExternalProgram): p = c.get_path() assert isinstance(p, str) cmd_args.append(p) elif isinstance(c, (build.BuildTarget, build.CustomTarget)): cmd_args.append(self.get_target_filename_abs(c)) elif isinstance(c, mesonlib.File): cmd_args.append(c.rel_to_builddir(self.environment.source_dir)) else: cmd_args.append(c) machine = self.environment.machines[exe_for_machine] if machine.is_windows() or machine.is_cygwin(): extra_paths = self.determine_windows_extra_paths(exe, extra_bdeps or []) else: extra_paths = [] 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 or not exe_wrapper.found(): msg = 'An exe_wrapper is needed but was not found. Please define one ' \ 'in cross file and check the command and/or add it to PATH.' raise MesonException(msg) 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() or mesonlib.is_wsl()): exe_cmd = ['mono'] + exe_cmd exe_wrapper = None workdir = workdir or self.environment.get_build_dir() return ExecutableSerialisation(exe_cmd + cmd_args, env, exe_wrapper, workdir, extra_paths, capture, feed, tag, verbose, installdir_map) def as_meson_exe_cmdline(self, exe: T.Union[str, mesonlib.File, build.BuildTarget, build.CustomTarget, programs.ExternalProgram], cmd_args: T.Sequence[T.Union[str, mesonlib.File, build.BuildTarget, build.CustomTarget, programs.ExternalProgram]], workdir: T.Optional[str] = None, extra_bdeps: T.Optional[T.List[build.BuildTarget]] = None, capture: T.Optional[str] = None, feed: T.Optional[str] = None, force_serialize: bool = False, env: T.Optional[mesonlib.EnvironmentVariables] = None, verbose: bool = False) -> T.Tuple[T.Sequence[T.Union[str, File, build.Target, programs.ExternalProgram]], str]: ''' Serialize an executable for running with a generator or a custom target ''' cmd: T.List[T.Union[str, mesonlib.File, build.BuildTarget, build.CustomTarget, programs.ExternalProgram]] = [] cmd.append(exe) cmd.extend(cmd_args) es = self.get_executable_serialisation(cmd, workdir, extra_bdeps, capture, feed, env, verbose=verbose) reasons: T.List[str] = [] if es.extra_paths: reasons.append('to set PATH') if es.exe_wrapper: reasons.append('to use exe_wrapper') if workdir: reasons.append('to set workdir') if any('\n' in c for c in es.cmd_args): reasons.append('because command contains newlines') if env and env.varnames: reasons.append('to set env') # force_serialize passed to this function means that the VS backend has # decided it absolutely cannot use real commands. This is "always", # because it's not clear what will work (other than compilers) and so # we don't bother to handle a variety of common cases that probably do # work. # # It's also overridden for a few conditions that can't be handled # inside a command line can_use_env = not force_serialize force_serialize = force_serialize or bool(reasons) if capture: reasons.append('to capture output') if feed: reasons.append('to feed input') if can_use_env and reasons == ['to set env'] and shutil.which('env'): envlist = [] for k, v in env.get_env({}).items(): envlist.append(f'{k}={v}') return ['env'] + envlist + es.cmd_args, ', '.join(reasons) if not force_serialize: if not capture and not feed: return es.cmd_args, '' args: T.List[str] = [] if capture: args += ['--capture', capture] if feed: args += ['--feed', feed] return ( self.environment.get_build_command() + ['--internal', 'exe'] + args + ['--'] + es.cmd_args, ', '.join(reasons) ) if isinstance(exe, (programs.ExternalProgram, build.BuildTarget, build.CustomTarget)): basename = os.path.basename(exe.name) elif isinstance(exe, mesonlib.File): basename = os.path.basename(exe.fname) 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, capture, and feed. This # avoids collisions and also makes the name deterministic over # regenerations which avoids a rebuild by Ninja because the cmdline # stays the same. hasher = hashlib.sha1() if es.env: es.env.hash(hasher) hasher.update(bytes(str(es.cmd_args), encoding='utf-8')) hasher.update(bytes(str(es.workdir), encoding='utf-8')) hasher.update(bytes(str(capture), encoding='utf-8')) hasher.update(bytes(str(feed), encoding='utf-8')) digest = hasher.hexdigest() scratch_file = f'meson_exe_{basename}_{digest}.dat' exe_data = os.path.join(self.environment.get_scratch_dir(), scratch_file) with open(exe_data, 'wb') as f: pickle.dump(es, f) return (self.environment.get_build_command() + ['--internal', 'exe', '--unpickle', exe_data], ', '.join(reasons)) def serialize_tests(self) -> T.Tuple[str, str]: 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: build.BuildTarget) -> T.Tuple[T.Union['Compiler', 'StaticLinker'], T.List[str]]: ''' 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: str, compilers: T.Mapping[str, 'Compiler'], env: 'Environment') -> bool: libdir = os.path.normpath(libdir) for cc in compilers.values(): if libdir in cc.get_library_dirs(env): return True return False def get_external_rpath_dirs(self, target: build.BuildTarget) -> T.Set[str]: args: T.List[str] = [] for lang in LANGUAGES_USING_LDFLAGS: try: e = self.environment.coredata.get_external_link_args(target.for_machine, lang) if isinstance(e, str): args.append(e) else: args.extend(e) except Exception: pass return self.get_rpath_dirs_from_link_args(args) @staticmethod def get_rpath_dirs_from_link_args(args: T.List[str]) -> T.Set[str]: dirs: T.Set[str] = set() # Match rpath formats: # -Wl,-rpath= # -Wl,-rpath, rpath_regex = re.compile(r'-Wl,-rpath[=,]([^,]+)') # Match solaris style compat runpath formats: # -Wl,-R # -Wl,-R, runpath_regex = re.compile(r'-Wl,-R[,]?([^,]+)') # Match symbols formats: # -Wl,--just-symbols= # -Wl,--just-symbols, symbols_regex = re.compile(r'-Wl,--just-symbols[=,]([^,]+)') for arg in args: rpath_match = rpath_regex.match(arg) if rpath_match: for dir in rpath_match.group(1).split(':'): dirs.add(dir) runpath_match = runpath_regex.match(arg) if runpath_match: for dir in runpath_match.group(1).split(':'): # The symbols arg is an rpath if the path is a directory if Path(dir).is_dir(): dirs.add(dir) symbols_match = symbols_regex.match(arg) if symbols_match: for dir in symbols_match.group(1).split(':'): # Prevent usage of --just-symbols to specify rpath if Path(dir).is_dir(): raise MesonException(f'Invalid arg for --just-symbols, {dir} is a directory.') return dirs @lru_cache(maxsize=None) def rpaths_for_non_system_absolute_shared_libraries(self, target: build.BuildTarget, exclude_system: bool = True) -> 'ImmutableListProtocol[str]': paths: OrderedSet[str] = OrderedSet() srcdir = self.environment.get_source_dir() for dep in target.external_deps: if dep.type_name not in {'library', 'pkgconfig', 'cmake'}: continue for libpath in dep.link_args: # For all link args that are absolute paths to a library file, add RPATH args if not os.path.isabs(libpath): continue 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 # Don't remove rpaths specified in LDFLAGS. if libdir in self.get_external_rpath_dirs(target): continue # Windows doesn't support rpaths, but we use this function to # emulate rpaths by setting PATH # .dll is there for mingw gcc # .so's may be extended with version information, e.g. libxyz.so.1.2.3 if not ( os.path.splitext(libpath)[1] in {'.dll', '.lib', '.so', '.dylib'} or re.match(r'.+\.so(\.|$)', os.path.basename(libpath)) ): continue try: commonpath = os.path.commonpath((libdir, srcdir)) except ValueError: # when paths are on different drives on Windows commonpath = '' if commonpath == srcdir: rel_to_src = libdir[len(srcdir) + 1:] assert not os.path.isabs(rel_to_src), f'rel_to_src: {rel_to_src} is absolute' paths.add(os.path.join(self.build_to_src, rel_to_src)) else: paths.add(libdir) # Don't remove rpaths specified by the dependency paths.difference_update(self.get_rpath_dirs_from_link_args(dep.link_args)) for i in chain(target.link_targets, target.link_whole_targets): if isinstance(i, build.BuildTarget): paths.update(self.rpaths_for_non_system_absolute_shared_libraries(i, exclude_system)) return list(paths) # This may take other types def determine_rpath_dirs(self, target: T.Union[build.BuildTarget, build.CustomTarget, build.CustomTargetIndex] ) -> T.Tuple[str, ...]: result: OrderedSet[str] if self.environment.coredata.get_option(OptionKey('layout')) == 'mirror': # Need a copy here result = OrderedSet(target.get_link_dep_subdirs()) else: result = OrderedSet() result.add('meson-out') if isinstance(target, build.BuildTarget): result.update(self.rpaths_for_non_system_absolute_shared_libraries(target)) target.rpath_dirs_to_remove.update([d.encode('utf-8') for d in result]) return tuple(result) @staticmethod def canonicalize_filename(fname: str) -> str: parts = Path(fname).parts hashed = '' if len(parts) > 5: temp = '/'.join(parts[-5:]) # is it shorter to hash the beginning of the path? if len(fname) > len(temp) + 41: hashed = hashlib.sha1(fname.encode('utf-8')).hexdigest() + '_' fname = temp for ch in ('/', '\\', ':'): fname = fname.replace(ch, '_') return hashed + fname def object_filename_from_source(self, target: build.BuildTarget, source: 'FileOrString') -> str: assert isinstance(source, mesonlib.File) if isinstance(target, build.CompileTarget): return target.sources_map[source] 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. gen_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. gen_source = 'meson-generated_' + os.path.relpath(rel_src, targetdir) else: if os.path.isabs(rel_src): # Use the absolute path directly to avoid file name conflicts gen_source = rel_src else: gen_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 self.canonicalize_filename(gen_source) + '.' + machine.get_object_suffix() def _determine_ext_objs(self, extobj: 'build.ExtractedObjects', proj_dir_to_build_root: str) -> T.List[str]: result: T.List[str] = [] targetdir = self.get_target_private_dir(extobj.target) # Merge sources and generated sources raw_sources = list(extobj.srclist) for gensrc in extobj.genlist: for r in gensrc.get_outputs(): path = self.get_target_generated_dir(extobj.target, gensrc, r) dirpart, fnamepart = os.path.split(path) raw_sources.append(File(True, dirpart, fnamepart)) # Filter out headers and all non-source files sources: T.List['FileOrString'] = [] for s in raw_sources: if self.environment.is_source(s): sources.append(s) elif self.environment.is_object(s): result.append(s.relative_name()) # MSVC generate an object file for PCH if extobj.pch and self.target_uses_pch(extobj.target): for lang, pch in extobj.target.pch.items(): compiler = extobj.target.compilers[lang] if compiler.get_argument_syntax() == 'msvc': objname = self.get_msvc_pch_objname(lang, pch) result.append(os.path.join(proj_dir_to_build_root, targetdir, objname)) # extobj could contain only objects and no sources if not sources: return result # With unity builds, sources don't map directly to objects, # we only support extracting all the objects in this mode, # so just return all object files. if extobj.target.is_unity: compsrcs = classify_unity_sources(extobj.target.compilers.values(), sources) sources = [] unity_size = extobj.target.get_option(OptionKey('unity_size')) assert isinstance(unity_size, int), 'for mypy' for comp, srcs in compsrcs.items(): if comp.language in LANGS_CANT_UNITY: sources += srcs continue for i in range((len(srcs) + unity_size - 1) // unity_size): _src = self.get_unity_source_file(extobj.target, comp.get_default_suffix(), i) sources.append(_src) 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: 'Compiler', target: build.BuildTarget) -> T.List[str]: args: T.List[str] = [] 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 get_msvc_pch_objname(self, lang: str, pch: T.List[str]) -> str: if len(pch) == 1: # Same name as in create_msvc_pch_implementation() below. return f'meson_pch-{lang}.obj' return os.path.splitext(pch[1])[0] + '.obj' def create_msvc_pch_implementation(self, target: build.BuildTarget, lang: str, pch_header: str) -> str: # 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 = f'meson_pch-{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 = f'#include "{os.path.basename(pch_header)}"' pch_file_tmp = pch_file + '.tmp' with open(pch_file_tmp, 'w', encoding='utf-8') as f: f.write(content) mesonlib.replace_if_different(pch_file, pch_file_tmp) return pch_rel_to_build def target_uses_pch(self, target: build.BuildTarget) -> bool: try: return T.cast('bool', target.get_option(OptionKey('b_pch'))) except KeyError: return False @staticmethod def escape_extra_args(args: T.List[str]) -> T.List[str]: # all backslashes in defines are doubly-escaped extra_args: T.List[str] = [] for arg in args: if arg.startswith(('-D', '/D')): arg = arg.replace('\\', '\\\\') extra_args.append(arg) return extra_args def get_no_stdlib_args(self, target: 'build.BuildTarget', compiler: 'Compiler') -> T.List[str]: if compiler.language in self.build.stdlibs[target.for_machine]: return compiler.get_no_stdinc_args() return [] def generate_basic_compiler_args(self, target: build.BuildTarget, compiler: 'Compiler', no_warn_args: bool = False) -> 'CompilerArgs': # 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 = compiler.compiler_args() copt_proxy = target.get_options() # First, the trivial ones that are impossible to override. # # Add -nostdinc/-nostdinc++ if needed; can't be overridden commands += self.get_no_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() else: # warning_level is a string, but mypy can't determine that commands += compiler.get_warn_args(T.cast('str', target.get_option(OptionKey('warning_level')))) # 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 target.get_option(OptionKey('werror')): 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. buildtype = target.get_option(OptionKey('buildtype')) assert isinstance(buildtype, str), 'for mypy' commands += compiler.get_buildtype_args(buildtype) optimization = target.get_option(OptionKey('optimization')) assert isinstance(optimization, str), 'for mypy' commands += compiler.get_optimization_args(optimization) debug = target.get_option(OptionKey('debug')) assert isinstance(debug, bool), 'for mypy' commands += compiler.get_debug_args(debug) # 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()) # Using both /Z7 or /ZI and /Zi at the same times produces a compiler warning. # We do not add /Z7 or /ZI by default. If it is being used it is because the user has explicitly enabled it. # /Zi needs to be removed in that case to avoid cl's warning to that effect (D9025 : overriding '/Zi' with '/ZI') if ('/Zi' in commands) and (('/ZI' in commands) or ('/Z7' in commands)): commands.remove('/Zi') # 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() elif isinstance(target, (build.StaticLibrary, 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 dep.type_name == 'pkgconfig': assert isinstance(dep, dependencies.ExternalDependency) 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 chain(target.link_targets, target.link_whole_targets): priv_dir = self.get_target_private_dir(lt) commands += compiler.get_include_args(priv_dir, False) return commands def build_target_link_arguments(self, compiler: 'Compiler', deps: T.List[build.Target]) -> T.List[str]: args: T.List[str] = [] for d in deps: if not d.is_linkable_target(): raise RuntimeError(f'Tried to link with a non-library target "{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: build.BuildTarget) -> T.List[str]: paths: OrderedSet[str] = 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) @staticmethod @lru_cache(maxsize=None) def search_dll_path(link_arg: str) -> T.Optional[str]: if link_arg.startswith(('-l', '-L')): link_arg = link_arg[2:] p = Path(link_arg) if not p.is_absolute(): return None try: p = p.resolve(strict=True) except FileNotFoundError: return None for f in p.parent.glob('*.dll'): # path contains dlls return str(p.parent) if p.is_file(): p = p.parent # Heuristic: replace *last* occurence of '/lib' binpath = Path('/bin'.join(p.as_posix().rsplit('/lib', maxsplit=1))) for _ in binpath.glob('*.dll'): return str(binpath) return None @classmethod @lru_cache(maxsize=None) def extract_dll_paths(cls, target: build.BuildTarget) -> T.Set[str]: """Find paths to all DLLs needed for a given target, since we link against import libs, and we don't know the actual path of the DLLs. 1. If there are DLLs in the same directory than the .lib dir, use it 2. If there is a sibbling directory named 'bin' with DLLs in it, use it """ results = set() for dep in target.external_deps: if dep.type_name == 'pkgconfig': # If by chance pkg-config knows the bin dir... bindir = dep.get_variable(pkgconfig='bindir', default_value='') if bindir: results.add(bindir) continue results.update(filter(None, map(cls.search_dll_path, dep.link_args))) # pylint: disable=bad-builtin for i in chain(target.link_targets, target.link_whole_targets): if isinstance(i, build.BuildTarget): results.update(cls.extract_dll_paths(i)) return results def determine_windows_extra_paths( self, target: T.Union[build.BuildTarget, build.CustomTarget, programs.ExternalProgram, mesonlib.File, str], extra_bdeps: T.Sequence[T.Union[build.BuildTarget, build.CustomTarget]]) -> T.List[str]: """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: T.Set[str] = set() prospectives: T.Set[build.BuildTargetTypes] = set() if isinstance(target, build.BuildTarget): prospectives.update(target.get_transitive_link_deps()) # External deps result.update(self.extract_dll_paths(target)) for bdep in extra_bdeps: prospectives.add(bdep) if isinstance(bdep, build.BuildTarget): prospectives.update(bdep.get_transitive_link_deps()) # Internal deps for ld in prospectives: 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: T.BinaryIO) -> None: self.write_test_serialisation(self.build.get_benchmarks(), datafile) def write_test_file(self, datafile: T.BinaryIO) -> None: self.write_test_serialisation(self.build.get_tests(), datafile) def create_test_serialisation(self, tests: T.List['Test']) -> T.List[TestSerialisation]: arr: T.List[TestSerialisation] = [] for t in sorted(tests, key=lambda tst: -1 * tst.priority): exe = t.get_exe() if isinstance(exe, programs.ExternalProgram): cmd = exe.get_command() else: cmd = [os.path.join(self.environment.get_build_dir(), self.get_target_filename(exe))] if isinstance(exe, (build.BuildTarget, programs.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 # we allow passing compiled executables to tests, which may be cross built. # We need to consider these as well when considering whether the target is cross or not. for a in t.cmd_args: if isinstance(a, build.BuildTarget): if a.for_machine is MachineChoice.HOST: test_for_machine = MachineChoice.HOST break is_cross = self.environment.is_cross_build(test_for_machine) exe_wrapper = self.environment.get_exe_wrapper() machine = self.environment.machines[exe.for_machine] if machine.is_windows() or machine.is_cygwin(): extra_bdeps: T.List[T.Union[build.BuildTarget, build.CustomTarget]] = [] if isinstance(exe, build.CustomTarget): extra_bdeps = list(exe.get_transitive_build_target_deps()) extra_paths = self.determine_windows_extra_paths(exe, extra_bdeps) for a in t.cmd_args: if isinstance(a, build.BuildTarget): for p in self.determine_windows_extra_paths(a, []): if p not in extra_paths: extra_paths.append(p) else: extra_paths = [] cmd_args: T.List[str] = [] depends: T.Set[build.Target] = set(t.depends) if isinstance(exe, build.Target): depends.add(exe) for a in t.cmd_args: if isinstance(a, build.Target): depends.add(a) elif isinstance(a, build.CustomTargetIndex): depends.add(a.target) 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, build.CustomTargetIndex)): cmd_args.extend(self.construct_target_rel_paths(a, t.workdir)) else: raise MesonException('Bad object in test command.') t_env = copy.deepcopy(t.env) if not machine.is_windows() and not machine.is_cygwin() and not machine.is_darwin(): ld_lib_path: T.Set[str] = set() for d in depends: if isinstance(d, build.BuildTarget): for l in d.get_all_link_deps(): if isinstance(l, build.SharedLibrary): ld_lib_path.add(os.path.join(self.environment.get_build_dir(), l.get_subdir())) if ld_lib_path: t_env.prepend('LD_LIBRARY_PATH', list(ld_lib_path), ':') 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, isinstance(exe, build.Target), isinstance(exe, build.Executable), [x.get_id() for x in depends], self.environment.coredata.version, t.verbose) arr.append(ts) return arr def write_test_serialisation(self, tests: T.List['Test'], datafile: T.BinaryIO) -> None: pickle.dump(self.create_test_serialisation(tests), datafile) def construct_target_rel_paths(self, t: T.Union[build.Target, build.CustomTargetIndex], workdir: T.Optional[str]) -> T.List[str]: target_dir = self.get_target_dir(t) # ensure that test executables can be run when passed as arguments if isinstance(t, build.Executable) and workdir is None: target_dir = target_dir or '.' if isinstance(t, build.BuildTarget): outputs = [t.get_filename()] else: assert isinstance(t, (build.CustomTarget, build.CustomTargetIndex)) outputs = t.get_outputs() outputs = [os.path.join(target_dir, x) for x in outputs] if workdir is not None: assert os.path.isabs(workdir) outputs = [os.path.join(self.environment.get_build_dir(), x) for x in outputs] outputs = [os.path.relpath(x, workdir) for x in outputs] return outputs def generate_depmf_install(self, d: InstallData) -> None: depmf_path = self.build.dep_manifest_name if depmf_path is None: option_dir = self.environment.coredata.get_option(OptionKey('licensedir')) assert isinstance(option_dir, str), 'for mypy' if option_dir: depmf_path = os.path.join(option_dir, 'depmf.json') else: return ifilename = os.path.join(self.environment.get_build_dir(), 'depmf.json') ofilename = os.path.join(self.environment.get_prefix(), depmf_path) odirname = os.path.join(self.environment.get_prefix(), os.path.dirname(depmf_path)) out_name = os.path.join('{prefix}', depmf_path) out_dir = os.path.join('{prefix}', os.path.dirname(depmf_path)) mfobj = {'type': 'dependency manifest', 'version': '1.0', 'projects': {k: v.to_json() for k, v in self.build.dep_manifest.items()}} with open(ifilename, 'w', encoding='utf-8') as f: f.write(json.dumps(mfobj)) # Copy file from, to, and with mode unchanged d.data.append(InstallDataBase(ifilename, ofilename, out_name, None, '', tag='devel', data_type='depmf')) for m in self.build.dep_manifest.values(): for ifilename, name in m.license_files: ofilename = os.path.join(odirname, name.relative_name()) out_name = os.path.join(out_dir, name.relative_name()) d.data.append(InstallDataBase(ifilename, ofilename, out_name, None, m.subproject, tag='devel', data_type='depmf')) def get_regen_filelist(self) -> T.List[str]: '''List of all files whose alteration means that the build definition needs to be regenerated.''' deps = OrderedSet([str(Path(self.build_to_src) / df) for df in self.interpreter.get_build_def_files()]) if self.environment.is_cross_build(): deps.update(self.environment.coredata.cross_files) deps.update(self.environment.coredata.config_files) deps.add('meson-private/coredata.dat') self.check_clock_skew(deps) return list(deps) def generate_regen_info(self) -> None: 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 check_clock_skew(self, file_list: T.Iterable[str]) -> None: # If a file that leads to reconfiguration has a time # stamp in the future, it will trigger an eternal reconfigure # loop. import time now = time.time() for f in file_list: absf = os.path.join(self.environment.get_build_dir(), f) ftime = os.path.getmtime(absf) delta = ftime - now # On Windows disk time stamps sometimes point # to the future by a minuscule amount, less than # 0.001 seconds. I don't know why. if delta > 0.001: raise MesonException(f'Clock skew detected. File {absf} has a time stamp {delta:.4f}s in the future.') def build_target_to_cmd_array(self, bt: T.Union[build.BuildTarget, programs.ExternalProgram]) -> T.List[str]: if isinstance(bt, build.BuildTarget): arr = [os.path.join(self.environment.get_build_dir(), self.get_target_filename(bt))] else: arr = bt.get_command() return arr def replace_extra_args(self, args: T.List[str], genlist: 'build.GeneratedList') -> T.List[str]: final_args: T.List[str] = [] 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: T.List[str], private_dir: str, output_list: T.List[str]) -> T.List[str]: newargs: T.List[str] = [] 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 = f'@OUTPUT{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) -> 'T.OrderedDict[str, T.Union[build.BuildTarget, build.CustomTarget]]': result: 'T.OrderedDict[str, T.Union[build.BuildTarget, build.CustomTarget]]' = OrderedDict() # Get all build and custom targets that must be built by default for name, b in self.build.get_targets().items(): if b.build_by_default: result[name] = b return result def get_testlike_targets(self, benchmark: bool = False) -> T.OrderedDict[str, T.Union[build.BuildTarget, build.CustomTarget]]: result: T.OrderedDict[str, T.Union[build.BuildTarget, build.CustomTarget]] = OrderedDict() targets = self.build.get_benchmarks() if benchmark else self.build.get_tests() for t in targets: exe = t.exe if isinstance(exe, (build.CustomTarget, build.BuildTarget)): result[exe.get_id()] = exe for arg in t.cmd_args: 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: build.CustomTarget) -> 'ImmutableListProtocol[str]': libs: T.List[str] = [] 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: T.Union[build.BuildTarget, build.CustomTarget]) -> 'ImmutableListProtocol[str]': libs: T.List[str] = [] for t in target.get_generated_sources(): if not isinstance(t, build.CustomTarget): continue libs.extend(self.get_custom_target_provided_by_generated_source(t)) return libs def get_custom_target_sources(self, target: build.CustomTarget) -> T.List[str]: ''' 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: T.List[str] = [] for i in target.get_sources(): 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_custom_target_output_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 = self.determine_ext_objs(i) elif isinstance(i, programs.ExternalProgram): assert i.found(), "This shouldn't be possible" assert i.path is not None, 'for mypy' fname = [i.path] 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_target_depend_files(self, target: T.Union[build.CustomTarget, build.BuildTarget], absolute_paths: bool = False) -> T.List[str]: deps: T.List[str] = [] 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 get_custom_target_output_dir(self, target: T.Union[build.Target, build.CustomTargetIndex]) -> str: # The XCode backend is special. A target foo/bar does # not go to ${BUILDDIR}/foo/bar but instead to # ${BUILDDIR}/${BUILDTYPE}/foo/bar. # Currently we set the include dir to be the former, # and not the latter. Thus we need this extra customisation # point. If in the future we make include dirs et al match # ${BUILDDIR}/${BUILDTYPE} instead, this becomes unnecessary. return self.get_target_dir(target) @lru_cache(maxsize=None) def get_normpath_target(self, source: str) -> str: return os.path.normpath(source) def get_custom_target_dirs(self, target: build.CustomTarget, compiler: 'Compiler', *, absolute_path: bool = False) -> T.List[str]: custom_target_include_dirs: T.List[str] = [] 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_normpath_target(self.get_custom_target_output_dir(i)) if not idir: idir = '.' if absolute_path: idir = os.path.join(self.environment.get_build_dir(), idir) if idir not in custom_target_include_dirs: custom_target_include_dirs.append(idir) return custom_target_include_dirs def get_custom_target_dir_include_args( self, target: build.CustomTarget, compiler: 'Compiler', *, absolute_path: bool = False) -> T.List[str]: incs: T.List[str] = [] for i in self.get_custom_target_dirs(target, compiler, absolute_path=absolute_path): incs += compiler.get_include_args(i, False) return incs def eval_custom_target_command( self, target: build.CustomTarget, absolute_outputs: bool = False) -> \ T.Tuple[T.List[str], T.List[str], T.List[str]]: # 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_custom_target_output_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 = [os.path.join(outdir, i) for i in target.get_outputs()] inputs = self.get_custom_target_sources(target) # Evaluate the command list cmd: T.List[str] = [] for i in target.command: if isinstance(i, build.BuildTarget): cmd += self.build_target_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_custom_target_output_dir(i), tmp) elif isinstance(i, mesonlib.File): i = i.rel_to_builddir(self.build_to_src) if target.absolute_paths or absolute_outputs: 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 isinstance(i, str): if '@SOURCE_ROOT@' in i: i = i.replace('@SOURCE_ROOT@', source_root) if '@BUILD_ROOT@' in i: i = i.replace('@BUILD_ROOT@', build_root) if '@CURRENT_SOURCE_DIR@' in i: i = i.replace('@CURRENT_SOURCE_DIR@', os.path.join(source_root, target.subdir)) if '@DEPFILE@' in i: if target.depfile is None: msg = f'Custom target {target.name!r} has @DEPFILE@ but no depfile ' \ 'keyword argument.' raise MesonException(msg) dfilename = os.path.join(outdir, target.depfile) i = i.replace('@DEPFILE@', dfilename) if '@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) else: raise RuntimeError(f'Argument {i} is of unknown type {type(i)}') 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 get_run_target_env(self, target: build.RunTarget) -> mesonlib.EnvironmentVariables: env = target.env if target.env else mesonlib.EnvironmentVariables() if target.default_env: introspect_cmd = join_args(self.environment.get_build_command() + ['introspect']) env.set('MESON_SOURCE_ROOT', [self.environment.get_source_dir()]) env.set('MESON_BUILD_ROOT', [self.environment.get_build_dir()]) env.set('MESON_SUBDIR', [target.subdir]) env.set('MESONINTROSPECT', [introspect_cmd]) return env def run_postconf_scripts(self) -> None: from ..scripts.meson_exe import run_exe introspect_cmd = join_args(self.environment.get_build_command() + ['introspect']) env = {'MESON_SOURCE_ROOT': self.environment.get_source_dir(), 'MESON_BUILD_ROOT': self.environment.get_build_dir(), 'MESONINTROSPECT': introspect_cmd, } for s in self.build.postconf_scripts: name = ' '.join(s.cmd_args) mlog.log(f'Running postconf script {name!r}') run_exe(s, env) def create_install_data(self) -> InstallData: strip_bin = self.environment.lookup_binary_entry(MachineChoice.HOST, '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 = [detect.defaults['strip'][0]] umask = self.environment.coredata.get_option(OptionKey('install_umask')) assert isinstance(umask, (str, int)), 'for mypy' d = InstallData(self.environment.get_source_dir(), self.environment.get_build_dir(), self.environment.get_prefix(), self.environment.get_libdir(), strip_bin, umask, self.environment.get_build_command() + ['introspect'], self.environment.coredata.version) self.generate_depmf_install(d) self.generate_target_install(d) self.generate_header_install(d) self.generate_man_install(d) self.generate_emptydir_install(d) self.generate_data_install(d) self.generate_symlink_install(d) self.generate_custom_install_script(d) self.generate_subdir_install(d) return d def create_install_data_files(self) -> None: 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 guess_install_tag(self, fname: str, outdir: T.Optional[str] = None) -> T.Optional[str]: prefix = self.environment.get_prefix() bindir = Path(prefix, self.environment.get_bindir()) libdir = Path(prefix, self.environment.get_libdir()) incdir = Path(prefix, self.environment.get_includedir()) _ldir = self.environment.coredata.get_option(mesonlib.OptionKey('localedir')) assert isinstance(_ldir, str), 'for mypy' localedir = Path(prefix, _ldir) dest_path = Path(prefix, outdir, Path(fname).name) if outdir else Path(prefix, fname) if bindir in dest_path.parents: return 'runtime' elif libdir in dest_path.parents: if dest_path.suffix in {'.a', '.pc'}: return 'devel' elif dest_path.suffix in {'.so', '.dll'}: return 'runtime' elif incdir in dest_path.parents: return 'devel' elif localedir in dest_path.parents: return 'i18n' elif 'installed-tests' in dest_path.parts: return 'tests' elif 'systemtap' in dest_path.parts: return 'systemtap' mlog.debug('Failed to guess install tag for', dest_path) return None def generate_target_install(self, d: InstallData) -> None: for t in self.build.get_targets().values(): if not t.should_install(): continue outdirs, install_dir_names, custom_install_dir = t.get_install_dir() # Sanity-check the outputs and install_dirs num_outdirs, num_out = len(outdirs), len(t.get_outputs()) if num_outdirs not in {1, 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)) assert len(t.install_tag) == num_out install_mode = t.get_custom_install_mode() # because mypy gets confused type narrowing in lists first_outdir = outdirs[0] first_outdir_name = install_dir_names[0] # 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. can_strip = not isinstance(t, build.StaticLibrary) should_strip = can_strip and t.get_option(OptionKey('strip')) assert isinstance(should_strip, bool), 'for mypy' # Install primary build output (library/executable/jar, etc) # Done separately because of strip/aliases/rpath if first_outdir is not False: tag = t.install_tag[0] or ('devel' if isinstance(t, build.StaticLibrary) else 'runtime') mappings = t.get_link_deps_mapping(d.prefix) i = TargetInstallData(self.get_target_filename(t), first_outdir, first_outdir_name, should_strip, mappings, t.rpath_dirs_to_remove, t.install_rpath, install_mode, t.subproject, tag=tag, can_strip=can_strip) d.targets.append(i) for alias, to, tag in t.get_aliases(): alias = os.path.join(first_outdir, alias) s = InstallSymlinkData(to, alias, first_outdir, t.subproject, tag, allow_missing=True) d.symlinks.append(s) 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 = first_outdir 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, first_outdir_name, False, {}, set(), '', install_mode, t.subproject, optional=isinstance(t, build.SharedModule), tag='devel') 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, first_outdir, first_outdir_name, False, {}, set(), '', install_mode, t.subproject, optional=True, tag='devel') d.targets.append(i) # Install secondary outputs. Only used for Vala right now. if num_outdirs > 1: for output, outdir, outdir_name, tag in zip(t.get_outputs()[1:], outdirs[1:], install_dir_names[1:], t.install_tag[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, outdir_name, False, {}, set(), None, install_mode, t.subproject, tag=tag) 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 # # XXX: this wouldn't be needed if we just always matches outdirs # to the length of outputs… if num_outdirs == 1 and num_out > 1: if first_outdir is not False: for output, tag in zip(t.get_outputs(), t.install_tag): tag = tag or self.guess_install_tag(output, first_outdir) f = os.path.join(self.get_target_dir(t), output) i = TargetInstallData(f, first_outdir, first_outdir_name, False, {}, set(), None, install_mode, t.subproject, optional=not t.build_by_default, tag=tag) d.targets.append(i) else: for output, outdir, outdir_name, tag in zip(t.get_outputs(), outdirs, install_dir_names, t.install_tag): # User requested that we not install this output if outdir is False: continue tag = tag or self.guess_install_tag(output, outdir) f = os.path.join(self.get_target_dir(t), output) i = TargetInstallData(f, outdir, outdir_name, False, {}, set(), None, install_mode, t.subproject, optional=not t.build_by_default, tag=tag) d.targets.append(i) def generate_custom_install_script(self, d: InstallData) -> None: d.install_scripts = self.build.install_scripts for i in d.install_scripts: if not i.tag: mlog.debug('Failed to guess install tag for install script:', ' '.join(i.cmd_args)) def generate_header_install(self, d: InstallData) -> None: 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 = outdir_name = h.get_custom_install_dir() if outdir is None: subdir = h.get_install_subdir() if subdir is None: outdir = incroot outdir_name = '{includedir}' else: outdir = os.path.join(incroot, subdir) outdir_name = os.path.join('{includedir}', subdir) for f in h.get_sources(): abspath = f.absolute_path(srcdir, builddir) i = InstallDataBase(abspath, outdir, outdir_name, h.get_custom_install_mode(), h.subproject, tag='devel', follow_symlinks=h.follow_symlinks) d.headers.append(i) def generate_man_install(self, d: InstallData) -> None: 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: if m.locale: subdir = os.path.join('{mandir}', m.locale, 'man' + num) else: subdir = os.path.join('{mandir}', 'man' + num) fname = f.fname if m.locale: # strip locale from file name fname = fname.replace(f'.{m.locale}', '') srcabs = f.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir()) dstname = os.path.join(subdir, os.path.basename(fname)) dstabs = dstname.replace('{mandir}', manroot) i = InstallDataBase(srcabs, dstabs, dstname, m.get_custom_install_mode(), m.subproject, tag='man') d.man.append(i) def generate_emptydir_install(self, d: InstallData) -> None: emptydir: T.List[build.EmptyDir] = self.build.get_emptydir() for e in emptydir: tag = e.install_tag or self.guess_install_tag(e.path) i = InstallEmptyDir(e.path, e.install_mode, e.subproject, tag) d.emptydir.append(i) def generate_data_install(self, d: InstallData) -> None: 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 subdir_name = de.install_dir_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) dstdir_name = os.path.join(subdir_name, dst_name) tag = de.install_tag or self.guess_install_tag(dst_abs) i = InstallDataBase(src_file.absolute_path(srcdir, builddir), dst_abs, dstdir_name, de.install_mode, de.subproject, tag=tag, data_type=de.data_type, follow_symlinks=de.follow_symlinks) d.data.append(i) def generate_symlink_install(self, d: InstallData) -> None: links: T.List[build.SymlinkData] = self.build.get_symlinks() for l in links: assert isinstance(l, build.SymlinkData) install_dir = l.install_dir name_abs = os.path.join(install_dir, l.name) tag = l.install_tag or self.guess_install_tag(name_abs) s = InstallSymlinkData(l.target, name_abs, install_dir, l.subproject, tag) d.symlinks.append(s) def generate_subdir_install(self, d: InstallData) -> None: for sd in self.build.get_install_subdirs(): if sd.from_source_dir: from_dir = self.environment.get_source_dir() else: from_dir = self.environment.get_build_dir() src_dir = os.path.join(from_dir, sd.source_subdir, sd.installable_subdir).rstrip('/') dst_dir = os.path.join(self.environment.get_prefix(), sd.install_dir) dst_name = os.path.join('{prefix}', sd.install_dir) if sd.install_dir != sd.install_dir_name: dst_name = sd.install_dir_name if not sd.strip_directory: dst_dir = os.path.join(dst_dir, os.path.basename(src_dir)) dst_name = os.path.join(dst_name, os.path.basename(src_dir)) tag = sd.install_tag or self.guess_install_tag(os.path.join(sd.install_dir, 'dummy')) i = SubdirInstallData(src_dir, dst_dir, dst_name, sd.install_mode, sd.exclude, sd.subproject, tag, follow_symlinks=sd.follow_symlinks) d.install_subdirs.append(i) def get_introspection_data(self, target_id: str, target: build.Target) -> T.List['TargetIntrospectionData']: ''' 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 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)] elif isinstance(j, (build.CustomTarget, build.BuildTarget)): source_list += [os.path.join(self.build_dir, j.get_subdir(), o) for o in j.get_outputs()] source_list = [os.path.normpath(s) for s in source_list] compiler: T.List[str] = [] if isinstance(target, build.CustomTarget): tmp_compiler = target.command 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(f'Type "{type(j).__name__}" is not supported in get_introspection_data. This is a bug') return [{ 'language': 'unknown', 'compiler': compiler, 'parameters': [], 'sources': source_list, 'generated_sources': [] }] return [] def get_devenv(self) -> mesonlib.EnvironmentVariables: env = mesonlib.EnvironmentVariables() extra_paths = set() library_paths = set() build_machine = self.environment.machines[MachineChoice.BUILD] host_machine = self.environment.machines[MachineChoice.HOST] need_wine = not build_machine.is_windows() and host_machine.is_windows() for t in self.build.get_targets().values(): in_default_dir = t.should_install() and not t.get_install_dir()[2] if t.for_machine != MachineChoice.HOST or not in_default_dir: continue tdir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(t)) if isinstance(t, build.Executable): # Add binaries that are going to be installed in bindir into PATH # so they get used by default instead of searching on system when # in developer environment. extra_paths.add(tdir) if host_machine.is_windows() or host_machine.is_cygwin(): # On windows we cannot rely on rpath to run executables from build # directory. We have to add in PATH the location of every DLL needed. library_paths.update(self.determine_windows_extra_paths(t, [])) elif isinstance(t, build.SharedLibrary): # Add libraries that are going to be installed in libdir into # LD_LIBRARY_PATH. This allows running system applications using # that library. library_paths.add(tdir) if need_wine: # Executable paths should be in both PATH and WINEPATH. # - Having them in PATH makes bash completion find it, # and make running "foo.exe" find it when wine-binfmt is installed. # - Having them in WINEPATH makes "wine foo.exe" find it. library_paths.update(extra_paths) if library_paths: if need_wine: env.prepend('WINEPATH', list(library_paths), separator=';') elif host_machine.is_windows() or host_machine.is_cygwin(): extra_paths.update(library_paths) elif host_machine.is_darwin(): env.prepend('DYLD_LIBRARY_PATH', list(library_paths)) else: env.prepend('LD_LIBRARY_PATH', list(library_paths)) if extra_paths: env.prepend('PATH', list(extra_paths)) return env def compiler_to_generator(self, target: build.BuildTarget, compiler: 'Compiler', sources: _ALL_SOURCES_TYPE, output_templ: str) -> build.GeneratedList: ''' Some backends don't support custom compilers. This is a convenience method to convert a Compiler to a Generator. ''' exelist = compiler.get_exelist() exe = programs.ExternalProgram(exelist[0]) args = exelist[1:] # FIXME: There are many other args missing commands = self.generate_basic_compiler_args(target, compiler) commands += compiler.get_dependency_gen_args('@OUTPUT@', '@DEPFILE@') commands += compiler.get_output_args('@OUTPUT@') commands += compiler.get_compile_only_args() + ['@INPUT@'] commands += self.get_source_dir_include_args(target, compiler) commands += self.get_build_dir_include_args(target, compiler) # 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(target.get_extra_args(compiler.get_language())) generator = build.Generator(exe, args + commands.to_native(), [output_templ], depfile='@PLAINNAME@.d') return generator.process_files(sources, self.interpreter) def compile_target_to_generator(self, target: build.CompileTarget) -> build.GeneratedList: all_sources = T.cast('_ALL_SOURCES_TYPE', target.sources) + T.cast('_ALL_SOURCES_TYPE', target.generated) return self.compiler_to_generator(target, target.compiler, all_sources, target.output_templ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0 meson-1.3.2/mesonbuild/backend/ninjabackend.py0000644000175000017500000055257314562742373021577 0ustar00jpakkanejpakkane# 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 __future__ import annotations from collections import OrderedDict from dataclasses import dataclass from enum import Enum, unique from functools import lru_cache from pathlib import PurePath, Path from textwrap import dedent import itertools import json import os import pickle import re import shlex import subprocess import typing as T from . import backends from .. import modules from .. import environment, mesonlib from .. import build from .. import mlog from .. import compilers from ..arglist import CompilerArgs from ..compilers import Compiler from ..linkers import ArLikeLinker, RSPFileSyntax from ..mesonlib import ( File, LibType, MachineChoice, MesonBugException, MesonException, OrderedSet, PerMachine, ProgressBar, quote_arg ) from ..mesonlib import get_compiler_for_source, has_path_sep, OptionKey from .backends import CleanTrees from ..build import GeneratedList, InvalidArguments if T.TYPE_CHECKING: from typing_extensions import Literal from .._typing import ImmutableListProtocol from ..build import ExtractedObjects, LibTypes from ..interpreter import Interpreter from ..linkers.linkers import DynamicLinker, StaticLinker from ..compilers.cs import CsCompiler from ..compilers.fortran import FortranCompiler CommandArgOrStr = T.List[T.Union['NinjaCommandArg', str]] RUST_EDITIONS = Literal['2015', '2018', '2021'] 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+)" def cmd_quote(arg: str) -> str: # see: https://docs.microsoft.com/en-us/windows/desktop/api/shellapi/nf-shellapi-commandlinetoargvw#remarks # backslash escape any existing double quotes # any existing backslashes preceding a quote are doubled arg = re.sub(r'(\\*)"', lambda m: '\\' * (len(m.group(1)) * 2 + 1) + '"', arg) # any terminal backslashes likewise need doubling arg = re.sub(r'(\\*)$', lambda m: '\\' * (len(m.group(1)) * 2), arg) # and double quote arg = f'"{arg}"' return arg def gcc_rsp_quote(s: str) -> str: # see: the function buildargv() in libiberty # # this differs from sh-quoting in that a backslash *always* escapes the # following character, even inside single quotes. s = s.replace('\\', '\\\\') return shlex.quote(s) # How ninja executes command lines differs between Unix and Windows # (see https://ninja-build.org/manual.html#ref_rule_command) if mesonlib.is_windows(): quote_func = cmd_quote execute_wrapper = ['cmd', '/c'] # unused rmfile_prefix = ['del', '/f', '/s', '/q', '{}', '&&'] else: quote_func = quote_arg execute_wrapper = [] rmfile_prefix = ['rm', '-f', '{}', '&&'] def get_rsp_threshold() -> int: '''Return a conservative estimate of the commandline size in bytes above which a response file should be used. May be overridden for debugging by setting environment variable MESON_RSP_THRESHOLD.''' if mesonlib.is_windows(): # Usually 32k, but some projects might use cmd.exe, # and that has a limit of 8k. limit = 8192 else: # On Linux, ninja always passes the commandline as a single # big string to /bin/sh, and the kernel limits the size of a # single argument; see MAX_ARG_STRLEN limit = 131072 # Be conservative limit = limit // 2 return int(os.environ.get('MESON_RSP_THRESHOLD', limit)) # a conservative estimate of the command-line length limit rsp_threshold = get_rsp_threshold() # 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_UNQUOTED', 'DESC', 'pool', 'description', 'targetdep', 'dyndep'} NINJA_QUOTE_BUILD_PAT = re.compile(r"[$ :\n]") NINJA_QUOTE_VAR_PAT = re.compile(r"[$ \n]") def ninja_quote(text: str, is_build_line: bool = False) -> str: if is_build_line: quote_re = NINJA_QUOTE_BUILD_PAT else: quote_re = NINJA_QUOTE_VAR_PAT # Fast path for when no quoting is necessary if not quote_re.search(text): return text if '\n' in text: errmsg = f'''Ninja does not support newlines in rules. The content was: {text} Please report this error with a test case to the Meson bug tracker.''' raise MesonException(errmsg) return quote_re.sub(r'$\g<0>', text) class TargetDependencyScannerInfo: def __init__(self, private_dir: str, source2object: T.Dict[str, str]): self.private_dir = private_dir self.source2object = source2object @unique class Quoting(Enum): both = 0 notShell = 1 notNinja = 2 none = 3 class NinjaCommandArg: def __init__(self, s: str, quoting: Quoting = Quoting.both) -> None: self.s = s self.quoting = quoting def __str__(self) -> str: return self.s @staticmethod def list(l: T.List[str], q: Quoting) -> T.List[NinjaCommandArg]: return [NinjaCommandArg(i, q) for i in l] @dataclass class NinjaComment: comment: str def write(self, outfile: T.TextIO) -> None: for l in self.comment.split('\n'): outfile.write('# ') outfile.write(l) outfile.write('\n') outfile.write('\n') class NinjaRule: def __init__(self, rule: str, command: CommandArgOrStr, args: CommandArgOrStr, description: str, rspable: bool = False, deps: T.Optional[str] = None, depfile: T.Optional[str] = None, extra: T.Optional[str] = None, rspfile_quote_style: RSPFileSyntax = RSPFileSyntax.GCC): def strToCommandArg(c: T.Union[NinjaCommandArg, str]) -> NinjaCommandArg: if isinstance(c, NinjaCommandArg): return c # deal with common cases here, so we don't have to explicitly # annotate the required quoting everywhere if c == '&&': # shell constructs shouldn't be shell quoted return NinjaCommandArg(c, Quoting.notShell) if c.startswith('$'): var = re.search(r'\$\{?(\w*)\}?', c).group(1) if var not in raw_names: # ninja variables shouldn't be ninja quoted, and their value # is already shell quoted return NinjaCommandArg(c, Quoting.none) else: # shell quote the use of ninja variables whose value must # not be shell quoted (as it also used by ninja) return NinjaCommandArg(c, Quoting.notNinja) return NinjaCommandArg(c) self.name = rule self.command: T.List[NinjaCommandArg] = [strToCommandArg(c) for c in command] # includes args which never go into a rspfile self.args: T.List[NinjaCommandArg] = [strToCommandArg(a) for a in 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 self.rsprefcount = 0 self.rspfile_quote_style = rspfile_quote_style if self.depfile == '$DEPFILE': self.depfile += '_UNQUOTED' @staticmethod def _quoter(x, qf = quote_func): if isinstance(x, NinjaCommandArg): if x.quoting == Quoting.none: return x.s elif x.quoting == Quoting.notNinja: return qf(x.s) elif x.quoting == Quoting.notShell: return ninja_quote(x.s) # fallthrough return ninja_quote(qf(str(x))) def write(self, outfile: T.TextIO) -> None: rspfile_args = self.args if self.rspfile_quote_style is RSPFileSyntax.MSVC: rspfile_quote_func = cmd_quote rspfile_args = [NinjaCommandArg('$in_newline', arg.quoting) if arg.s == '$in' else arg for arg in rspfile_args] else: rspfile_quote_func = gcc_rsp_quote def rule_iter(): if self.refcount: yield '' if self.rsprefcount: yield '_RSP' for rsp in rule_iter(): outfile.write(f'rule {self.name}{rsp}\n') if rsp == '_RSP': outfile.write(' command = {} @$out.rsp\n'.format(' '.join([self._quoter(x) for x in self.command]))) outfile.write(' rspfile = $out.rsp\n') outfile.write(' rspfile_content = {}\n'.format(' '.join([self._quoter(x, rspfile_quote_func) for x in rspfile_args]))) else: outfile.write(' command = {}\n'.format(' '.join([self._quoter(x) for x in self.command + self.args]))) if self.deps: outfile.write(f' deps = {self.deps}\n') if self.depfile: outfile.write(f' depfile = {self.depfile}\n') outfile.write(f' description = {self.description}\n') if self.extra: for l in self.extra.split('\n'): outfile.write(' ') outfile.write(l) outfile.write('\n') outfile.write('\n') def length_estimate(self, infiles, outfiles, elems): # determine variables # this order of actions only approximates ninja's scoping rules, as # documented at: https://ninja-build.org/manual.html#ref_scope ninja_vars = {} for e in elems: (name, value) = e ninja_vars[name] = value ninja_vars['deps'] = self.deps ninja_vars['depfile'] = self.depfile ninja_vars['in'] = infiles ninja_vars['out'] = outfiles # expand variables in command command = ' '.join([self._quoter(x) for x in self.command + self.args]) estimate = len(command) for m in re.finditer(r'(\${\w+}|\$\w+)?[^$]*', command): if m.start(1) != -1: estimate -= m.end(1) - m.start(1) + 1 chunk = m.group(1) if chunk[1] == '{': chunk = chunk[2:-1] else: chunk = chunk[1:] chunk = ninja_vars.get(chunk, []) # undefined ninja variables are empty estimate += len(' '.join(chunk)) # determine command length return estimate class NinjaBuildElement: def __init__(self, all_outputs: T.Set[str], outfilenames, rulename, infilenames, implicit_outs=None): self.implicit_outfilenames = implicit_outs or [] if isinstance(outfilenames, str): self.outfilenames = [outfilenames] else: self.outfilenames = outfilenames assert isinstance(rulename, str) self.rulename = rulename if isinstance(infilenames, str): self.infilenames = [infilenames] else: self.infilenames = infilenames self.deps = OrderedSet() self.orderdeps = OrderedSet() self.elems = [] self.all_outputs = all_outputs self.output_errors = '' def add_dep(self, dep: T.Union[str, T.List[str]]) -> None: 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: str, elems: T.Union[str, T.List[str, CompilerArgs]]) -> None: # Always convert from GCC-style argument naming to the naming used by the # current compiler. Also filter system include paths, deduplicate, etc. if isinstance(elems, CompilerArgs): elems = elems.to_native() if isinstance(elems, str): elems = [elems] self.elems.append((name, elems)) if name == 'DEPFILE': self.elems.append((name + '_UNQUOTED', elems)) def _should_use_rspfile(self): # 'phony' is a rule built-in to ninja if self.rulename == 'phony': return False if not self.rule.rspable: return False infilenames = ' '.join([ninja_quote(i, True) for i in self.infilenames]) outfilenames = ' '.join([ninja_quote(i, True) for i in self.outfilenames]) return self.rule.length_estimate(infilenames, outfilenames, self.elems) >= rsp_threshold def count_rule_references(self): if self.rulename != 'phony': if self._should_use_rspfile(): self.rule.rsprefcount += 1 else: self.rule.refcount += 1 def write(self, outfile): if self.output_errors: raise MesonException(self.output_errors) ins = ' '.join([ninja_quote(i, True) for i in self.infilenames]) outs = ' '.join([ninja_quote(i, True) for i in self.outfilenames]) implicit_outs = ' '.join([ninja_quote(i, True) for i in self.implicit_outfilenames]) if implicit_outs: implicit_outs = ' | ' + implicit_outs use_rspfile = self._should_use_rspfile() if use_rspfile: rulename = self.rulename + '_RSP' mlog.debug(f'Command line for building {self.outfilenames} is long, using a response file') else: rulename = self.rulename line = f'build {outs}{implicit_outs}: {rulename} {ins}' if len(self.deps) > 0: line += ' | ' + ' '.join([ninja_quote(x, True) for x in sorted(self.deps)]) if len(self.orderdeps) > 0: orderdeps = [str(x) for x in self.orderdeps] line += ' || ' + ' '.join([ninja_quote(x, True) for x in sorted(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('\\', '/') if mesonlib.is_windows(): # Support network paths as backslash, otherwise they are interpreted as # arguments for compile/link commands when using MSVC line = ' '.join( (l.replace('//', '\\\\', 1) if l.startswith('//') else l) for l in line.split(' ') ) outfile.write(line) if use_rspfile: if self.rule.rspfile_quote_style is RSPFileSyntax.MSVC: qf = cmd_quote else: qf = gcc_rsp_quote else: qf = quote_func for e in self.elems: (name, elems) = e should_quote = name not in raw_names line = f' {name} = ' newelems = [] for i in elems: if not should_quote or i == '&&': # Hackety hack hack newelems.append(ninja_quote(i)) else: newelems.append(ninja_quote(qf(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: self.output_errors = f'Multiple producers for Ninja target "{n}". Please rename your targets.' self.all_outputs.add(n) @dataclass class RustDep: name: str # equal to the order value of the `RustCrate` crate: int def to_json(self) -> T.Dict[str, object]: return { "crate": self.crate, "name": self.name, } @dataclass class RustCrate: # When the json file is written, the list of Crates will be sorted by this # value order: int display_name: str root_module: str edition: RUST_EDITIONS deps: T.List[RustDep] cfg: T.List[str] is_proc_macro: bool # This is set to True for members of this project, and False for all # subprojects is_workspace_member: bool proc_macro_dylib_path: T.Optional[str] = None def to_json(self) -> T.Dict[str, object]: ret: T.Dict[str, object] = { "display_name": self.display_name, "root_module": self.root_module, "edition": self.edition, "cfg": self.cfg, "is_proc_macro": self.is_proc_macro, "deps": [d.to_json() for d in self.deps], } if self.is_proc_macro: assert self.proc_macro_dylib_path is not None, "This shouldn't happen" ret["proc_macro_dylib_path"] = self.proc_macro_dylib_path return ret class NinjaBackend(backends.Backend): def __init__(self, build: T.Optional[build.Build], interpreter: T.Optional[Interpreter]): super().__init__(build, interpreter) self.name = 'ninja' self.ninja_filename = 'build.ninja' self.fortran_deps = {} self.all_outputs: T.Set[str] = set() self.introspection_data = {} self.created_llvm_ir_rule = PerMachine(False, False) self.rust_crates: T.Dict[str, RustCrate] = {} self.implicit_meson_outs = [] def create_phony_target(self, dummy_outfile: str, rulename: str, phony_infilename: str) -> NinjaBuildElement: ''' 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 dummy_outfile.startswith('meson-internal__'): raise AssertionError(f'Invalid usage of create_phony_target with {dummy_outfile!r}') to_name = f'meson-internal__{dummy_outfile}' elem = NinjaBuildElement(self.all_outputs, dummy_outfile, 'phony', to_name) self.add_build(elem) return NinjaBuildElement(self.all_outputs, to_name, rulename, phony_infilename) 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 / masm on windows is MSVC like, but doesn't have /showincludes if compiler.language in {'fortran', 'masm'}: continue if compiler.id == 'pgi' 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 compiler.get_argument_syntax() == 'msvc': break else: # None of our compilers are MSVC, we're done. return open(tempfilename, 'a', encoding='utf-8') filebase = 'incdetect.' + compilers.lang_suffixes[compiler.language][0] filename = os.path.join(self.environment.get_scratch_dir(), filebase) with open(filename, 'w', encoding='utf-8') as f: f.write(dedent('''\ #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', filebase], 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 drive name 'd:\'. # When used in cross compilation, the path separator is a # forward slash rather than a backslash so handle both; i.e. # the path is /MyDir/include/stdio.h. # With certain cross compilation wrappings of MSVC, the paths # use backslashes, but without the leading drive name, so # allow the path to start with any path separator, i.e. # \MyDir\include\stdio.h. 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(f'Could not determine vs dep dependency prefix string. output: {stderr} {stdout}') def generate(self, capture: bool = False, vslite_ctx: dict = None) -> T.Optional[dict]: if vslite_ctx: # We don't yet have a use case where we'd expect to make use of this, # so no harm in catching and reporting something unexpected. raise MesonBugException('We do not expect the ninja backend to be given a valid \'vslite_ctx\'') ninja = environment.detect_ninja_command_and_version(log=True) if self.environment.coredata.get_option(OptionKey('vsenv')): builddir = Path(self.environment.get_build_dir()) try: # For prettier printing, reduce to a relative path. If # impossible (e.g., because builddir and cwd are on # different Windows drives), skip and use the full path. builddir = builddir.relative_to(Path.cwd()) except ValueError: pass meson_command = mesonlib.join_args(mesonlib.get_meson_command()) mlog.log() mlog.log('Visual Studio environment is needed to run Ninja. It is recommended to use Meson wrapper:') mlog.log(f'{meson_command} compile -C {builddir}') if ninja is None: raise MesonException('Could not detect Ninja v1.8.2 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(f'# This is the build file for project "{self.build.get_project()}"\n') 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.8.2\n\n') num_pools = self.environment.coredata.options[OptionKey('backend_max_links')].value if num_pools > 0: outfile.write(f'''pool link_pool depth = {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')) # Optionally capture compile args per target, for later use (i.e. VisStudio project's NMake intellisense include dirs, defines, and compile options). if capture: captured_compile_args_per_target = {} for target in self.build.get_targets().values(): if isinstance(target, build.BuildTarget): captured_compile_args_per_target[target.get_id()] = self.generate_common_compile_args_per_src_type(target) for t in ProgressBar(self.build.get_targets().values(), desc='Generating targets'): self.generate_target(t) mlog.log_timestamp("Targets generated") self.add_build_comment(NinjaComment('Test rules')) self.generate_tests() mlog.log_timestamp("Tests generated") self.add_build_comment(NinjaComment('Install rules')) self.generate_install() mlog.log_timestamp("Install generated") self.generate_dist() mlog.log_timestamp("Dist generated") key = OptionKey('b_coverage') if (key in self.environment.coredata.options and self.environment.coredata.options[key].value): gcovr_exe, gcovr_version, lcov_exe, lcov_version, genhtml_exe, _ = environment.find_coverage_tools() if gcovr_exe or (lcov_exe and genhtml_exe): self.add_build_comment(NinjaComment('Coverage rules')) self.generate_coverage_rules(gcovr_exe, gcovr_version) mlog.log_timestamp("Coverage rules generated") else: # FIXME: since we explicitly opted in, should this be an error? # The docs just say these targets will be created "if possible". mlog.warning('Need gcovr or lcov/genhtml to generate any coverage reports') self.add_build_comment(NinjaComment('Suffix')) self.generate_utils() mlog.log_timestamp("Utils generated") 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 # Refresh Ninja's caches. https://github.com/ninja-build/ninja/pull/1685 if mesonlib.version_compare(self.ninja_version, '>=1.10.0') and os.path.exists(os.path.join(self.environment.build_dir, '.ninja_log')): subprocess.call(self.ninja_command + ['-t', 'restat'], cwd=self.environment.build_dir) subprocess.call(self.ninja_command + ['-t', 'cleandead'], cwd=self.environment.build_dir) self.generate_compdb() self.generate_rust_project_json() if capture: return captured_compile_args_per_target def generate_rust_project_json(self) -> None: """Generate a rust-analyzer compatible rust-project.json file.""" if not self.rust_crates: return with open(os.path.join(self.environment.get_build_dir(), 'rust-project.json'), 'w', encoding='utf-8') as f: json.dump( { "sysroot_src": os.path.join(self.environment.coredata.compilers.host['rust'].get_sysroot(), 'lib/rustlib/src/rust/library/'), "crates": [c.to_json() for c in self.rust_crates.values()], }, f, indent=4) # http://clang.llvm.org/docs/JSONCompilationDatabase.html def generate_compdb(self): rules = [] # TODO: Rather than an explicit list here, rules could be marked in the # rule store as being wanted in compdb for for_machine in MachineChoice: for compiler in self.environment.coredata.compilers[for_machine].values(): rules += [f"{rule}{ext}" for rule in [self.compiler_to_rule_name(compiler)] for ext in ['', '_RSP']] rules += [f"{rule}{ext}" for rule in [self.compiler_to_pch_rule_name(compiler)] for ext in ['', '_RSP']] 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.', fatal=False) # 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: build.BuildTarget) -> T.MutableMapping[str, File]: """ Returns a dictionary with the keys being the path to the file (relative to the build directory) and the value being the File object representing the same path. """ srcs: T.MutableMapping[str, File] = OrderedDict() for gensrc in target.get_generated_sources(): for s in gensrc.get_outputs(): rel_src = self.get_target_generated_dir(target, gensrc, s) srcs[rel_src] = File.from_built_relative(rel_src) return srcs def get_target_sources(self, target: build.BuildTarget) -> T.MutableMapping[str, File]: srcs: T.MutableMapping[str, File] = 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(f'All sources in target {s!r} must be of type mesonlib.File') f = s.rel_to_builddir(self.build_to_src) srcs[f] = s return srcs 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:].lower() for lang in backends.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, unity_sources: T.Optional[T.List[mesonlib.FileOrString]] = None): ''' Adds the source file introspection information for a language of a target Internal introspection storage format: 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': [], 'unity_sources': [], } tgt[id_hash] = src_block def compute_path(file: mesonlib.FileOrString) -> str: """ Make source files absolute """ if isinstance(file, File): return file.absolute_path(self.source_dir, self.build_dir) return os.path.normpath(os.path.join(self.build_dir, file)) src_block['sources'].extend(compute_path(x) for x in sources) src_block['generated_sources'].extend(compute_path(x) for x in generated_sources) if unity_sources: src_block['unity_sources'].extend(compute_path(x) for x in unity_sources) def create_target_linker_introspection(self, target: build.Target, linker: T.Union[Compiler, StaticLinker], parameters): tid = target.get_id() tgt = self.introspection_data[tid] lnk_hash = tuple(parameters) lnk_block = tgt.get(lnk_hash, None) if lnk_block is None: if isinstance(parameters, CompilerArgs): parameters = parameters.to_native(copy=True) if isinstance(linker, Compiler): linkers = linker.get_linker_exelist() else: linkers = linker.get_exelist() lnk_block = { 'linker': linkers, 'parameters': parameters, } tgt[lnk_hash] = lnk_block def generate_target(self, target): try: if isinstance(target, build.BuildTarget): os.makedirs(self.get_target_private_dir_abs(target)) except FileExistsError: pass if isinstance(target, build.CustomTarget): self.generate_custom_target(target) if isinstance(target, build.RunTarget): self.generate_run_target(target) compiled_sources = [] source2object = {} name = target.get_id() if name in self.processed_targets: return self.processed_targets.add(name) # Initialize an empty introspection source list self.introspection_data[name] = {} # Generate rules for all dependency targets self.process_target_dependencies(target) self.generate_shlib_aliases(target, self.get_target_dir(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 target.uses_rust(): 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 # CompileTarget compiles all its sources and does not do a final link. # This is, for example, a preprocessor. is_compile_target = isinstance(target, build.CompileTarget) # Preexisting target C/C++ sources to be built; dict of full path to # source relative to build root and the original File object. target_sources: T.MutableMapping[str, File] # GeneratedList and CustomTarget sources to be built; dict of the full # path to source relative to build root and the generating target/list generated_sources: T.MutableMapping[str, File] # List of sources that have been transpiled from a DSL (like Vala) into # a language that is handled below, such as C or C++ transpiled_sources: T.List[str] 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, \ transpiled_sources = self.generate_vala_compile(target) elif 'cython' in target.compilers: target_sources, generated_sources, \ transpiled_sources = self.generate_cython_transpile(target) else: target_sources = self.get_target_sources(target) generated_sources = self.get_target_generated_sources(target) transpiled_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 = target.is_unity 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(backends.LANGS_CANT_UNITY) if langs_cant: langs_are = langs = ', '.join(langs_cant).upper() langs_are += ' are' if len(langs_cant) > 1 else ' is' msg = f'{langs_are} not supported in Unity builds yet, so {langs} ' \ f'sources in the {target.name!r} target will be compiled normally' 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 preexisting 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(): raw_src = File.from_built_relative(rel_src) if self.environment.is_source(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) or modules.is_module_library(rel_src): pass elif is_compile_target: generated_source_files.append(raw_src) 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) # For D language, the object of generated source files are added # as order only deps because other files may depend on them d_generated_deps = [] # 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, s = self.generate_llvm_ir_compile(target, src) else: o, s = self.generate_single_compile(target, src, True, order_deps=header_deps) compiled_sources.append(s) source2object[s] = o obj_list.append(o) if s.split('.')[-1] in compilers.lang_suffixes['d']: d_generated_deps.append(o) use_pch = self.target_uses_pch(target) if use_pch and target.has_pch(): pch_objects = self.generate_pch(target, header_deps=header_deps) else: pch_objects = [] o, od = self.flatten_object_list(target) obj_targets = [t for t in od if t.uses_fortran()] obj_list.extend(o) fortran_order_deps = [File(True, *os.path.split(self.get_target_filename(t))) for t in obj_targets] fortran_inc_args: T.List[str] = [] if target.uses_fortran(): fortran_inc_args = mesonlib.listify([target.compilers['fortran'].get_include_args( self.get_target_private_dir(t), is_system=False) for t in obj_targets]) # 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 # # Do not try to unity-build the generated c files from vala, as these # often contain duplicate symbols and will fail to compile properly vala_generated_source_files = [] for src in transpiled_sources: raw_src = File.from_built_relative(src) # 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. o, s = self.generate_single_compile(target, src, 'vala', [], header_deps) obj_list.append(o) # Generate compile targets for all the preexisting sources for this target for src in target_sources.values(): if not self.environment.is_header(src) or is_compile_target: if self.environment.is_llvm_ir(src): o, s = self.generate_llvm_ir_compile(target, src) obj_list.append(o) 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: o, s = self.generate_single_compile(target, src, False, [], header_deps + d_generated_deps + fortran_order_deps, fortran_inc_args) obj_list.append(o) compiled_sources.append(s) source2object[s] = o if is_unity: for src in self.generate_unity_files(target, unity_src): o, s = self.generate_single_compile(target, src, True, unity_deps + header_deps + d_generated_deps, fortran_order_deps, fortran_inc_args, unity_src) obj_list.append(o) compiled_sources.append(s) source2object[s] = o if is_compile_target: # Skip the link stage for this special type of target return linker, stdlib_args = self.determine_linker_and_stdlib_args(target) if isinstance(target, build.StaticLibrary) and target.prelink: final_obj_list = self.generate_prelink(target, obj_list) else: final_obj_list = obj_list elem = self.generate_link(target, outname, final_obj_list, linker, pch_objects, stdlib_args=stdlib_args) self.generate_dependency_scan_target(target, compiled_sources, source2object, generated_source_files, fortran_order_deps) self.add_build(elem) #In AIX, we archive shared libraries. If the instance is a shared library, we add a command to archive the shared library #object and create the build element. if isinstance(target, build.SharedLibrary) and self.environment.machines[target.for_machine].is_aix(): if target.aix_so_archive: elem = NinjaBuildElement(self.all_outputs, linker.get_archive_name(outname), 'AIX_LINKER', [outname]) self.add_build(elem) def should_use_dyndeps_for_target(self, target: 'build.BuildTarget') -> bool: if mesonlib.version_compare(self.ninja_version, '<1.10.0'): return False if 'fortran' in target.compilers: return True if 'cpp' not in target.compilers: return False if '-fmodules-ts' in target.extra_args['cpp']: return True # Currently only the preview version of Visual Studio is supported. cpp = target.compilers['cpp'] if cpp.get_id() != 'msvc': return False cppversion = target.get_option(OptionKey('std', machine=target.for_machine, lang='cpp')) if cppversion not in ('latest', 'c++latest', 'vc++latest'): return False if not mesonlib.current_vs_supports_modules(): return False if mesonlib.version_compare(cpp.version, '<19.28.28617'): return False return True def generate_dependency_scan_target(self, target: build.BuildTarget, compiled_sources, source2object, generated_source_files: T.List[mesonlib.File], object_deps: T.List['mesonlib.FileOrString']) -> None: if not self.should_use_dyndeps_for_target(target): return depscan_file = self.get_dep_scan_file_for(target) pickle_base = target.name + '.dat' pickle_file = os.path.join(self.get_target_private_dir(target), pickle_base).replace('\\', '/') pickle_abs = os.path.join(self.get_target_private_dir_abs(target), pickle_base).replace('\\', '/') json_abs = os.path.join(self.get_target_private_dir_abs(target), f'{target.name}-deps.json').replace('\\', '/') rule_name = 'depscan' scan_sources = self.select_sources_to_scan(compiled_sources) # Dump the sources as a json list. This avoids potential problems where # the number of sources passed to depscan exceeds the limit imposed by # the OS. with open(json_abs, 'w', encoding='utf-8') as f: json.dump(scan_sources, f) elem = NinjaBuildElement(self.all_outputs, depscan_file, rule_name, json_abs) elem.add_item('picklefile', pickle_file) # Add any generated outputs to the order deps of the scan target, so # that those sources are present for g in generated_source_files: elem.orderdeps.add(g.relative_name()) elem.orderdeps.update(object_deps) scaninfo = TargetDependencyScannerInfo(self.get_target_private_dir(target), source2object) with open(pickle_abs, 'wb') as p: pickle.dump(scaninfo, p) self.add_build(elem) def select_sources_to_scan(self, compiled_sources): # in practice pick up C++ and Fortran files. If some other language # requires scanning (possibly Java to deal with inner class files) # then add them here. all_suffixes = set(compilers.lang_suffixes['cpp']) | set(compilers.lang_suffixes['fortran']) selected_sources = [] for source in compiled_sources: ext = os.path.splitext(source)[1][1:] if ext != 'C': ext = ext.lower() if ext in all_suffixes: selected_sources.append(source) return selected_sources 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 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: build.CustomTarget): self.custom_target_generator_inputs(target) (srcs, ofilenames, cmd) = self.eval_custom_target_command(target) deps = self.unwrap_dep_list(target) deps += self.get_target_depend_files(target) 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)) cmd, reason = self.as_meson_exe_cmdline(target.command[0], cmd[1:], extra_bdeps=target.get_transitive_build_target_deps(), capture=ofilenames[0] if target.capture else None, feed=srcs[0] if target.feed else None, env=target.env, verbose=target.console) if reason: cmd_type = f' (wrapped by meson {reason})' else: cmd_type = '' 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') full_name = Path(target.subdir, target.name).as_posix() elem.add_item('COMMAND', cmd) elem.add_item('description', target.description.format(full_name) + cmd_type) self.add_build(elem) self.processed_targets.add(target.get_id()) def build_run_target_name(self, target): if target.subproject != '': subproject_prefix = f'{target.subproject}@@' else: subproject_prefix = '' return f'{subproject_prefix}{target.name}' def generate_run_target(self, target: build.RunTarget): target_name = self.build_run_target_name(target) if not target.command: # This is an alias target, it has no command, it just depends on # other targets. elem = NinjaBuildElement(self.all_outputs, target_name, 'phony', []) else: target_env = self.get_run_target_env(target) _, _, cmd = self.eval_custom_target_command(target) meson_exe_cmd, reason = self.as_meson_exe_cmdline(target.command[0], cmd[1:], env=target_env, verbose=True) cmd_type = f' (wrapped by meson {reason})' if reason else '' elem = self.create_phony_target(target_name, 'CUSTOM_COMMAND', []) elem.add_item('COMMAND', meson_exe_cmd) elem.add_item('description', f'Running external command {target.name}{cmd_type}') elem.add_item('pool', 'console') deps = self.unwrap_dep_list(target) deps += self.get_target_depend_files(target) elem.add_dep(deps) self.add_build(elem) self.processed_targets.add(target.get_id()) def generate_coverage_command(self, elem, outputs): targets = self.build.get_targets().values() use_llvm_cov = False for target in targets: if not hasattr(target, 'compilers'): continue for compiler in target.compilers.values(): if compiler.get_id() == 'clang' and not compiler.info.is_darwin(): use_llvm_cov = True break 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()] + (['--use_llvm_cov'] if use_llvm_cov else [])) def generate_coverage_rules(self, gcovr_exe: T.Optional[str], gcovr_version: T.Optional[str]): e = self.create_phony_target('coverage', 'CUSTOM_COMMAND', 'PHONY') self.generate_coverage_command(e, []) e.add_item('description', 'Generates coverage reports') self.add_build(e) self.generate_coverage_legacy_rules(gcovr_exe, gcovr_version) def generate_coverage_legacy_rules(self, gcovr_exe: T.Optional[str], gcovr_version: T.Optional[str]): e = self.create_phony_target('coverage-html', 'CUSTOM_COMMAND', 'PHONY') self.generate_coverage_command(e, ['--html']) e.add_item('description', 'Generates HTML coverage report') self.add_build(e) if gcovr_exe: e = self.create_phony_target('coverage-xml', 'CUSTOM_COMMAND', 'PHONY') self.generate_coverage_command(e, ['--xml']) e.add_item('description', 'Generates XML coverage report') self.add_build(e) e = self.create_phony_target('coverage-text', 'CUSTOM_COMMAND', 'PHONY') self.generate_coverage_command(e, ['--text']) e.add_item('description', 'Generates text coverage report') self.add_build(e) if mesonlib.version_compare(gcovr_version, '>=4.2'): e = self.create_phony_target('coverage-sonarqube', 'CUSTOM_COMMAND', 'PHONY') self.generate_coverage_command(e, ['--sonarqube']) e.add_item('description', 'Generates Sonarqube XML coverage report') self.add_build(e) def generate_install(self): self.create_install_data_files() elem = self.create_phony_target('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) def generate_tests(self): self.serialize_tests() cmd = self.environment.get_build_command(True) + ['test', '--no-rebuild'] if not self.environment.coredata.get_option(OptionKey('stdsplit')): cmd += ['--no-stdsplit'] if self.environment.coredata.get_option(OptionKey('errorlogs')): cmd += ['--print-errorlogs'] elem = self.create_phony_target('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) # And then benchmarks. cmd = self.environment.get_build_command(True) + [ 'test', '--benchmark', '--logbase', 'benchmarklog', '--num-processes=1', '--no-rebuild'] elem = self.create_phony_target('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) def generate_rules(self): self.rules = [] self.ruledict = {} self.add_rule_comment(NinjaComment('Rules for module scanning.')) self.generate_scanner_rules() 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')) self.add_rule(NinjaRule('COPY_FILE', self.environment.get_build_command() + ['--internal', 'copy'], ['$in', '$out'], 'Copying $in to $out')) c = self.environment.get_build_command() + \ ['--internal', 'regenerate', self.environment.get_source_dir(), # Ninja always runs from the build_dir. This includes cases where the user moved the # build directory and invalidated most references. Make sure it still regenerates. '.'] self.add_rule(NinjaRule('REGENERATE_BUILD', c, [], 'Regenerating build files.', extra='generator = 1')) def add_rule_comment(self, comment: NinjaComment) -> None: self.rules.append(comment) def add_build_comment(self, comment: NinjaComment) -> None: self.build_elements.append(comment) def add_rule(self, rule: NinjaRule) -> None: if rule.name in self.ruledict: raise MesonException(f'Tried to add rule {rule.name} twice.') self.rules.append(rule) self.ruledict[rule.name] = rule def add_build(self, build: NinjaBuildElement) -> None: build.check_outputs() self.build_elements.append(build) if build.rulename != 'phony': # reference rule if build.rulename in self.ruledict: build.rule = self.ruledict[build.rulename] else: mlog.warning(f"build statement for {build.outfilenames} references nonexistent rule {build.rulename}") def write_rules(self, outfile: T.TextIO) -> None: for b in self.build_elements: if isinstance(b, NinjaBuildElement): b.count_rule_references() for r in self.rules: r.write(outfile) def write_builds(self, outfile: T.TextIO) -> None: for b in ProgressBar(self.build_elements, desc='Writing build.ninja'): b.write(outfile) mlog.log_timestamp("build.ninja generated") def generate_phony(self) -> None: 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: build.Jar): fname = target.get_filename() outname_rel = os.path.join(self.get_target_dir(target), fname) src_list = target.get_sources() resources = target.get_java_resources() 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(): raw_src = File.from_built_relative(rel_src) 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', encoding='utf-8') 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) if resources: # Copy all resources into the root of the jar. elem.add_orderdep(self.__generate_sources_structure(Path(self.get_target_private_dir(target)), resources)[0]) 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', f'Compiling resource {rel_sourcefile}') self.add_build(elem) deps.append(ofilename) a = '-resource:' + ofilename else: raise InvalidArguments(f'Unknown resource file {r}.') args.append(a) return args, deps def generate_cs_target(self, target: build.BuildTarget): buildtype = target.get_option(OptionKey('buildtype')) 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 = compiler.compiler_args(target.extra_args['cs']) commands += compiler.get_buildtype_args(buildtype) commands += compiler.get_optimization_args(target.get_option(OptionKey('optimization'))) commands += compiler.get_debug_args(target.get_option(OptionKey('debug'))) 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.compiler_to_rule_name(compiler), 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(target.get_option(OptionKey('buildtype'))) 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.split('.')[-1] in compilers.lang_suffixes['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: build.BuildTarget) -> \ T.Tuple[T.MutableMapping[str, File], T.MutableMapping[str, File], T.Tuple[T.MutableMapping[str, File], T.MutableMapping]]: """ Splits the target's sources into .vala, .gs, .vapi, and other sources. Handles both preexisting 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: T.MutableMapping[str, File] = OrderedDict() vapi: T.MutableMapping[str, File] = OrderedDict() others: T.MutableMapping[str, File] = OrderedDict() othersgen: T.MutableMapping[str, File] = OrderedDict() # Split preexisting 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): raise InvalidArguments(f'All sources in target {t!r} must be of type mesonlib.File, not {s!r}') 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: build.BuildTarget) -> \ T.Tuple[T.MutableMapping[str, File], T.MutableMapping[str, File], T.List[str]]: """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: raise InvalidArguments(f'Vala library {target.name!r} has no Vala or Genie source files.') valac = target.compilers['vala'] c_out_dir = self.get_target_private_dir(target) # C files generated by valac vala_c_src: T.List[str] = [] # Files generated by valac valac_outputs: T.List = [] # All sources that are passed to valac on the commandline all_files = list(vapi_src) # 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(target.get_option(OptionKey('b_colorout'))) # 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 target.is_unity: # 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) # 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) # 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] dependency_vapis = self.determine_dep_vapis(target) extra_dep_files += dependency_vapis extra_dep_files.extend(self.get_target_depend_files(target)) args += target.get_extra_args('vala') 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_cython_transpile(self, target: build.BuildTarget) -> \ T.Tuple[T.MutableMapping[str, File], T.MutableMapping[str, File], T.List[str]]: """Generate rules for transpiling Cython files to C or C++ XXX: Currently only C is handled. """ static_sources: T.MutableMapping[str, File] = OrderedDict() generated_sources: T.MutableMapping[str, File] = OrderedDict() cython_sources: T.List[str] = [] cython = target.compilers['cython'] args: T.List[str] = [] args += cython.get_always_args() args += cython.get_buildtype_args(target.get_option(OptionKey('buildtype'))) args += cython.get_debug_args(target.get_option(OptionKey('debug'))) args += cython.get_optimization_args(target.get_option(OptionKey('optimization'))) args += cython.get_option_compile_args(target.get_options()) args += self.build.get_global_args(cython, target.for_machine) args += self.build.get_project_args(cython, target.subproject, target.for_machine) args += target.get_extra_args('cython') ext = target.get_option(OptionKey('language', machine=target.for_machine, lang='cython')) pyx_sources = [] # Keep track of sources we're adding to build for src in target.get_sources(): if src.endswith('.pyx'): output = os.path.join(self.get_target_private_dir(target), f'{src}.{ext}') element = NinjaBuildElement( self.all_outputs, [output], self.compiler_to_rule_name(cython), [src.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir())]) element.add_item('ARGS', args) self.add_build(element) # TODO: introspection? cython_sources.append(output) pyx_sources.append(element) else: static_sources[src.rel_to_builddir(self.build_to_src)] = src header_deps = [] # Keep track of generated headers for those sources for gen in target.get_generated_sources(): for ssrc in gen.get_outputs(): if isinstance(gen, GeneratedList): ssrc = os.path.join(self.get_target_private_dir(target), ssrc) else: ssrc = os.path.join(gen.get_subdir(), ssrc) if ssrc.endswith('.pyx'): output = os.path.join(self.get_target_private_dir(target), f'{ssrc}.{ext}') element = NinjaBuildElement( self.all_outputs, [output], self.compiler_to_rule_name(cython), [ssrc]) element.add_item('ARGS', args) self.add_build(element) pyx_sources.append(element) # TODO: introspection? cython_sources.append(output) else: generated_sources[ssrc] = mesonlib.File.from_built_file(gen.get_subdir(), ssrc) # Following logic in L883-900 where we determine whether to add generated source # as a header(order-only) dep to the .so compilation rule if not self.environment.is_source(ssrc) and \ not self.environment.is_object(ssrc) and \ not self.environment.is_library(ssrc) and \ not modules.is_module_library(ssrc): header_deps.append(ssrc) for source in pyx_sources: source.add_orderdep(header_deps) return static_sources, generated_sources, cython_sources def _generate_copy_target(self, src: 'mesonlib.FileOrString', output: Path) -> None: """Create a target to copy a source file from one location to another.""" if isinstance(src, File): instr = src.absolute_path(self.environment.source_dir, self.environment.build_dir) else: instr = src elem = NinjaBuildElement(self.all_outputs, [str(output)], 'COPY_FILE', [instr]) elem.add_orderdep(instr) self.add_build(elem) def __generate_sources_structure(self, root: Path, structured_sources: build.StructuredSources) -> T.Tuple[T.List[str], T.Optional[str]]: first_file: T.Optional[str] = None orderdeps: T.List[str] = [] for path, files in structured_sources.sources.items(): for file in files: if isinstance(file, File): out = root / path / Path(file.fname).name orderdeps.append(str(out)) self._generate_copy_target(file, out) if first_file is None: first_file = str(out) else: for f in file.get_outputs(): out = root / path / f orderdeps.append(str(out)) self._generate_copy_target(str(Path(file.subdir) / f), out) if first_file is None: first_file = str(out) return orderdeps, first_file def _add_rust_project_entry(self, name: str, main_rust_file: str, args: CompilerArgs, from_subproject: bool, proc_macro_dylib_path: T.Optional[str], deps: T.List[RustDep]) -> None: raw_edition: T.Optional[str] = mesonlib.first(reversed(args), lambda x: x.startswith('--edition')) edition: RUST_EDITIONS = '2015' if not raw_edition else raw_edition.split('=')[-1] cfg: T.List[str] = [] arg_itr: T.Iterator[str] = iter(args) for arg in arg_itr: if arg == '--cfg': cfg.append(next(arg_itr)) elif arg.startswith('--cfg'): cfg.append(arg[len('--cfg'):]) crate = RustCrate( len(self.rust_crates), name, main_rust_file, edition, deps, cfg, is_workspace_member=not from_subproject, is_proc_macro=proc_macro_dylib_path is not None, proc_macro_dylib_path=proc_macro_dylib_path, ) self.rust_crates[name] = crate def _get_rust_dependency_name(self, target: build.BuildTarget, dependency: LibTypes) -> str: # Convert crate names with dashes to underscores by default like # cargo does as dashes can't be used as parts of identifiers # in Rust return target.rust_dependency_map.get(dependency.name, dependency.name).replace('-', '_') def generate_rust_target(self, target: build.BuildTarget) -> None: 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. base_proxy = target.get_options() args = rustc.compiler_args() # Compiler args for compiling this target args += compilers.get_base_compile_args(base_proxy, rustc) self.generate_generator_list_rules(target) # dependencies need to cause a relink, they're not just for ordering deps: T.List[str] = [] # Dependencies for rust-project.json project_deps: T.List[RustDep] = [] orderdeps: T.List[str] = [] main_rust_file = None if target.structured_sources: if target.structured_sources.needs_copy(): _ods, main_rust_file = self.__generate_sources_structure(Path( self.get_target_private_dir(target)) / 'structured', target.structured_sources) orderdeps.extend(_ods) else: # The only way to get here is to have only files in the "root" # positional argument, which are all generated into the same # directory g = target.structured_sources.first_file() if isinstance(g, File): main_rust_file = g.rel_to_builddir(self.build_to_src) elif isinstance(g, GeneratedList): main_rust_file = os.path.join(self.get_target_private_dir(target), g.get_outputs()[0]) else: main_rust_file = os.path.join(g.get_subdir(), g.get_outputs()[0]) for f in target.structured_sources.as_list(): if isinstance(f, File): orderdeps.append(f.rel_to_builddir(self.build_to_src)) else: orderdeps.extend([os.path.join(self.build_to_src, f.subdir, s) for s in f.get_outputs()]) for i in target.get_sources(): if not rustc.can_compile(i): raise InvalidArguments(f'Rust target {target.get_basename()} contains a non-rust source file.') if main_rust_file is None: main_rust_file = i.rel_to_builddir(self.build_to_src) for g in target.get_generated_sources(): for i in g.get_outputs(): if not rustc.can_compile(i): raise InvalidArguments(f'Rust target {target.get_basename()} contains a non-rust source file.') if isinstance(g, GeneratedList): fname = os.path.join(self.get_target_private_dir(target), i) else: fname = os.path.join(g.get_subdir(), i) if main_rust_file is None: main_rust_file = fname orderdeps.append(fname) 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()) cratetype = target.rust_crate_type args.extend(['--crate-type', 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'}: args.extend(rustc.get_linker_always_args()) args += self.generate_basic_compiler_args(target, rustc, False) # Rustc replaces - with _. spaces or dots are not allowed, so we replace them with underscores args += ['--crate-name', target.name.replace('-', '_').replace(' ', '_').replace('.', '_')] depfile = os.path.join(target.subdir, target.name + '.d') args += ['--emit', f'dep-info={depfile}', '--emit', f'link={target_name}'] args += ['--out-dir', self.get_target_private_dir(target)] args += ['-C', 'metadata=' + target.get_id()] args += target.get_extra_args('rust') # Rustc always use non-debug Windows runtime. Inject the one selected # by Meson options instead. # https://github.com/rust-lang/rust/issues/39016 if not isinstance(target, build.StaticLibrary): try: buildtype = target.get_option(OptionKey('buildtype')) crt = target.get_option(OptionKey('b_vscrt')) args += rustc.get_crt_link_args(crt, buildtype) except KeyError: pass if mesonlib.version_compare(rustc.version, '>= 1.67.0'): verbatim = '+verbatim' else: verbatim = '' def _link_library(libname: str, static: bool, bundle: bool = False): type_ = 'static' if static else 'dylib' modifiers = [] if not bundle and static: modifiers.append('-bundle') if verbatim: modifiers.append(verbatim) if modifiers: type_ += ':' + ','.join(modifiers) args.append(f'-l{type_}={libname}') linkdirs = mesonlib.OrderedSet() external_deps = target.external_deps.copy() target_deps = target.get_dependencies() for d in target_deps: linkdirs.add(d.subdir) deps.append(self.get_dependency_filename(d)) if d.uses_rust_abi(): if d not in itertools.chain(target.link_targets, target.link_whole_targets): # Indirect Rust ABI dependency, we only need its path in linkdirs. continue # specify `extern CRATE_NAME=OUTPUT_FILE` for each Rust # dependency, so that collisions with libraries in rustc's # sysroot don't cause ambiguity d_name = self._get_rust_dependency_name(target, d) args += ['--extern', '{}={}'.format(d_name, os.path.join(d.subdir, d.filename))] project_deps.append(RustDep(d_name, self.rust_crates[d.name].order)) continue # Link a C ABI library if isinstance(d, build.StaticLibrary): external_deps.extend(d.external_deps) # Pass native libraries directly to the linker with "-C link-arg" # because rustc's "-l:+verbatim=" is not portable and we cannot rely # on linker to find the right library without using verbatim filename. # For example "-lfoo" won't find "foo.so" in the case name_prefix set # to "", or would always pick the shared library when both "libfoo.so" # and "libfoo.a" are available. # See https://doc.rust-lang.org/rustc/command-line-arguments.html#linking-modifiers-verbatim. # # However, rustc static linker (rlib and staticlib) requires using # "-l" argument and does not rely on platform specific dynamic linker. lib = self.get_target_filename_for_linking(d) link_whole = d in target.link_whole_targets if isinstance(target, build.StaticLibrary) or (isinstance(target, build.Executable) and rustc.get_crt_static()): static = isinstance(d, build.StaticLibrary) libname = os.path.basename(lib) if verbatim else d.name _link_library(libname, static, bundle=link_whole) elif link_whole: link_whole_args = rustc.linker.get_link_whole_for([lib]) args += [f'-Clink-arg={a}' for a in link_whole_args] else: args.append(f'-Clink-arg={lib}') for e in external_deps: for a in e.get_link_args(): if a in rustc.native_static_libs: # Exclude link args that rustc already add by default pass elif a.startswith('-L'): args.append(a) elif a.endswith(('.dll', '.so', '.dylib', '.a', '.lib')) and isinstance(target, build.StaticLibrary): dir_, lib = os.path.split(a) linkdirs.add(dir_) if not verbatim: lib, ext = os.path.splitext(lib) if lib.startswith('lib'): lib = lib[3:] static = a.endswith(('.a', '.lib')) _link_library(lib, static) else: args.append(f'-Clink-arg={a}') for d in linkdirs: d = d or '.' args.append(f'-L{d}') # Because of the way rustc links, this must come after any potential # library need to link with their stdlibs (C++ and Fortran, for example) args.extend(f'-Clink-arg={a}' for a in target.get_used_stdlib_args('rust')) has_shared_deps = any(isinstance(dep, build.SharedLibrary) for dep in target_deps) has_rust_shared_deps = any(dep.uses_rust() and dep.rust_crate_type == 'dylib' for dep in target_deps) if cratetype in {'dylib', 'proc-macro'} or has_rust_shared_deps: # add prefer-dynamic if any of the Rust libraries we link # against are dynamic or this is a dynamic library itself, # otherwise we'll end up with multiple implementations of libstd. args += ['-C', 'prefer-dynamic'] if isinstance(target, build.SharedLibrary) or has_shared_deps: # 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, target.rpath_dirs_to_remove = ( 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')] proc_macro_dylib_path = None if getattr(target, 'rust_crate_type', '') == 'proc-macro': proc_macro_dylib_path = os.path.abspath(os.path.join(target.subdir, target.get_filename())) self._add_rust_project_entry(target.name, os.path.abspath(os.path.join(self.environment.build_dir, main_rust_file)), args, bool(target.subproject), proc_macro_dylib_path, project_deps) compiler_name = self.compiler_to_rule_name(rustc) element = NinjaBuildElement(self.all_outputs, target_name, compiler_name, main_rust_file) if orderdeps: element.add_orderdep(orderdeps) if deps: element.add_dep(deps) 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, mode: str = 'COMPILER') -> str: return f'{lang}_{mode}{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, compiler.mode) @classmethod def compiler_to_pch_rule_name(cls, compiler: Compiler) -> str: return cls.get_compiler_rule_name(compiler.get_language(), compiler.for_machine, 'PCH') 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 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 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(f'Swift target {target.get_basename()} contains a non-swift source file.') 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(target.get_option(OptionKey('optimization'))) compile_args += swiftc.get_debug_args(target.get_option(OptionKey('debug'))) 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, False) 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, False) 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.compiler_to_rule_name(swiftc) # 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, rulename, 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 _rsp_options(self, tool: T.Union['Compiler', 'StaticLinker', 'DynamicLinker']) -> T.Dict[str, T.Union[bool, RSPFileSyntax]]: """Helper method to get rsp options. rsp_file_syntax() is only guaranteed to be implemented if can_linker_accept_rsp() returns True. """ options = {'rspable': tool.can_linker_accept_rsp()} if options['rspable']: options['rspfile_quote_style'] = tool.rsp_file_syntax() return options def generate_static_link_rules(self): num_pools = self.environment.coredata.options[OptionKey('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: continue rule = 'STATIC_LINKER{}'.format(self.get_rule_suffix(for_machine)) cmdlist: T.List[T.Union[str, NinjaCommandArg]] = [] 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, ArLikeLinker) 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 += NinjaCommandArg.list(static_linker.get_output_args('$out'), Quoting.none) # The default ar on MacOS (at least through version 12), does not # add extern'd variables to the symbol table by default, and # requires that apple's ranlib be called with a special flag # instead after linking if static_linker.id == 'applear': # This is a bit of a hack, but we assume that that we won't need # an rspfile on MacOS, otherwise the arguments are passed to # ranlib, not to ar cmdlist.extend(args) args = [] # Ensure that we use the user-specified ranlib if any, and # fallback to just picking up some ranlib otherwise ranlib = self.environment.lookup_binary_entry(for_machine, 'ranlib') if ranlib is None: ranlib = ['ranlib'] cmdlist.extend(['&&'] + ranlib + ['-c', '$out']) description = 'Linking static target $out' if num_pools > 0: pool = 'pool = link_pool' else: pool = None options = self._rsp_options(static_linker) self.add_rule(NinjaRule(rule, cmdlist, args, description, **options, extra=pool)) def generate_dynamic_link_rules(self): num_pools = self.environment.coredata.options[OptionKey('backend_max_links')].value for for_machine in MachineChoice: complist = self.environment.coredata.compilers[for_machine] for langname, compiler in complist.items(): if langname in {'java', 'vala', 'rust', 'cs', 'cython'}: continue rule = '{}_LINKER{}'.format(langname, self.get_rule_suffix(for_machine)) command = compiler.get_linker_exelist() args = ['$ARGS'] + NinjaCommandArg.list(compiler.get_linker_output_args('$out'), Quoting.none) + ['$in', '$LINK_ARGS'] description = 'Linking target $out' if num_pools > 0: pool = 'pool = link_pool' else: pool = None options = self._rsp_options(compiler) self.add_rule(NinjaRule(rule, command, args, description, **options, extra=pool)) if self.environment.machines[for_machine].is_aix(): rule = 'AIX_LINKER{}'.format(self.get_rule_suffix(for_machine)) description = 'Archiving AIX shared library' cmdlist = compiler.get_command_to_archive_shlib() args = [] options = {} self.add_rule(NinjaRule(rule, cmdlist, args, description, **options, extra=None)) args = self.environment.get_build_command() + \ ['--internal', 'symbolextractor', self.environment.get_build_dir(), '$in', '$IMPLIB', '$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) command = compiler.get_exelist() + ['$ARGS', '$in'] description = 'Compiling Java object $in' self.add_rule(NinjaRule(rule, command, [], description)) def generate_cs_compile_rule(self, compiler: 'CsCompiler') -> None: rule = self.compiler_to_rule_name(compiler) command = compiler.get_exelist() args = ['$ARGS', '$in'] description = 'Compiling C Sharp target $out' self.add_rule(NinjaRule(rule, command, args, description, rspable=mesonlib.is_windows(), rspfile_quote_style=compiler.rsp_file_syntax())) def generate_vala_compile_rules(self, compiler): rule = self.compiler_to_rule_name(compiler) command = compiler.get_exelist() + ['$ARGS', '$in'] description = 'Compiling Vala source $in' self.add_rule(NinjaRule(rule, command, [], description, extra='restat = 1')) def generate_cython_compile_rules(self, compiler: 'Compiler') -> None: rule = self.compiler_to_rule_name(compiler) description = 'Compiling Cython source $in' command = compiler.get_exelist() depargs = compiler.get_dependency_gen_args('$out', '$DEPFILE') depfile = '$out.dep' if depargs else None args = depargs + ['$ARGS', '$in'] args += NinjaCommandArg.list(compiler.get_output_args('$out'), Quoting.none) self.add_rule(NinjaRule(rule, command + args, [], description, depfile=depfile, extra='restat = 1')) def generate_rust_compile_rules(self, compiler): rule = self.compiler_to_rule_name(compiler) command = compiler.get_exelist() + ['$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 = self.environment.get_build_command() + [ '--internal', 'dirchanger', '$RUNDIR', ] invoc = full_exe + compiler.get_exelist() command = invoc + ['$ARGS', '$in'] description = 'Compiling Swift source $in' self.add_rule(NinjaRule(rule, command, [], description)) def use_dyndeps_for_fortran(self) -> bool: '''Use the new Ninja feature for scanning dependencies during build, rather than up front. Remove this and all old scanning code once Ninja minimum version is bumped to 1.10.''' return mesonlib.version_compare(self.ninja_version, '>=1.10.0') def generate_fortran_dep_hack(self, crstr: str) -> None: if self.use_dyndeps_for_fortran(): return rule = f'FORTRAN_DEP_HACK{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 = compiler.get_exelist() args = ['$ARGS'] + NinjaCommandArg.list(compiler.get_output_args('$out'), Quoting.none) + compiler.get_compile_only_args() + ['$in'] description = 'Compiling LLVM IR object $in' options = self._rsp_options(compiler) self.add_rule(NinjaRule(rule, command, args, description, **options)) self.created_llvm_ir_rule[compiler.for_machine] = True def generate_compile_rule_for(self, langname, compiler): if langname == 'java': 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 if langname == 'cython': self.generate_cython_compile_rules(compiler) return crstr = self.get_rule_suffix(compiler.for_machine) options = self._rsp_options(compiler) if langname == 'fortran': self.generate_fortran_dep_hack(crstr) # gfortran does not update the modification time of *.mod files, therefore restat is needed. # See also: https://github.com/ninja-build/ninja/pull/2275 options['extra'] = 'restat = 1' rule = self.compiler_to_rule_name(compiler) depargs = NinjaCommandArg.list(compiler.get_dependency_gen_args('$out', '$DEPFILE'), Quoting.none) command = compiler.get_exelist() args = ['$ARGS'] + depargs + NinjaCommandArg.list(compiler.get_output_args('$out'), Quoting.none) + compiler.get_compile_only_args() + ['$in'] description = f'Compiling {compiler.get_display_language()} object $out' if compiler.get_argument_syntax() == 'msvc': deps = 'msvc' depfile = None else: deps = 'gcc' depfile = '$DEPFILE' self.add_rule(NinjaRule(rule, command, args, description, **options, deps=deps, depfile=depfile)) def generate_pch_rule_for(self, langname, compiler): if langname not in {'c', 'cpp'}: return rule = self.compiler_to_pch_rule_name(compiler) depargs = compiler.get_dependency_gen_args('$out', '$DEPFILE') if compiler.get_argument_syntax() == 'msvc': output = [] else: output = NinjaCommandArg.list(compiler.get_output_args('$out'), Quoting.none) if 'mwcc' in compiler.id: output[0].s = '-precompile' command = compiler.get_exelist() + ['$ARGS'] + depargs + output + ['$in'] # '-c' must be removed else: command = compiler.get_exelist() + ['$ARGS'] + depargs + output + compiler.get_compile_only_args() + ['$in'] description = 'Precompiling header $in' if compiler.get_argument_syntax() == 'msvc': deps = 'msvc' depfile = None else: deps = 'gcc' depfile = '$DEPFILE' self.add_rule(NinjaRule(rule, command, [], description, deps=deps, depfile=depfile)) def generate_scanner_rules(self): rulename = 'depscan' if rulename in self.ruledict: # Scanning command is the same for native and cross compilation. return command = self.environment.get_build_command() + \ ['--internal', 'depscan'] args = ['$picklefile', '$out', '$in'] description = 'Module scanner.' rule = NinjaRule(rulename, command, args, description) self.add_rule(rule) 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) for mode in compiler.get_modes(): self.generate_compile_rule_for(langname, mode) 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: build.GeneratedList, target: build.BuildTarget) -> None: for x in genlist.depends: if isinstance(x, build.GeneratedList): self.generate_genlist_for_target(x, target) generator = genlist.get_generator() subdir = genlist.subdir exe = generator.get_exe() infilelist = genlist.get_inputs() outfilelist = genlist.get_outputs() extra_dependencies = self.get_target_depend_files(genlist) for i, curfile in enumerate(infilelist): if len(generator.outputs) == 1: sole_output = os.path.join(self.get_target_private_dir(target), outfilelist[i]) else: sole_output = f'{curfile}' infilename = curfile.rel_to_builddir(self.build_to_src, self.get_target_private_dir(target)) 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, reason = self.as_meson_exe_cmdline(exe, self.replace_extra_args(args, genlist), capture=outfiles[0] if generator.capture else None, env=genlist.env) 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: what = f'{sole_output!r}' else: # since there are multiple outputs, we log the source that caused the rebuild what = f'from {sole_output!r}' if reason: reason = f' (wrapped by meson {reason})' elem.add_item('DESC', f'Generating {what}{reason}') 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. """ if self.use_dyndeps_for_fortran(): return 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( f'Namespace collision: module {modname} defined in ' f'two files {module_files[modname]} and {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( f'Namespace collision: submodule {submodname} defined in ' f'two files {submodule_files[submodname]} and {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 """ if self.use_dyndeps_for_fortran(): return [] 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_no_stdlib_link_args(self, target, linker): if hasattr(linker, 'language') and linker.language in self.build.stdlibs[target.for_machine]: return linker.get_no_stdlib_link_args() return [] 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 cannot 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 avoid 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_debug_filename_abs(target) if not tfilename: 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_name(self, linker, target) -> T.Optional[str]: return linker.get_link_debugfile_name(self.get_target_debug_filename(target)) def get_link_debugfile_args(self, linker, target): return linker.get_link_debugfile_args(self.get_target_debug_filename(target)) def generate_llvm_ir_compile(self, target, src): base_proxy = target.get_options() compiler = get_compiler_for_source(target.compilers.values(), src) commands = compiler.compiler_args() # Compiler args for compiling this target commands += compilers.get_base_compile_args(base_proxy, 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 = self.canonicalize_filename(src_filename) 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(f'Invalid source type: {src!r}') # 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) element.add_item('ARGS', commands) self.add_build(element) return (rel_obj, rel_src) @lru_cache(maxsize=None) def generate_inc_dir(self, compiler: 'Compiler', d: str, basedir: str, is_system: bool) -> \ T.Tuple['ImmutableListProtocol[str]', 'ImmutableListProtocol[str]']: # Avoid superfluous '/.' at the end of paths when d is '.' if d not in ('', '.'): expdir = os.path.normpath(os.path.join(basedir, d)) else: expdir = basedir srctreedir = os.path.normpath(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) def _generate_single_compile(self, target: build.BuildTarget, compiler: 'Compiler', is_generated: bool = False) -> 'CompilerArgs': commands = self._generate_single_compile_base_args(target, compiler) commands += self._generate_single_compile_target_args(target, compiler, is_generated) return commands def _generate_single_compile_base_args(self, target: build.BuildTarget, compiler: 'Compiler') -> 'CompilerArgs': base_proxy = target.get_options() # Create an empty commands list, and start adding arguments from # various sources in the order in which they must override each other commands = compiler.compiler_args() # 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) return commands @lru_cache(maxsize=None) def _generate_single_compile_target_args(self, target: build.BuildTarget, compiler: 'Compiler', is_generated: bool = False) -> 'ImmutableListProtocol[str]': # 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. if target.implicit_include_directories: 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(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 # Returns a dictionary, mapping from each compiler src type (e.g. 'c', 'cpp', etc.) to a list of compiler arg strings # used for that respective src type. # Currently used for the purpose of populating VisualStudio intellisense fields but possibly useful in other scenarios. def generate_common_compile_args_per_src_type(self, target: build.BuildTarget) -> dict[str, list[str]]: src_type_to_args = {} use_pch = self.target_uses_pch(target) for src_type_str in target.compilers.keys(): compiler = target.compilers[src_type_str] commands = self._generate_single_compile_base_args(target, compiler) # Include PCH header as first thing as it must be the first one or it will be # ignored by gcc https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100462 if use_pch and 'mw' not in compiler.id: commands += self.get_pch_include_args(compiler, target) commands += self._generate_single_compile_target_args(target, compiler, is_generated=False) # Metrowerks compilers require PCH include args to come after intraprocedural analysis args if use_pch and 'mw' in compiler.id: commands += self.get_pch_include_args(compiler, target) commands = commands.compiler.compiler_args(commands) src_type_to_args[src_type_str] = commands.to_native() return src_type_to_args def generate_single_compile(self, target: build.BuildTarget, src, is_generated=False, header_deps=None, order_deps: T.Optional[T.List['mesonlib.FileOrString']] = None, extra_args: T.Optional[T.List[str]] = None, unity_sources: T.Optional[T.List[mesonlib.FileOrString]] = None) -> 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(f'BUG: sources should not contain headers {src!r}') compiler = get_compiler_for_source(target.compilers.values(), src) commands = self._generate_single_compile_base_args(target, compiler) # Include PCH header as first thing as it must be the first one or it will be # ignored by gcc https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100462 use_pch = self.target_uses_pch(target) and is_generated != 'pch' if use_pch and 'mw' not in compiler.id: commands += self.get_pch_include_args(compiler, target) commands += self._generate_single_compile_target_args(target, compiler, is_generated) # Metrowerks compilers require PCH include args to come after intraprocedural analysis args if use_pch and 'mw' in compiler.id: commands += self.get_pch_include_args(compiler, target) commands = commands.compiler.compiler_args(commands) # Create introspection information if is_generated is False: self.create_target_source_introspection(target, compiler, commands, [src], [], unity_sources) else: self.create_target_source_introspection(target, compiler, commands, [], [src], unity_sources) 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(f'BUG: broken generated source file handling for {src!r}') else: raise InvalidArguments(f'Invalid source type: {src!r}') 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.target_uses_pch(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) if not self.use_dyndeps_for_fortran(): # 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)) if extra_args is not None: commands.extend(extra_args) 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) for i in self.get_fortran_orderdeps(target, compiler): element.add_orderdep(i) if dep_file: element.add_item('DEPFILE', dep_file) element.add_item('ARGS', commands) self.add_dependency_scanner_entries_to_element(target, compiler, element, src) self.add_build(element) assert isinstance(rel_obj, str) assert isinstance(rel_src, str) return (rel_obj, rel_src.replace('\\', '/')) def add_dependency_scanner_entries_to_element(self, target: build.BuildTarget, compiler, element, src): if not self.should_use_dyndeps_for_target(target): return if isinstance(target, build.CompileTarget): return extension = os.path.splitext(src.fname)[1][1:] if extension != 'C': extension = extension.lower() if not (extension in compilers.lang_suffixes['fortran'] or extension in compilers.lang_suffixes['cpp']): return dep_scan_file = self.get_dep_scan_file_for(target) element.add_item('dyndep', dep_scan_file) element.add_orderdep(dep_scan_file) def get_dep_scan_file_for(self, target: build.BuildTarget) -> str: return os.path.join(self.get_target_private_dir(target), 'depscan.dd') 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: mesonlib.FileOrString) -> bool: # 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 itertools.chain(target.link_targets, target.link_whole_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_mwcc_pch_command(self, target, compiler, pch): commands = self._generate_single_compile(target, compiler) dst = os.path.join(self.get_target_private_dir(target), os.path.basename(pch) + '.' + compiler.get_pch_suffix()) dep = os.path.splitext(dst)[0] + '.' + compiler.get_depfile_suffix() return commands, dep, dst, [] # mwcc compilers do 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 = f'Precompiled header of {target.get_basename()!r} must not be in the same ' \ 'directory as source, please put it in a subdirectory.' raise InvalidArguments(msg) compiler: Compiler = target.compilers[lang] if compiler.get_argument_syntax() == 'msvc': (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 elif 'mwcc' in compiler.id: src = os.path.join(self.build_to_src, target.get_source_subdir(), pch[0]) (commands, dep, dst, objs) = self.generate_mwcc_pch_command(target, compiler, pch[0]) extradep = None 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, objs + [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 get_target_shsym_filename(self, target): # Always name the .symbols file after the primary build output because it always exists targetdir = self.get_target_private_dir(target) return os.path.join(targetdir, target.get_filename() + '.symbols') def generate_shsym(self, target): target_file = self.get_target_filename(target) symname = self.get_target_shsym_filename(target) elem = NinjaBuildElement(self.all_outputs, symname, 'SHSYM', target_file) # The library we will actually link to, which is an import library on Windows (not the DLL) elem.add_item('IMPLIB', self.get_target_filename_for_linking(target)) 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_import_filename(self, target): return os.path.join(self.get_target_dir(target), target.import_filename) 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(self.get_import_filename(target)) if target.pie: commands += linker.get_pie_link_args() 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)) elif isinstance(target, build.SharedLibrary): if isinstance(target, build.SharedModule): commands += linker.get_std_shared_module_link_args(target.get_options()) else: commands += linker.get_std_shared_lib_link_args() # All shared libraries are PIC commands += linker.get_pic_args() if not isinstance(target, build.SharedModule) or target.force_soname: # 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) # 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(self.get_import_filename(target)) elif isinstance(target, build.StaticLibrary): commands += linker.get_std_link_args(self.environment, not target.should_install()) 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 win_subsystem 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. m = self.environment.machines[target.for_machine] if m.is_windows() or m.is_cygwin(): commands += linker.get_win_subsystem_args(target.win_subsystem) return commands def get_link_whole_args(self, linker, target): use_custom = False if linker.id == 'msvc': # Expand our object lists manually if we are on pre-Visual Studio 2015 Update 2 # (incidentally, the "linker" here actually refers to cl.exe) if mesonlib.version_compare(linker.version, '<19.00.23918'): use_custom = True if use_custom: objects_from_static_libs: T.List[ExtractedObjects] = [] for dep in target.link_whole_targets: l = dep.extract_all_objects(False) objects_from_static_libs += self.determine_ext_objs(l, '') objects_from_static_libs.extend(self.flatten_object_list(dep)[0]) return objects_from_static_libs else: target_args = self.build_target_link_arguments(linker, target.link_whole_targets) return linker.get_link_whole_for(target_args) if target_args else [] @lru_cache(maxsize=None) def guess_library_absolute_path(self, linker, libname, search_dirs, patterns) -> Path: from ..compilers.c import CCompiler 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 cannot 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 try: static_patterns = linker.get_library_naming(self.environment, LibType.STATIC, strict=True) shared_patterns = linker.get_library_naming(self.environment, LibType.SHARED, strict=True) search_dirs = tuple(search_dirs) + tuple(linker.get_library_dirs(self.environment)) 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()) except (mesonlib.MesonException, AttributeError) as e: if 'get_library_naming' not in str(e): raise return guessed_dependencies + absolute_libs def generate_prelink(self, target, obj_list): assert isinstance(target, build.StaticLibrary) prelink_name = os.path.join(self.get_target_private_dir(target), target.name + '-prelink.o') elem = NinjaBuildElement(self.all_outputs, [prelink_name], 'CUSTOM_COMMAND', obj_list) prelinker = target.get_prelinker() cmd = prelinker.exelist[:] cmd += prelinker.get_prelink_args(prelink_name, obj_list) cmd = self.replace_paths(target, cmd) elem.add_item('COMMAND', cmd) elem.add_item('description', f'Prelinking {prelink_name}.') self.add_build(elem) return [prelink_name] def generate_link(self, target: build.BuildTarget, outname, obj_list, linker: T.Union['Compiler', 'StaticLinker'], 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 [] implicit_outs = [] 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 = linker.compiler_args() # 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(target.get_options()) else: commands += compilers.get_base_link_args(target.get_options(), linker, isinstance(target, build.SharedModule), self.environment.get_build_dir()) # Add -nostdlib if needed; can't be overridden commands += self.get_no_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(target.get_option(OptionKey('buildtype'))) # Add /DEBUG and the pdb filename when using MSVC if target.get_option(OptionKey('debug')): commands += self.get_link_debugfile_args(linker, target) debugfile = self.get_link_debugfile_name(linker, target) if debugfile is not None: implicit_outs += [debugfile] # 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 # 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, target.rpath_dirs_to_remove) = ( 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)) commands += rpath_args # 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. if isinstance(linker, Compiler): # The static linker doesn't know what language it is building, so we # don't know what option. Fortunately, it doesn't care to see the # language-specific options either. # # We shouldn't check whether we are making a static library, because # in the LTO case we do use a real compiler here. commands += linker.get_option_link_args(target.get_options()) dep_targets = [] dep_targets.extend(self.guess_external_link_dependencies(linker, target, commands, internal)) # 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. 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, implicit_outs=implicit_outs) elem.add_dep(dep_targets + custom_target_libraries) elem.add_item('LINK_ARGS', commands) self.create_target_linker_introspection(target, linker, commands) return elem def get_dependency_filename(self, t): if isinstance(t, build.SharedLibrary): return self.get_target_shsym_filename(t) 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): for alias, to, tag in target.get_aliases(): aliasfile = os.path.join(outdir, alias) abs_aliasfile = os.path.join(self.environment.get_build_dir(), outdir, alias) try: os.remove(abs_aliasfile) except Exception: pass try: os.symlink(to, abs_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.") else: self.implicit_meson_outs.append(aliasfile) def generate_custom_target_clean(self, trees: T.List[str]) -> str: e = self.create_phony_target('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) # 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) -> None: gcno_elem = self.create_phony_target('clean-gcno', 'CUSTOM_COMMAND', 'PHONY') gcno_elem.add_item('COMMAND', mesonlib.get_meson_command() + ['--internal', 'delwithsuffix', '.', 'gcno']) gcno_elem.add_item('description', 'Deleting gcno files') self.add_build(gcno_elem) gcda_elem = self.create_phony_target('clean-gcda', 'CUSTOM_COMMAND', 'PHONY') gcda_elem.add_item('COMMAND', mesonlib.get_meson_command() + ['--internal', 'delwithsuffix', '.', 'gcda']) gcda_elem.add_item('description', 'Deleting gcda files') self.add_build(gcda_elem) def get_user_option_args(self): cmds = [] for (k, v) in self.environment.coredata.options.items(): if k.is_project(): cmds.append('-D' + str(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) -> None: elem = self.create_phony_target('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) def generate_scanbuild(self) -> None: if not environment.detect_scanbuild(): return if 'scan-build' in self.all_outputs: return cmd = self.environment.get_build_command() + \ ['--internal', 'scanbuild', self.environment.source_dir, self.environment.build_dir, self.build.get_subproject_dir()] + \ self.environment.get_build_command() + self.get_user_option_args() elem = self.create_phony_target('scan-build', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', cmd) elem.add_item('pool', 'console') self.add_build(elem) def generate_clangtool(self, name: str, extra_arg: T.Optional[str] = None) -> None: target_name = 'clang-' + name extra_args = [] if extra_arg: target_name += f'-{extra_arg}' extra_args.append(f'--{extra_arg}') 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 cmd = self.environment.get_build_command() + \ ['--internal', 'clang' + name, self.environment.source_dir, self.environment.build_dir] + \ extra_args elem = self.create_phony_target(target_name, 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', cmd) elem.add_item('pool', 'console') self.add_build(elem) def generate_clangformat(self) -> None: if not environment.detect_clangformat(): return self.generate_clangtool('format') self.generate_clangtool('format', 'check') def generate_clangtidy(self) -> None: import shutil if not shutil.which('clang-tidy'): return self.generate_clangtool('tidy') self.generate_clangtool('tidy', 'fix') def generate_tags(self, tool: str, target_name: str) -> None: import shutil if not shutil.which(tool): return if target_name in self.all_outputs: return cmd = self.environment.get_build_command() + \ ['--internal', 'tags', tool, self.environment.source_dir] elem = self.create_phony_target(target_name, 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', cmd) elem.add_item('pool', 'console') self.add_build(elem) # For things like scan-build and other helper tools we might have. def generate_utils(self) -> None: 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 = self.create_phony_target('uninstall', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', cmd) elem.add_item('pool', 'console') self.add_build(elem) def generate_ending(self) -> None: for targ, deps in [ ('all', self.get_build_by_default_targets()), ('meson-test-prereq', self.get_testlike_targets()), ('meson-benchmark-prereq', self.get_testlike_targets(True))]: targetlist = [] # These must also be built by default. # XXX: Sometime in the future these should be built only before running tests. if targ == 'all': targetlist.extend(['meson-test-prereq', 'meson-benchmark-prereq']) for t in deps.values(): # Add the first output of each target to the 'all' target so that # they are all built #Add archive file if shared library in AIX for build all. if isinstance(t, build.SharedLibrary) and t.aix_so_archive: if self.environment.machines[t.for_machine].is_aix(): linker, stdlib_args = self.determine_linker_and_stdlib_args(t) t.get_outputs()[0] = linker.get_archive_name(t.get_outputs()[0]) targetlist.append(os.path.join(self.get_target_dir(t), t.get_outputs()[0])) elem = NinjaBuildElement(self.all_outputs, targ, 'phony', targetlist) self.add_build(elem) elem = self.create_phony_target('clean', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', self.ninja_command + ['-t', 'clean']) elem.add_item('description', 'Cleaning') # 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 OptionKey('b_coverage') in self.environment.coredata.options and \ self.environment.coredata.options[OptionKey('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) # If these files used to be explicitly created, they need to appear on the build graph somehow, # otherwise cleandead deletes them. See https://github.com/ninja-build/ninja/issues/2299 if self.implicit_meson_outs: elem = NinjaBuildElement(self.all_outputs, 'meson-implicit-outs', 'phony', self.implicit_meson_outs) 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: str, target: build.Target) -> T.List[T.Dict[str, T.Union[bool, str, T.List[T.Union[str, T.Dict[str, T.Union[str, T.List[str], bool]]]]]]]: data = self.introspection_data.get(target_id) if not data: return super().get_introspection_data(target_id, target) return list(data.values()) 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 = src.parent / incmatch.group(1) # NOTE: src.parent is most general, in particular for CMake subproject with Fortran file # having an `include 'foo.f'` statement. 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 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' f' ancestor:parent but Meson found {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('_', maxsplit=1)[0])) submodsrcfile = srcdir / tdeps[ancestor_child].fname 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/backend/nonebackend.py0000644000175000017500000000271714562742363021424 0ustar00jpakkanejpakkane# Copyright 2022 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 __future__ import annotations import typing as T from .backends import Backend from .. import mlog from ..mesonlib import MesonBugException class NoneBackend(Backend): name = 'none' def generate(self, capture: bool = False, vslite_ctx: dict = None) -> T.Optional[dict]: # Check for (currently) unexpected capture arg use cases - if capture: raise MesonBugException('We do not expect the none backend to generate with \'capture = True\'') if vslite_ctx: raise MesonBugException('We do not expect the none backend to be given a valid \'vslite_ctx\'') if self.build.get_targets(): raise MesonBugException('None backend cannot generate target rules, but should have failed earlier.') mlog.log('Generating simple install-only backend') self.serialize_tests() self.create_install_data_files() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0 meson-1.3.2/mesonbuild/backend/vs2010backend.py0000644000175000017500000035631114562742373021423 0ustar00jpakkanejpakkane# 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 __future__ import annotations import copy import itertools import os import xml.dom.minidom import xml.etree.ElementTree as ET import uuid import typing as T from pathlib import Path, PurePath, PureWindowsPath import re from collections import Counter from . import backends from .. import build from .. import mlog from .. import compilers from .. import mesonlib from ..mesonlib import ( File, MesonBugException, MesonException, replace_if_different, OptionKey, version_compare, MachineChoice ) from ..environment import Environment, build_filename from .. import coredata if T.TYPE_CHECKING: from ..arglist import CompilerArgs from ..interpreter import Interpreter Project = T.Tuple[str, Path, str, MachineChoice] def autodetect_vs_version(build: T.Optional[build.Build], interpreter: T.Optional[Interpreter]) -> backends.Backend: 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 11.0, but sometimes # vcvarsall.bat doesn't set it, so also use VSINSTALLDIR if vs_version == '11.0' or 'Visual Studio 11' in vs_install_dir: from mesonbuild.backend.vs2012backend import Vs2012Backend return Vs2012Backend(build, interpreter) if vs_version == '12.0' or 'Visual Studio 12' in vs_install_dir: from mesonbuild.backend.vs2013backend import Vs2013Backend return Vs2013Backend(build, interpreter) if vs_version == '14.0' or 'Visual Studio 14' in vs_install_dir: from mesonbuild.backend.vs2015backend import Vs2015Backend return Vs2015Backend(build, interpreter) 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, interpreter) 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, interpreter) if vs_version == '17.0' or 'Visual Studio 22' in vs_install_dir or \ 'Visual Studio\\2022' in vs_install_dir: from mesonbuild.backend.vs2022backend import Vs2022Backend return Vs2022Backend(build, interpreter) if 'Visual Studio 10.0' in vs_install_dir: return Vs2010Backend(build, interpreter) 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: T.List[str]) -> T.List[str]: """ 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) -> str: return str(uuid.uuid5(uuid.NAMESPACE_URL, 'meson-vs-' + path_type + ':' + str(path))).upper() def detect_microsoft_gdk(platform: str) -> bool: return re.match(r'Gaming\.(Desktop|Xbox.XboxOne|Xbox.Scarlett)\.x64', platform, re.IGNORECASE) def filtered_src_langs_generator(sources: T.List[str]): for src in sources: ext = src.split('.')[-1] if compilers.compilers.is_source_suffix(ext): yield compilers.compilers.SUFFIX_TO_LANG[ext] # Returns the source language (i.e. a key from 'lang_suffixes') of the most frequent source language in the given # list of sources. # We choose the most frequent language as 'primary' because it means the most sources in a target/project can # simply refer to the project's shared intellisense define and include fields, rather than have to fill out their # own duplicate full set of defines/includes/opts intellisense fields. All of which helps keep the vcxproj file # size down. def get_primary_source_lang(target_sources: T.List[File], custom_sources: T.List[str]) -> T.Optional[str]: lang_counts = Counter([compilers.compilers.SUFFIX_TO_LANG[src.suffix] for src in target_sources if compilers.compilers.is_source_suffix(src.suffix)]) lang_counts += Counter(filtered_src_langs_generator(custom_sources)) most_common_lang_list = lang_counts.most_common(1) # It may be possible that we have a target with no actual src files of interest (e.g. a generator target), # leaving us with an empty list, which we should handle - return most_common_lang_list[0][0] if most_common_lang_list else None # Returns a dictionary (by [src type][build type]) that contains a tuple of - # (pre-processor defines, include paths, additional compiler options) # fields to use to fill in the respective intellisense fields of sources that can't simply # reference and re-use the shared 'primary' language intellisense fields of the vcxproj. def get_non_primary_lang_intellisense_fields(vslite_ctx: dict, target_id: str, primary_src_lang: str) -> T.Dict[str, T.Dict[str, T.Tuple[str, str, str]]]: defs_paths_opts_per_lang_and_buildtype = {} for buildtype in coredata.get_genvs_default_buildtype_list(): captured_build_args = vslite_ctx[buildtype][target_id] # Results in a 'Src types to compile args' dict non_primary_build_args_per_src_lang = [(lang, build_args) for lang, build_args in captured_build_args.items() if lang != primary_src_lang] # Only need to individually populate intellisense fields for sources of non-primary types. for src_lang, args_list in non_primary_build_args_per_src_lang: if src_lang not in defs_paths_opts_per_lang_and_buildtype: defs_paths_opts_per_lang_and_buildtype[src_lang] = {} defs_paths_opts_per_lang_and_buildtype[src_lang][buildtype] = Vs2010Backend._extract_nmake_fields(args_list) return defs_paths_opts_per_lang_and_buildtype class Vs2010Backend(backends.Backend): name = 'vs2010' def __init__(self, build: T.Optional[build.Build], interpreter: T.Optional[Interpreter], gen_lite: bool = False): super().__init__(build, interpreter) self.project_file_version = '10.0.30319.1' self.sln_file_version = '11.00' self.sln_version_comment = '2010' self.platform_toolset = None self.vs_version = '2010' self.windows_target_platform_version = None self.subdirs = {} self.handled_target_deps = {} self.gen_lite = gen_lite # Synonymous with generating the simpler makefile-style multi-config projects that invoke 'meson compile' builds, avoiding native MSBuild complications def get_target_private_dir(self, target): return os.path.join(self.get_target_dir(target), target.get_id()) def generate_genlist_for_target(self, genlist: T.Union[build.GeneratedList, build.CustomTarget, build.CustomTargetIndex], target: build.BuildTarget, parent_node: ET.Element, generator_output_files: T.List[str], custom_target_include_dirs: T.List[str], custom_target_output_files: T.List[str]) -> None: if isinstance(genlist, build.GeneratedList): for x in genlist.depends: self.generate_genlist_for_target(x, target, parent_node, [], [], []) target_private_dir = self.relpath(self.get_target_private_dir(target), self.get_target_dir(target)) down = self.target_to_build_root(target) 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) idgroup = ET.SubElement(parent_node, 'ItemGroup') samelen = len(infilelist) == len(outfilelist) for i, curfile in enumerate(infilelist): if samelen: sole_output = os.path.join(target_private_dir, outfilelist[i]) else: sole_output = '' infilename = os.path.join(down, curfile.rel_to_builddir(self.build_to_src, target_private_dir)) deps = self.get_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] # 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( exe, self.replace_extra_args(args, genlist), workdir=tdir_abs, capture=outfiles[0] if generator.capture else None, force_serialize=True, env=genlist.env ) 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) def generate_custom_generator_commands(self, target, parent_node): generator_output_files = [] custom_target_include_dirs = [] custom_target_output_files = [] for genlist in target.get_generated_sources(): self.generate_genlist_for_target(genlist, target, parent_node, generator_output_files, custom_target_include_dirs, custom_target_output_files) return generator_output_files, custom_target_output_files, custom_target_include_dirs def generate(self, capture: bool = False, vslite_ctx: dict = None) -> T.Optional[dict]: # Check for (currently) unexpected capture arg use cases - if capture: raise MesonBugException('We do not expect any vs backend to generate with \'capture = True\'') target_machine = self.interpreter.builtin['target_machine'].cpu_family_method(None, None) if target_machine in {'64', 'x86_64'}: # amd64 or x86_64 target_system = self.interpreter.builtin['target_machine'].system_method(None, None) if detect_microsoft_gdk(target_system): self.platform = target_system else: self.platform = 'x64' elif target_machine == 'x86': # x86 self.platform = 'Win32' elif target_machine in {'aarch64', 'arm64'}: target_cpu = self.interpreter.builtin['target_machine'].cpu_method(None, None) if target_cpu == 'arm64ec': self.platform = 'arm64ec' else: self.platform = 'arm64' elif 'arm' in target_machine.lower(): self.platform = 'ARM' else: raise MesonException('Unsupported Visual Studio platform: ' + target_machine) build_machine = self.interpreter.builtin['build_machine'].cpu_family_method(None, None) if build_machine in {'64', 'x86_64'}: # amd64 or x86_64 self.build_platform = 'x64' elif build_machine == 'x86': # x86 self.build_platform = 'Win32' elif build_machine in {'aarch64', 'arm64'}: target_cpu = self.interpreter.builtin['build_machine'].cpu_method(None, None) if target_cpu == 'arm64ec': self.build_platform = 'arm64ec' else: self.build_platform = 'arm64' elif 'arm' in build_machine.lower(): self.build_platform = 'ARM' else: raise MesonException('Unsupported Visual Studio platform: ' + build_machine) self.buildtype = self.environment.coredata.get_option(OptionKey('buildtype')) self.optimization = self.environment.coredata.get_option(OptionKey('optimization')) self.debug = self.environment.coredata.get_option(OptionKey('debug')) try: self.sanitize = self.environment.coredata.get_option(OptionKey('b_sanitize')) except MesonException: self.sanitize = 'none' sln_filename = os.path.join(self.environment.get_build_dir(), self.build.project_name + '.sln') projlist = self.generate_projects(vslite_ctx) self.gen_testproj() self.gen_installproj() self.gen_regenproj() 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: str) -> None: return os.path.join(os.path.join(build_dir, Environment.private_dir), 'regen.stamp') @staticmethod def touch_regen_timestamp(build_dir: str) -> None: with open(Vs2010Backend.get_regen_stampfile(build_dir), 'w', encoding='utf-8'): pass 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 is not None and vs_version >= '15.0' else '' script_path = os.environ['VCINSTALLDIR'] + relative_path + 'vcvarsall.bat' if os.path.exists(script_path): if has_arch_values: 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 f'"{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: T.Dict[T.Any, build.Target], recursive=False): all_deps: T.Dict[str, build.Target] = {} for target in t.values(): if isinstance(target, build.CustomTarget): for d in target.get_target_dependencies(): # FIXME: this isn't strictly correct, as the target doesn't # Get dependencies on non-targets, such as Files if isinstance(d, build.Target): all_deps[d.get_id()] = d elif isinstance(target, build.RunTarget): for d in target.get_dependencies(): 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 ldep in target.link_depends: if isinstance(ldep, build.CustomTargetIndex): all_deps[ldep.get_id()] = ldep.target elif isinstance(ldep, File): # Already built, no target references needed pass else: all_deps[ldep.get_id()] = ldep for obj_id, objdep in self.get_obj_target_deps(target.objects): all_deps[obj_id] = objdep else: raise MesonException(f'Unknown target type for target {target}') 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: generator = gendep.get_generator() gen_exe = generator.get_exe() if isinstance(gen_exe, build.Executable): all_deps[gen_exe.get_id()] = gen_exe for d in itertools.chain(generator.depends, gendep.depends): if isinstance(d, build.CustomTargetIndex): all_deps[d.get_id()] = d.target elif isinstance(d, build.Target): all_deps[d.get_id()] = d # FIXME: we don't handle other kinds of deps correctly here, such # as GeneratedLists, StructuredSources, and generated File. 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: str, parents: T.Sequence[Path]) -> None: 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: str, projlist: T.List[Project]) -> None: default_projlist = self.get_build_by_default_targets() default_projlist.update(self.get_testlike_targets()) sln_filename_tmp = sln_filename + '~' # Note using the utf-8 BOM requires the blank line, otherwise Visual Studio Version Selector fails. # Without the BOM, VSVS fails if there is a blank line. with open(sln_filename_tmp, 'w', encoding='utf-8-sig') as ofile: ofile.write('\nMicrosoft Visual Studio Solution File, Format Version %s\n' % self.sln_file_version) ofile.write('# Visual Studio %s\n' % self.sln_version_comment) prj_templ = 'Project("{%s}") = "%s", "%s", "{%s}"\n' for prj in projlist: if self.environment.coredata.get_option(OptionKey('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') if self.gen_lite: # REGEN is replaced by the lighter-weight RECONFIGURE utility, for now. See comment in 'gen_regenproj' regen_proj_name = 'RECONFIGURE' regen_proj_fname = 'RECONFIGURE.vcxproj' else: regen_proj_name = 'REGEN' regen_proj_fname = 'REGEN.vcxproj' regen_line = prj_templ % (self.environment.coredata.lang_guids['default'], regen_proj_name, regen_proj_fname, 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') multi_config_buildtype_list = coredata.get_genvs_default_buildtype_list() if self.gen_lite else [self.buildtype] for buildtype in multi_config_buildtype_list: ofile.write('\t\t%s|%s = %s|%s\n' % (buildtype, self.platform, buildtype, self.platform)) ofile.write('\tEndGlobalSection\n') ofile.write('\tGlobalSection(ProjectConfigurationPlatforms) = ' 'postSolution\n') # REGEN project (multi-)configurations for buildtype in multi_config_buildtype_list: ofile.write('\t\t{%s}.%s|%s.ActiveCfg = %s|%s\n' % (self.environment.coredata.regen_guid, buildtype, self.platform, buildtype, self.platform)) if not self.gen_lite: # With a 'genvslite'-generated solution, the regen (i.e. reconfigure) utility is only intended to run when the user explicitly builds this proj. ofile.write('\t\t{%s}.%s|%s.Build.0 = %s|%s\n' % (self.environment.coredata.regen_guid, buildtype, self.platform, buildtype, self.platform)) # Create the solution configuration for project_index, p in enumerate(projlist): if p[3] is MachineChoice.BUILD: config_platform = self.build_platform else: config_platform = self.platform # Add to the list of projects in this solution for buildtype in multi_config_buildtype_list: ofile.write('\t\t{%s}.%s|%s.ActiveCfg = %s|%s\n' % (p[2], buildtype, self.platform, buildtype, config_platform)) # If we're building the solution with Visual Studio's build system, enable building of buildable # projects. However, if we're building with meson (via --genvslite), then, since each project's # 'build' action just ends up doing the same 'meson compile ...' we don't want the 'solution build' # repeatedly going off and doing the same 'meson compile ...' multiple times over, so we default # to building the startup project, which is the first listed project in the solution file by # default for Visual Studio. The user is free to change this afterwards, but this provides a # sensible default. if (not self.gen_lite or project_index == 0) and \ p[0] in default_projlist and \ not isinstance(self.build.targets[p[0]], build.RunTarget): ofile.write('\t\t{%s}.%s|%s.Build.0 = %s|%s\n' % (p[2], buildtype, self.platform, buildtype, config_platform)) # RUN_TESTS and RUN_INSTALL project (multi-)configurations for buildtype in multi_config_buildtype_list: ofile.write('\t\t{%s}.%s|%s.ActiveCfg = %s|%s\n' % (self.environment.coredata.test_guid, buildtype, self.platform, buildtype, self.platform)) ofile.write('\t\t{%s}.%s|%s.ActiveCfg = %s|%s\n' % (self.environment.coredata.install_guid, buildtype, self.platform, 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{{{}}} = {{{}}}\n".format(p[2], self.subdirs[p[1].parent][0])) for subdir in self.subdirs.values(): if subdir[1]: ofile.write("\t\t{{{}}} = {{{}}}\n".format(subdir[0], subdir[1])) ofile.write('\tEndGlobalSection\n') ofile.write('EndGlobal\n') replace_if_different(sln_filename, sln_filename_tmp) def generate_projects(self, vslite_ctx: dict = None) -> T.List[Project]: startup_project = self.environment.coredata.options[OptionKey('backend_startup_project')].value projlist: T.List[Project] = [] 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] generated = self.gen_vcxproj(target, str(projfile_path), proj_uuid, vslite_ctx) if generated: projlist.append((name, relname, proj_uuid, target.for_machine)) # Put the startup project first in the project list if startup_idx: projlist.insert(0, projlist.pop(startup_idx)) 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: ET.Element, include: str, projid: str, link_outputs: bool = False) -> None: 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: ET.Element, 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_project(self, target_name, *, temp_dir, guid, conftype='Utility', target_ext=None, target_platform=None) -> T.Tuple[ET.Element, ET.Element]: root = ET.Element('Project', {'DefaultTargets': "Build", 'ToolsVersion': '4.0', 'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'}) confitems = ET.SubElement(root, 'ItemGroup', {'Label': 'ProjectConfigurations'}) if not target_platform: target_platform = self.platform multi_config_buildtype_list = coredata.get_genvs_default_buildtype_list() if self.gen_lite else [self.buildtype] for buildtype in multi_config_buildtype_list: prjconf = ET.SubElement(confitems, 'ProjectConfiguration', {'Include': buildtype + '|' + target_platform}) ET.SubElement(prjconf, 'Configuration').text = buildtype ET.SubElement(prjconf, 'Platform').text = target_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' ET.SubElement(root, 'Import', Project=r'$(VCTargetsPath)\Microsoft.Cpp.Default.props') # Configuration type_config = ET.SubElement(root, 'PropertyGroup', Label='Configuration') ET.SubElement(type_config, 'ConfigurationType').text = conftype if self.platform_toolset: ET.SubElement(type_config, 'PlatformToolset').text = self.platform_toolset # This must come AFTER the '' element; importing before the 'PlatformToolset' elt # gets set leads to msbuild failures reporting - # "The build tools for v142 (Platform Toolset = 'v142') cannot be found. ... please install v142 build tools." # This is extremely unhelpful and misleading since the v14x build tools ARE installed. ET.SubElement(root, 'Import', Project=r'$(VCTargetsPath)\Microsoft.Cpp.props') # This attribute makes sure project names are displayed as expected in solution files even when their project file names differ pname = ET.SubElement(globalgroup, 'ProjectName') pname.text = target_name if not self.gen_lite: # Plenty of elements aren't necessary for 'makefile'-style project that just redirects to meson builds # XXX Wasn't here before for anything but gen_vcxproj , but seems fine? ns = ET.SubElement(globalgroup, 'RootNamespace') ns.text = target_name p = ET.SubElement(globalgroup, 'Platform') p.text = target_platform if self.windows_target_platform_version: ET.SubElement(globalgroup, 'WindowsTargetPlatformVersion').text = self.windows_target_platform_version ET.SubElement(globalgroup, 'UseMultiToolTask').text = 'true' ET.SubElement(type_config, 'CharacterSet').text = 'MultiByte' # Fixme: wasn't here before for gen_vcxproj() ET.SubElement(type_config, 'UseOfMfc').text = 'false' # 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 = temp_dir + '\\' tname = ET.SubElement(direlem, 'TargetName') tname.text = target_name if target_ext: ET.SubElement(direlem, 'TargetExt').text = target_ext return (root, type_config) def gen_run_target_vcxproj(self, target: build.RunTarget, ofname: str, guid: str) -> None: (root, type_config) = self.create_basic_project(target.name, temp_dir=target.get_id(), guid=guid) depend_files = self.get_target_depend_files(target) if not target.command: # This is an alias target and thus doesn't run any command. It's # enough to emit the references to the other projects for them to # be built/run/..., if necessary. assert isinstance(target, build.AliasTarget) assert len(depend_files) == 0 else: assert not isinstance(target, build.AliasTarget) target_env = self.get_run_target_env(target) _, _, cmd_raw = self.eval_custom_target_command(target) wrapper_cmd, _ = self.as_meson_exe_cmdline(target.command[0], cmd_raw[1:], force_serialize=True, env=target_env, verbose=True) self.add_custom_build(root, 'run_target', ' '.join(self.quote_arguments(wrapper_cmd)), deps=depend_files) # The import is needed even for alias targets, otherwise the build # target isn't defined 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: build.CustomTarget, ofname: str, guid: str) -> None: if target.for_machine is MachineChoice.BUILD: platform = self.build_platform else: platform = self.platform (root, type_config) = self.create_basic_project(target.name, temp_dir=target.get_id(), guid=guid, target_platform=platform) # 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_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.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, feed=srcs[0] if target.feed else None, force_serialize=True, env=target.env, verbose=target.console) 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, verify_files=not target.build_always_stale) 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) def gen_compile_target_vcxproj(self, target: build.CompileTarget, ofname: str, guid: str) -> None: if target.for_machine is MachineChoice.BUILD: platform = self.build_platform else: platform = self.platform (root, type_config) = self.create_basic_project(target.name, temp_dir=target.get_id(), guid=guid, target_platform=platform) ET.SubElement(root, 'Import', Project=r'$(VCTargetsPath)\Microsoft.Cpp.targets') target.generated = [self.compile_target_to_generator(target)] target.sources = [] 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(f'Could not guess language from source file {src}.') def add_pch(self, pch_sources, lang, inc_cl): if lang in pch_sources: 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): pch = ET.SubElement(inc_cl, 'PrecompiledHeader') pch.text = 'Use' 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 = f'$(IntDir)$(TargetName)-{lang}.pch' # Need to set the name for the pdb, as cl otherwise gives it a static # name. Which leads to problems when there is more than one pch # (e.g. for different languages). pch_pdb = ET.SubElement(inc_cl, 'ProgramDataBaseFileName') pch_pdb.text = f'$(IntDir)$(TargetName)-{lang}.pdb' 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. if entry[1:].startswith('fsanitize'): return True 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) # Set up each project's source file ('CLCompile') element with appropriate preprocessor, include dir, and compile option values for correct intellisense. def add_project_nmake_defs_incs_and_opts(self, parent_node, src: str, defs_paths_opts_per_lang_and_buildtype: dict, platform: str): # For compactness, sources whose type matches the primary src type (i.e. most frequent in the set of source types used in the target/project, # according to the 'captured_build_args' map), can simply reference the preprocessor definitions, include dirs, and compile option NMake fields of # the project itself. # However, if a src is of a non-primary type, it could have totally different defs/dirs/options so we're going to have to fill in the full, verbose # set of values for these fields, which needs to be fully expanded per build type / configuration. # # FIXME: Suppose a project contains .cpp and .c src files with different compile defs/dirs/options, while also having .h files, some of which # are included by .cpp sources and others included by .c sources: How do we know whether the .h source should be using the .cpp or .c src # defs/dirs/options? Might it also be possible for a .h header to be shared between .cpp and .c sources? If so, I don't see how we can # correctly configure these intellisense fields. # For now, all sources/headers that fail to find their extension's language in the '...nmake_defs_paths_opts...' map will just adopt the project # defs/dirs/opts that are set for the nominal 'primary' src type. ext = src.split('.')[-1] lang = compilers.compilers.SUFFIX_TO_LANG.get(ext, None) if lang in defs_paths_opts_per_lang_and_buildtype.keys(): # This is a non-primary src type for which can't simply reference the project's nmake fields; # we must laboriously fill in the fields for all buildtypes. for buildtype in coredata.get_genvs_default_buildtype_list(): (defs, paths, opts) = defs_paths_opts_per_lang_and_buildtype[lang][buildtype] condition = f'\'$(Configuration)|$(Platform)\'==\'{buildtype}|{platform}\'' ET.SubElement(parent_node, 'PreprocessorDefinitions', Condition=condition).text = defs ET.SubElement(parent_node, 'AdditionalIncludeDirectories', Condition=condition).text = paths ET.SubElement(parent_node, 'AdditionalOptions', Condition=condition).text = opts else: # Can't find bespoke nmake defs/dirs/opts fields for this extention, so just reference the project's fields ET.SubElement(parent_node, 'PreprocessorDefinitions').text = '$(NMakePreprocessorDefinitions)' ET.SubElement(parent_node, 'AdditionalIncludeDirectories').text = '$(NMakeIncludeSearchPath)' ET.SubElement(parent_node, 'AdditionalOptions').text = '$(AdditionalOptions)' 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 escape_preprocessor_define(define: str) -> str: # 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: str) -> str: # 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 f'"{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: ET.ElementTree, ofname: str) -> None: ofname_tmp = ofname + '~' tree.write(ofname_tmp, encoding='utf-8', xml_declaration=True) # ElementTree cannot do pretty-printing, 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) # Returns: (target_args,file_args), (target_defines,file_defines), (target_inc_dirs,file_inc_dirs) def get_args_defines_and_inc_dirs(self, target, compiler, generated_files_include_dirs, proj_to_src_root, proj_to_src_dir, build_args): # 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: T.Dict[str, CompilerArgs] = {l: c.compiler_args() for l, c in target.compilers.items()} file_defines = {l: [] for l in target.compilers} file_inc_dirs = {l: [] for l 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( target.get_options(), comp) file_args[l] += comp.get_option_compile_args( target.get_options()) # 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 l in file_args.keys(): file_args[l] += target.get_option(OptionKey('args', machine=target.for_machine, lang=l)) 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) try: # Add source subdir first so that the build subdir overrides it args.append('-I' + os.path.join(proj_to_src_root, curdir)) # src dir args.append('-I' + self.relpath(curdir, target.subdir)) # build dir except ValueError: # Include is on different drive args.append('-I' + os.path.normpath(curdir)) 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 += ['.', 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 not in file_defines[l]: 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) # Add include dirs to target as well so that "Go to Document" works in headers if inc_dir not in target_inc_dirs: target_inc_dirs.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 d.name != 'openmp': 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) if '/Gw' in build_args: target_args.append('/Gw') return (target_args, file_args), (target_defines, file_defines), (target_inc_dirs, file_inc_dirs) @staticmethod def get_build_args(compiler, buildtype: str, optimization_level: str, debug: bool, sanitize: str) -> T.List[str]: build_args = compiler.get_buildtype_args(buildtype) build_args += compiler.get_optimization_args(optimization_level) build_args += compiler.get_debug_args(debug) build_args += compiler.sanitizer_compile_args(sanitize) return build_args # Used in populating a simple nmake-style project's intellisense fields. # Given a list of compile args, for example - # [ '-I..\\some\\dir\\include', '-I../../some/other/dir', '/MDd', '/W2', '/std:c++17', '/Od', '/Zi', '-DSOME_DEF=1', '-DANOTHER_DEF=someval', ...] # returns a tuple of pre-processor defs (for this example) - # 'SOME_DEF=1;ANOTHER_DEF=someval;' # and include paths, e.g. - # '..\\some\\dir\\include;../../some/other/dir;' # and finally any remaining compiler options, e.g. - # '/MDd /W2 /std:c++17 /Od/Zi' @staticmethod def _extract_nmake_fields(captured_build_args: list[str]) -> T.Tuple[str, str, str]: include_dir_options = [ '-I', '/I', '-isystem', # regular gcc / clang option to denote system header include search paths '/clang:-isystem', # clang-cl (msvc 'cl'-style clang wrapper) option to pass '-isystem' option to clang driver '/imsvc', # clang-cl option to 'Add directory to system include search path' '/external:I', # msvc cl option to add 'external' include search paths ] defs = '' paths = '$(VC_IncludePath);$(WindowsSDK_IncludePath);' additional_opts = '' for arg in captured_build_args: if arg.startswith(('-D', '/D')): defs += arg[2:] + ';' else: opt_match = next((opt for opt in include_dir_options if arg.startswith(opt)), None) if opt_match: paths += arg[len(opt_match):] + ';' elif arg.startswith(('-', '/')): additional_opts += arg + ' ' return (defs, paths, additional_opts) @staticmethod def get_nmake_base_meson_command_and_exe_search_paths() -> T.Tuple[str, str]: meson_cmd_list = mesonlib.get_meson_command() assert (len(meson_cmd_list) == 1) or (len(meson_cmd_list) == 2) # We expect get_meson_command() to either be of the form - # 1: ['path/to/meson.exe'] # or - # 2: ['path/to/python.exe', 'and/path/to/meson.py'] # so we'd like to ensure our makefile-style project invokes the same meson executable or python src as this instance. exe_search_paths = os.path.dirname(meson_cmd_list[0]) nmake_base_meson_command = os.path.basename(meson_cmd_list[0]) if len(meson_cmd_list) != 1: # We expect to be dealing with case '2', shown above. # With Windows, it's also possible that we get a path to the second element of meson_cmd_list that contains spaces # (e.g. 'and/path to/meson.py'). So, because this will end up directly in the makefile/NMake command lines, we'd # better always enclose it in quotes. Only strictly necessary for paths with spaces but no harm for paths without - nmake_base_meson_command += ' \"' + meson_cmd_list[1] + '\"' exe_search_paths += ';' + os.path.dirname(meson_cmd_list[1]) # Additionally, in some cases, we appear to have to add 'C:\Windows\system32;C:\Windows' to the 'Path' environment (via the # ExecutablePath element), without which, the 'meson compile ...' (NMakeBuildCommandLine) command can fail (failure to find # stdio.h and similar), so something is quietly switching some critical build behaviour based on the presence of these in # the 'Path'. # Not sure if this ultimately comes down to some 'find and guess' hidden behaviours within meson or within MSVC tools, but # I guess some projects may implicitly rely on this behaviour. # Things would be cleaner, more robust, repeatable, and portable if meson (and msvc tools) replaced all this kind of # find/guess behaviour with the requirement that things just be explicitly specified by the user. # An example of this can be seen with - # 1: Download https://github.com/facebook/zstd source # 2: cd to the 'zstd-dev\build\meson' dir # 3: meson setup -Dbin_programs=true -Dbin_contrib=true --genvslite vs2022 builddir_vslite # 4: Open the generated 'builddir_vslite_vs\zstd.sln' and build through a project, which should explicitly add the above to # the project's 'Executable Directories' paths and build successfully. # 5: Remove 'C:\Windows\system32;C:\Windows;' from the same project's 'Executable Directories' paths and rebuild. # This should now fail. # It feels uncomfortable to do this but what better alternative is there (and might this introduce new problems)? - exe_search_paths += ';C:\\Windows\\system32;C:\\Windows' # A meson project that explicitly specifies compiler/linker tools and sdk/include paths is not going to have any problems # with this addition. return (nmake_base_meson_command, exe_search_paths) def add_gen_lite_makefile_vcxproj_elements(self, root: ET.Element, platform: str, target_ext: str, vslite_ctx: dict, target, proj_to_build_root: str, primary_src_lang: T.Optional[str]) -> None: ET.SubElement(root, 'ImportGroup', Label='ExtensionSettings') ET.SubElement(root, 'ImportGroup', Label='Shared') prop_sheets_grp = ET.SubElement(root, 'ImportGroup', Label='PropertySheets') ET.SubElement(prop_sheets_grp, 'Import', {'Project': r'$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props', 'Condition': r"exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')", 'Label': 'LocalAppDataPlatform' }) ET.SubElement(root, 'PropertyGroup', Label='UserMacros') (nmake_base_meson_command, exe_search_paths) = Vs2010Backend.get_nmake_base_meson_command_and_exe_search_paths() # Relative path from this .vcxproj to the directory containing the set of '..._[debug/debugoptimized/release]' setup meson build dirs. proj_to_multiconfigured_builds_parent_dir = os.path.join(proj_to_build_root, '..') # Conditional property groups per configuration (buildtype). E.g. - # multi_config_buildtype_list = coredata.get_genvs_default_buildtype_list() for buildtype in multi_config_buildtype_list: per_config_prop_group = ET.SubElement(root, 'PropertyGroup', Condition=f'\'$(Configuration)|$(Platform)\'==\'{buildtype}|{platform}\'') (_, build_dir_tail) = os.path.split(self.src_to_build) meson_build_dir_for_buildtype = build_dir_tail[:-2] + buildtype # Get the buildtype suffixed 'builddir_[debug/release/etc]' from 'builddir_vs', for example. proj_to_build_dir_for_buildtype = str(os.path.join(proj_to_multiconfigured_builds_parent_dir, meson_build_dir_for_buildtype)) ET.SubElement(per_config_prop_group, 'OutDir').text = f'{proj_to_build_dir_for_buildtype}\\' ET.SubElement(per_config_prop_group, 'IntDir').text = f'{proj_to_build_dir_for_buildtype}\\' ET.SubElement(per_config_prop_group, 'NMakeBuildCommandLine').text = f'{nmake_base_meson_command} compile -C "{proj_to_build_dir_for_buildtype}"' ET.SubElement(per_config_prop_group, 'NMakeOutput').text = f'$(OutDir){target.name}{target_ext}' captured_build_args = vslite_ctx[buildtype][target.get_id()] # 'captured_build_args' is a dictionary, mapping from each src file type to a list of compile args to use for that type. # Usually, there's just one but we could have multiple src types. However, since there's only one field for the makefile # project's NMake... preprocessor/include intellisense fields, we'll just use the first src type we have to fill in # these fields. Then, any src files in this VS project that aren't of this first src type will then need to override # its intellisense fields instead of simply referencing the values in the project. ET.SubElement(per_config_prop_group, 'NMakeReBuildCommandLine').text = f'{nmake_base_meson_command} compile -C "{proj_to_build_dir_for_buildtype}" --clean && {nmake_base_meson_command} compile -C "{proj_to_build_dir_for_buildtype}"' ET.SubElement(per_config_prop_group, 'NMakeCleanCommandLine').text = f'{nmake_base_meson_command} compile -C "{proj_to_build_dir_for_buildtype}" --clean' # Need to set the 'ExecutablePath' element for the above NMake... commands to be able to invoke the meson command. ET.SubElement(per_config_prop_group, 'ExecutablePath').text = exe_search_paths # We may not have any src files and so won't have a primary src language. In which case, we've nothing to fill in for this target's intellisense fields - if primary_src_lang: primary_src_type_build_args = captured_build_args[primary_src_lang] preproc_defs, inc_paths, other_compile_opts = Vs2010Backend._extract_nmake_fields(primary_src_type_build_args) ET.SubElement(per_config_prop_group, 'NMakePreprocessorDefinitions').text = preproc_defs ET.SubElement(per_config_prop_group, 'NMakeIncludeSearchPath').text = inc_paths ET.SubElement(per_config_prop_group, 'AdditionalOptions').text = other_compile_opts # Unless we explicitly specify the following empty path elements, the project is assigned a load of nasty defaults that fill these # with values like - # $(VC_IncludePath);$(WindowsSDK_IncludePath); # which are all based on the current install environment (a recipe for non-reproducibility problems), not the paths that will be used by # the actual meson compile jobs. Although these elements look like they're only for MSBuild operations, they're not needed with our simple, # lite/makefile-style projects so let's just remove them in case they do get used/confused by intellisense. ET.SubElement(per_config_prop_group, 'IncludePath') ET.SubElement(per_config_prop_group, 'ExternalIncludePath') ET.SubElement(per_config_prop_group, 'ReferencePath') ET.SubElement(per_config_prop_group, 'LibraryPath') ET.SubElement(per_config_prop_group, 'LibraryWPath') ET.SubElement(per_config_prop_group, 'SourcePath') ET.SubElement(per_config_prop_group, 'ExcludePath') def add_non_makefile_vcxproj_elements( self, root: ET.Element, type_config: ET.Element, target, platform: str, subsystem, build_args, target_args, target_defines, target_inc_dirs, file_args ) -> None: compiler = self._get_cl_compiler(target) buildtype_link_args = compiler.get_buildtype_linker_args(self.buildtype) # Prefix to use to access the build root from the vcxproj dir down = self.target_to_build_root(target) # FIXME: Should the following just be set in create_basic_project(), even if # irrelevant for current target? # 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') if True in ((dep.name == 'openmp') for dep in target.get_external_deps()): ET.SubElement(clconf, 'OpenMPSupport').text = 'true' # CRT type; debug or release vscrt_type = target.get_option(OptionKey('b_vscrt')) vscrt_val = compiler.get_crt_val(vscrt_type, self.buildtype) if vscrt_val == 'mdd': ET.SubElement(type_config, 'UseDebugLibraries').text = 'true' ET.SubElement(clconf, 'RuntimeLibrary').text = 'MultiThreadedDebugDLL' elif vscrt_val == 'mt': # FIXME, wrong ET.SubElement(type_config, 'UseDebugLibraries').text = 'false' ET.SubElement(clconf, 'RuntimeLibrary').text = 'MultiThreaded' elif vscrt_val == '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' # Sanitizers if '/fsanitize=address' in build_args: ET.SubElement(type_config, 'EnableASAN').text = 'true' # Debug format if '/ZI' in build_args: ET.SubElement(clconf, 'DebugInformationFormat').text = 'EditAndContinue' elif '/Zi' in build_args: ET.SubElement(clconf, 'DebugInformationFormat').text = 'ProgramDatabase' elif '/Z7' in build_args: ET.SubElement(clconf, 'DebugInformationFormat').text = 'OldStyle' else: ET.SubElement(clconf, 'DebugInformationFormat').text = 'None' # Runtime checks if '/RTC1' in build_args: ET.SubElement(clconf, 'BasicRuntimeChecks').text = 'EnableFastChecks' elif '/RTCu' in build_args: ET.SubElement(clconf, 'BasicRuntimeChecks').text = 'UninitializedLocalUsageCheck' elif '/RTCs' in build_args: ET.SubElement(clconf, 'BasicRuntimeChecks').text = 'StackFrameRuntimeCheck' # Exception handling has to be set in the xml in addition to the "AdditionalOptions" because otherwise # cl will give warning D9025: overriding '/Ehs' with cpp_eh value if 'cpp' in target.compilers: eh = target.get_option(OptionKey('eh', machine=target.for_machine, lang='cpp')) if eh == 'a': ET.SubElement(clconf, 'ExceptionHandling').text = 'Async' elif eh == 's': ET.SubElement(clconf, 'ExceptionHandling').text = 'SyncCThrow' elif eh == 'none': ET.SubElement(clconf, 'ExceptionHandling').text = 'false' else: # 'sc' or 'default' ET.SubElement(clconf, 'ExceptionHandling').text = 'Sync' if len(target_args) > 0: target_args.append('%(AdditionalOptions)') ET.SubElement(clconf, "AdditionalOptions").text = ' '.join(target_args) 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 = T.cast('str', target.get_option(OptionKey('warning_level'))) warning_level = 'EnableAllWarnings' if warning_level == 'everything' else 'Level' + str(1 + int(warning_level)) ET.SubElement(clconf, 'WarningLevel').text = warning_level if target.get_option(OptionKey('werror')): ET.SubElement(clconf, 'TreatWarningAsError').text = 'true' # Optimization flags o_flags = split_o_flags_args(build_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 or '/O1' in o_flags: ET.SubElement(clconf, 'FavorSizeOrSpeed').text = 'Size' # Note: setting FavorSizeOrSpeed with clang-cl conflicts with /Od and can make debugging difficult, so don't. elif '/Od' not in o_flags: ET.SubElement(clconf, 'FavorSizeOrSpeed').text = 'Speed' # Note: SuppressStartupBanner is /NOLOGO and is 'true' by default self.generate_lang_standard_info(file_args, clconf) resourcecompile = ET.SubElement(compiles, 'ResourceCompile') ET.SubElement(resourcecompile, 'PreprocessorDefinitions') # Linker options link = ET.SubElement(compiles, 'Link') extra_link_args = compiler.compiler_args() # 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.debug: self.generate_debug_information(link) else: ET.SubElement(link, 'GenerateDebugInformation').text = 'false' if not isinstance(target, build.StaticLibrary): if isinstance(target, build.SharedModule): extra_link_args += compiler.get_std_shared_module_link_args(target.get_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 dep.name == 'openmp': ET.SubElement(clconf, 'OpenMPSupport').text = 'true' 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 dep.name == 'openmp': ET.SubElement(clconf, 'OpenMPSupport').text = 'true' 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(target.get_options()) (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: if compiler.id == 'msvc' and version_compare(compiler.version, '<19.00.23918'): # Expand our object lists manually if we are on pre-Visual Studio 2015 Update 2 l = t.extract_all_objects(False) # Unfortunately, we can't use self.object_filename_from_source() for gen in l.genlist: for src in gen.get_outputs(): if self.environment.is_source(src): path = self.get_target_generated_dir(t, gen, src) gen_src_ext = '.' + os.path.splitext(path)[1][1:] extra_link_args.append(path[:-len(gen_src_ext)] + '.obj') for src in l.srclist: obj_basename = None if self.environment.is_source(src): obj_basename = self.object_filename_from_source(t, src) target_private_dir = self.relpath(self.get_target_private_dir(t), self.get_target_dir(t)) rel_obj = os.path.join(target_private_dir, obj_basename) extra_link_args.append(rel_obj) extra_link_args.extend(self.flatten_object_list(t)) else: # /WHOLEARCHIVE:foo must go into AdditionalOptions extra_link_args += compiler.get_link_whole_for(linkname) # To force Visual Studio to build this project even though it # has no sources, we include a reference to the vcxproj file # that builds this target. Technically we should add this only # 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))) 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 = f'$(OutDir){target.get_filename()}' subsys = ET.SubElement(link, 'SubSystem') subsys.text = subsystem if isinstance(target, (build.SharedLibrary, 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, build.Executable)): # 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 self.debug: pdb = ET.SubElement(link, 'ProgramDataBaseFileName') pdb.text = f'$(OutDir){target.name}.pdb' targetmachine = ET.SubElement(link, 'TargetMachine') if target.for_machine is MachineChoice.BUILD: targetplatform = platform.lower() else: targetplatform = self.platform.lower() if targetplatform == 'win32': targetmachine.text = 'MachineX86' elif targetplatform == 'x64' or detect_microsoft_gdk(targetplatform): targetmachine.text = 'MachineX64' elif targetplatform == 'arm': targetmachine.text = 'MachineARM' elif targetplatform == 'arm64': targetmachine.text = 'MachineARM64' elif targetplatform == 'arm64ec': targetmachine.text = 'MachineARM64EC' else: raise MesonException('Unsupported Visual Studio target machine: ' + targetplatform) # /nologo ET.SubElement(link, 'SuppressStartupBanner').text = 'true' # /release if not target.get_option(OptionKey('debug')): ET.SubElement(link, 'SetChecksum').text = 'true' # Visual studio doesn't simply allow the src files of a project to be added with the 'Condition=...' attribute, # to allow us to point to the different debug/debugoptimized/release sets of generated src files for each of # the solution's configurations. Similarly, 'ItemGroup' also doesn't support 'Condition'. So, without knowing # a better (simple) alternative, for now, we'll repoint these generated sources (which will be incorrectly # pointing to non-existent files under our '[builddir]_vs' directory) to the appropriate location under one of # our buildtype build directores (e.g. '[builddir]_debug'). # This will at least allow the user to open the files of generated sources listed in the solution explorer, # once a build/compile has generated these sources. # # This modifies the paths in 'gen_files' in place, as opposed to returning a new list of modified paths. def relocate_generated_file_paths_to_concrete_build_dir(self, gen_files: T.List[str], target: T.Union[build.Target, build.CustomTargetIndex]) -> None: (_, build_dir_tail) = os.path.split(self.src_to_build) meson_build_dir_for_buildtype = build_dir_tail[:-2] + coredata.get_genvs_default_buildtype_list()[0] # Get the first buildtype suffixed dir (i.e. '[builddir]_debug') from '[builddir]_vs' # Relative path from this .vcxproj to the directory containing the set of '..._[debug/debugoptimized/release]' setup meson build dirs. proj_to_build_root = self.target_to_build_root(target) proj_to_multiconfigured_builds_parent_dir = os.path.join(proj_to_build_root, '..') proj_to_build_dir_for_buildtype = str(os.path.join(proj_to_multiconfigured_builds_parent_dir, meson_build_dir_for_buildtype)) relocate_to_concrete_builddir_target = os.path.normpath(os.path.join(proj_to_build_dir_for_buildtype, self.get_target_dir(target))) for idx, file_path in enumerate(gen_files): gen_files[idx] = os.path.normpath(os.path.join(relocate_to_concrete_builddir_target, file_path)) # Returns bool indicating whether the .vcxproj has been generated. # Under some circumstances, it's unnecessary to create some .vcxprojs, so, when generating the .sln, # we need to respect that not all targets will have generated a project. def gen_vcxproj(self, target: build.BuildTarget, ofname: str, guid: str, vslite_ctx: dict = None) -> bool: mlog.debug(f'Generating vcxproj {target.name}.') subsystem = 'Windows' self.handled_target_deps[target.get_id()] = [] if self.gen_lite: if not isinstance(target, build.BuildTarget): # Since we're going to delegate all building to the one true meson build command, we don't need # to generate .vcxprojs for targets that don't add any source files or just perform custom build # commands. These are targets of types CustomTarget or RunTarget. So let's just skip generating # these otherwise insubstantial non-BuildTarget targets. return False conftype = 'Makefile' elif isinstance(target, build.Executable): conftype = 'Application' # If someone knows how to set the version properly, # please send a patch. subsystem = target.win_subsystem.split(',')[0] elif isinstance(target, build.StaticLibrary): conftype = 'StaticLibrary' elif isinstance(target, build.SharedLibrary): conftype = 'DynamicLibrary' elif isinstance(target, build.CustomTarget): self.gen_custom_target_vcxproj(target, ofname, guid) return True elif isinstance(target, build.RunTarget): self.gen_run_target_vcxproj(target, ofname, guid) return True elif isinstance(target, build.CompileTarget): self.gen_compile_target_vcxproj(target, ofname, guid) return True else: raise MesonException(f'Unknown target type for {target.get_basename()}') (sources, headers, objects, _languages) = self.split_sources(target.sources) if target.is_unity: sources = self.generate_unity_files(target, sources) if target.for_machine is MachineChoice.BUILD: platform = self.build_platform else: platform = self.platform tfilename = os.path.splitext(target.get_filename()) (root, type_config) = self.create_basic_project(tfilename[0], temp_dir=target.get_id(), guid=guid, conftype=conftype, target_ext=tfilename[1], target_platform=platform) 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 compiler = self._get_cl_compiler(target) build_args = Vs2010Backend.get_build_args(compiler, self.buildtype, self.optimization, self.debug, self.sanitize) assert isinstance(target, (build.Executable, build.SharedLibrary, build.StaticLibrary, build.SharedModule)), 'for mypy' # Prefix to use to access the build root from the vcxproj dir proj_to_build_root = 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(proj_to_build_root, 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)) (target_args, file_args), (target_defines, file_defines), (target_inc_dirs, file_inc_dirs) = self.get_args_defines_and_inc_dirs( target, compiler, generated_files_include_dirs, proj_to_src_root, proj_to_src_dir, build_args) if self.gen_lite: assert vslite_ctx is not None primary_src_lang = get_primary_source_lang(target.sources, custom_src) self.add_gen_lite_makefile_vcxproj_elements(root, platform, tfilename[1], vslite_ctx, target, proj_to_build_root, primary_src_lang) else: self.add_non_makefile_vcxproj_elements(root, type_config, target, platform, subsystem, build_args, target_args, target_defines, target_inc_dirs, file_args) 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 pch_sources = {} if self.target_uses_pch(target): for lang in ['c', 'cpp']: pch = target.get_pch(lang) if not pch: continue if compiler.id == 'msvc': if len(pch) == 1: # Auto generate PCH. src = os.path.join(proj_to_build_root, 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] previous_includes = [] if len(headers) + len(gen_hdrs) + len(target.extra_files) + len(pch_sources) > 0: if self.gen_lite and gen_hdrs: # Although we're constructing our .vcxproj under our '..._vs' directory, we want to reference generated files # in our concrete build directories (e.g. '..._debug'), where generated files will exist after building. self.relocate_generated_file_paths_to_concrete_build_dir(gen_hdrs, target) inc_hdrs = ET.SubElement(root, 'ItemGroup') for h in headers: relpath = os.path.join(proj_to_build_root, 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(proj_to_build_root, h.rel_to_builddir(self.build_to_src)) if path_normalize_add(relpath, previous_includes): ET.SubElement(inc_hdrs, 'CLInclude', Include=relpath) for headers in pch_sources.values(): path = os.path.join(proj_to_src_dir, headers[0]) 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: if self.gen_lite: # Get data to fill in intellisense fields for sources that can't reference the project-wide values defs_paths_opts_per_lang_and_buildtype = get_non_primary_lang_intellisense_fields( vslite_ctx, target.get_id(), primary_src_lang) if gen_src: # Although we're constructing our .vcxproj under our '..._vs' directory, we want to reference generated files # in our concrete build directories (e.g. '..._debug'), where generated files will exist after building. self.relocate_generated_file_paths_to_concrete_build_dir(gen_src, target) inc_src = ET.SubElement(root, 'ItemGroup') for s in sources: relpath = os.path.join(proj_to_build_root, s.rel_to_builddir(self.build_to_src)) if path_normalize_add(relpath, previous_sources): inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath) if self.gen_lite: self.add_project_nmake_defs_incs_and_opts(inc_cl, relpath, defs_paths_opts_per_lang_and_buildtype, platform) else: 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) if self.gen_lite: self.add_project_nmake_defs_incs_and_opts(inc_cl, s, defs_paths_opts_per_lang_and_buildtype, platform) else: 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) s = File.from_built_file(target.get_subdir(), s) ET.SubElement(inc_cl, 'ObjectFileName').text = "$(IntDir)" + \ self.object_filename_from_source(target, s) for lang, headers in pch_sources.items(): impl = headers[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) if self.gen_lite: self.add_project_nmake_defs_incs_and_opts(inc_cl, impl, defs_paths_opts_per_lang_and_buildtype, platform) else: 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) # XXX: Do we need to set the object file name here too? additional_objects = [] for o in self.flatten_object_list(target, proj_to_build_root)[0]: assert isinstance(o, str) additional_objects.append(o) for o in custom_objs: additional_objects.append(o) # VS automatically links CustomBuild outputs whose name ends in .obj or .res, # but the others need to be included explicitly explicit_link_gen_objs = [obj for obj in gen_objs if not obj.endswith(('.obj', '.res'))] previous_objects = [] if len(objects) + len(additional_objects) + len(explicit_link_gen_objs) > 0: inc_objs = ET.SubElement(root, 'ItemGroup') for s in objects: relpath = os.path.join(proj_to_build_root, 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 + explicit_link_gen_objs: if path_normalize_add(s, previous_objects): ET.SubElement(inc_objs, 'Object', Include=s) ET.SubElement(root, 'Import', Project=r'$(VCTargetsPath)\Microsoft.Cpp.targets') self.add_regen_dependency(root) if not self.gen_lite: # Injecting further target dependencies into this vcxproj implies and forces a Visual Studio BUILD dependency, # which we don't want when using 'genvslite'. A gen_lite build as little involvement with the visual studio's # build system as possible. self.add_target_deps(root, target) self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname) if self.environment.coredata.get_option(OptionKey('layout')) == 'mirror': self.gen_vcxproj_filters(target, ofname) return True def gen_vcxproj_filters(self, target, ofname): # Generate pitchfork of filters based on directory structure. root = ET.Element('Project', {'ToolsVersion': '4.0', 'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'}) filter_folders = ET.SubElement(root, 'ItemGroup') filter_items = ET.SubElement(root, 'ItemGroup') mlog.debug(f'Generating vcxproj filters {target.name}.') def relative_to_defined_in(file): # Get the relative path to file's directory from the location of the meson.build that defines this target. return os.path.dirname(self.relpath(PureWindowsPath(file.subdir, file.fname), self.get_target_dir(target))) found_folders_to_filter = {} all_files = target.sources + target.extra_files # Build a dictionary of all used relative paths (i.e. from the meson.build defining this target) # for all sources. for i in all_files: if not os.path.isabs(i.fname): dirname = relative_to_defined_in(i) if dirname: found_folders_to_filter[dirname] = '' # Now walk up each of those relative paths checking for empty intermediate dirs to generate the filter. for folder in found_folders_to_filter: dirname = folder filter = '' while dirname: basename = os.path.basename(dirname) if filter == '': filter = basename else: # Use '/' to squash empty dirs. To actually get a '\', use '%255c'. filter = basename + ('\\' if dirname in found_folders_to_filter else '/') + filter dirname = os.path.dirname(dirname) # Don't add an empty filter, breaks all other (?) filters. if filter != '': found_folders_to_filter[folder] = filter filter_element = ET.SubElement(filter_folders, 'Filter', {'Include': filter}) uuid_element = ET.SubElement(filter_element, 'UniqueIdentifier') uuid_element.text = '{' + str(uuid.uuid4()).upper() + '}' sources, headers, objects, _ = self.split_sources(all_files) down = self.target_to_build_root(target) def add_element(type_name, elements): for i in elements: if not os.path.isabs(i.fname): dirname = relative_to_defined_in(i) if dirname and dirname in found_folders_to_filter: relpath = os.path.join(down, i.rel_to_builddir(self.build_to_src)) target_element = ET.SubElement(filter_items, type_name, {'Include': relpath}) filter_element = ET.SubElement(target_element, 'Filter') filter_element.text = found_folders_to_filter[dirname] add_element('ClCompile', sources) add_element('ClInclude', headers) add_element('Object', objects) self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname + '.filters') def gen_regenproj(self): # To fully adapt the REGEN work for a 'genvslite' solution, to check timestamps, settings, and regenerate the # '[builddir]_vs' solution/vcxprojs, as well as regenerating the accompanying buildtype-suffixed ninja build # directories (from which we need to first collect correct, updated preprocessor defs and compiler options in # order to fill in the regenerated solution's intellisense settings) would require some non-trivial intrusion # into the 'meson --internal regencheck ./meson-private' execution path (and perhaps also the '--internal # regenerate' and even 'meson setup --reconfigure' code). So, for now, we'll instead give the user a simpler # 'reconfigure' utility project that just runs 'meson setup --reconfigure [builddir]_[buildtype] [srcdir]' on # each of the ninja build dirs. # # FIXME: That will keep the building and compiling correctly configured but obviously won't update the # solution and vcxprojs, which may allow solution src files and intellisense options to go out-of-date; the # user would still have to manually 'meson setup --genvslite [vsxxxx] [builddir] [srcdir]' to fully regenerate # a complete and correct solution. if self.gen_lite: project_name = 'RECONFIGURE' ofname = os.path.join(self.environment.get_build_dir(), 'RECONFIGURE.vcxproj') conftype = 'Makefile' # I find the REGEN project doesn't work; it fails to invoke the appropriate - # python meson.py --internal regencheck builddir\meson-private # command, despite the fact that manually running such a command in a shell runs just fine. # Running/building the regen project produces the error - # ...Microsoft.CppBuild.targets(460,5): error MSB8020: The build tools for ClangCL (Platform Toolset = 'ClangCL') cannot be found. To build using the ClangCL build tools, please install ... # Not sure why but a simple makefile-style project that executes the full '...regencheck...' command actually works (and seems a little simpler). # Although I've limited this change to only happen under '--genvslite', perhaps ... # FIXME : Should all utility projects use the simpler and less problematic makefile-style project? else: project_name = 'REGEN' ofname = os.path.join(self.environment.get_build_dir(), 'REGEN.vcxproj') conftype = 'Utility' guid = self.environment.coredata.regen_guid (root, type_config) = self.create_basic_project(project_name, temp_dir='regen-temp', guid=guid, conftype=conftype ) if self.gen_lite: (nmake_base_meson_command, exe_search_paths) = Vs2010Backend.get_nmake_base_meson_command_and_exe_search_paths() all_configs_prop_group = ET.SubElement(root, 'PropertyGroup') # Multi-line command to reconfigure all buildtype-suffixed build dirs multi_config_buildtype_list = coredata.get_genvs_default_buildtype_list() (_, build_dir_tail) = os.path.split(self.src_to_build) proj_to_multiconfigured_builds_parent_dir = '..' # We know this RECONFIGURE.vcxproj will always be in the '[buildir]_vs' dir. proj_to_src_dir = self.build_to_src reconfigure_all_cmd = '' for buildtype in multi_config_buildtype_list: meson_build_dir_for_buildtype = build_dir_tail[:-2] + buildtype # Get the buildtype suffixed 'builddir_[debug/release/etc]' from 'builddir_vs', for example. proj_to_build_dir_for_buildtype = str(os.path.join(proj_to_multiconfigured_builds_parent_dir, meson_build_dir_for_buildtype)) reconfigure_all_cmd += f'{nmake_base_meson_command} setup --reconfigure "{proj_to_build_dir_for_buildtype}" "{proj_to_src_dir}"\n' ET.SubElement(all_configs_prop_group, 'NMakeBuildCommandLine').text = reconfigure_all_cmd ET.SubElement(all_configs_prop_group, 'NMakeReBuildCommandLine').text = reconfigure_all_cmd ET.SubElement(all_configs_prop_group, 'NMakeCleanCommandLine').text = '' #Need to set the 'ExecutablePath' element for the above NMake... commands to be able to execute ET.SubElement(all_configs_prop_group, 'ExecutablePath').text = exe_search_paths else: 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): project_name = 'RUN_TESTS' ofname = os.path.join(self.environment.get_build_dir(), f'{project_name}.vcxproj') guid = self.environment.coredata.test_guid if self.gen_lite: (root, type_config) = self.create_basic_project(project_name, temp_dir='install-temp', guid=guid, conftype='Makefile' ) (nmake_base_meson_command, exe_search_paths) = Vs2010Backend.get_nmake_base_meson_command_and_exe_search_paths() multi_config_buildtype_list = coredata.get_genvs_default_buildtype_list() (_, build_dir_tail) = os.path.split(self.src_to_build) proj_to_multiconfigured_builds_parent_dir = '..' # We know this .vcxproj will always be in the '[buildir]_vs' dir. # Add appropriate 'test' commands for the 'build' action of this project, for all buildtypes for buildtype in multi_config_buildtype_list: meson_build_dir_for_buildtype = build_dir_tail[:-2] + buildtype # Get the buildtype suffixed 'builddir_[debug/release/etc]' from 'builddir_vs', for example. proj_to_build_dir_for_buildtype = str(os.path.join(proj_to_multiconfigured_builds_parent_dir, meson_build_dir_for_buildtype)) test_cmd = f'{nmake_base_meson_command} test -C "{proj_to_build_dir_for_buildtype}" --no-rebuild' if not self.environment.coredata.get_option(OptionKey('stdsplit')): test_cmd += ' --no-stdsplit' if self.environment.coredata.get_option(OptionKey('errorlogs')): test_cmd += ' --print-errorlogs' condition = f'\'$(Configuration)|$(Platform)\'==\'{buildtype}|{self.platform}\'' prop_group = ET.SubElement(root, 'PropertyGroup', Condition=condition) ET.SubElement(prop_group, 'NMakeBuildCommandLine').text = test_cmd #Need to set the 'ExecutablePath' element for the NMake... commands to be able to execute ET.SubElement(prop_group, 'ExecutablePath').text = exe_search_paths else: (root, type_config) = self.create_basic_project(project_name, temp_dir='test-temp', guid=guid) 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_option(OptionKey('stdsplit')): test_command += ['--no-stdsplit'] if self.environment.coredata.get_option(OptionKey('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): project_name = 'RUN_INSTALL' ofname = os.path.join(self.environment.get_build_dir(), f'{project_name}.vcxproj') guid = self.environment.coredata.install_guid if self.gen_lite: (root, type_config) = self.create_basic_project(project_name, temp_dir='install-temp', guid=guid, conftype='Makefile' ) (nmake_base_meson_command, exe_search_paths) = Vs2010Backend.get_nmake_base_meson_command_and_exe_search_paths() multi_config_buildtype_list = coredata.get_genvs_default_buildtype_list() (_, build_dir_tail) = os.path.split(self.src_to_build) proj_to_multiconfigured_builds_parent_dir = '..' # We know this .vcxproj will always be in the '[buildir]_vs' dir. # Add appropriate 'install' commands for the 'build' action of this project, for all buildtypes for buildtype in multi_config_buildtype_list: meson_build_dir_for_buildtype = build_dir_tail[:-2] + buildtype # Get the buildtype suffixed 'builddir_[debug/release/etc]' from 'builddir_vs', for example. proj_to_build_dir_for_buildtype = str(os.path.join(proj_to_multiconfigured_builds_parent_dir, meson_build_dir_for_buildtype)) install_cmd = f'{nmake_base_meson_command} install -C "{proj_to_build_dir_for_buildtype}" --no-rebuild' condition = f'\'$(Configuration)|$(Platform)\'==\'{buildtype}|{self.platform}\'' prop_group = ET.SubElement(root, 'PropertyGroup', Condition=condition) ET.SubElement(prop_group, 'NMakeBuildCommandLine').text = install_cmd #Need to set the 'ExecutablePath' element for the NMake... commands to be able to execute ET.SubElement(prop_group, 'ExecutablePath').text = exe_search_paths else: self.create_install_data_files() (root, type_config) = self.create_basic_project(project_name, temp_dir='install-temp', guid=guid) 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: ET.Element, rulename: str, command: str, deps: T.Optional[T.List[str]] = None, outputs: T.Optional[T.List[str]] = None, msg: T.Optional[str] = None, verify_files: bool = True) -> 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 if not verify_files: ET.SubElement(custombuild, 'VerifyInputsAndOutputsExist').text = 'false' # If a command ever were to change the current directory or set local # variables this would need to be more complicated, as msbuild by # default executes all CustomBuilds in a project using the same # shell. Right now such tasks are all done inside the meson_exe # wrapper. The trailing newline appears to be necessary to allow # parallel custom builds to work. ET.SubElement(custombuild, 'Command').text = f"{command}\n" 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: str) -> str: i = 0 file = prefix while os.path.exists(file): file = '%s%d' % (prefix, i) return file def generate_debug_information(self, link: ET.Element) -> None: # valid values for vs2015 is 'false', 'true', 'DebugFastLink' ET.SubElement(link, 'GenerateDebugInformation').text = 'true' def add_regen_dependency(self, root: ET.Element) -> None: # For now, with 'genvslite' solutions, REGEN is replaced by the lighter-weight RECONFIGURE utility that is # no longer a forced build dependency. See comment in 'gen_regenproj' if not self.gen_lite: regen_vcxproj = os.path.join(self.environment.get_build_dir(), 'REGEN.vcxproj') self.add_project_reference(root, regen_vcxproj, self.environment.coredata.regen_guid) def generate_lang_standard_info(self, file_args: T.Dict[str, CompilerArgs], clconf: ET.Element) -> None: pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/backend/vs2012backend.py0000644000175000017500000000343114562742363021414 0ustar00jpakkanejpakkane# 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 __future__ import annotations import typing as T from .vs2010backend import Vs2010Backend from ..mesonlib import MesonException if T.TYPE_CHECKING: from ..build import Build from ..interpreter import Interpreter class Vs2012Backend(Vs2010Backend): name = 'vs2012' def __init__(self, build: T.Optional[Build], interpreter: T.Optional[Interpreter]): super().__init__(build, interpreter) self.vs_version = '2012' self.sln_file_version = '12.00' self.sln_version_comment = '2012' if self.environment is not None: # TODO: we assume host == build comps = self.environment.coredata.compilers.host if comps and all(c.id == 'intel-cl' for c in comps.values()): c = list(comps.values())[0] if c.version.startswith('19'): self.platform_toolset = 'Intel C++ Compiler 19.0' else: # We don't have support for versions older than 2019 right now. raise MesonException('There is currently no support for ICL before 19, patches welcome.') if self.platform_toolset is None: self.platform_toolset = 'v110' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/backend/vs2013backend.py0000644000175000017500000000343014562742363021414 0ustar00jpakkanejpakkane# 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 __future__ import annotations from .vs2010backend import Vs2010Backend from ..mesonlib import MesonException import typing as T if T.TYPE_CHECKING: from ..build import Build from ..interpreter import Interpreter class Vs2013Backend(Vs2010Backend): name = 'vs2013' def __init__(self, build: T.Optional[Build], interpreter: T.Optional[Interpreter]): super().__init__(build, interpreter) self.vs_version = '2013' self.sln_file_version = '12.00' self.sln_version_comment = '2013' if self.environment is not None: # TODO: we assume host == build comps = self.environment.coredata.compilers.host if comps and all(c.id == 'intel-cl' for c in comps.values()): c = list(comps.values())[0] if c.version.startswith('19'): self.platform_toolset = 'Intel C++ Compiler 19.0' else: # We don't have support for versions older than 2019 right now. raise MesonException('There is currently no support for ICL before 19, patches welcome.') if self.platform_toolset is None: self.platform_toolset = 'v120' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/backend/vs2015backend.py0000644000175000017500000000342714562742363021424 0ustar00jpakkanejpakkane# 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 __future__ import annotations import typing as T from .vs2010backend import Vs2010Backend from ..mesonlib import MesonException if T.TYPE_CHECKING: from ..build import Build from ..interpreter import Interpreter class Vs2015Backend(Vs2010Backend): name = 'vs2015' def __init__(self, build: T.Optional[Build], interpreter: T.Optional[Interpreter]): super().__init__(build, interpreter) self.vs_version = '2015' self.sln_file_version = '12.00' self.sln_version_comment = '14' 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' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/backend/vs2017backend.py0000644000175000017500000000566614562742363021435 0ustar00jpakkanejpakkane# 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 __future__ import annotations import os import typing as T import xml.etree.ElementTree as ET from .vs2010backend import Vs2010Backend from ..mesonlib import MesonException if T.TYPE_CHECKING: from ..build import Build from ..interpreter import Interpreter class Vs2017Backend(Vs2010Backend): name = 'vs2017' def __init__(self, build: T.Optional[Build], interpreter: T.Optional[Interpreter]): super().__init__(build, interpreter) self.vs_version = '2017' self.sln_file_version = '12.00' self.sln_version_comment = '15' # 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' def generate_lang_standard_info(self, file_args, clconf): if 'cpp' in file_args: optargs = [x for x in file_args['cpp'] if x.startswith('/std:c++')] if optargs: ET.SubElement(clconf, 'LanguageStandard').text = optargs[0].replace("/std:c++", "stdcpp") if 'c' in file_args: optargs = [x for x in file_args['c'] if x.startswith('/std:c')] if optargs: ET.SubElement(clconf, 'LanguageStandard_C').text = optargs[0].replace("/std:c", "stdc") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/backend/vs2019backend.py0000644000175000017500000000527214562742363021430 0ustar00jpakkanejpakkane# 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. from __future__ import annotations import os import typing as T import xml.etree.ElementTree as ET from .vs2010backend import Vs2010Backend if T.TYPE_CHECKING: from ..build import Build from ..interpreter import Interpreter class Vs2019Backend(Vs2010Backend): name = 'vs2019' def __init__(self, build: T.Optional[Build], interpreter: T.Optional[Interpreter]): super().__init__(build, interpreter) self.sln_file_version = '12.00' self.sln_version_comment = 'Version 16' 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 = 'ClangCL' 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' def generate_lang_standard_info(self, file_args, clconf): if 'cpp' in file_args: optargs = [x for x in file_args['cpp'] if x.startswith('/std:c++')] if optargs: ET.SubElement(clconf, 'LanguageStandard').text = optargs[0].replace("/std:c++", "stdcpp") if 'c' in file_args: optargs = [x for x in file_args['c'] if x.startswith('/std:c')] if optargs: ET.SubElement(clconf, 'LanguageStandard_C').text = optargs[0].replace("/std:c", "stdc") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/backend/vs2022backend.py0000644000175000017500000000534514562742363021423 0ustar00jpakkanejpakkane# Copyright 2014-2021 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import annotations import os import typing as T import xml.etree.ElementTree as ET from .vs2010backend import Vs2010Backend if T.TYPE_CHECKING: from ..build import Build from ..interpreter import Interpreter class Vs2022Backend(Vs2010Backend): name = 'vs2022' def __init__(self, build: T.Optional[Build], interpreter: T.Optional[Interpreter], gen_lite: bool = False): super().__init__(build, interpreter, gen_lite=gen_lite) self.sln_file_version = '12.00' self.sln_version_comment = 'Version 17' 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 = 'ClangCL' 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 2022 right now. if not self.platform_toolset: self.platform_toolset = 'v143' self.vs_version = '2022' # 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 vs2022 is 'false', 'true', 'DebugFastLink', 'DebugFull' ET.SubElement(link, 'GenerateDebugInformation').text = 'DebugFull' def generate_lang_standard_info(self, file_args, clconf): if 'cpp' in file_args: optargs = [x for x in file_args['cpp'] if x.startswith('/std:c++')] if optargs: ET.SubElement(clconf, 'LanguageStandard').text = optargs[0].replace("/std:c++", "stdcpp") if 'c' in file_args: optargs = [x for x in file_args['c'] if x.startswith('/std:c')] if optargs: ET.SubElement(clconf, 'LanguageStandard_C').text = optargs[0].replace("/std:c", "stdc") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/backend/xcodebackend.py0000644000175000017500000025065714562742363021577 0ustar00jpakkanejpakkane# Copyright 2014-2021 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import annotations import uuid, os, operator import typing as T from . import backends from .. import build from .. import mesonlib from .. import mlog from ..mesonlib import MesonBugException, MesonException, OptionKey if T.TYPE_CHECKING: from ..interpreter import Interpreter INDENT = '\t' 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', 'swift': 'sourcecode.swift', 'dylib': 'compiled.mach-o.dylib', 'o': 'compiled.mach-o.objfile', 's': 'sourcecode.asm', 'asm': 'sourcecode.asm', } LANGNAMEMAP = {'c': 'C', 'cpp': 'CPLUSPLUS', 'objc': 'OBJC', 'objcpp': 'OBJCPLUSPLUS', 'swift': 'SWIFT_' } OPT2XCODEOPT = {'plain': None, '0': '0', 'g': '0', '1': '1', '2': '2', '3': '3', 's': 's', } BOOL2XCODEBOOL = {True: 'YES', False: 'NO'} LINKABLE_EXTENSIONS = {'.o', '.a', '.obj', '.so', '.dylib'} class FileTreeEntry: def __init__(self) -> None: self.subdirs = {} self.targets = [] class PbxArray: def __init__(self) -> None: self.items = [] def add_item(self, item: T.Union[PbxArrayItem, str], comment: str = '') -> None: if isinstance(item, PbxArrayItem): self.items.append(item) else: self.items.append(PbxArrayItem(item, comment)) def write(self, ofile: T.TextIO, indent_level: int) -> None: ofile.write('(\n') indent_level += 1 for i in self.items: if i.comment: ofile.write(indent_level*INDENT + f'{i.value} {i.comment},\n') else: ofile.write(indent_level*INDENT + f'{i.value},\n') indent_level -= 1 ofile.write(indent_level*INDENT + ');\n') class PbxArrayItem: def __init__(self, value: str, comment: str = ''): self.value = value if comment: if '/*' in comment: self.comment = comment else: self.comment = f'/* {comment} */' else: self.comment = comment class PbxComment: def __init__(self, text: str): assert isinstance(text, str) assert '/*' not in text self.text = f'/* {text} */' def write(self, ofile: T.TextIO, indent_level: int) -> None: ofile.write(f'\n{self.text}\n') class PbxDictItem: def __init__(self, key: str, value: T.Union[PbxArray, PbxDict, str, int], comment: str = ''): self.key = key self.value = value if comment: if '/*' in comment: self.comment = comment else: self.comment = f'/* {comment} */' else: self.comment = comment class PbxDict: def __init__(self) -> None: # This class is a bit weird, because we want to write PBX dicts in # defined order _and_ we want to write intermediate comments also in order. self.keys = set() self.items = [] def add_item(self, key: str, value: T.Union[PbxArray, PbxDict, str, int], comment: str = '') -> None: assert key not in self.keys item = PbxDictItem(key, value, comment) self.keys.add(key) self.items.append(item) def has_item(self, key): return key in self.keys def add_comment(self, comment: PbxComment) -> None: assert isinstance(comment, PbxComment) self.items.append(comment) def write(self, ofile: T.TextIO, indent_level: int) -> None: ofile.write('{\n') indent_level += 1 for i in self.items: if isinstance(i, PbxComment): i.write(ofile, indent_level) elif isinstance(i, PbxDictItem): if isinstance(i.value, (str, int)): if i.comment: ofile.write(indent_level*INDENT + f'{i.key} = {i.value} {i.comment};\n') else: ofile.write(indent_level*INDENT + f'{i.key} = {i.value};\n') elif isinstance(i.value, PbxDict): if i.comment: ofile.write(indent_level*INDENT + f'{i.key} {i.comment} = ') else: ofile.write(indent_level*INDENT + f'{i.key} = ') i.value.write(ofile, indent_level) elif isinstance(i.value, PbxArray): if i.comment: ofile.write(indent_level*INDENT + f'{i.key} {i.comment} = ') else: ofile.write(indent_level*INDENT + f'{i.key} = ') i.value.write(ofile, indent_level) else: print(i) print(i.key) print(i.value) raise RuntimeError('missing code') else: print(i) raise RuntimeError('missing code2') indent_level -= 1 ofile.write(indent_level*INDENT + '}') if indent_level == 0: ofile.write('\n') else: ofile.write(';\n') class XCodeBackend(backends.Backend): name = 'xcode' def __init__(self, build: T.Optional[build.Build], interpreter: T.Optional[Interpreter]): super().__init__(build, interpreter) self.project_uid = self.environment.coredata.lang_guids['default'].replace('-', '')[:24] self.buildtype = T.cast('str', self.environment.coredata.get_option(OptionKey('buildtype'))) self.project_conflist = self.gen_id() self.maingroup_id = self.gen_id() self.all_id = self.gen_id() self.all_buildconf_id = self.gen_id() self.buildtypes = [self.buildtype] self.test_id = self.gen_id() self.test_command_id = self.gen_id() self.test_buildconf_id = self.gen_id() self.regen_id = self.gen_id() self.regen_command_id = self.gen_id() self.regen_buildconf_id = self.gen_id() self.regen_dependency_id = self.gen_id() self.top_level_dict = PbxDict() self.generator_outputs = {} # In Xcode files are not accessed via their file names, but rather every one of them # gets an unique id. More precisely they get one unique id per target they are used # in. If you generate only one id per file and use them, compilation will work but the # UI will only show the file in one target but not the others. Thus they key is # a tuple containing the target and filename. self.buildfile_ids = {} # That is not enough, though. Each target/file combination also gets a unique id # in the file reference section. Because why not. This means that a source file # that is used in two targets gets a total of four unique ID numbers. self.fileref_ids = {} def write_pbxfile(self, top_level_dict, ofilename): tmpname = ofilename + '.tmp' with open(tmpname, 'w', encoding='utf-8') as ofile: ofile.write('// !$*UTF8*$!\n') top_level_dict.write(ofile, 0) os.replace(tmpname, ofilename) def gen_id(self) -> str: return str(uuid.uuid4()).upper().replace('-', '')[:24] def get_target_dir(self, target): dirname = os.path.join(target.get_subdir(), T.cast('str', self.environment.coredata.get_option(OptionKey('buildtype')))) #os.makedirs(os.path.join(self.environment.get_build_dir(), dirname), exist_ok=True) return dirname def get_custom_target_output_dir(self, target): dirname = target.get_subdir() 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 object_filename_from_source(self, target, source): # Xcode has the following naming scheme: # projectname.build/debug/prog@exe.build/Objects-normal/x86_64/func.o project = self.build.project_name buildtype = self.buildtype tname = target.get_id() arch = 'x86_64' if isinstance(source, mesonlib.File): source = source.fname stem = os.path.splitext(os.path.basename(source))[0] obj_path = f'{project}.build/{buildtype}/{tname}.build/Objects-normal/{arch}/{stem}.o' return obj_path def generate(self, capture: bool = False, vslite_ctx: dict = None) -> T.Optional[dict]: # Check for (currently) unexpected capture arg use cases - if capture: raise MesonBugException('We do not expect the xcode backend to generate with \'capture = True\'') if vslite_ctx: raise MesonBugException('We do not expect the xcode backend to be given a valid \'vslite_ctx\'') self.serialize_tests() # Cache the result as the method rebuilds the array every time it is called. self.build_targets = self.build.get_build_targets() self.custom_targets = self.build.get_custom_targets() self.generate_filemap() 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_custom_target_map() self.generate_generator_target_map() self.generate_source_phase_map() self.generate_target_dependency_map() self.generate_pbxdep_map() self.generate_containerproxy_map() self.generate_target_file_maps() self.generate_build_file_maps() 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') objects_dict = self.generate_prefix(self.top_level_dict) objects_dict.add_comment(PbxComment('Begin PBXAggregateTarget section')) self.generate_pbx_aggregate_target(objects_dict) objects_dict.add_comment(PbxComment('End PBXAggregateTarget section')) objects_dict.add_comment(PbxComment('Begin PBXBuildFile section')) self.generate_pbx_build_file(objects_dict) objects_dict.add_comment(PbxComment('End PBXBuildFile section')) objects_dict.add_comment(PbxComment('Begin PBXBuildStyle section')) self.generate_pbx_build_style(objects_dict) objects_dict.add_comment(PbxComment('End PBXBuildStyle section')) objects_dict.add_comment(PbxComment('Begin PBXContainerItemProxy section')) self.generate_pbx_container_item_proxy(objects_dict) objects_dict.add_comment(PbxComment('End PBXContainerItemProxy section')) objects_dict.add_comment(PbxComment('Begin PBXFileReference section')) self.generate_pbx_file_reference(objects_dict) objects_dict.add_comment(PbxComment('End PBXFileReference section')) objects_dict.add_comment(PbxComment('Begin PBXFrameworksBuildPhase section')) self.generate_pbx_frameworks_buildphase(objects_dict) objects_dict.add_comment(PbxComment('End PBXFrameworksBuildPhase section')) objects_dict.add_comment(PbxComment('Begin PBXGroup section')) self.generate_pbx_group(objects_dict) objects_dict.add_comment(PbxComment('End PBXGroup section')) objects_dict.add_comment(PbxComment('Begin PBXNativeTarget section')) self.generate_pbx_native_target(objects_dict) objects_dict.add_comment(PbxComment('End PBXNativeTarget section')) objects_dict.add_comment(PbxComment('Begin PBXProject section')) self.generate_pbx_project(objects_dict) objects_dict.add_comment(PbxComment('End PBXProject section')) objects_dict.add_comment(PbxComment('Begin PBXShellScriptBuildPhase section')) self.generate_pbx_shell_build_phase(objects_dict) objects_dict.add_comment(PbxComment('End PBXShellScriptBuildPhase section')) objects_dict.add_comment(PbxComment('Begin PBXSourcesBuildPhase section')) self.generate_pbx_sources_build_phase(objects_dict) objects_dict.add_comment(PbxComment('End PBXSourcesBuildPhase section')) objects_dict.add_comment(PbxComment('Begin PBXTargetDependency section')) self.generate_pbx_target_dependency(objects_dict) objects_dict.add_comment(PbxComment('End PBXTargetDependency section')) objects_dict.add_comment(PbxComment('Begin XCBuildConfiguration section')) self.generate_xc_build_configuration(objects_dict) objects_dict.add_comment(PbxComment('End XCBuildConfiguration section')) objects_dict.add_comment(PbxComment('Begin XCConfigurationList section')) self.generate_xc_configurationList(objects_dict) objects_dict.add_comment(PbxComment('End XCConfigurationList section')) self.generate_suffix(self.top_level_dict) self.write_pbxfile(self.top_level_dict, self.proj_file) self.generate_regen_info() def get_xcodetype(self, fname): extension = fname.split('.')[-1] if extension == 'C': extension = 'cpp' xcodetype = XCODETYPEMAP.get(extension.lower()) if not xcodetype: xcodetype = 'sourcecode.unknown' return xcodetype def generate_filemap(self) -> None: 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_buildstylemap(self) -> None: self.buildstylemap = {self.buildtype: self.gen_id()} def generate_build_phase_map(self) -> None: 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) -> None: self.buildconfmap = {} for t in self.build_targets: bconfs = {self.buildtype: self.gen_id()} self.buildconfmap[t] = bconfs for t in self.custom_targets: bconfs = {self.buildtype: self.gen_id()} self.buildconfmap[t] = bconfs def generate_project_configurations_map(self) -> None: self.project_configurations = {self.buildtype: self.gen_id()} def generate_buildall_configurations_map(self) -> None: self.buildall_configurations = {self.buildtype: self.gen_id()} def generate_test_configurations_map(self) -> None: self.test_configurations = {self.buildtype: self.gen_id()} def generate_build_configurationlist_map(self) -> None: self.buildconflistmap = {} for t in self.build_targets: self.buildconflistmap[t] = self.gen_id() for t in self.custom_targets: self.buildconflistmap[t] = self.gen_id() def generate_native_target_map(self) -> None: self.native_targets = {} for t in self.build_targets: self.native_targets[t] = self.gen_id() def generate_custom_target_map(self) -> None: self.shell_targets = {} self.custom_target_output_buildfile = {} self.custom_target_output_fileref = {} for tname, t in self.custom_targets.items(): self.shell_targets[tname] = self.gen_id() if not isinstance(t, build.CustomTarget): continue (srcs, ofilenames, cmd) = self.eval_custom_target_command(t) for o in ofilenames: self.custom_target_output_buildfile[o] = self.gen_id() self.custom_target_output_fileref[o] = self.gen_id() def generate_generator_target_map(self) -> None: # Generator objects do not have natural unique ids # so use a counter. self.generator_fileref_ids = {} self.generator_buildfile_ids = {} for tname, t in self.build_targets.items(): generator_id = 0 for genlist in t.generated: if not isinstance(genlist, build.GeneratedList): continue self.gen_single_target_map(genlist, tname, t, generator_id) generator_id += 1 # FIXME add outputs. for tname, t in self.custom_targets.items(): generator_id = 0 for genlist in t.sources: if not isinstance(genlist, build.GeneratedList): continue self.gen_single_target_map(genlist, tname, t, generator_id) generator_id += 1 def gen_single_target_map(self, genlist, tname, t, generator_id): k = (tname, generator_id) assert k not in self.shell_targets self.shell_targets[k] = self.gen_id() ofile_abs = [] for i in genlist.get_inputs(): for o_base in genlist.get_outputs_for(i): o = os.path.join(self.get_target_private_dir(t), o_base) ofile_abs.append(os.path.join(self.environment.get_build_dir(), o)) assert k not in self.generator_outputs self.generator_outputs[k] = ofile_abs buildfile_ids = [] fileref_ids = [] for i in range(len(ofile_abs)): buildfile_ids.append(self.gen_id()) fileref_ids.append(self.gen_id()) self.generator_buildfile_ids[k] = buildfile_ids self.generator_fileref_ids[k] = fileref_ids def generate_native_frameworks_map(self) -> None: self.native_frameworks = {} self.native_frameworks_fileref = {} for t in self.build_targets.values(): for dep in t.get_external_deps(): if dep.name == '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) -> None: self.target_dependency_map = {} for tname, t in self.build_targets.items(): for target in t.link_targets: if isinstance(target, build.CustomTargetIndex): k = (tname, target.target.get_basename()) if k in self.target_dependency_map: continue else: k = (tname, target.get_basename()) assert k not in self.target_dependency_map self.target_dependency_map[k] = self.gen_id() for tname, t in self.custom_targets.items(): k = tname assert k not in self.target_dependency_map self.target_dependency_map[k] = self.gen_id() def generate_pbxdep_map(self) -> None: self.pbx_dep_map = {} self.pbx_custom_dep_map = {} for t in self.build_targets: self.pbx_dep_map[t] = self.gen_id() for t in self.custom_targets: self.pbx_custom_dep_map[t] = self.gen_id() def generate_containerproxy_map(self) -> None: self.containerproxy_map = {} for t in self.build_targets: self.containerproxy_map[t] = self.gen_id() def generate_target_file_maps(self) -> None: self.generate_target_file_maps_impl(self.build_targets) self.generate_target_file_maps_impl(self.custom_targets) def generate_target_file_maps_impl(self, targets): for tname, t in targets.items(): for s in t.sources: if isinstance(s, mesonlib.File): s = os.path.join(s.subdir, s.fname) if not isinstance(s, str): continue k = (tname, s) assert k not in self.buildfile_ids self.buildfile_ids[k] = self.gen_id() assert k not in self.fileref_ids self.fileref_ids[k] = self.gen_id() if not hasattr(t, 'objects'): continue for o in t.objects: if isinstance(o, build.ExtractedObjects): # Extracted objects do not live in "the Xcode world". continue if isinstance(o, mesonlib.File): o = os.path.join(o.subdir, o.fname) if isinstance(o, str): o = os.path.join(t.subdir, o) k = (tname, o) assert k not in self.buildfile_ids self.buildfile_ids[k] = self.gen_id() assert k not in self.fileref_ids self.fileref_ids[k] = self.gen_id() else: raise RuntimeError('Unknown input type ' + str(o)) def generate_build_file_maps(self) -> None: for buildfile in self.interpreter.get_build_def_files(): assert isinstance(buildfile, str) self.buildfile_ids[buildfile] = self.gen_id() self.fileref_ids[buildfile] = self.gen_id() def generate_source_phase_map(self) -> None: self.source_phase = {} for t in self.build_targets: self.source_phase[t] = self.gen_id() def generate_pbx_aggregate_target(self, objects_dict): self.custom_aggregate_targets = {} self.build_all_tdep_id = self.gen_id() # FIXME: filter out targets that are not built by default. target_dependencies = [self.pbx_dep_map[t] for t in self.build_targets] custom_target_dependencies = [self.pbx_custom_dep_map[t] for t in self.custom_targets] aggregated_targets = [] aggregated_targets.append((self.all_id, 'ALL_BUILD', self.all_buildconf_id, [], [self.regen_dependency_id] + target_dependencies + custom_target_dependencies)) aggregated_targets.append((self.test_id, 'RUN_TESTS', self.test_buildconf_id, [self.test_command_id], [self.regen_dependency_id, self.build_all_tdep_id])) aggregated_targets.append((self.regen_id, 'REGENERATE', self.regen_buildconf_id, [self.regen_command_id], [])) for tname, t in self.build.get_custom_targets().items(): ct_id = self.gen_id() self.custom_aggregate_targets[tname] = ct_id build_phases = [] dependencies = [self.regen_dependency_id] generator_id = 0 for s in t.sources: if not isinstance(s, build.GeneratedList): continue build_phases.append(self.shell_targets[(tname, generator_id)]) for d in s.depends: dependencies.append(self.pbx_custom_dep_map[d.get_id()]) generator_id += 1 build_phases.append(self.shell_targets[tname]) aggregated_targets.append((ct_id, tname, self.buildconflistmap[tname], build_phases, dependencies)) # Sort objects by ID before writing sorted_aggregated_targets = sorted(aggregated_targets, key=operator.itemgetter(0)) for t in sorted_aggregated_targets: agt_dict = PbxDict() name = t[1] buildconf_id = t[2] build_phases = t[3] dependencies = t[4] agt_dict.add_item('isa', 'PBXAggregateTarget') agt_dict.add_item('buildConfigurationList', buildconf_id, f'Build configuration list for PBXAggregateTarget "{name}"') bp_arr = PbxArray() agt_dict.add_item('buildPhases', bp_arr) for bp in build_phases: bp_arr.add_item(bp, 'ShellScript') dep_arr = PbxArray() agt_dict.add_item('dependencies', dep_arr) for td in dependencies: dep_arr.add_item(td, 'PBXTargetDependency') agt_dict.add_item('name', f'"{name}"') agt_dict.add_item('productName', f'"{name}"') objects_dict.add_item(t[0], agt_dict, name) def generate_pbx_build_file(self, objects_dict): for tname, t in self.build_targets.items(): for dep in t.get_external_deps(): if dep.name == 'appleframeworks': for f in dep.frameworks: fw_dict = PbxDict() fwkey = self.native_frameworks[f] if fwkey not in objects_dict.keys: objects_dict.add_item(fwkey, fw_dict, f'{f}.framework in Frameworks') fw_dict.add_item('isa', 'PBXBuildFile') fw_dict.add_item('fileRef', self.native_frameworks_fileref[f], f) for s in t.sources: in_build_dir = False if isinstance(s, mesonlib.File): if s.is_built: in_build_dir = True s = os.path.join(s.subdir, s.fname) if not isinstance(s, str): continue sdict = PbxDict() k = (tname, s) idval = self.buildfile_ids[k] fileref = self.fileref_ids[k] if in_build_dir: fullpath = os.path.join(self.environment.get_build_dir(), s) else: fullpath = os.path.join(self.environment.get_source_dir(), s) sdict.add_item('isa', 'PBXBuildFile') sdict.add_item('fileRef', fileref, fullpath) objects_dict.add_item(idval, sdict) for o in t.objects: if isinstance(o, build.ExtractedObjects): # Object files are not source files as such. We add them # by hand in linker flags. It is also not particularly # clear how to define build files in Xcode's file format. continue if isinstance(o, mesonlib.File): o = os.path.join(o.subdir, o.fname) elif isinstance(o, str): o = os.path.join(t.subdir, o) idval = self.buildfile_ids[(tname, o)] k = (tname, o) fileref = self.fileref_ids[k] assert o not in self.filemap self.filemap[o] = idval fullpath = os.path.join(self.environment.get_source_dir(), o) fullpath2 = fullpath o_dict = PbxDict() objects_dict.add_item(idval, o_dict, fullpath) o_dict.add_item('isa', 'PBXBuildFile') o_dict.add_item('fileRef', fileref, fullpath2) generator_id = 0 for g in t.generated: if not isinstance(g, build.GeneratedList): continue self.create_generator_shellphase(objects_dict, tname, generator_id) generator_id += 1 # Custom targets are shell build phases in Xcode terminology. for tname, t in self.custom_targets.items(): if not isinstance(t, build.CustomTarget): continue (srcs, ofilenames, cmd) = self.eval_custom_target_command(t) for o in ofilenames: custom_dict = PbxDict() objects_dict.add_item(self.custom_target_output_buildfile[o], custom_dict, f'/* {o} */') custom_dict.add_item('isa', 'PBXBuildFile') custom_dict.add_item('fileRef', self.custom_target_output_fileref[o]) generator_id = 0 for g in t.sources: if not isinstance(g, build.GeneratedList): continue self.create_generator_shellphase(objects_dict, tname, generator_id) generator_id += 1 def create_generator_shellphase(self, objects_dict, tname, generator_id): file_ids = self.generator_buildfile_ids[(tname, generator_id)] ref_ids = self.generator_fileref_ids[(tname, generator_id)] assert len(ref_ids) == len(file_ids) for file_o, ref_id in zip(file_ids, ref_ids): odict = PbxDict() objects_dict.add_item(file_o, odict) odict.add_item('isa', 'PBXBuildFile') odict.add_item('fileRef', ref_id) def generate_pbx_build_style(self, objects_dict): # FIXME: Xcode 9 and later does not uses PBXBuildStyle and it gets removed. Maybe we can remove this part. for name, idval in self.buildstylemap.items(): styledict = PbxDict() objects_dict.add_item(idval, styledict, name) styledict.add_item('isa', 'PBXBuildStyle') settings_dict = PbxDict() styledict.add_item('buildSettings', settings_dict) settings_dict.add_item('COPY_PHASE_STRIP', 'NO') styledict.add_item('name', f'"{name}"') def generate_pbx_container_item_proxy(self, objects_dict): for t in self.build_targets: proxy_dict = PbxDict() objects_dict.add_item(self.containerproxy_map[t], proxy_dict, 'PBXContainerItemProxy') proxy_dict.add_item('isa', 'PBXContainerItemProxy') proxy_dict.add_item('containerPortal', self.project_uid, 'Project object') proxy_dict.add_item('proxyType', '1') proxy_dict.add_item('remoteGlobalIDString', self.native_targets[t]) proxy_dict.add_item('remoteInfo', '"' + t + '"') def generate_pbx_file_reference(self, objects_dict): for tname, t in self.build_targets.items(): for dep in t.get_external_deps(): if dep.name == 'appleframeworks': for f in dep.frameworks: fw_dict = PbxDict() framework_fileref = self.native_frameworks_fileref[f] if objects_dict.has_item(framework_fileref): continue objects_dict.add_item(framework_fileref, fw_dict, f) fw_dict.add_item('isa', 'PBXFileReference') fw_dict.add_item('lastKnownFileType', 'wrapper.framework') fw_dict.add_item('name', f'{f}.framework') fw_dict.add_item('path', f'System/Library/Frameworks/{f}.framework') fw_dict.add_item('sourceTree', 'SDKROOT') for s in t.sources: in_build_dir = False if isinstance(s, mesonlib.File): if s.is_built: in_build_dir = True s = os.path.join(s.subdir, s.fname) if not isinstance(s, str): continue idval = self.fileref_ids[(tname, s)] fullpath = os.path.join(self.environment.get_source_dir(), s) src_dict = PbxDict() xcodetype = self.get_xcodetype(s) name = os.path.basename(s) path = s objects_dict.add_item(idval, src_dict, fullpath) src_dict.add_item('isa', 'PBXFileReference') src_dict.add_item('explicitFileType', '"' + xcodetype + '"') src_dict.add_item('fileEncoding', '4') if in_build_dir: src_dict.add_item('name', '"' + name + '"') # This makes no sense. This should say path instead of name # but then the path gets added twice. src_dict.add_item('path', '"' + name + '"') src_dict.add_item('sourceTree', 'BUILD_ROOT') else: src_dict.add_item('name', '"' + name + '"') src_dict.add_item('path', '"' + path + '"') src_dict.add_item('sourceTree', 'SOURCE_ROOT') generator_id = 0 for g in t.generated: if not isinstance(g, build.GeneratedList): continue outputs = self.generator_outputs[(tname, generator_id)] ref_ids = self.generator_fileref_ids[tname, generator_id] assert len(ref_ids) == len(outputs) for o, ref_id in zip(outputs, ref_ids): odict = PbxDict() name = os.path.basename(o) objects_dict.add_item(ref_id, odict, o) xcodetype = self.get_xcodetype(o) rel_name = mesonlib.relpath(o, self.environment.get_source_dir()) odict.add_item('isa', 'PBXFileReference') odict.add_item('explicitFileType', '"' + xcodetype + '"') odict.add_item('fileEncoding', '4') odict.add_item('name', f'"{name}"') odict.add_item('path', f'"{rel_name}"') odict.add_item('sourceTree', 'SOURCE_ROOT') generator_id += 1 for o in t.objects: if isinstance(o, build.ExtractedObjects): # Same as with pbxbuildfile. continue if isinstance(o, mesonlib.File): fullpath = o.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir()) o = os.path.join(o.subdir, o.fname) else: o = os.path.join(t.subdir, o) fullpath = os.path.join(self.environment.get_source_dir(), o) idval = self.fileref_ids[(tname, o)] rel_name = mesonlib.relpath(fullpath, self.environment.get_source_dir()) o_dict = PbxDict() name = os.path.basename(o) objects_dict.add_item(idval, o_dict, fullpath) o_dict.add_item('isa', 'PBXFileReference') o_dict.add_item('explicitFileType', '"' + self.get_xcodetype(o) + '"') o_dict.add_item('fileEncoding', '4') o_dict.add_item('name', f'"{name}"') o_dict.add_item('path', f'"{rel_name}"') o_dict.add_item('sourceTree', 'SOURCE_ROOT') for tname, idval in self.target_filemap.items(): target_dict = PbxDict() objects_dict.add_item(idval, target_dict, tname) 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() target_dict.add_item('isa', 'PBXFileReference') target_dict.add_item('explicitFileType', '"' + typestr + '"') if ' ' in path and path[0] != '"': target_dict.add_item('path', f'"{path}"') else: target_dict.add_item('path', path) target_dict.add_item('refType', reftype) target_dict.add_item('sourceTree', 'BUILT_PRODUCTS_DIR') for tname, t in self.custom_targets.items(): if not isinstance(t, build.CustomTarget): continue (srcs, ofilenames, cmd) = self.eval_custom_target_command(t) for s in t.sources: if isinstance(s, mesonlib.File): s = os.path.join(s.subdir, s.fname) elif isinstance(s, str): s = os.path.join(t.subdir, s) else: continue custom_dict = PbxDict() typestr = self.get_xcodetype(s) custom_dict.add_item('isa', 'PBXFileReference') custom_dict.add_item('explicitFileType', '"' + typestr + '"') custom_dict.add_item('name', f'"{s}"') custom_dict.add_item('path', f'"{s}"') custom_dict.add_item('refType', 0) custom_dict.add_item('sourceTree', 'SOURCE_ROOT') objects_dict.add_item(self.fileref_ids[(tname, s)], custom_dict) for o in ofilenames: custom_dict = PbxDict() typestr = self.get_xcodetype(o) custom_dict.add_item('isa', 'PBXFileReference') custom_dict.add_item('explicitFileType', '"' + typestr + '"') custom_dict.add_item('name', o) custom_dict.add_item('path', os.path.join(self.src_to_build, o)) custom_dict.add_item('refType', 0) custom_dict.add_item('sourceTree', 'SOURCE_ROOT') objects_dict.add_item(self.custom_target_output_fileref[o], custom_dict) for buildfile in self.interpreter.get_build_def_files(): basename = os.path.split(buildfile)[1] buildfile_dict = PbxDict() typestr = self.get_xcodetype(buildfile) buildfile_dict.add_item('isa', 'PBXFileReference') buildfile_dict.add_item('explicitFileType', '"' + typestr + '"') buildfile_dict.add_item('name', f'"{basename}"') buildfile_dict.add_item('path', f'"{buildfile}"') buildfile_dict.add_item('refType', 0) buildfile_dict.add_item('sourceTree', 'SOURCE_ROOT') objects_dict.add_item(self.fileref_ids[buildfile], buildfile_dict) def generate_pbx_frameworks_buildphase(self, objects_dict): for t in self.build_targets.values(): bt_dict = PbxDict() objects_dict.add_item(t.buildphasemap['Frameworks'], bt_dict, 'Frameworks') bt_dict.add_item('isa', 'PBXFrameworksBuildPhase') bt_dict.add_item('buildActionMask', 2147483647) file_list = PbxArray() bt_dict.add_item('files', file_list) for dep in t.get_external_deps(): if dep.name == 'appleframeworks': for f in dep.frameworks: file_list.add_item(self.native_frameworks[f], f'{f}.framework in Frameworks') bt_dict.add_item('runOnlyForDeploymentPostprocessing', 0) def generate_pbx_group(self, objects_dict): groupmap = {} target_src_map = {} for t in self.build_targets: groupmap[t] = self.gen_id() target_src_map[t] = self.gen_id() for t in self.custom_targets: groupmap[t] = self.gen_id() target_src_map[t] = self.gen_id() projecttree_id = self.gen_id() resources_id = self.gen_id() products_id = self.gen_id() frameworks_id = self.gen_id() main_dict = PbxDict() objects_dict.add_item(self.maingroup_id, main_dict) main_dict.add_item('isa', 'PBXGroup') main_children = PbxArray() main_dict.add_item('children', main_children) main_children.add_item(projecttree_id, 'Project tree') main_children.add_item(resources_id, 'Resources') main_children.add_item(products_id, 'Products') main_children.add_item(frameworks_id, 'Frameworks') main_dict.add_item('sourceTree', '""') self.add_projecttree(objects_dict, projecttree_id) resource_dict = PbxDict() objects_dict.add_item(resources_id, resource_dict, 'Resources') resource_dict.add_item('isa', 'PBXGroup') resource_children = PbxArray() resource_dict.add_item('children', resource_children) resource_dict.add_item('name', 'Resources') resource_dict.add_item('sourceTree', '""') frameworks_dict = PbxDict() objects_dict.add_item(frameworks_id, frameworks_dict, 'Frameworks') frameworks_dict.add_item('isa', 'PBXGroup') frameworks_children = PbxArray() frameworks_dict.add_item('children', frameworks_children) # write frameworks for t in self.build_targets.values(): for dep in t.get_external_deps(): if dep.name == 'appleframeworks': for f in dep.frameworks: frameworks_children.add_item(self.native_frameworks_fileref[f], f) frameworks_dict.add_item('name', 'Frameworks') frameworks_dict.add_item('sourceTree', '""') for tname, t in self.custom_targets.items(): target_dict = PbxDict() objects_dict.add_item(groupmap[tname], target_dict, tname) target_dict.add_item('isa', 'PBXGroup') target_children = PbxArray() target_dict.add_item('children', target_children) target_children.add_item(target_src_map[tname], 'Source files') if t.subproject: target_dict.add_item('name', f'"{t.subproject} • {t.name}"') else: target_dict.add_item('name', f'"{t.name}"') target_dict.add_item('sourceTree', '""') source_files_dict = PbxDict() objects_dict.add_item(target_src_map[tname], source_files_dict, 'Source files') source_files_dict.add_item('isa', 'PBXGroup') source_file_children = PbxArray() source_files_dict.add_item('children', source_file_children) for s in t.sources: if isinstance(s, mesonlib.File): s = os.path.join(s.subdir, s.fname) elif isinstance(s, str): s = os.path.join(t.subdir, s) else: continue source_file_children.add_item(self.fileref_ids[(tname, s)], s) source_files_dict.add_item('name', '"Source files"') source_files_dict.add_item('sourceTree', '""') # And finally products product_dict = PbxDict() objects_dict.add_item(products_id, product_dict, 'Products') product_dict.add_item('isa', 'PBXGroup') product_children = PbxArray() product_dict.add_item('children', product_children) for t in self.build_targets: product_children.add_item(self.target_filemap[t], t) product_dict.add_item('name', 'Products') product_dict.add_item('sourceTree', '""') def write_group_target_entry(self, objects_dict, t): tid = t.get_id() group_id = self.gen_id() target_dict = PbxDict() objects_dict.add_item(group_id, target_dict, tid) target_dict.add_item('isa', 'PBXGroup') target_children = PbxArray() target_dict.add_item('children', target_children) target_dict.add_item('name', f'"{t} Ā· target"') target_dict.add_item('sourceTree', '""') source_files_dict = PbxDict() for s in t.sources: if isinstance(s, mesonlib.File): s = os.path.join(s.subdir, s.fname) elif isinstance(s, str): s = os.path.join(t.subdir, s) else: continue target_children.add_item(self.fileref_ids[(tid, s)], s) for o in t.objects: if isinstance(o, build.ExtractedObjects): # Do not show built object files in the project tree. continue if isinstance(o, mesonlib.File): o = os.path.join(o.subdir, o.fname) else: o = os.path.join(t.subdir, o) target_children.add_item(self.fileref_ids[(tid, o)], o) source_files_dict.add_item('name', '"Source files"') source_files_dict.add_item('sourceTree', '""') return group_id def add_projecttree(self, objects_dict, projecttree_id): root_dict = PbxDict() objects_dict.add_item(projecttree_id, root_dict, "Root of project tree") root_dict.add_item('isa', 'PBXGroup') target_children = PbxArray() root_dict.add_item('children', target_children) root_dict.add_item('name', '"Project root"') root_dict.add_item('sourceTree', '""') project_tree = self.generate_project_tree() self.write_tree(objects_dict, project_tree, target_children, '') def write_tree(self, objects_dict, tree_node, children_array, current_subdir): for subdir_name, subdir_node in tree_node.subdirs.items(): subdir_dict = PbxDict() subdir_children = PbxArray() subdir_id = self.gen_id() objects_dict.add_item(subdir_id, subdir_dict) children_array.add_item(subdir_id) subdir_dict.add_item('isa', 'PBXGroup') subdir_dict.add_item('children', subdir_children) subdir_dict.add_item('name', f'"{subdir_name}"') subdir_dict.add_item('sourceTree', '""') self.write_tree(objects_dict, subdir_node, subdir_children, os.path.join(current_subdir, subdir_name)) for target in tree_node.targets: group_id = self.write_group_target_entry(objects_dict, target) children_array.add_item(group_id) potentials = [os.path.join(current_subdir, 'meson.build'), os.path.join(current_subdir, 'meson.options'), os.path.join(current_subdir, 'meson_options.txt')] for bf in potentials: i = self.fileref_ids.get(bf, None) if i: children_array.add_item(i) def generate_project_tree(self): tree_info = FileTreeEntry() for tname, t in self.build_targets.items(): self.add_target_to_tree(tree_info, t) return tree_info def add_target_to_tree(self, tree_root, t): current_node = tree_root path_segments = t.subdir.split('/') for s in path_segments: if not s: continue if s not in current_node.subdirs: current_node.subdirs[s] = FileTreeEntry() current_node = current_node.subdirs[s] current_node.targets.append(t) def generate_pbx_native_target(self, objects_dict): for tname, idval in self.native_targets.items(): ntarget_dict = PbxDict() t = self.build_targets[tname] objects_dict.add_item(idval, ntarget_dict, tname) ntarget_dict.add_item('isa', 'PBXNativeTarget') ntarget_dict.add_item('buildConfigurationList', self.buildconflistmap[tname], f'Build configuration list for PBXNativeTarget "{tname}"') buildphases_array = PbxArray() ntarget_dict.add_item('buildPhases', buildphases_array) generator_id = 0 for g in t.generated: # Custom target are handled via inter-target dependencies. # Generators are built as a shellscriptbuildphase. if isinstance(g, build.GeneratedList): buildphases_array.add_item(self.shell_targets[(tname, generator_id)], f'Generator {generator_id}/{tname}') generator_id += 1 for bpname, bpval in t.buildphasemap.items(): buildphases_array.add_item(bpval, f'{bpname} yyy') ntarget_dict.add_item('buildRules', PbxArray()) dep_array = PbxArray() ntarget_dict.add_item('dependencies', dep_array) dep_array.add_item(self.regen_dependency_id) # These dependencies only tell Xcode that the deps must be built # before this one. They don't set up linkage or anything # like that. Those are set up in the XCBuildConfiguration. for lt in self.build_targets[tname].link_targets: # NOT DOCUMENTED, may need to make different links # to same target have different targetdependency item. if isinstance(lt, build.CustomTarget): dep_array.add_item(self.pbx_custom_dep_map[lt.get_id()], lt.name) elif isinstance(lt, build.CustomTargetIndex): dep_array.add_item(self.pbx_custom_dep_map[lt.target.get_id()], lt.target.name) else: idval = self.pbx_dep_map[lt.get_id()] dep_array.add_item(idval, 'PBXTargetDependency') for o in t.objects: if isinstance(o, build.ExtractedObjects): source_target_id = o.target.get_id() idval = self.pbx_dep_map[source_target_id] dep_array.add_item(idval, 'PBXTargetDependency') generator_id = 0 for o in t.generated: if isinstance(o, build.CustomTarget): dep_array.add_item(self.pbx_custom_dep_map[o.get_id()], o.name) elif isinstance(o, build.CustomTargetIndex): dep_array.add_item(self.pbx_custom_dep_map[o.target.get_id()], o.target.name) generator_id += 1 ntarget_dict.add_item('name', f'"{tname}"') ntarget_dict.add_item('productName', f'"{tname}"') ntarget_dict.add_item('productReference', 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) ntarget_dict.add_item('productType', f'"{typestr}"') def generate_pbx_project(self, objects_dict): project_dict = PbxDict() objects_dict.add_item(self.project_uid, project_dict, 'Project object') project_dict.add_item('isa', 'PBXProject') attr_dict = PbxDict() project_dict.add_item('attributes', attr_dict) attr_dict.add_item('BuildIndependentTargetsInParallel', 'YES') project_dict.add_item('buildConfigurationList', self.project_conflist, f'Build configuration list for PBXProject "{self.build.project_name}"') project_dict.add_item('buildSettings', PbxDict()) style_arr = PbxArray() project_dict.add_item('buildStyles', style_arr) for name, idval in self.buildstylemap.items(): style_arr.add_item(idval, name) project_dict.add_item('compatibilityVersion', '"Xcode 3.2"') project_dict.add_item('hasScannedForEncodings', 0) project_dict.add_item('mainGroup', self.maingroup_id) project_dict.add_item('projectDirPath', '"' + self.environment.get_source_dir() + '"') project_dict.add_item('projectRoot', '""') targets_arr = PbxArray() project_dict.add_item('targets', targets_arr) targets_arr.add_item(self.all_id, 'ALL_BUILD') targets_arr.add_item(self.test_id, 'RUN_TESTS') targets_arr.add_item(self.regen_id, 'REGENERATE') for t in self.build_targets: targets_arr.add_item(self.native_targets[t], t) for t in self.custom_targets: targets_arr.add_item(self.custom_aggregate_targets[t], t) def generate_pbx_shell_build_phase(self, objects_dict): self.generate_test_shell_build_phase(objects_dict) self.generate_regen_shell_build_phase(objects_dict) self.generate_custom_target_shell_build_phases(objects_dict) self.generate_generator_target_shell_build_phases(objects_dict) def generate_test_shell_build_phase(self, objects_dict): shell_dict = PbxDict() objects_dict.add_item(self.test_command_id, shell_dict, 'ShellScript') shell_dict.add_item('isa', 'PBXShellScriptBuildPhase') shell_dict.add_item('buildActionMask', 2147483647) shell_dict.add_item('files', PbxArray()) shell_dict.add_item('inputPaths', PbxArray()) shell_dict.add_item('outputPaths', PbxArray()) shell_dict.add_item('runOnlyForDeploymentPostprocessing', 0) shell_dict.add_item('shellPath', '/bin/sh') cmd = mesonlib.get_meson_command() + ['test', '--no-rebuild', '-C', self.environment.get_build_dir()] cmdstr = ' '.join(["'%s'" % i for i in cmd]) shell_dict.add_item('shellScript', f'"{cmdstr}"') shell_dict.add_item('showEnvVarsInLog', 0) def generate_regen_shell_build_phase(self, objects_dict): shell_dict = PbxDict() objects_dict.add_item(self.regen_command_id, shell_dict, 'ShellScript') shell_dict.add_item('isa', 'PBXShellScriptBuildPhase') shell_dict.add_item('buildActionMask', 2147483647) shell_dict.add_item('files', PbxArray()) shell_dict.add_item('inputPaths', PbxArray()) shell_dict.add_item('outputPaths', PbxArray()) shell_dict.add_item('runOnlyForDeploymentPostprocessing', 0) shell_dict.add_item('shellPath', '/bin/sh') cmd = mesonlib.get_meson_command() + ['--internal', 'regencheck', os.path.join(self.environment.get_build_dir(), 'meson-private')] cmdstr = ' '.join(["'%s'" % i for i in cmd]) shell_dict.add_item('shellScript', f'"{cmdstr}"') shell_dict.add_item('showEnvVarsInLog', 0) def generate_custom_target_shell_build_phases(self, objects_dict): # Custom targets are shell build phases in Xcode terminology. for tname, t in self.custom_targets.items(): if not isinstance(t, build.CustomTarget): continue (srcs, ofilenames, cmd) = self.eval_custom_target_command(t, absolute_outputs=True) fixed_cmd, _ = self.as_meson_exe_cmdline(cmd[0], cmd[1:], capture=ofilenames[0] if t.capture else None, feed=srcs[0] if t.feed else None, env=t.env) custom_dict = PbxDict() objects_dict.add_item(self.shell_targets[tname], custom_dict, f'/* Custom target {tname} */') custom_dict.add_item('isa', 'PBXShellScriptBuildPhase') custom_dict.add_item('buildActionMask', 2147483647) custom_dict.add_item('files', PbxArray()) custom_dict.add_item('inputPaths', PbxArray()) outarray = PbxArray() custom_dict.add_item('name', '"Generate {}."'.format(ofilenames[0])) custom_dict.add_item('outputPaths', outarray) for o in ofilenames: outarray.add_item(os.path.join(self.environment.get_build_dir(), o)) custom_dict.add_item('runOnlyForDeploymentPostprocessing', 0) custom_dict.add_item('shellPath', '/bin/sh') workdir = self.environment.get_build_dir() quoted_cmd = [] for c in fixed_cmd: quoted_cmd.append(c.replace('"', chr(92) + '"')) cmdstr = ' '.join([f"\\'{x}\\'" for x in quoted_cmd]) custom_dict.add_item('shellScript', f'"cd {workdir}; {cmdstr}"') custom_dict.add_item('showEnvVarsInLog', 0) def generate_generator_target_shell_build_phases(self, objects_dict): for tname, t in self.build_targets.items(): generator_id = 0 for genlist in t.generated: if isinstance(genlist, build.GeneratedList): self.generate_single_generator_phase(tname, t, genlist, generator_id, objects_dict) generator_id += 1 for tname, t in self.custom_targets.items(): generator_id = 0 for genlist in t.sources: if isinstance(genlist, build.GeneratedList): self.generate_single_generator_phase(tname, t, genlist, generator_id, objects_dict) generator_id += 1 def generate_single_generator_phase(self, tname, t, genlist, generator_id, objects_dict): # TODO: this should be rewritten to use the meson wrapper, like the other generators do # Currently it doesn't handle a host binary that requires an exe wrapper correctly. generator = genlist.get_generator() exe = generator.get_exe() exe_arr = self.build_target_to_cmd_array(exe) workdir = self.environment.get_build_dir() gen_dict = PbxDict() objects_dict.add_item(self.shell_targets[(tname, generator_id)], gen_dict, f'"Generator {generator_id}/{tname}"') infilelist = genlist.get_inputs() outfilelist = genlist.get_outputs() gen_dict.add_item('isa', 'PBXShellScriptBuildPhase') gen_dict.add_item('buildActionMask', 2147483647) gen_dict.add_item('files', PbxArray()) gen_dict.add_item('inputPaths', PbxArray()) gen_dict.add_item('name', f'"Generator {generator_id}/{tname}"') commands = [["cd", workdir]] # Array of arrays, each one a single command, will get concatenated below. k = (tname, generator_id) ofile_abs = self.generator_outputs[k] outarray = PbxArray() gen_dict.add_item('outputPaths', outarray) for of in ofile_abs: outarray.add_item(of) for i in infilelist: # This might be needed to be added to inputPaths. It's not done yet as it is # unclear whether it is necessary, what actually happens when it is defined # and currently the build works without it. #infile_abs = i.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir()) infilename = i.rel_to_builddir(self.build_to_src) base_args = generator.get_arglist(infilename) for o_base in genlist.get_outputs_for(i): o = os.path.join(self.get_target_private_dir(t), o_base) args = [] for arg in base_args: arg = arg.replace("@INPUT@", infilename) arg = arg.replace('@OUTPUT@', o).replace('@BUILD_DIR@', self.get_target_private_dir(t)) arg = arg.replace("@CURRENT_SOURCE_DIR@", os.path.join(self.build_to_src, t.subdir)) args.append(arg) args = self.replace_outputs(args, self.get_target_private_dir(t), outfilelist) args = self.replace_extra_args(args, genlist) if generator.capture: # When capturing, stdout is the output. Forward it with the shell. full_command = ['('] + exe_arr + args + ['>', o, ')'] else: full_command = exe_arr + args commands.append(full_command) gen_dict.add_item('runOnlyForDeploymentPostprocessing', 0) gen_dict.add_item('shellPath', '/bin/sh') quoted_cmds = [] for cmnd in commands: q = [] for c in cmnd: if ' ' in c: q.append(f'\\"{c}\\"') else: q.append(c) quoted_cmds.append(' '.join(q)) cmdstr = '"' + ' && '.join(quoted_cmds) + '"' gen_dict.add_item('shellScript', cmdstr) gen_dict.add_item('showEnvVarsInLog', 0) def generate_pbx_sources_build_phase(self, objects_dict): for name in self.source_phase: phase_dict = PbxDict() t = self.build_targets[name] objects_dict.add_item(t.buildphasemap[name], phase_dict, 'Sources') phase_dict.add_item('isa', 'PBXSourcesBuildPhase') phase_dict.add_item('buildActionMask', 2147483647) file_arr = PbxArray() phase_dict.add_item('files', file_arr) for s in self.build_targets[name].sources: s = os.path.join(s.subdir, s.fname) if not self.environment.is_header(s): file_arr.add_item(self.buildfile_ids[(name, s)], os.path.join(self.environment.get_source_dir(), s)) generator_id = 0 for gt in t.generated: if isinstance(gt, build.CustomTarget): (srcs, ofilenames, cmd) = self.eval_custom_target_command(gt) for o in ofilenames: file_arr.add_item(self.custom_target_output_buildfile[o], os.path.join(self.environment.get_build_dir(), o)) elif isinstance(gt, build.CustomTargetIndex): for o in gt.get_outputs(): file_arr.add_item(self.custom_target_output_buildfile[o], os.path.join(self.environment.get_build_dir(), o)) elif isinstance(gt, build.GeneratedList): genfiles = self.generator_buildfile_ids[(name, generator_id)] generator_id += 1 for o in genfiles: file_arr.add_item(o) else: raise RuntimeError('Unknown input type: ' + str(gt)) phase_dict.add_item('runOnlyForDeploymentPostprocessing', 0) def generate_pbx_target_dependency(self, objects_dict): all_dict = PbxDict() objects_dict.add_item(self.build_all_tdep_id, all_dict, 'ALL_BUILD') all_dict.add_item('isa', 'PBXTargetDependency') all_dict.add_item('target', self.all_id) targets = [] targets.append((self.regen_dependency_id, self.regen_id, 'REGEN', None)) 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])) for t in self.custom_targets: idval = self.pbx_custom_dep_map[t] targets.append((idval, self.custom_aggregate_targets[t], t, None)) # self.containerproxy_map[t])) # Sort object by ID sorted_targets = sorted(targets, key=operator.itemgetter(0)) for t in sorted_targets: t_dict = PbxDict() objects_dict.add_item(t[0], t_dict, 'PBXTargetDependency') t_dict.add_item('isa', 'PBXTargetDependency') t_dict.add_item('target', t[1], t[2]) if t[3] is not None: t_dict.add_item('targetProxy', t[3], 'PBXContainerItemProxy') def generate_xc_build_configuration(self, objects_dict): # First the setup for the toplevel project. for buildtype in self.buildtypes: bt_dict = PbxDict() objects_dict.add_item(self.project_configurations[buildtype], bt_dict, buildtype) bt_dict.add_item('isa', 'XCBuildConfiguration') settings_dict = PbxDict() bt_dict.add_item('buildSettings', settings_dict) settings_dict.add_item('ARCHS', '"$(NATIVE_ARCH_ACTUAL)"') settings_dict.add_item('ONLY_ACTIVE_ARCH', 'YES') settings_dict.add_item('SWIFT_VERSION', '5.0') settings_dict.add_item('SDKROOT', '"macosx"') settings_dict.add_item('SYMROOT', '"%s/build"' % self.environment.get_build_dir()) bt_dict.add_item('name', f'"{buildtype}"') # Then the all target. for buildtype in self.buildtypes: bt_dict = PbxDict() objects_dict.add_item(self.buildall_configurations[buildtype], bt_dict, buildtype) bt_dict.add_item('isa', 'XCBuildConfiguration') settings_dict = PbxDict() bt_dict.add_item('buildSettings', settings_dict) settings_dict.add_item('SYMROOT', '"%s"' % self.environment.get_build_dir()) warn_array = PbxArray() warn_array.add_item('"$(inherited)"') settings_dict.add_item('WARNING_CFLAGS', warn_array) bt_dict.add_item('name', f'"{buildtype}"') # Then the test target. for buildtype in self.buildtypes: bt_dict = PbxDict() objects_dict.add_item(self.test_configurations[buildtype], bt_dict, buildtype) bt_dict.add_item('isa', 'XCBuildConfiguration') settings_dict = PbxDict() bt_dict.add_item('buildSettings', settings_dict) settings_dict.add_item('SYMROOT', '"%s"' % self.environment.get_build_dir()) warn_array = PbxArray() settings_dict.add_item('WARNING_CFLAGS', warn_array) warn_array.add_item('"$(inherited)"') bt_dict.add_item('name', f'"{buildtype}"') # Now finally targets. for target_name, target in self.build_targets.items(): self.generate_single_build_target(objects_dict, target_name, target) for target_name, target in self.custom_targets.items(): bt_dict = PbxDict() objects_dict.add_item(self.buildconfmap[target_name][buildtype], bt_dict, buildtype) bt_dict.add_item('isa', 'XCBuildConfiguration') settings_dict = PbxDict() bt_dict.add_item('buildSettings', settings_dict) settings_dict.add_item('ARCHS', '"$(NATIVE_ARCH_ACTUAL)"') settings_dict.add_item('ONLY_ACTIVE_ARCH', 'YES') settings_dict.add_item('SDKROOT', '"macosx"') settings_dict.add_item('SYMROOT', '"%s/build"' % self.environment.get_build_dir()) bt_dict.add_item('name', f'"{buildtype}"') def determine_internal_dep_link_args(self, target, buildtype): links_dylib = False dep_libs = [] for l in target.link_targets: if isinstance(target, build.SharedModule) and isinstance(l, build.Executable): continue if isinstance(l, build.CustomTargetIndex): rel_dir = self.get_custom_target_output_dir(l.target) libname = l.get_filename() elif isinstance(l, build.CustomTarget): rel_dir = self.get_custom_target_output_dir(l) libname = l.get_filename() else: rel_dir = self.get_target_dir(l) libname = l.get_filename() abs_path = os.path.join(self.environment.get_build_dir(), rel_dir, libname) dep_libs.append("'%s'" % abs_path) if isinstance(l, build.SharedLibrary): links_dylib = True if isinstance(l, build.StaticLibrary): (sub_libs, sub_links_dylib) = self.determine_internal_dep_link_args(l, buildtype) dep_libs += sub_libs links_dylib = links_dylib or sub_links_dylib return (dep_libs, links_dylib) def generate_single_build_target(self, objects_dict, target_name, target): 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 extra in d.extra_build_dirs: headerdirs.append(os.path.join(self.environment.get_build_dir(), extra)) (dep_libs, links_dylib) = self.determine_internal_dep_link_args(target, buildtype) if links_dylib: dep_libs = ['-Wl,-search_paths_first', '-Wl,-headerpad_max_install_names'] + dep_libs dylib_version = None if isinstance(target, build.SharedLibrary): if isinstance(target, build.SharedModule): ldargs = [] else: ldargs = ['-dynamiclib'] ldargs += ['-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 # Swift is special. Again. You can't mix Swift with other languages # in the same target. Thus for Swift we only use if self.is_swift_target(target): linker, stdlib_args = target.compilers['swift'], [] else: linker, stdlib_args = self.determine_linker_and_stdlib_args(target) if not isinstance(target, build.StaticLibrary): ldargs += self.build.get_project_link_args(linker, target.subproject, target.for_machine) ldargs += self.build.get_global_link_args(linker, target.for_machine) cargs = [] for dep in target.get_external_deps(): cargs += dep.get_compile_args() ldargs += dep.get_link_args() for o in target.objects: # Add extracted objects to the link line by hand. if isinstance(o, build.ExtractedObjects): added_objs = set() for objname_rel in self.determine_ext_objs(o): objname_abs = os.path.join(self.environment.get_build_dir(), o.target.subdir, objname_rel) if objname_abs not in added_objs: added_objs.add(objname_abs) ldargs += [r'\"' + objname_abs + r'\"'] generator_id = 0 for o in target.generated: if isinstance(o, build.GeneratedList): outputs = self.generator_outputs[target_name, generator_id] generator_id += 1 for o_abs in outputs: if o_abs.endswith('.o') or o_abs.endswith('.obj'): ldargs += [r'\"' + o_abs + r'\"'] else: if isinstance(o, build.CustomTarget): (srcs, ofilenames, cmd) = self.eval_custom_target_command(o) for ofname in ofilenames: if os.path.splitext(ofname)[-1] in LINKABLE_EXTENSIONS: ldargs += [r'\"' + os.path.join(self.environment.get_build_dir(), ofname) + r'\"'] elif isinstance(o, build.CustomTargetIndex): for ofname in o.get_outputs(): if os.path.splitext(ofname)[-1] in LINKABLE_EXTENSIONS: ldargs += [r'\"' + os.path.join(self.environment.get_build_dir(), ofname) + r'\"'] else: raise RuntimeError(o) if isinstance(target, build.SharedModule): ldargs += linker.get_std_shared_module_link_args(target.get_options()) elif isinstance(target, build.SharedLibrary): ldargs += linker.get_std_shared_lib_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 compiler = target.compilers.get(lang) if compiler is None: continue # Start with warning args warn_args = compiler.get_warn_args(target.get_option(OptionKey('warning_level'))) copt_proxy = target.get_options() std_args = compiler.get_option_compile_args(copt_proxy) # 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 = warn_args + std_args + pargs + gargs + targs if lang == 'swift': # For some reason putting Swift module dirs in HEADER_SEARCH_PATHS does not work, # but adding -I/path to manual args does work. swift_dep_dirs = self.determine_swift_dep_dirs(target) for d in swift_dep_dirs: args += compiler.get_include_args(d, False) if args: lang_cargs = cargs if compiler and target.implicit_include_directories: # It is unclear what is the cwd when xcode runs. -I. does not seem to # add the root build dir to the search path. So add an absolute path instead. # This may break reproducible builds, in which case patches are welcome. lang_cargs += self.get_custom_target_dir_include_args(target, compiler, absolute_path=True) # Xcode cannot handle separate compilation flags for C and ObjectiveC. They are both # put in OTHER_CFLAGS. Same with C++ and ObjectiveC++. if lang == 'objc': lang = 'c' elif lang == 'objcpp': lang = 'cpp' langname = LANGNAMEMAP[lang] if langname in langargs: langargs[langname] += args else: langargs[langname] = args langargs[langname] += lang_cargs symroot = os.path.join(self.environment.get_build_dir(), target.subdir) bt_dict = PbxDict() objects_dict.add_item(valid, bt_dict, buildtype) bt_dict.add_item('isa', 'XCBuildConfiguration') settings_dict = PbxDict() bt_dict.add_item('buildSettings', settings_dict) settings_dict.add_item('COMBINE_HIDPI_IMAGES', 'YES') if isinstance(target, build.SharedModule): settings_dict.add_item('DYLIB_CURRENT_VERSION', '""') settings_dict.add_item('DYLIB_COMPATIBILITY_VERSION', '""') else: if dylib_version is not None: settings_dict.add_item('DYLIB_CURRENT_VERSION', f'"{dylib_version}"') if target.prefix: settings_dict.add_item('EXECUTABLE_PREFIX', target.prefix) if target.suffix: suffix = '.' + target.suffix settings_dict.add_item('EXECUTABLE_SUFFIX', suffix) settings_dict.add_item('GCC_GENERATE_DEBUGGING_SYMBOLS', BOOL2XCODEBOOL[target.get_option(OptionKey('debug'))]) settings_dict.add_item('GCC_INLINES_ARE_PRIVATE_EXTERN', 'NO') opt_flag = OPT2XCODEOPT[target.get_option(OptionKey('optimization'))] if opt_flag is not None: settings_dict.add_item('GCC_OPTIMIZATION_LEVEL', opt_flag) 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(f'Unsupported Xcode configuration: More than 1 precompiled header found "{pchs!s}". Target "{target.name}" might not compile correctly.') relative_pch_path = os.path.join(target.get_subdir(), pchs[0]) # Path relative to target so it can be used with "$(PROJECT_DIR)" settings_dict.add_item('GCC_PRECOMPILE_PREFIX_HEADER', 'YES') settings_dict.add_item('GCC_PREFIX_HEADER', f'"$(PROJECT_DIR)/{relative_pch_path}"') settings_dict.add_item('GCC_PREPROCESSOR_DEFINITIONS', '""') settings_dict.add_item('GCC_SYMBOLS_PRIVATE_EXTERN', 'NO') header_arr = PbxArray() unquoted_headers = [] unquoted_headers.append(self.get_target_private_dir_abs(target)) if target.implicit_include_directories: unquoted_headers.append(os.path.join(self.environment.get_build_dir(), target.get_subdir())) unquoted_headers.append(os.path.join(self.environment.get_source_dir(), target.get_subdir())) if headerdirs: for i in headerdirs: i = os.path.normpath(i) unquoted_headers.append(i) for i in unquoted_headers: header_arr.add_item(f'"\\"{i}\\""') settings_dict.add_item('HEADER_SEARCH_PATHS', header_arr) settings_dict.add_item('INSTALL_PATH', f'"{install_path}"') settings_dict.add_item('LIBRARY_SEARCH_PATHS', '""') if isinstance(target, build.SharedModule): settings_dict.add_item('LIBRARY_STYLE', 'BUNDLE') settings_dict.add_item('MACH_O_TYPE', 'mh_bundle') elif isinstance(target, build.SharedLibrary): settings_dict.add_item('LIBRARY_STYLE', 'DYNAMIC') self.add_otherargs(settings_dict, langargs) settings_dict.add_item('OTHER_LDFLAGS', f'"{ldstr}"') settings_dict.add_item('OTHER_REZFLAGS', '""') if ' ' in product_name: settings_dict.add_item('PRODUCT_NAME', f'"{product_name}"') else: settings_dict.add_item('PRODUCT_NAME', product_name) settings_dict.add_item('SECTORDER_FLAGS', '""') settings_dict.add_item('SYMROOT', f'"{symroot}"') sysheader_arr = PbxArray() # XCode will change every -I flag that points inside these directories # to an -isystem. Thus set nothing in it since we control our own # include flags. settings_dict.add_item('SYSTEM_HEADER_SEARCH_PATHS', sysheader_arr) settings_dict.add_item('USE_HEADERMAP', 'NO') warn_array = PbxArray() settings_dict.add_item('WARNING_CFLAGS', warn_array) warn_array.add_item('"$(inherited)"') bt_dict.add_item('name', buildtype) def add_otherargs(self, settings_dict, langargs): for langname, args in langargs.items(): if args: quoted_args = [] for a in args: # This works but # a) it's ugly as sin # b) I don't know why it works or why every backslash must be escaped into eight backslashes a = a.replace(chr(92), 8*chr(92)) # chr(92) is backslash, this how we smuggle it in without Python's quoting grabbing it. a = a.replace(r'"', r'\\\"') if ' ' in a or "'" in a: a = r'\"' + a + r'\"' quoted_args.append(a) settings_dict.add_item(f'OTHER_{langname}FLAGS', '"' + ' '.join(quoted_args) + '"') def generate_xc_configurationList(self, objects_dict: PbxDict) -> None: # FIXME: sort items conf_dict = PbxDict() objects_dict.add_item(self.project_conflist, conf_dict, f'Build configuration list for PBXProject "{self.build.project_name}"') conf_dict.add_item('isa', 'XCConfigurationList') confs_arr = PbxArray() conf_dict.add_item('buildConfigurations', confs_arr) for buildtype in self.buildtypes: confs_arr.add_item(self.project_configurations[buildtype], buildtype) conf_dict.add_item('defaultConfigurationIsVisible', 0) conf_dict.add_item('defaultConfigurationName', self.buildtype) # Now the all target all_dict = PbxDict() objects_dict.add_item(self.all_buildconf_id, all_dict, 'Build configuration list for PBXAggregateTarget "ALL_BUILD"') all_dict.add_item('isa', 'XCConfigurationList') conf_arr = PbxArray() all_dict.add_item('buildConfigurations', conf_arr) for buildtype in self.buildtypes: conf_arr.add_item(self.buildall_configurations[buildtype], buildtype) all_dict.add_item('defaultConfigurationIsVisible', 0) all_dict.add_item('defaultConfigurationName', self.buildtype) # Test target test_dict = PbxDict() objects_dict.add_item(self.test_buildconf_id, test_dict, 'Build configuration list for PBXAggregateTarget "RUN_TEST"') test_dict.add_item('isa', 'XCConfigurationList') conf_arr = PbxArray() test_dict.add_item('buildConfigurations', conf_arr) for buildtype in self.buildtypes: conf_arr.add_item(self.test_configurations[buildtype], buildtype) test_dict.add_item('defaultConfigurationIsVisible', 0) test_dict.add_item('defaultConfigurationName', self.buildtype) # Regen target regen_dict = PbxDict() objects_dict.add_item(self.regen_buildconf_id, test_dict, 'Build configuration list for PBXAggregateTarget "REGENERATE"') regen_dict.add_item('isa', 'XCConfigurationList') conf_arr = PbxArray() regen_dict.add_item('buildConfigurations', conf_arr) for buildtype in self.buildtypes: conf_arr.add_item(self.test_configurations[buildtype], buildtype) regen_dict.add_item('defaultConfigurationIsVisible', 0) regen_dict.add_item('defaultConfigurationName', self.buildtype) for target_name in self.build_targets: t_dict = PbxDict() listid = self.buildconflistmap[target_name] objects_dict.add_item(listid, t_dict, f'Build configuration list for PBXNativeTarget "{target_name}"') t_dict.add_item('isa', 'XCConfigurationList') conf_arr = PbxArray() t_dict.add_item('buildConfigurations', conf_arr) idval = self.buildconfmap[target_name][self.buildtype] conf_arr.add_item(idval, self.buildtype) t_dict.add_item('defaultConfigurationIsVisible', 0) t_dict.add_item('defaultConfigurationName', self.buildtype) for target_name in self.custom_targets: t_dict = PbxDict() listid = self.buildconflistmap[target_name] objects_dict.add_item(listid, t_dict, f'Build configuration list for PBXAggregateTarget "{target_name}"') t_dict.add_item('isa', 'XCConfigurationList') conf_arr = PbxArray() t_dict.add_item('buildConfigurations', conf_arr) idval = self.buildconfmap[target_name][self.buildtype] conf_arr.add_item(idval, self.buildtype) t_dict.add_item('defaultConfigurationIsVisible', 0) t_dict.add_item('defaultConfigurationName', self.buildtype) def generate_prefix(self, pbxdict: PbxDict) -> PbxDict: pbxdict.add_item('archiveVersion', '1') pbxdict.add_item('classes', PbxDict()) pbxdict.add_item('objectVersion', '46') objects_dict = PbxDict() pbxdict.add_item('objects', objects_dict) return objects_dict def generate_suffix(self, pbxdict: PbxDict) -> None: pbxdict.add_item('rootObject', self.project_uid, 'Project object') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0 meson-1.3.2/mesonbuild/build.py0000644000175000017500000040577214562742373016676 0ustar00jpakkanejpakkane# 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 __future__ import annotations from collections import defaultdict, OrderedDict from dataclasses import dataclass, field, InitVar from functools import lru_cache import abc import hashlib import itertools, pathlib import os import pickle import re import textwrap import typing as T from . import coredata from . import dependencies from . import mlog from . import programs from .mesonlib import ( HoldableObject, SecondLevelHolder, File, MesonException, MachineChoice, PerMachine, OrderedSet, listify, extract_as_list, typeslistify, stringlistify, classify_unity_sources, get_filenames_templates_dict, substitute_values, has_path_sep, OptionKey, PerMachineDefaultable, MesonBugException, EnvironmentVariables, pickle_load, ) from .compilers import ( is_header, is_object, is_source, clink_langs, sort_clink, all_languages, is_known_suffix, detect_static_linker ) from .interpreterbase import FeatureNew, FeatureDeprecated if T.TYPE_CHECKING: from typing_extensions import Literal, TypedDict from . import environment from ._typing import ImmutableListProtocol from .backend.backends import Backend from .compilers import Compiler from .interpreter.interpreter import SourceOutputs, Interpreter from .interpreter.interpreterobjects import Test from .interpreterbase import SubProject from .linkers.linkers import StaticLinker from .mesonlib import ExecutableSerialisation, FileMode, FileOrString from .modules import ModuleState from .mparser import BaseNode from .wrap import WrapMode GeneratedTypes = T.Union['CustomTarget', 'CustomTargetIndex', 'GeneratedList'] LibTypes = T.Union['SharedLibrary', 'StaticLibrary', 'CustomTarget', 'CustomTargetIndex'] BuildTargetTypes = T.Union['BuildTarget', 'CustomTarget', 'CustomTargetIndex'] ObjectTypes = T.Union[str, 'File', 'ExtractedObjects', 'GeneratedTypes'] class DFeatures(TypedDict): unittest: bool debug: T.List[T.Union[str, int]] import_dirs: T.List[IncludeDirs] versions: T.List[T.Union[str, int]] pch_kwargs = {'c_pch', 'cpp_pch'} lang_arg_kwargs = {f'{lang}_args' for lang in all_languages} lang_arg_kwargs |= { 'd_import_dirs', 'd_unittest', 'd_module_versions', 'd_debug', } vala_kwargs = {'vala_header', 'vala_gir', 'vala_vapi'} rust_kwargs = {'rust_crate_type', 'rust_dependency_map'} cs_kwargs = {'resources', 'cs_args'} buildtarget_kwargs = { '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', 'install_tag', 'name_prefix', 'name_suffix', 'native', 'objects', 'override_options', 'sources', 'gnu_symbol_visibility', 'link_language', 'win_subsystem', } 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', 'pie', 'vs_module_defs'} known_shlib_kwargs = known_build_target_kwargs | {'version', 'soversion', 'vs_module_defs', 'darwin_versions', 'rust_abi'} known_shmod_kwargs = known_build_target_kwargs | {'vs_module_defs', 'rust_abi'} known_stlib_kwargs = known_build_target_kwargs | {'pic', 'prelink', 'rust_abi'} known_jar_kwargs = known_exe_kwargs | {'main_class', 'java_resources'} def _process_install_tag(install_tag: T.Optional[T.List[T.Optional[str]]], num_outputs: int) -> T.List[T.Optional[str]]: _install_tag: T.List[T.Optional[str]] if not install_tag: _install_tag = [None] * num_outputs elif len(install_tag) == 1: _install_tag = install_tag * num_outputs else: _install_tag = install_tag return _install_tag @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 @dataclass(eq=False) class DependencyOverride(HoldableObject): dep: dependencies.Dependency node: 'BaseNode' explicit: bool = True @dataclass(eq=False) class Headers(HoldableObject): sources: T.List[File] install_subdir: T.Optional[str] custom_install_dir: T.Optional[str] custom_install_mode: 'FileMode' subproject: str follow_symlinks: T.Optional[bool] = None # TODO: we really don't need any of these methods, but they're preserved to # keep APIs relying on them working. def set_install_subdir(self, subdir: str) -> None: self.install_subdir = subdir def get_install_subdir(self) -> T.Optional[str]: return self.install_subdir def get_sources(self) -> T.List[File]: return self.sources def get_custom_install_dir(self) -> T.Optional[str]: return self.custom_install_dir def get_custom_install_mode(self) -> 'FileMode': return self.custom_install_mode @dataclass(eq=False) class Man(HoldableObject): sources: T.List[File] custom_install_dir: T.Optional[str] custom_install_mode: 'FileMode' subproject: str locale: T.Optional[str] def get_custom_install_dir(self) -> T.Optional[str]: return self.custom_install_dir def get_custom_install_mode(self) -> 'FileMode': return self.custom_install_mode def get_sources(self) -> T.List['File']: return self.sources @dataclass(eq=False) class EmptyDir(HoldableObject): path: str install_mode: 'FileMode' subproject: str install_tag: T.Optional[str] = None @dataclass(eq=False) class InstallDir(HoldableObject): source_subdir: str installable_subdir: str install_dir: str install_dir_name: str install_mode: 'FileMode' exclude: T.Tuple[T.Set[str], T.Set[str]] strip_directory: bool subproject: str from_source_dir: bool = True install_tag: T.Optional[str] = None follow_symlinks: T.Optional[bool] = None @dataclass(eq=False) class DepManifest: version: str license: T.List[str] license_files: T.List[T.Tuple[str, File]] subproject: str def to_json(self) -> T.Dict[str, T.Union[str, T.List[str]]]: return { 'version': self.version, 'license': self.license, 'license_files': [l[1].relative_name() for l in self.license_files], } # literally everything isn't dataclass stuff class Build: """A class that holds the status of one build including all dependencies and so on. """ def __init__(self, environment: environment.Environment): self.version = coredata.version self.project_name = 'name of master project' self.project_version = None self.environment = environment self.projects = {} self.targets: 'T.OrderedDict[str, T.Union[CustomTarget, BuildTarget]]' = OrderedDict() self.targetnames: T.Set[T.Tuple[str, str]] = set() # Set of executable names and their subdir self.global_args: PerMachine[T.Dict[str, T.List[str]]] = PerMachine({}, {}) self.global_link_args: PerMachine[T.Dict[str, T.List[str]]] = PerMachine({}, {}) self.projects_args: PerMachine[T.Dict[str, T.Dict[str, T.List[str]]]] = PerMachine({}, {}) self.projects_link_args: PerMachine[T.Dict[str, T.Dict[str, T.List[str]]]] = PerMachine({}, {}) self.tests: T.List['Test'] = [] self.benchmarks: T.List['Test'] = [] self.headers: T.List[Headers] = [] self.man: T.List[Man] = [] self.emptydir: T.List[EmptyDir] = [] self.data: T.List[Data] = [] self.symlinks: T.List[SymlinkData] = [] self.static_linker: PerMachine[StaticLinker] = PerMachine(None, None) self.subprojects = {} self.subproject_dir = '' self.install_scripts: T.List['ExecutableSerialisation'] = [] self.postconf_scripts: T.List['ExecutableSerialisation'] = [] self.dist_scripts: T.List['ExecutableSerialisation'] = [] self.install_dirs: T.List[InstallDir] = [] self.dep_manifest_name: T.Optional[str] = None self.dep_manifest: T.Dict[str, DepManifest] = {} self.stdlibs = PerMachine({}, {}) self.test_setups: T.Dict[str, TestSetup] = {} self.test_setup_default_name = None self.find_overrides: T.Dict[str, T.Union['Executable', programs.ExternalProgram, programs.OverrideProgram]] = {} self.searched_programs: T.Set[str] = set() # The list of all programs that have been searched for. # If we are doing a cross build we need two caches, if we're doing a # build == host compilation the both caches should point to the same place. self.dependency_overrides: PerMachine[T.Dict[T.Tuple, DependencyOverride]] = PerMachineDefaultable.default( environment.is_cross_build(), {}, {}) self.devenv: T.List[EnvironmentVariables] = [] self.modules: T.List[str] = [] def get_build_targets(self): build_targets = OrderedDict() for name, t in self.targets.items(): if isinstance(t, BuildTarget): build_targets[name] = t return build_targets def get_custom_targets(self): custom_targets = OrderedDict() for name, t in self.targets.items(): if isinstance(t, CustomTarget): custom_targets[name] = t return custom_targets def copy(self) -> Build: 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: Build) -> None: for k, v in other.__dict__.items(): self.__dict__[k] = v def ensure_static_linker(self, compiler: Compiler) -> None: if self.static_linker[compiler.for_machine] is None and compiler.needs_static_linker(): self.static_linker[compiler.for_machine] = detect_static_linker(self.environment, compiler) def get_project(self): return self.projects[''] def get_subproject_dir(self): return self.subproject_dir def get_targets(self) -> 'T.OrderedDict[str, T.Union[CustomTarget, BuildTarget]]': return self.targets def get_tests(self) -> T.List['Test']: return self.tests def get_benchmarks(self) -> T.List['Test']: return self.benchmarks def get_headers(self) -> T.List['Headers']: return self.headers def get_man(self) -> T.List['Man']: return self.man def get_data(self) -> T.List['Data']: return self.data def get_symlinks(self) -> T.List['SymlinkData']: return self.symlinks def get_emptydir(self) -> T.List['EmptyDir']: return self.emptydir def get_install_subdirs(self) -> T.List['InstallDir']: return self.install_dirs def get_global_args(self, compiler: 'Compiler', for_machine: 'MachineChoice') -> T.List[str]: d = self.global_args[for_machine] return d.get(compiler.get_language(), []) def get_project_args(self, compiler: 'Compiler', project: str, for_machine: 'MachineChoice') -> T.List[str]: 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: 'Compiler', for_machine: 'MachineChoice') -> T.List[str]: d = self.global_link_args[for_machine] return d.get(compiler.get_language(), []) def get_project_link_args(self, compiler: 'Compiler', project: str, for_machine: 'MachineChoice') -> T.List[str]: d = self.projects_link_args[for_machine] link_args = d.get(project) if not link_args: return [] return link_args.get(compiler.get_language(), []) @dataclass(eq=False) class IncludeDirs(HoldableObject): """Internal representation of an include_directories call.""" curdir: str incdirs: T.List[str] is_system: bool # Interpreter has validated that all given directories # actually exist. extra_build_dirs: T.List[str] = field(default_factory=list) def __repr__(self) -> str: r = '<{} {}/{}>' return r.format(self.__class__.__name__, self.curdir, self.incdirs) def get_curdir(self) -> str: return self.curdir def get_incdirs(self) -> T.List[str]: return self.incdirs def get_extra_build_dirs(self) -> T.List[str]: return self.extra_build_dirs def to_string_list(self, sourcedir: str, builddir: str) -> T.List[str]: """Convert IncludeDirs object to a list of strings. :param sourcedir: The absolute source directory :param builddir: The absolute build directory, option, build dir will not be added if this is unset :returns: A list of strings (without compiler argument) """ strlist: T.List[str] = [] for idir in self.incdirs: strlist.append(os.path.join(sourcedir, self.curdir, idir)) strlist.append(os.path.join(builddir, self.curdir, idir)) return strlist @dataclass(eq=False) class ExtractedObjects(HoldableObject): ''' Holds a list of sources for which the objects must be extracted ''' target: 'BuildTarget' srclist: T.List[File] = field(default_factory=list) genlist: T.List['GeneratedTypes'] = field(default_factory=list) objlist: T.List[T.Union[str, 'File', 'ExtractedObjects']] = field(default_factory=list) recursive: bool = True pch: bool = False def __post_init__(self) -> None: if self.target.is_unity: self.check_unity_compatible() def __repr__(self) -> str: r = '<{0} {1!r}: {2}>' return r.format(self.__class__.__name__, self.target.name, self.srclist) @staticmethod def get_sources(sources: T.Sequence['FileOrString'], generated_sources: T.Sequence['GeneratedTypes']) -> T.List['FileOrString']: # 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 return [s for s in sources if is_source(s)] def classify_all_sources(self, sources: T.List[FileOrString], generated_sources: T.Sequence['GeneratedTypes']) -> T.Dict['Compiler', T.List['FileOrString']]: sources_ = self.get_sources(sources, generated_sources) return classify_unity_sources(self.target.compilers.values(), sources_) def check_unity_compatible(self) -> None: # 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 cannot be extracted ' 'in Unity builds. You can only extract all ' 'the object files for each compiler at once.') @dataclass(eq=False, order=False) class StructuredSources(HoldableObject): """A container for sources in languages that use filesystem hierarchy. Languages like Rust and Cython rely on the layout of files in the filesystem as part of the compiler implementation. This structure allows us to represent the required filesystem layout. """ sources: T.DefaultDict[str, T.List[T.Union[File, CustomTarget, CustomTargetIndex, GeneratedList]]] = field( default_factory=lambda: defaultdict(list)) def __add__(self, other: StructuredSources) -> StructuredSources: sources = self.sources.copy() for k, v in other.sources.items(): sources[k].extend(v) return StructuredSources(sources) def __bool__(self) -> bool: return bool(self.sources) def first_file(self) -> T.Union[File, CustomTarget, CustomTargetIndex, GeneratedList]: """Get the first source in the root :return: The first source in the root """ return self.sources[''][0] def as_list(self) -> T.List[T.Union[File, CustomTarget, CustomTargetIndex, GeneratedList]]: return list(itertools.chain.from_iterable(self.sources.values())) def needs_copy(self) -> bool: """Do we need to create a structure in the build directory. This allows us to avoid making copies if the structures exists in the source dir. Which could happen in situations where a generated source only exists in some configurations """ for files in self.sources.values(): for f in files: if isinstance(f, File): if f.is_built: return True else: return True return False @dataclass(eq=False) class Target(HoldableObject, metaclass=abc.ABCMeta): name: str subdir: str subproject: 'SubProject' build_by_default: bool for_machine: MachineChoice environment: environment.Environment install: bool = False build_always_stale: bool = False extra_files: T.List[File] = field(default_factory=list) override_options: InitVar[T.Optional[T.Dict[OptionKey, str]]] = None @abc.abstractproperty def typename(self) -> str: pass @abc.abstractmethod def type_suffix(self) -> str: pass def __post_init__(self, overrides: T.Optional[T.Dict[OptionKey, str]]) -> None: if overrides: ovr = {k.evolve(machine=self.for_machine) if k.lang else k: v for k, v in overrides.items()} else: ovr = {} self.options = coredata.OptionsView(self.environment.coredata.options, self.subproject, ovr) # XXX: this should happen in the interpreter if has_path_sep(self.name): # Fix failing test 53 when this becomes an error. mlog.warning(textwrap.dedent(f'''\ Target "{self.name}" 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.''')) # dataclass comparators? def __lt__(self, other: object) -> bool: if not isinstance(other, Target): return NotImplemented return self.get_id() < other.get_id() def __le__(self, other: object) -> bool: if not isinstance(other, Target): return NotImplemented return self.get_id() <= other.get_id() def __gt__(self, other: object) -> bool: if not isinstance(other, Target): return NotImplemented return self.get_id() > other.get_id() def __ge__(self, other: object) -> bool: if not isinstance(other, Target): return NotImplemented return self.get_id() >= other.get_id() def get_default_install_dir(self) -> T.Tuple[str, str]: raise NotImplementedError def get_custom_install_dir(self) -> T.List[T.Union[str, Literal[False]]]: raise NotImplementedError def get_install_dir(self) -> T.Tuple[T.List[T.Union[str, Literal[False]]], str, Literal[False]]: # Find the installation directory. default_install_dir, default_install_dir_name = self.get_default_install_dir() outdirs = self.get_custom_install_dir() if outdirs 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 install_dir_names = [getattr(i, 'optname', None) for i in outdirs] else: custom_install_dir = False # if outdirs is empty we need to set to something, otherwise we set # only the first value to the default. if outdirs: outdirs[0] = default_install_dir else: outdirs = [default_install_dir] install_dir_names = [default_install_dir_name] * len(outdirs) return outdirs, install_dir_names, custom_install_dir def get_basename(self) -> str: return self.name def get_subdir(self) -> str: return self.subdir def get_typename(self) -> str: return self.typename @staticmethod def _get_id_hash(target_id: str) -> str: # 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: str, name: str, type_suffix: str) -> str: """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) -> str: name = self.name if getattr(self, 'name_suffix_set', False): name += '.' + self.suffix return self.construct_id_from_path( self.subdir, name, self.type_suffix()) def process_kwargs_base(self, kwargs: T.Dict[str, T.Any]) -> None: 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.') if not self.build_by_default and 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.set_option_overrides(self.parse_overrides(kwargs)) def set_option_overrides(self, option_overrides: T.Dict[OptionKey, str]) -> None: self.options.overrides = {} for k, v in option_overrides.items(): if k.lang: self.options.overrides[k.evolve(machine=self.for_machine)] = v else: self.options.overrides[k] = v def get_options(self) -> coredata.OptionsView: return self.options def get_option(self, key: 'OptionKey') -> T.Union[str, int, bool, 'WrapMode']: # We don't actually have wrapmode here to do an assert, so just do a # cast, we know what's in coredata anyway. # TODO: if it's possible to annotate get_option or validate_option_value # in the future we might be able to remove the cast here return T.cast('T.Union[str, int, bool, WrapMode]', self.options[key].value) @staticmethod def parse_overrides(kwargs: T.Dict[str, T.Any]) -> T.Dict[OptionKey, str]: opts = kwargs.get('override_options', []) # In this case we have an already parsed and ready to go dictionary # provided by typed_kwargs if isinstance(opts, dict): return T.cast('T.Dict[OptionKey, str]', opts) result: T.Dict[OptionKey, str] = {} overrides = stringlistify(opts) for o in overrides: if '=' not in o: raise InvalidArguments('Overrides must be of form "key=value"') k, v = o.split('=', 1) key = OptionKey.from_string(k.strip()) v = v.strip() result[key] = v return result def is_linkable_target(self) -> bool: return False def get_outputs(self) -> T.List[str]: return [] def should_install(self) -> bool: return False class BuildTarget(Target): known_kwargs = known_build_target_kwargs install_dir: T.List[T.Union[str, Literal[False]]] # This set contains all the languages a linker can link natively # without extra flags. For instance, nvcc (cuda) can link C++ # without injecting -lc++/-lstdc++, see # https://github.com/mesonbuild/meson/issues/10570 _MASK_LANGS: T.FrozenSet[T.Tuple[str, str]] = frozenset([ # (language, linker) ('cpp', 'cuda'), ]) def __init__( self, name: str, subdir: str, subproject: SubProject, for_machine: MachineChoice, sources: T.List['SourceOutputs'], structured_sources: T.Optional[StructuredSources], objects: T.List[ObjectTypes], environment: environment.Environment, compilers: T.Dict[str, 'Compiler'], kwargs: T.Dict[str, T.Any]): super().__init__(name, subdir, subproject, True, for_machine, environment, install=kwargs.get('install', False)) self.all_compilers = compilers self.compilers: OrderedDict[str, Compiler] = OrderedDict() self.objects: T.List[ObjectTypes] = [] self.structured_sources = structured_sources self.external_deps: T.List[dependencies.Dependency] = [] self.include_dirs: T.List['IncludeDirs'] = [] self.link_language = kwargs.get('link_language') self.link_targets: T.List[LibTypes] = [] self.link_whole_targets: T.List[T.Union[StaticLibrary, CustomTarget, CustomTargetIndex]] = [] self.depend_files: T.List[File] = [] self.link_depends = [] self.added_deps = set() self.name_prefix_set = False self.name_suffix_set = False self.filename = 'no_name' # The debugging information file this target will generate self.debug_filename = None # 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.pch: T.Dict[str, T.List[str]] = {} self.extra_args: T.DefaultDict[str, T.List[str]] = kwargs.get('language_args', defaultdict(list)) self.sources: T.List[File] = [] self.generated: T.List['GeneratedTypes'] = [] self.extra_files: T.List[File] = [] self.d_features: DFeatures = { 'debug': kwargs.get('d_debug', []), 'import_dirs': kwargs.get('d_import_dirs', []), 'versions': kwargs.get('d_module_versions', []), 'unittest': kwargs.get('d_unittest', False), } self.pic = False self.pie = False # Track build_rpath entries so we can remove them at install time self.rpath_dirs_to_remove: T.Set[bytes] = set() self.process_sourcelist(sources) # Objects can be: # 1. Preexisting 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) self.missing_languages = self.process_compilers() # self.link_targets and self.link_whole_targets contains libraries from # dependencies (see add_deps()). They have not been processed yet because # we have to call process_compilers() first and we need to process libraries # from link_with and link_whole first. # See https://github.com/mesonbuild/meson/pull/11957#issuecomment-1629243208. link_targets = extract_as_list(kwargs, 'link_with') + self.link_targets link_whole_targets = extract_as_list(kwargs, 'link_whole') + self.link_whole_targets self.link_targets.clear() self.link_whole_targets.clear() self.link(link_targets) self.link_whole(link_whole_targets) if not any([self.sources, self.generated, self.objects, self.link_whole_targets, self.structured_sources, kwargs.pop('_allow_no_sources', False)]): mlog.warning(f'Build target {name} has no sources. ' 'This was never supposed to be allowed but did because of a bug, ' 'support will be removed in a future release of Meson') self.check_unknown_kwargs(kwargs) self.validate_install() self.check_module_linking() def post_init(self) -> None: ''' Initialisations and checks requiring the final list of compilers to be known ''' self.validate_sources() if self.structured_sources and any([self.sources, self.generated]): raise MesonException('cannot mix structured sources and unstructured sources') if self.structured_sources and 'rust' not in self.compilers: raise MesonException('structured sources are only supported in Rust targets') if self.uses_rust(): # relocation-model=pic is rustc's default and Meson does not # currently have a way to disable PIC. self.pic = True if 'vala' in self.compilers and self.is_linkable_target(): self.outputs += [self.vala_header, self.vala_vapi] self.install_tag += ['devel', 'devel'] if self.vala_gir: self.outputs.append(self.vala_gir) self.install_tag.append('devel') def __repr__(self): repr_str = "<{0} {1}: {2}>" return repr_str.format(self.__class__.__name__, self.get_id(), self.filename) def __str__(self): return f"{self.name}" @property def is_unity(self) -> bool: unity_opt = self.get_option(OptionKey('unity')) return unity_opt == 'on' or (unity_opt == 'subprojects' and self.subproject != '') def validate_install(self): if self.for_machine is MachineChoice.BUILD and self.install: if self.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 == 'language_args': continue if k not in known_kwargs: unknowns.append(k) if len(unknowns) > 0: mlog.warning('Unknown keyword argument(s) in target {}: {}.'.format(self.name, ', '.join(unknowns))) def process_objectlist(self, objects): assert isinstance(objects, list) deprecated_non_objects = [] for s in objects: if isinstance(s, (str, File, ExtractedObjects)): self.objects.append(s) if not isinstance(s, ExtractedObjects) and not is_object(s): deprecated_non_objects.append(s) elif isinstance(s, (CustomTarget, CustomTargetIndex, GeneratedList)): non_objects = [o for o in s.get_outputs() if not is_object(o)] if non_objects: raise InvalidArguments(f'Generated file {non_objects[0]} in the \'objects\' kwarg is not an object.') self.generated.append(s) else: raise InvalidArguments(f'Bad object of type {type(s).__name__!r} in target {self.name!r}.') if deprecated_non_objects: FeatureDeprecated.single_use(f'Source file {deprecated_non_objects[0]} in the \'objects\' kwarg is not an object.', '1.3.0', self.subproject) def process_sourcelist(self, sources: T.List['SourceOutputs']) -> None: """Split sources into generated and static sources. Sources can be: 1. Preexisting source files in the source tree (static) 2. Preexisting sources generated by configure_file in the build tree. (static as they are only regenerated if meson itself is regenerated) 3. Sources files generated by another target or a Generator (generated) """ added_sources: T.Set[File] = set() # If the same source is defined multiple times, use it only once. for s in sources: if isinstance(s, File): if s not in added_sources: self.sources.append(s) added_sources.add(s) elif isinstance(s, (CustomTarget, CustomTargetIndex, GeneratedList)): self.generated.append(s) @staticmethod def can_compile_remove_sources(compiler: 'Compiler', sources: T.List['FileOrString']) -> bool: 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. """ for lang in self.missing_languages: self.compilers[lang] = self.all_compilers[lang] # 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: for t in itertools.chain(self.link_targets, self.link_whole_targets): if isinstance(t, (CustomTarget, CustomTargetIndex)): continue # We can't know anything about these. for name, compiler in t.compilers.items(): if name in link_langs and name not in self.compilers: 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 self.all_compilers: self.compilers[lang] = self.all_compilers[lang] break # Now that we have the final list of compilers we can sort it according # to clink_langs and do sanity checks. self.compilers = OrderedDict(sorted(self.compilers.items(), key=lambda t: sort_clink(t[0]))) self.post_init() def process_compilers(self) -> T.List[str]: ''' 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. Returns a list of missing languages that we can add implicitly, such as C/C++ compiler for cython. ''' missing_languages: T.List[str] = [] if not any([self.sources, self.generated, self.objects, self.structured_sources]): return missing_languages # Preexisting sources sources: T.List['FileOrString'] = list(self.sources) generated = self.generated.copy() if self.structured_sources: for v in self.structured_sources.sources.values(): for src in v: if isinstance(src, (str, File)): sources.append(src) else: generated.append(src) # All generated sources for gensrc in 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: 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 compsrcs = o.classify_all_sources(o.srclist, []) for comp in compsrcs: # 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 comp.language == 'vala': continue if comp.language not in self.compilers: self.compilers[comp.language] = comp if sources: # For each source, try to add one compiler that can compile it. # # If it has a suffix that belongs to a known language, we must have # a compiler for that language. # # Otherwise, it's ok if no compilers can compile it, 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 self.all_compilers.items(): if compiler.can_compile(s): if lang not in self.compilers: self.compilers[lang] = compiler break else: if is_known_suffix(s): path = pathlib.Path(str(s)).as_posix() m = f'No {self.for_machine.get_lower_case_name()} machine compiler for {path!r}' raise MesonException(m) # 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'] = self.all_compilers['c'] if 'cython' in self.compilers: key = OptionKey('language', machine=self.for_machine, lang='cython') value = self.get_option(key) try: self.compilers[value] = self.all_compilers[value] except KeyError: missing_languages.append(value) return missing_languages def validate_sources(self): if len(self.compilers) > 1 and any(lang in self.compilers for lang in ['cs', 'java']): langs = ', '.join(self.compilers.keys()) raise InvalidArguments(f'Cannot mix those languages into a target: {langs}') def process_link_depends(self, sources): """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 isinstance(s, File): self.link_depends.append(s) elif isinstance(s, str): self.link_depends.append( File.from_source_file(self.environment.source_dir, self.subdir, s)) elif hasattr(s, 'get_outputs'): self.link_depends.append(s) else: raise InvalidArguments( 'Link_depends arguments must be strings, Files, ' 'or a Custom Target, or lists thereof.') def extract_objects(self, srclist: T.List[T.Union['FileOrString', 'GeneratedTypes']]) -> ExtractedObjects: sources_set = set(self.sources) generated_set = set(self.generated) obj_src: T.List['File'] = [] obj_gen: T.List['GeneratedTypes'] = [] for src in srclist: if isinstance(src, (str, File)): if isinstance(src, str): src = File(False, self.subdir, src) else: FeatureNew.single_use('File argument for extract_objects', '0.50.0', self.subproject) if src not in sources_set: raise MesonException(f'Tried to extract unknown source {src}.') obj_src.append(src) elif isinstance(src, (CustomTarget, CustomTargetIndex, GeneratedList)): FeatureNew.single_use('Generated sources for extract_objects', '0.61.0', self.subproject) target = src.target if isinstance(src, CustomTargetIndex) else src if src not in generated_set and target not in generated_set: raise MesonException(f'Tried to extract unknown source {target.get_basename()}.') obj_gen.append(src) else: raise MesonException(f'Object extraction arguments must be strings, Files or targets (got {type(src).__name__}).') return ExtractedObjects(self, obj_src, obj_gen) def extract_all_objects(self, recursive: bool = True) -> ExtractedObjects: return ExtractedObjects(self, self.sources, self.generated, self.objects, recursive, pch=True) def get_all_link_deps(self) -> ImmutableListProtocol[BuildTargetTypes]: return self.get_transitive_link_deps() @lru_cache(maxsize=None) def get_transitive_link_deps(self) -> ImmutableListProtocol[BuildTargetTypes]: result: T.List[Target] = [] for i in self.link_targets: result += i.get_all_link_deps() return result def get_link_deps_mapping(self, prefix: str) -> T.Mapping[str, str]: return self.get_transitive_link_deps_mapping(prefix) @lru_cache(maxsize=None) def get_transitive_link_deps_mapping(self, prefix: str) -> T.Mapping[str, str]: result: T.Dict[str, str] = {} for i in self.link_targets: mapping = i.get_link_deps_mapping(prefix) #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) -> T.AbstractSet[str]: result: OrderedSet[str] = OrderedSet() for i in self.link_targets: if not isinstance(i, StaticLibrary): result.add(i.get_subdir()) result.update(i.get_link_dep_subdirs()) return result def get_default_install_dir(self) -> T.Tuple[str, str]: return self.environment.get_libdir(), '{libdir}' def get_custom_install_dir(self) -> T.List[T.Union[str, Literal[False]]]: return self.install_dir def get_custom_install_mode(self) -> T.Optional['FileMode']: return self.install_mode def process_kwargs(self, kwargs): self.process_kwargs_base(kwargs) self.original_kwargs = kwargs self.add_pch('c', extract_as_list(kwargs, 'c_pch')) self.add_pch('cpp', extract_as_list(kwargs, 'cpp_pch')) if not isinstance(self, Executable) or kwargs.get('export_dynamic', False): 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) 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(textwrap.dedent('''\ 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', [])) # 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', []), (str, bool)) self.install_mode = kwargs.get('install_mode', None) self.install_tag = stringlistify(kwargs.get('install_tag', [None])) if not isinstance(self, Executable): # build_target will always populate these as `None`, which is fine if kwargs.get('gui_app') is not None: raise InvalidArguments('Argument gui_app can only be used on executables.') if kwargs.get('win_subsystem') is not None: raise InvalidArguments('Argument win_subsystem can only be used on executables.') extra_files = extract_as_list(kwargs, 'extra_files') for i in extra_files: assert isinstance(i, File) if i in self.extra_files: continue trial = os.path.join(self.environment.get_source_dir(), i.subdir, i.fname) if not os.path.isfile(trial): raise InvalidArguments(f'Tried to add non-existing extra file {i}.') self.extra_files.append(i) self.install_rpath: str = 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(self.environment.get_source_dir(), self.subdir, r) if not os.path.isfile(trial): raise InvalidArguments(f'Tried to add non-existing resource {r}.') self.resources = resources if kwargs.get('name_prefix') is not None: name_prefix = kwargs['name_prefix'] if isinstance(name_prefix, list): if name_prefix: raise InvalidArguments('name_prefix array must be empty to signify default.') else: if not isinstance(name_prefix, str): raise InvalidArguments('name_prefix must be a string.') self.prefix = name_prefix self.name_prefix_set = True if kwargs.get('name_suffix') is not None: name_suffix = kwargs['name_suffix'] if isinstance(name_suffix, list): if name_suffix: raise InvalidArguments('name_suffix array must be empty to signify default.') 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', 'b_staticpic') if isinstance(self, Executable) or (isinstance(self, StaticLibrary) and not self.pic): # 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', 'b_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 {} not one of: {}'.format(self.gnu_symbol_visibility, ', '.join(permitted))) rust_dependency_map = kwargs.get('rust_dependency_map', {}) if not isinstance(rust_dependency_map, dict): raise InvalidArguments(f'Invalid rust_dependency_map "{rust_dependency_map}": must be a dictionary.') if any(not isinstance(v, str) for v in rust_dependency_map.values()): raise InvalidArguments(f'Invalid rust_dependency_map "{rust_dependency_map}": must be a dictionary with string values.') self.rust_dependency_map = rust_dependency_map def _extract_pic_pie(self, kwargs: T.Dict[str, T.Any], arg: str, option: str) -> bool: # 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(f"Use the '{arg}' kwarg instead of passing '-f{arg}' manually to {self.name!r}") return True k = OptionKey(option) if kwargs.get(arg) is not None: val = T.cast('bool', kwargs[arg]) elif k in self.environment.coredata.options: val = self.environment.coredata.options[k].value else: val = False if not isinstance(val, bool): raise InvalidArguments(f'Argument {arg} to {self.name!r} must be boolean') return val def get_filename(self) -> str: return self.filename def get_debug_filename(self) -> T.Optional[str]: """ 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_outputs(self) -> T.List[str]: return self.outputs def get_extra_args(self, language: str) -> T.List[str]: return self.extra_args[language] @lru_cache(maxsize=None) def get_dependencies(self) -> OrderedSet[BuildTargetTypes]: # Get all targets needed for linking. This includes all link_with and # link_whole targets, and also all dependencies of static libraries # recursively. The algorithm here is closely related to what we do in # get_internal_static_libraries(): Installed static libraries include # objects from all their dependencies already. result: OrderedSet[BuildTargetTypes] = OrderedSet() for t in itertools.chain(self.link_targets, self.link_whole_targets): if t not in result: result.add(t) if isinstance(t, StaticLibrary): t.get_dependencies_recurse(result) return result def get_dependencies_recurse(self, result: OrderedSet[BuildTargetTypes], include_internals: bool = True) -> None: # self is always a static library because we don't need to pull dependencies # of shared libraries. If self is installed (not internal) it already # include objects extracted from all its internal dependencies so we can # skip them. include_internals = include_internals and self.is_internal() for t in self.link_targets: if t in result: continue if t.rust_crate_type == 'proc-macro': continue if include_internals or not t.is_internal(): result.add(t) if isinstance(t, StaticLibrary): t.get_dependencies_recurse(result, include_internals) for t in self.link_whole_targets: t.get_dependencies_recurse(result, include_internals) def get_source_subdir(self): return self.subdir def get_sources(self): return self.sources def get_objects(self) -> T.List[T.Union[str, 'File', 'ExtractedObjects']]: return self.objects def get_generated_sources(self) -> T.List['GeneratedTypes']: return self.generated def should_install(self) -> bool: return self.install def has_pch(self) -> bool: return bool(self.pch) def get_pch(self, language: str) -> T.List[str]: return self.pch.get(language, []) def get_include_dirs(self) -> T.List['IncludeDirs']: return self.include_dirs def add_deps(self, deps): deps = listify(deps) for dep in deps: if dep in self.added_deps: continue if isinstance(dep, dependencies.InternalDependency): # Those parts that are internal. self.process_sourcelist(dep.sources) self.extra_files.extend(f for f in dep.extra_files if f not in self.extra_files) self.add_include_dirs(dep.include_directories, dep.get_include_type()) self.objects.extend(dep.objects) self.link_targets.extend(dep.libraries) self.link_whole_targets.extend(dep.whole_libraries) 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(f'Tried to use a build target {dep.name} as a dependency of target {self.name}.\n' '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, 'held_object'): # FIXME: subproject is not a real ObjectHolder so we have to do this by hand dep = dep.held_object 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(f'Argument is of an unacceptable type {type(dep).__name__!r}.\nMust be ' 'either an external dependency (returned by find_library() or ' 'dependency()) or an internal dependency (returned by ' 'declare_dependency()).') dep_d_features = dep.d_features for feature in ('versions', 'import_dirs'): if feature in dep_d_features: self.d_features[feature].extend(dep_d_features[feature]) self.added_deps.add(dep) def get_external_deps(self) -> T.List[dependencies.Dependency]: return self.external_deps def is_internal(self) -> bool: return False def link(self, targets: T.List[BuildTargetTypes]) -> None: for t in targets: if not isinstance(t, (Target, CustomTargetIndex)): if isinstance(t, dependencies.ExternalLibrary): raise MesonException(textwrap.dedent('''\ 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. ''')) raise InvalidArguments(f'{t!r} is not a target.') if not t.is_linkable_target(): raise InvalidArguments(f"Link target '{t!s}' is not linkable.") if isinstance(self, StaticLibrary) and self.install and t.is_internal(): # When we're a static library and we link_with to an # internal/convenience library, promote to link_whole. self.link_whole([t], promoted=True) continue if isinstance(self, SharedLibrary) and isinstance(t, StaticLibrary) and not t.pic: msg = f"Can't link non-PIC static library {t.name!r} into shared library {self.name!r}. " msg += "Use the 'pic' option to static_library to build with PIC." raise InvalidArguments(msg) self.check_can_link_together(t) self.link_targets.append(t) def link_whole(self, targets: T.List[BuildTargetTypes], promoted: bool = False) -> None: for t in targets: if isinstance(t, (CustomTarget, CustomTargetIndex)): if not t.is_linkable_target(): raise InvalidArguments(f'Custom target {t!r} is not linkable.') if t.links_dynamically(): raise InvalidArguments('Can only link_whole custom targets that are static archives.') elif not isinstance(t, StaticLibrary): raise InvalidArguments(f'{t!r} is not a static library.') elif isinstance(self, SharedLibrary) and not t.pic: msg = f"Can't link non-PIC static library {t.name!r} into shared library {self.name!r}. " msg += "Use the 'pic' option to static_library to build with PIC." raise InvalidArguments(msg) self.check_can_link_together(t) 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._bundle_static_library(t, promoted) # If we install this static library we also need to include objects # from all uninstalled static libraries it depends on. if self.install: for lib in t.get_internal_static_libraries(): self._bundle_static_library(lib, True) self.link_whole_targets.append(t) @lru_cache(maxsize=None) def get_internal_static_libraries(self) -> OrderedSet[BuildTargetTypes]: result: OrderedSet[BuildTargetTypes] = OrderedSet() self.get_internal_static_libraries_recurse(result) return result def get_internal_static_libraries_recurse(self, result: OrderedSet[BuildTargetTypes]) -> None: for t in self.link_targets: if t.is_internal() and t not in result: result.add(t) t.get_internal_static_libraries_recurse(result) for t in self.link_whole_targets: if t.is_internal(): t.get_internal_static_libraries_recurse(result) def _bundle_static_library(self, t: T.Union[BuildTargetTypes], promoted: bool = False) -> None: if self.uses_rust(): # Rustc can bundle static libraries, no need to extract objects. self.link_whole_targets.append(t) elif isinstance(t, (CustomTarget, CustomTargetIndex)) or t.uses_rust(): # To extract objects from a custom target we would have to extract # the archive, WIP implementation can be found in # https://github.com/mesonbuild/meson/pull/9218. # For Rust C ABI we could in theory have access to objects, but there # are several meson issues that need to be fixed: # https://github.com/mesonbuild/meson/issues/10722 # https://github.com/mesonbuild/meson/issues/10723 # https://github.com/mesonbuild/meson/issues/10724 m = (f'Cannot link_whole a custom or Rust target {t.name!r} into a static library {self.name!r}. ' 'Instead, pass individual object files with the "objects:" keyword argument if possible.') if promoted: m += (f' Meson had to promote link to link_whole because {self.name!r} is installed but not {t.name!r},' f' and thus has to include objects from {t.name!r} to be usable.') raise InvalidArguments(m) else: self.objects.append(t.extract_all_objects()) def check_can_link_together(self, t: BuildTargetTypes) -> None: links_with_rust_abi = isinstance(t, BuildTarget) and t.uses_rust_abi() if not self.uses_rust() and links_with_rust_abi: raise InvalidArguments(f'Try to link Rust ABI library {t.name!r} with a non-Rust target {self.name!r}') if self.for_machine is not t.for_machine and (not links_with_rust_abi or t.rust_crate_type != 'proc-macro'): msg = f'Tried to mix libraries for machines {self.for_machine} and {t.for_machine} in target {self.name!r}' 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.') def add_pch(self, language: str, pchlist: T.List[str]) -> None: if not pchlist: return elif len(pchlist) == 1: if not is_header(pchlist[0]): raise InvalidArguments(f'PCH argument {pchlist[0]} is not a header.') elif len(pchlist) == 2: if is_header(pchlist[0]): if not is_source(pchlist[1]): raise InvalidArguments('PCH definition must contain one header and at most one source.') elif is_source(pchlist[0]): if not 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(f'PCH argument {pchlist[0]} is of unknown type.') if os.path.dirname(pchlist[0]) != os.path.dirname(pchlist[1]): raise InvalidArguments('PCH files must be stored in the same folder.') FeatureDeprecated.single_use('PCH source files', '0.50.0', self.subproject, '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(f'File {f} does not exist.') self.pch[language] = pchlist def add_include_dirs(self, args: T.Sequence['IncludeDirs'], set_is_system: T.Optional[str] = None) -> None: ids: T.List['IncludeDirs'] = [] for a in args: 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 get_aliases(self) -> T.List[T.Tuple[str, str, str]]: 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: T.List[str] = [] # 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_prelinker(self): if self.link_language: comp = self.all_compilers[self.link_language] return comp for l in clink_langs: if l in self.compilers: try: prelinker = self.all_compilers[l] except KeyError: raise MesonException( f'Could not get a prelinker linker for build target {self.name!r}. ' f'Requires a compiler for language "{l}", but that is not ' 'a project language.') return prelinker raise MesonException(f'Could not determine prelinker for {self.name!r}.') def get_clink_dynamic_linker_and_stdlibs(self) -> T.Tuple['Compiler', T.List[str]]: ''' 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. ''' # If the user set the link_language, just return that. if self.link_language: comp = self.all_compilers[self.link_language] return comp, comp.language_stdlib_only_link_flags(self.environment) # Since dependencies could come from subprojects, they could have # languages we don't have in self.all_compilers. Use the global list of # all compilers here. 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( f'Could not get a dynamic linker for build target {self.name!r}. ' f'Requires a linker for language "{l}", but that is not ' 'a project language.') stdlib_args: T.List[str] = self.get_used_stdlib_args(linker.language) # Type of var 'linker' is Compiler. # Pretty hard to fix because the return value is passed everywhere return linker, stdlib_args # None of our compilers can do clink, this happens for example if the # target only has ASM sources. Pick the first capable compiler. for l in clink_langs: try: comp = self.all_compilers[l] return comp, comp.language_stdlib_only_link_flags(self.environment) except KeyError: pass raise AssertionError(f'Could not get a dynamic linker for build target {self.name!r}') def get_used_stdlib_args(self, link_language: str) -> T.List[str]: all_compilers = self.environment.coredata.compilers[self.for_machine] all_langs = set(self.compilers).union(self.get_langs_used_by_deps()) stdlib_args: T.List[str] = [] for dl in all_langs: if dl != link_language and (dl, link_language) not in self._MASK_LANGS: # We need to use all_compilers here because # get_langs_used_by_deps could return a language from a # subproject stdlib_args.extend(all_compilers[dl].language_stdlib_only_link_flags(self.environment)) return stdlib_args def uses_rust(self) -> bool: return 'rust' in self.compilers def uses_rust_abi(self) -> bool: return self.uses_rust() and self.rust_crate_type in {'dylib', 'rlib', 'proc-macro'} def uses_fortran(self) -> bool: return 'fortran' in self.compilers def get_using_msvc(self) -> bool: ''' 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. ''' # Rustc can use msvc style linkers if self.uses_rust(): compiler = self.all_compilers['rust'] else: compiler, _ = self.get_clink_dynamic_linker_and_stdlibs() # Mixing many languages with MSVC is not supported yet so ignore stdlibs. return compiler and compiler.get_linker_id() in {'link', 'lld-link', 'xilink', 'optlink'} 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) and not link_target.force_soname: if self.environment.machines[self.for_machine].is_darwin(): raise MesonException( f'target {self.name} links against shared module {link_target.name}. This is not permitted on OSX') elif self.environment.machines[self.for_machine].is_android() and isinstance(self, SharedModule): # Android requires shared modules that use symbols from other shared modules to # be linked before they can be dlopen()ed in the correct order. Not doing so # leads to a missing symbol error: https://github.com/android/ndk/issues/201 link_target.force_soname = True else: mlog.deprecation(f'target {self.name} links against shared module {link_target.name}, which is incorrect.' '\n ' f'This will be an error in the future, so please use shared_library() for {link_target.name} instead.' '\n ' f'If shared_module() was used for {link_target.name} because it has references to undefined symbols,' '\n ' 'use shared_library() with `override_options: [\'b_lundef=false\']` instead.') link_target.force_soname = True def process_vs_module_defs_kw(self, kwargs: T.Dict[str, T.Any]) -> None: if kwargs.get('vs_module_defs') is None: return path: T.Union[str, File, CustomTarget, CustomTargetIndex] = kwargs['vs_module_defs'] 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(self.environment.source_dir, self.subdir, path) elif isinstance(path, File): # When passing a generated file. self.vs_module_defs = path elif isinstance(path, (CustomTarget, CustomTargetIndex)): # When passing output of a Custom Target self.vs_module_defs = File.from_built_file(path.get_subdir(), path.get_filename()) else: raise InvalidArguments( 'vs_module_defs must be either a string, ' 'a file object, a Custom Target, or a Custom Target Index') self.process_link_depends(path) class FileInTargetPrivateDir: """Represents a file with the path '/path/to/build/target_private_dir/fname'. target_private_dir is the return value of get_target_private_dir which is e.g. 'subdir/target.p'. """ def __init__(self, fname: str): self.fname = fname def __str__(self) -> str: return self.fname class FileMaybeInTargetPrivateDir: """Union between 'File' and 'FileInTargetPrivateDir'""" def __init__(self, inner: T.Union[File, FileInTargetPrivateDir]): self.inner = inner @property def fname(self) -> str: return self.inner.fname def rel_to_builddir(self, build_to_src: str, target_private_dir: str) -> str: if isinstance(self.inner, FileInTargetPrivateDir): return os.path.join(target_private_dir, self.inner.fname) return self.inner.rel_to_builddir(build_to_src) def absolute_path(self, srcdir: str, builddir: str) -> str: if isinstance(self.inner, FileInTargetPrivateDir): raise RuntimeError('Unreachable code') return self.inner.absolute_path(srcdir, builddir) def __str__(self) -> str: return self.fname class Generator(HoldableObject): def __init__(self, exe: T.Union['Executable', programs.ExternalProgram], arguments: T.List[str], output: T.List[str], # how2dataclass *, depfile: T.Optional[str] = None, capture: bool = False, depends: T.Optional[T.List[T.Union[BuildTarget, 'CustomTarget']]] = None, name: str = 'Generator'): self.exe = exe self.depfile = depfile self.capture = capture self.depends: T.List[T.Union[BuildTarget, 'CustomTarget']] = depends or [] self.arglist = arguments self.outputs = output self.name = name def __repr__(self) -> str: repr_str = "<{0}: {1}>" return repr_str.format(self.__class__.__name__, self.exe) def get_exe(self) -> T.Union['Executable', programs.ExternalProgram]: return self.exe def get_base_outnames(self, inname: str) -> T.List[str]: 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: str) -> T.List[str]: 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: str) -> T.List[str]: plainname = os.path.basename(inname) basename = os.path.splitext(plainname)[0] return [x.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname) for x in self.arglist] @staticmethod def is_parent_path(parent: str, trial: str) -> bool: relpath = pathlib.PurePath(trial).relative_to(parent) return relpath.parts[0] != '..' # For subdirs we can only go "down". def process_files(self, files: T.Iterable[T.Union[str, File, 'CustomTarget', 'CustomTargetIndex', 'GeneratedList']], state: T.Union['Interpreter', 'ModuleState'], preserve_path_from: T.Optional[str] = None, extra_args: T.Optional[T.List[str]] = None, env: T.Optional[EnvironmentVariables] = None) -> 'GeneratedList': output = GeneratedList( self, state.subdir, preserve_path_from, extra_args=extra_args if extra_args is not None else [], env=env if env is not None else EnvironmentVariables()) for e in files: if isinstance(e, CustomTarget): output.depends.add(e) if isinstance(e, CustomTargetIndex): output.depends.add(e.target) if isinstance(e, (CustomTarget, CustomTargetIndex)): output.depends.add(e) fs = [File.from_built_file(state.subdir, f) for f in e.get_outputs()] elif isinstance(e, GeneratedList): if preserve_path_from: raise InvalidArguments("generator.process: 'preserve_path_from' is not allowed if one input is a 'generated_list'.") output.depends.add(e) fs = [FileInTargetPrivateDir(f) for f in e.get_outputs()] elif isinstance(e, str): fs = [File.from_source_file(state.environment.source_dir, state.subdir, e)] else: fs = [e] for f in fs: 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('generator.process: When using preserve_path_from, all input files must be in a subdirectory of the given dir.') f = FileMaybeInTargetPrivateDir(f) output.add_file(f, state) return output @dataclass(eq=False) class GeneratedList(HoldableObject): """The output of generator.process.""" generator: Generator subdir: str preserve_path_from: T.Optional[str] extra_args: T.List[str] env: T.Optional[EnvironmentVariables] def __post_init__(self) -> None: self.name = self.generator.exe self.depends: T.Set[GeneratedTypes] = set() self.infilelist: T.List[FileMaybeInTargetPrivateDir] = [] self.outfilelist: T.List[str] = [] self.outmap: T.Dict[FileMaybeInTargetPrivateDir, T.List[str]] = {} self.extra_depends = [] # XXX: Doesn't seem to be used? self.depend_files: T.List[File] = [] if self.extra_args is None: self.extra_args: T.List[str] = [] if self.env is None: self.env: EnvironmentVariables = EnvironmentVariables() if isinstance(self.generator.exe, programs.ExternalProgram): if not self.generator.exe.found(): raise InvalidArguments('Tried to use not-found external program as generator') path = self.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: FileMaybeInTargetPrivateDir, outfiles: T.List[str], state: T.Union['Interpreter', 'ModuleState']) -> T.List[str]: result: T.List[str] = [] 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: FileMaybeInTargetPrivateDir, state: T.Union['Interpreter', 'ModuleState']) -> None: 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) -> T.List[FileMaybeInTargetPrivateDir]: return self.infilelist def get_outputs(self) -> T.List[str]: return self.outfilelist def get_outputs_for(self, filename: FileMaybeInTargetPrivateDir) -> T.List[str]: return self.outmap[filename] def get_generator(self) -> 'Generator': return self.generator def get_extra_args(self) -> T.List[str]: return self.extra_args def get_subdir(self) -> str: return self.subdir class Executable(BuildTarget): known_kwargs = known_exe_kwargs typename = 'executable' def __init__( self, name: str, subdir: str, subproject: SubProject, for_machine: MachineChoice, sources: T.List['SourceOutputs'], structured_sources: T.Optional[StructuredSources], objects: T.List[ObjectTypes], environment: environment.Environment, compilers: T.Dict[str, 'Compiler'], kwargs): key = OptionKey('b_pie') if 'pie' not in kwargs and key in environment.coredata.options: kwargs['pie'] = environment.coredata.options[key].value super().__init__(name, subdir, subproject, for_machine, sources, structured_sources, objects, environment, compilers, kwargs) self.win_subsystem = kwargs.get('win_subsystem') or 'console' # Check for export_dynamic self.export_dynamic = kwargs.get('export_dynamic', False) if not isinstance(self.export_dynamic, bool): raise InvalidArguments('"export_dynamic" keyword argument must be a boolean') self.implib = kwargs.get('implib') if not isinstance(self.implib, (bool, str, type(None))): raise InvalidArguments('"export_dynamic" keyword argument must be a boolean or string') # Only linkwithable if using export_dynamic self.is_linkwithable = self.export_dynamic # Remember that this exe was returned by `find_program()` through an override self.was_returned_by_find_program = False self.vs_module_defs: T.Optional[File] = None self.process_vs_module_defs_kw(kwargs) def post_init(self) -> None: super().post_init() machine = self.environment.machines[self.for_machine] # 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'): # 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('armclang') or 'cpp' in self.compilers and self.compilers['cpp'].get_id().startswith('armclang')): 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' elif ('c' in self.compilers and self.compilers['c'].get_id().startswith('xc16')): self.suffix = 'elf' elif ('c' in self.compilers and self.compilers['c'].get_id() in {'ti', 'c2000'} or 'cpp' in self.compilers and self.compilers['cpp'].get_id() in {'ti', 'c2000'}): self.suffix = 'out' elif ('c' in self.compilers and self.compilers['c'].get_id() in {'mwccarm', 'mwcceppc'} or 'cpp' in self.compilers and self.compilers['cpp'].get_id() in {'mwccarm', 'mwcceppc'}): self.suffix = 'nef' else: self.suffix = machine.get_exe_suffix() self.filename = self.name if self.suffix: self.filename += '.' + self.suffix self.outputs[0] = self.filename # The import library this target will generate self.import_filename = None # The debugging information file this target will generate self.debug_filename = None # If using export_dynamic, set the import library name if self.export_dynamic: implib_basename = self.name + '.exe' if isinstance(self.implib, str): implib_basename = self.implib if machine.is_windows() or machine.is_cygwin(): if self.get_using_msvc(): self.import_filename = f'{implib_basename}.lib' else: self.import_filename = f'lib{implib_basename}.a' create_debug_file = ( machine.is_windows() and ('cs' in self.compilers or self.uses_rust() or self.get_using_msvc()) # .pdb file is created only when debug symbols are enabled and self.environment.coredata.get_option(OptionKey("debug")) ) if create_debug_file: # If the target is has a standard exe extension (i.e. 'foo.exe'), # then the pdb name simply becomes 'foo.pdb'. If the extension is # something exotic, then include that in the name for uniqueness # reasons (e.g. 'foo_com.pdb'). name = self.name if getattr(self, 'suffix', 'exe') != 'exe': name += '_' + self.suffix self.debug_filename = name + '.pdb' def process_kwargs(self, kwargs): super().process_kwargs(kwargs) self.rust_crate_type = kwargs.get('rust_crate_type') or 'bin' if self.rust_crate_type != 'bin': raise InvalidArguments('Invalid rust_crate_type: must be "bin" for executables.') def get_default_install_dir(self) -> T.Tuple[str, str]: return self.environment.get_bindir(), '{bindir}' def description(self): '''Human friendly description of the executable''' return self.name def type_suffix(self): return "@exe" def get_import_filename(self) -> T.Optional[str]: """ 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) -> T.Optional[str]: """ 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 def get_command(self) -> 'ImmutableListProtocol[str]': """Provides compatibility with ExternalProgram. Since you can override ExternalProgram instances with Executables. """ return self.outputs def get_path(self) -> str: """Provides compatibility with ExternalProgram.""" return os.path.join(self.subdir, self.filename) def found(self) -> bool: """Provides compatibility with ExternalProgram.""" return True class StaticLibrary(BuildTarget): known_kwargs = known_stlib_kwargs typename = 'static library' def __init__( self, name: str, subdir: str, subproject: SubProject, for_machine: MachineChoice, sources: T.List['SourceOutputs'], structured_sources: T.Optional[StructuredSources], objects: T.List[ObjectTypes], environment: environment.Environment, compilers: T.Dict[str, 'Compiler'], kwargs): self.prelink = T.cast('bool', kwargs.get('prelink', False)) super().__init__(name, subdir, subproject, for_machine, sources, structured_sources, objects, environment, compilers, kwargs) def post_init(self) -> None: super().post_init() if 'cs' in self.compilers: raise InvalidArguments('Static libraries not supported for C#.') if self.uses_rust(): # See https://github.com/rust-lang/rust/issues/110460 if self.rust_crate_type == 'rlib' and any(c in self.name for c in ['-', ' ', '.']): raise InvalidArguments(f'Rust crate {self.name} type {self.rust_crate_type} does not allow spaces, ' 'periods or dashes in the library name due to a limitation of rustc. ' 'Replace them with underscores, for example') if self.rust_crate_type == 'staticlib': # FIXME: In the case of no-std we should not add those libraries, # but we have no way to know currently. rustc = self.compilers['rust'] d = dependencies.InternalDependency('undefined', [], [], rustc.native_static_libs, [], [], [], [], [], {}, [], [], []) self.external_deps.append(d) # 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. # # See our FAQ for more detailed rationale: # https://mesonbuild.com/FAQ.html#why-does-building-my-project-with-msvc-output-static-libraries-called-libfooa if not hasattr(self, 'prefix'): self.prefix = 'lib' if not hasattr(self, 'suffix'): if self.uses_rust(): if 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[0] = self.filename def get_link_deps_mapping(self, prefix: str) -> T.Mapping[str, str]: return {} def get_default_install_dir(self) -> T.Tuple[str, str]: return self.environment.get_static_lib_dir(), '{libdir_static}' def type_suffix(self): return "@sta" def process_kwargs(self, kwargs): super().process_kwargs(kwargs) rust_abi = kwargs.get('rust_abi') rust_crate_type = kwargs.get('rust_crate_type') if rust_crate_type: if rust_abi: raise InvalidArguments('rust_abi and rust_crate_type are mutually exclusive.') if rust_crate_type == 'lib': self.rust_crate_type = 'rlib' elif rust_crate_type in {'rlib', 'staticlib'}: self.rust_crate_type = rust_crate_type else: raise InvalidArguments(f'Crate type {rust_crate_type!r} invalid for static libraries; must be "rlib" or "staticlib"') else: self.rust_crate_type = 'staticlib' if rust_abi == 'c' else 'rlib' def is_linkable_target(self): return True def is_internal(self) -> bool: return not self.install class SharedLibrary(BuildTarget): known_kwargs = known_shlib_kwargs typename = 'shared library' # Used by AIX to decide whether to archive shared library or not. aix_so_archive = True def __init__( self, name: str, subdir: str, subproject: SubProject, for_machine: MachineChoice, sources: T.List['SourceOutputs'], structured_sources: T.Optional[StructuredSources], objects: T.List[ObjectTypes], environment: environment.Environment, compilers: T.Dict[str, 'Compiler'], kwargs): self.soversion: T.Optional[str] = None self.ltversion: T.Optional[str] = None # Max length 2, first element is compatibility_version, second is current_version self.darwin_versions: T.Optional[T.Tuple[str, str]] = None self.vs_module_defs = None # The import library this target will generate self.import_filename = None # The debugging information file this target will generate self.debug_filename = None # Use by the pkgconfig module self.shared_library_only = False super().__init__(name, subdir, subproject, for_machine, sources, structured_sources, objects, environment, compilers, kwargs) def post_init(self) -> None: super().post_init() if self.uses_rust(): # See https://github.com/rust-lang/rust/issues/110460 if self.rust_crate_type != 'cdylib' and any(c in self.name for c in ['-', ' ', '.']): raise InvalidArguments(f'Rust crate {self.name} type {self.rust_crate_type} does not allow spaces, ' 'periods or dashes in the library name due to a limitation of rustc. ' 'Replace them with underscores, for example') 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() def get_link_deps_mapping(self, prefix: str) -> T.Mapping[str, str]: result: T.Dict[str, str] = {} mappings = self.get_transitive_link_deps_mapping(prefix) old = get_target_macos_dylib_install_name(self) if old not in mappings: fname = self.get_filename() outdirs, _, _ = self.get_install_dir() new = os.path.join(prefix, outdirs[0], fname) result.update({old: new}) mappings.update(result) return mappings def get_default_install_dir(self) -> T.Tuple[str, str]: return self.environment.get_shared_lib_dir(), '{libdir_shared}' def determine_filenames(self): """ 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 (self.import_filename), 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). """ prefix = '' suffix = '' create_debug_file = False self.filename_tpl = self.basic_filename_tpl import_filename_tpl = None # 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 self.environment.machines[self.for_machine].is_windows(): suffix = 'dll' if self.uses_rust(): # Shared library is of the form foo.dll prefix = '' # Import library is called foo.dll.lib import_filename_tpl = '{0.prefix}{0.name}.dll.lib' # .pdb file is only created when debug symbols are enabled create_debug_file = self.environment.coredata.get_option(OptionKey("debug")) elif self.get_using_msvc(): # Shared library is of the form foo.dll prefix = '' # Import library is called foo.lib import_filename_tpl = '{0.prefix}{0.name}.lib' # .pdb file is only created when debug symbols are enabled create_debug_file = self.environment.coredata.get_option(OptionKey("debug")) # Assume GCC-compatible naming else: # Shared library is of the form libfoo.dll prefix = 'lib' # Import library is called libfoo.dll.a import_filename_tpl = '{0.prefix}{0.name}.dll.a' # 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 self.environment.machines[self.for_machine].is_cygwin(): suffix = 'dll' # 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 import_prefix = self.prefix if self.prefix is not None else 'lib' import_filename_tpl = import_prefix + '{0.name}.dll.a' 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 self.environment.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 self.environment.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) if import_filename_tpl: self.import_filename = import_filename_tpl.format(self) # There may have been more outputs added by the time we get here, so # only replace the first entry self.outputs[0] = self.filename if create_debug_file: self.debug_filename = os.path.splitext(self.filename)[0] + '.pdb' def process_kwargs(self, kwargs): super().process_kwargs(kwargs) if not self.environment.machines[self.for_machine].is_android(): # Shared library version self.ltversion = T.cast('T.Optional[str]', kwargs.get('version')) self.soversion = T.cast('T.Optional[str]', kwargs.get('soversion')) if self.soversion is None and self.ltversion is not None: # 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 self.darwin_versions = T.cast('T.Optional[T.Tuple[str, str]]', kwargs.get('darwin_versions')) if self.darwin_versions is None and self.soversion is not None: # If unspecified, pick the soversion self.darwin_versions = (self.soversion, self.soversion) # Visual Studio module-definitions file self.process_vs_module_defs_kw(kwargs) rust_abi = kwargs.get('rust_abi') rust_crate_type = kwargs.get('rust_crate_type') if rust_crate_type: if rust_abi: raise InvalidArguments('rust_abi and rust_crate_type are mutually exclusive.') if rust_crate_type == 'lib': self.rust_crate_type = 'dylib' elif rust_crate_type in {'dylib', 'cdylib', 'proc-macro'}: self.rust_crate_type = rust_crate_type else: raise InvalidArguments(f'Crate type {rust_crate_type!r} invalid for shared libraries; must be "dylib", "cdylib" or "proc-macro"') else: self.rust_crate_type = 'cdylib' if rust_abi == 'c' else 'dylib' def get_import_filename(self) -> T.Optional[str]: """ 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) -> T.Optional[str]: """ 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_all_link_deps(self): return [self] + self.get_transitive_link_deps() def get_aliases(self) -> T.List[T.Tuple[str, str, str]]: """ 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: T.List[T.Tuple[str, str, str]] = [] # 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 aliases # 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) tag = self.install_tag[0] or 'runtime' aliases.append((ltversion_filename, self.filename, tag)) # 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 tag = self.install_tag[0] or 'devel' aliases.append((self.basic_filename_tpl.format(self), ltversion_filename, tag)) 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 typename = 'shared module' # Used by AIX to not archive shared library for dlopen mechanism aix_so_archive = False def __init__( self, name: str, subdir: str, subproject: SubProject, for_machine: MachineChoice, sources: T.List['SourceOutputs'], structured_sources: T.Optional[StructuredSources], objects: T.List[ObjectTypes], environment: environment.Environment, compilers: T.Dict[str, 'Compiler'], 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, structured_sources, objects, environment, compilers, kwargs) # We need to set the soname in cases where build files link the module # to build targets, see: https://github.com/mesonbuild/meson/issues/9492 self.force_soname = False def get_default_install_dir(self) -> T.Tuple[str, str]: return self.environment.get_shared_module_dir(), '{moduledir_shared}' class BothLibraries(SecondLevelHolder): def __init__(self, shared: SharedLibrary, static: StaticLibrary) -> None: self._preferred_library = 'shared' self.shared = shared self.static = static self.subproject = self.shared.subproject def __repr__(self) -> str: return f'' def get_default_object(self) -> BuildTarget: if self._preferred_library == 'shared': return self.shared elif self._preferred_library == 'static': return self.static raise MesonBugException(f'self._preferred_library == "{self._preferred_library}" is neither "shared" nor "static".') class CommandBase: depend_files: T.List[File] dependencies: T.List[T.Union[BuildTarget, 'CustomTarget']] subproject: str def flatten_command(self, cmd: T.Sequence[T.Union[str, File, programs.ExternalProgram, BuildTargetTypes]]) -> \ T.List[T.Union[str, File, BuildTarget, 'CustomTarget']]: cmd = listify(cmd) final_cmd: T.List[T.Union[str, File, BuildTarget, 'CustomTarget']] = [] 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, programs.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, CustomTargetIndex): FeatureNew.single_use('CustomTargetIndex for command argument', '0.60', self.subproject) self.dependencies.append(c.target) final_cmd += self.flatten_command(File.from_built_file(c.get_subdir(), c.get_filename())) elif isinstance(c, list): final_cmd += self.flatten_command(c) else: raise InvalidArguments(f'Argument {c!r} in "command" is invalid') return final_cmd class CustomTargetBase: ''' Base class for CustomTarget and CustomTargetIndex This base class can be used to provide a dummy implementation of some private methods to avoid repeating `isinstance(t, BuildTarget)` when dealing with custom targets. ''' rust_crate_type = '' def get_dependencies_recurse(self, result: OrderedSet[BuildTargetTypes], include_internals: bool = True) -> None: pass def get_internal_static_libraries(self) -> OrderedSet[BuildTargetTypes]: return OrderedSet() def get_internal_static_libraries_recurse(self, result: OrderedSet[BuildTargetTypes]) -> None: pass class CustomTarget(Target, CustomTargetBase, CommandBase): typename = 'custom' def __init__(self, name: T.Optional[str], subdir: str, subproject: str, environment: environment.Environment, command: T.Sequence[T.Union[ str, BuildTargetTypes, GeneratedList, programs.ExternalProgram, File]], sources: T.Sequence[T.Union[ str, File, BuildTargetTypes, ExtractedObjects, GeneratedList, programs.ExternalProgram]], outputs: T.List[str], *, build_always_stale: bool = False, build_by_default: T.Optional[bool] = None, capture: bool = False, console: bool = False, depend_files: T.Optional[T.Sequence[FileOrString]] = None, extra_depends: T.Optional[T.Sequence[T.Union[str, SourceOutputs]]] = None, depfile: T.Optional[str] = None, env: T.Optional[EnvironmentVariables] = None, feed: bool = False, install: bool = False, install_dir: T.Optional[T.List[T.Union[str, Literal[False]]]] = None, install_mode: T.Optional[FileMode] = None, install_tag: T.Optional[T.List[T.Optional[str]]] = None, absolute_paths: bool = False, backend: T.Optional['Backend'] = None, description: str = 'Generating {} with a custom command', ): # TODO expose keyword arg to make MachineChoice.HOST configurable super().__init__(name, subdir, subproject, False, MachineChoice.HOST, environment, install, build_always_stale) self.sources = list(sources) self.outputs = substitute_values( outputs, get_filenames_templates_dict( get_sources_string_names(sources, backend), [])) self.build_by_default = build_by_default if build_by_default is not None else install self.capture = capture self.console = console self.depend_files = list(depend_files or []) self.dependencies: T.List[T.Union[CustomTarget, BuildTarget]] = [] # must be after depend_files and dependencies self.command = self.flatten_command(command) self.depfile = depfile self.env = env or EnvironmentVariables() self.extra_depends = list(extra_depends or []) self.feed = feed self.install_dir = list(install_dir or []) self.install_mode = install_mode self.install_tag = _process_install_tag(install_tag, len(self.outputs)) self.name = name if name else self.outputs[0] self.description = description # Whether to use absolute paths for all files on the commandline self.absolute_paths = absolute_paths def get_default_install_dir(self) -> T.Tuple[str, str]: return None, 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) -> T.List[T.Union[SourceOutputs, str]]: deps: T.List[T.Union[SourceOutputs, str]] = [] deps.extend(self.dependencies) deps.extend(self.extra_depends) for c in self.sources: if isinstance(c, CustomTargetIndex): deps.append(c.target) elif not isinstance(c, programs.ExternalProgram): deps.append(c) return deps def get_transitive_build_target_deps(self) -> T.Set[T.Union[BuildTarget, 'CustomTarget']]: ''' 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: T.Set[T.Union[BuildTarget, 'CustomTarget']] = 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 get_dependencies(self): return self.dependencies def should_install(self) -> bool: return self.install def get_custom_install_dir(self) -> T.List[T.Union[str, Literal[False]]]: return self.install_dir def get_custom_install_mode(self) -> T.Optional['FileMode']: return self.install_mode def get_outputs(self) -> T.List[str]: return self.outputs def get_filename(self) -> str: return self.outputs[0] def get_sources(self) -> T.List[T.Union[str, File, BuildTarget, GeneratedTypes, ExtractedObjects, programs.ExternalProgram]]: return self.sources def get_generated_lists(self) -> T.List[GeneratedList]: genlists: T.List[GeneratedList] = [] for c in self.sources: if isinstance(c, GeneratedList): genlists.append(c) return genlists def get_generated_sources(self) -> T.List[GeneratedList]: 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 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_output(self, output: str) -> bool: if output.endswith(('.a', '.dll', '.lib', '.so', '.dylib')): return True # libfoo.so.X soname if re.search(r'\.so(\.\d+)*$', output): return True return False def is_linkable_target(self) -> bool: if len(self.outputs) != 1: return False return self.is_linkable_output(self.outputs[0]) def links_dynamically(self) -> bool: """Whether this target links dynamically or statically Does not assert the target is linkable, just that it is not shared :return: True if is dynamically linked, otherwise False """ suf = os.path.splitext(self.outputs[0])[-1] return suf not in {'.a', '.lib'} def get_link_deps_mapping(self, prefix: str) -> T.Mapping[str, str]: return {} def get_link_dep_subdirs(self) -> T.AbstractSet[str]: return OrderedSet() def get_all_link_deps(self): return [] def is_internal(self) -> bool: ''' Returns True if this is a not installed static library. ''' if len(self.outputs) != 1: return False return CustomTargetIndex(self, self.outputs[0]).is_internal() def extract_all_objects(self) -> T.List[T.Union[str, 'ExtractedObjects']]: return self.get_outputs() def type_suffix(self): return "@cus" def __getitem__(self, index: int) -> 'CustomTargetIndex': return CustomTargetIndex(self, self.outputs[index]) def __setitem__(self, index, value): raise NotImplementedError def __delitem__(self, index): raise NotImplementedError def __iter__(self): for i in self.outputs: yield CustomTargetIndex(self, i) def __len__(self) -> int: return len(self.outputs) class CompileTarget(BuildTarget): ''' Target that only compile sources without linking them together. It can be used as preprocessor, or transpiler. ''' typename = 'compile' def __init__(self, name: str, subdir: str, subproject: str, environment: environment.Environment, sources: T.List['SourceOutputs'], output_templ: str, compiler: Compiler, backend: Backend, compile_args: T.List[str], include_directories: T.List[IncludeDirs], dependencies: T.List[dependencies.Dependency]): compilers = {compiler.get_language(): compiler} kwargs = { 'build_by_default': False, 'language_args': {compiler.language: compile_args}, 'include_directories': include_directories, 'dependencies': dependencies, } super().__init__(name, subdir, subproject, compiler.for_machine, sources, None, [], environment, compilers, kwargs) self.filename = name self.compiler = compiler self.output_templ = output_templ self.outputs = [] self.sources_map: T.Dict[File, str] = {} for f in self.sources: self._add_output(f) for gensrc in self.generated: for s in gensrc.get_outputs(): rel_src = backend.get_target_generated_dir(self, gensrc, s) self._add_output(File.from_built_relative(rel_src)) def type_suffix(self) -> str: return "@compile" @property def is_unity(self) -> bool: return False def _add_output(self, f: File) -> None: plainname = os.path.basename(f.fname) basename = os.path.splitext(plainname)[0] o = self.output_templ.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname) self.outputs.append(o) self.sources_map[f] = o class RunTarget(Target, CommandBase): typename = 'run' def __init__(self, name: str, command: T.Sequence[T.Union[str, File, BuildTargetTypes, programs.ExternalProgram]], dependencies: T.Sequence[Target], subdir: str, subproject: str, environment: environment.Environment, env: T.Optional['EnvironmentVariables'] = None, default_env: bool = True): # These don't produce output artifacts super().__init__(name, subdir, subproject, False, MachineChoice.BUILD, environment) self.dependencies = dependencies self.depend_files = [] self.command = self.flatten_command(command) self.absolute_paths = False self.env = env self.default_env = default_env def __repr__(self) -> str: repr_str = "<{0} {1}: {2}>" return repr_str.format(self.__class__.__name__, self.get_id(), self.command[0]) def get_dependencies(self) -> T.List[T.Union[BuildTarget, 'CustomTarget']]: return self.dependencies def get_generated_sources(self) -> T.List['GeneratedTypes']: return [] def get_sources(self) -> T.List[File]: return [] def should_install(self) -> bool: return False def get_filename(self) -> str: return self.name def get_outputs(self) -> T.List[str]: 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) -> str: return "@run" class AliasTarget(RunTarget): typename = 'alias' def __init__(self, name: str, dependencies: T.Sequence['Target'], subdir: str, subproject: str, environment: environment.Environment): super().__init__(name, [], dependencies, subdir, subproject, environment) def __repr__(self): repr_str = "<{0} {1}>" return repr_str.format(self.__class__.__name__, self.get_id()) class Jar(BuildTarget): known_kwargs = known_jar_kwargs typename = 'jar' def __init__(self, name: str, subdir: str, subproject: str, for_machine: MachineChoice, sources: T.List[SourceOutputs], structured_sources: T.Optional['StructuredSources'], objects, environment: environment.Environment, compilers: T.Dict[str, 'Compiler'], kwargs): super().__init__(name, subdir, subproject, for_machine, sources, structured_sources, objects, environment, compilers, kwargs) for s in self.sources: if not s.endswith('.java'): raise InvalidArguments(f'Jar source {s} is not a java file.') for t in self.link_targets: if not isinstance(t, Jar): raise InvalidArguments(f'Link target {t} is not a jar target.') if self.structured_sources: raise InvalidArguments('structured sources are not supported in Java targets.') self.filename = self.name + '.jar' self.outputs = [self.filename] self.java_args = self.extra_args['java'] self.main_class = kwargs.get('main_class', '') self.java_resources: T.Optional[StructuredSources] = kwargs.get('java_resources', None) 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 get_java_resources(self) -> T.Optional[StructuredSources]: return self.java_resources def validate_install(self): # 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 [] def get_default_install_dir(self) -> T.Tuple[str, str]: return self.environment.get_jar_dir(), '{jardir}' @dataclass(eq=False) class CustomTargetIndex(CustomTargetBase, HoldableObject): """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. """ typename: T.ClassVar[str] = 'custom' target: T.Union[CustomTarget, CompileTarget] output: str def __post_init__(self) -> None: self.for_machine = self.target.for_machine @property def name(self) -> str: return f'{self.target.name}[{self.output}]' def __repr__(self): return ''.format(self.target, self.output) def get_outputs(self) -> T.List[str]: return [self.output] def get_subdir(self) -> str: return self.target.get_subdir() def get_filename(self) -> str: return self.output def get_id(self) -> str: 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: str) -> T.Mapping[str, str]: return self.target.get_link_deps_mapping(prefix) def get_link_dep_subdirs(self) -> T.AbstractSet[str]: return self.target.get_link_dep_subdirs() def is_linkable_target(self) -> bool: return self.target.is_linkable_output(self.output) def links_dynamically(self) -> bool: """Whether this target links dynamically or statically Does not assert the target is linkable, just that it is not shared :return: True if is dynamically linked, otherwise False """ suf = os.path.splitext(self.output)[-1] return suf not in {'.a', '.lib'} def should_install(self) -> bool: return self.target.should_install() def is_internal(self) -> bool: ''' Returns True if this is a not installed static library ''' suf = os.path.splitext(self.output)[-1] return suf in {'.a', '.lib'} and not self.should_install() def extract_all_objects(self) -> T.List[T.Union[str, 'ExtractedObjects']]: return self.target.extract_all_objects() def get_custom_install_dir(self) -> T.List[T.Union[str, Literal[False]]]: return self.target.get_custom_install_dir() class ConfigurationData(HoldableObject): def __init__(self, initial_values: T.Optional[T.Union[ T.Dict[str, T.Tuple[T.Union[str, int, bool], T.Optional[str]]], T.Dict[str, T.Union[str, int, bool]]] ] = None): super().__init__() self.values: T.Dict[str, T.Tuple[T.Union[str, int, bool], T.Optional[str]]] = \ {k: v if isinstance(v, tuple) else (v, None) for k, v in initial_values.items()} if initial_values else {} self.used: bool = False def __repr__(self) -> str: return repr(self.values) def __contains__(self, value: str) -> bool: return value in self.values def __bool__(self) -> bool: return bool(self.values) def get(self, name: str) -> T.Tuple[T.Union[str, int, bool], T.Optional[str]]: return self.values[name] # (val, desc) def keys(self) -> T.Iterator[str]: return self.values.keys() # A bit poorly named, but this represents plain data files to copy # during install. @dataclass(eq=False) class Data(HoldableObject): sources: T.List[File] install_dir: str install_dir_name: str install_mode: 'FileMode' subproject: str rename: T.List[str] = None install_tag: T.Optional[str] = None data_type: str = None follow_symlinks: T.Optional[bool] = None def __post_init__(self) -> None: if self.rename is None: self.rename = [os.path.basename(f.fname) for f in self.sources] @dataclass(eq=False) class SymlinkData(HoldableObject): target: str name: str install_dir: str subproject: str install_tag: T.Optional[str] = None def __post_init__(self) -> None: if self.name != os.path.basename(self.name): raise InvalidArguments(f'Link name is "{self.name}", but link names cannot contain path separators. ' 'The dir part should be in install_dir.') @dataclass(eq=False) class TestSetup: exe_wrapper: T.List[str] gdb: bool timeout_multiplier: int env: EnvironmentVariables exclude_suites: T.List[str] 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 isinstance(s, str): names.append(s) elif isinstance(s, (BuildTarget, CustomTarget, CustomTargetIndex, GeneratedList)): names += s.get_outputs() elif isinstance(s, ExtractedObjects): names += backend.determine_ext_objs(s) elif isinstance(s, File): names.append(s.fname) else: raise AssertionError(f'Unknown source type: {s!r}') return names def load(build_dir: str) -> Build: filename = os.path.join(build_dir, 'meson-private', 'build.dat') try: b = pickle_load(filename, 'Build data', Build) # We excluded coredata when saving Build object, load it separately b.environment.coredata = coredata.load(build_dir) return b except FileNotFoundError: raise MesonException(f'No such build data file as {filename!r}.') def save(obj: Build, filename: str) -> None: # Exclude coredata because we pickle it separately already cdata = obj.environment.coredata obj.environment.coredata = None try: with open(filename, 'wb') as f: pickle.dump(obj, f) finally: obj.environment.coredata = cdata ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.6106374 meson-1.3.2/mesonbuild/cargo/0000755000175000017500000000000014562742414016275 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336264.0 meson-1.3.2/mesonbuild/cargo/__init__.py0000644000175000017500000000010214516507010020365 0ustar00jpakkanejpakkane__all__ = [ 'interpret' ] from .interpreter import interpret ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336264.0 meson-1.3.2/mesonbuild/cargo/builder.py0000644000175000017500000001407614516507010020273 0ustar00jpakkanejpakkane# SPDX-License-Identifier: Apache-2.0 # Copyright Ā© 2022-2023 Intel Corporation """Provides helpers for building AST This is meant to make building Meson AST from foreign (largely declarative) build descriptions easier. """ from __future__ import annotations import dataclasses import typing as T from .. import mparser if T.TYPE_CHECKING: import builtins @dataclasses.dataclass class Builder: filename: str def _token(self, tid: str, value: mparser.TV_TokenTypes) -> mparser.Token[mparser.TV_TokenTypes]: """Create a Token object, but with the line numbers stubbed out. :param tid: the token id (such as string, number, etc) :param filename: the filename that the token was generated from :param value: the value of the token :return: A Token object """ return mparser.Token(tid, self.filename, -1, -1, -1, (-1, -1), value) def _symbol(self, val: str) -> mparser.SymbolNode: return mparser.SymbolNode(self._token('', val)) def assign(self, value: mparser.BaseNode, varname: str) -> mparser.AssignmentNode: return mparser.AssignmentNode(self.identifier(varname), self._symbol('='), value) def string(self, value: str) -> mparser.StringNode: """Build A StringNode :param value: the value of the string :return: A StringNode """ return mparser.StringNode(self._token('string', value)) def number(self, value: int) -> mparser.NumberNode: """Build A NumberNode :param value: the value of the number :return: A NumberNode """ return mparser.NumberNode(self._token('number', str(value))) def bool(self, value: builtins.bool) -> mparser.BooleanNode: """Build A BooleanNode :param value: the value of the boolean :return: A BooleanNode """ return mparser.BooleanNode(self._token('bool', value)) def array(self, value: T.List[mparser.BaseNode]) -> mparser.ArrayNode: """Build an Array Node :param value: A list of nodes to insert into the array :return: An ArrayNode built from the arguments """ args = mparser.ArgumentNode(self._token('array', 'unused')) args.arguments = value return mparser.ArrayNode(self._symbol('['), args, self._symbol(']')) def dict(self, value: T.Dict[mparser.BaseNode, mparser.BaseNode]) -> mparser.DictNode: """Build an Dictionary Node :param value: A dict of nodes to insert into the dictionary :return: An DictNode built from the arguments """ args = mparser.ArgumentNode(self._token('dict', 'unused')) for key, val in value.items(): args.set_kwarg_no_check(key, val) return mparser.DictNode(self._symbol('{'), args, self._symbol('}')) def identifier(self, value: str) -> mparser.IdNode: """Build A IdNode :param value: the value of the boolean :return: A BooleanNode """ return mparser.IdNode(self._token('id', value)) def method(self, name: str, id_: mparser.IdNode, pos: T.Optional[T.List[mparser.BaseNode]] = None, kw: T.Optional[T.Mapping[str, mparser.BaseNode]] = None, ) -> mparser.MethodNode: """Create a method call. :param name: the name of the method :param id_: the object to call the method of :param pos: a list of positional arguments, defaults to None :param kw: a dictionary of keyword arguments, defaults to None :return: a method call object """ args = mparser.ArgumentNode(self._token('array', 'unused')) if pos is not None: args.arguments = pos if kw is not None: args.kwargs = {self.identifier(k): v for k, v in kw.items()} return mparser.MethodNode(id_, self._symbol('.'), self.identifier(name), self._symbol('('), args, self._symbol(')')) def function(self, name: str, pos: T.Optional[T.List[mparser.BaseNode]] = None, kw: T.Optional[T.Mapping[str, mparser.BaseNode]] = None, ) -> mparser.FunctionNode: """Create a function call. :param name: the name of the function :param pos: a list of positional arguments, defaults to None :param kw: a dictionary of keyword arguments, defaults to None :return: a method call object """ args = mparser.ArgumentNode(self._token('array', 'unused')) if pos is not None: args.arguments = pos if kw is not None: args.kwargs = {self.identifier(k): v for k, v in kw.items()} return mparser.FunctionNode(self.identifier(name), self._symbol('('), args, self._symbol(')')) def equal(self, lhs: mparser.BaseNode, rhs: mparser.BaseNode) -> mparser.ComparisonNode: """Create an equality operation :param lhs: The left hand side of the equal :param rhs: the right hand side of the equal :return: A compraison node """ return mparser.ComparisonNode('==', lhs, self._symbol('=='), rhs) def or_(self, lhs: mparser.BaseNode, rhs: mparser.BaseNode) -> mparser.OrNode: """Create and OrNode :param lhs: The Left of the Node :param rhs: The Right of the Node :return: The OrNode """ return mparser.OrNode(lhs, self._symbol('or'), rhs) def and_(self, lhs: mparser.BaseNode, rhs: mparser.BaseNode) -> mparser.AndNode: """Create an AndNode :param lhs: The left of the And :param rhs: The right of the And :return: The AndNode """ return mparser.AndNode(lhs, self._symbol('and'), rhs) def not_(self, value: mparser.BaseNode) -> mparser.NotNode: """Create a not node :param value: The value to negate :return: The NotNode """ return mparser.NotNode(self._token('not', ''), self._symbol('not'), value) def block(self, lines: T.List[mparser.BaseNode]) -> mparser.CodeBlockNode: block = mparser.CodeBlockNode(self._token('node', '')) block.lines = lines return block ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336264.0 meson-1.3.2/mesonbuild/cargo/cfg.py0000644000175000017500000001616114516507010017401 0ustar00jpakkanejpakkane# SPDX-License-Identifier: Apache-2.0 # Copyright Ā© 2022-2023 Intel Corporation """Rust CFG parser. Rust uses its `cfg()` format in cargo. This may have the following functions: - all() - any() - not() And additionally is made up of `identifier [ = str]`. Where the str is optional, so you could have examples like: ``` [target.`cfg(unix)`.dependencies] [target.'cfg(target_arch = "x86_64")'.dependencies] [target.'cfg(all(target_arch = "x86_64", target_arch = "x86"))'.dependencies] ``` """ from __future__ import annotations import dataclasses import enum import functools import typing as T from . import builder from .. import mparser from ..mesonlib import MesonBugException if T.TYPE_CHECKING: _T = T.TypeVar('_T') _LEX_TOKEN = T.Tuple['TokenType', T.Optional[str]] _LEX_STREAM = T.Iterable[_LEX_TOKEN] _LEX_STREAM_AH = T.Iterator[T.Tuple[_LEX_TOKEN, T.Optional[_LEX_TOKEN]]] class TokenType(enum.Enum): LPAREN = enum.auto() RPAREN = enum.auto() STRING = enum.auto() IDENTIFIER = enum.auto() ALL = enum.auto() ANY = enum.auto() NOT = enum.auto() COMMA = enum.auto() EQUAL = enum.auto() def lexer(raw: str) -> _LEX_STREAM: """Lex a cfg() expression. :param raw: The raw cfg() expression :return: An iterable of tokens """ buffer: T.List[str] = [] is_string: bool = False for s in raw: if s.isspace() or s in {')', '(', ',', '='} or (s == '"' and buffer): val = ''.join(buffer) buffer.clear() if is_string: yield (TokenType.STRING, val) elif val == 'any': yield (TokenType.ANY, None) elif val == 'all': yield (TokenType.ALL, None) elif val == 'not': yield (TokenType.NOT, None) elif val: yield (TokenType.IDENTIFIER, val) if s == '(': yield (TokenType.LPAREN, None) continue elif s == ')': yield (TokenType.RPAREN, None) continue elif s == ',': yield (TokenType.COMMA, None) continue elif s == '=': yield (TokenType.EQUAL, None) continue elif s.isspace(): continue if s == '"': is_string = not is_string else: buffer.append(s) if buffer: # This should always be an identifier yield (TokenType.IDENTIFIER, ''.join(buffer)) def lookahead(iter: T.Iterator[_T]) -> T.Iterator[T.Tuple[_T, T.Optional[_T]]]: """Get the current value of the iterable, and the next if possible. :param iter: The iterable to look into :yield: A tuple of the current value, and, if possible, the next :return: nothing """ current: _T next_: T.Optional[_T] try: next_ = next(iter) except StopIteration: # This is an empty iterator, there's nothing to look ahead to return while True: current = next_ try: next_ = next(iter) except StopIteration: next_ = None yield current, next_ if next_ is None: break @dataclasses.dataclass class IR: """Base IR node for Cargo CFG.""" @dataclasses.dataclass class String(IR): value: str @dataclasses.dataclass class Identifier(IR): value: str @dataclasses.dataclass class Equal(IR): lhs: IR rhs: IR @dataclasses.dataclass class Any(IR): args: T.List[IR] @dataclasses.dataclass class All(IR): args: T.List[IR] @dataclasses.dataclass class Not(IR): value: IR def _parse(ast: _LEX_STREAM_AH) -> IR: (token, value), n_stream = next(ast) if n_stream is not None: ntoken, _ = n_stream else: ntoken, _ = (None, None) stream: T.List[_LEX_TOKEN] if token is TokenType.IDENTIFIER: if ntoken is TokenType.EQUAL: return Equal(Identifier(value), _parse(ast)) if token is TokenType.STRING: return String(value) if token is TokenType.EQUAL: # In this case the previous caller already has handled the equal return _parse(ast) if token in {TokenType.ANY, TokenType.ALL}: type_ = All if token is TokenType.ALL else Any assert ntoken is TokenType.LPAREN next(ast) # advance the iterator to get rid of the LPAREN stream = [] args: T.List[IR] = [] while token is not TokenType.RPAREN: (token, value), _ = next(ast) if token is TokenType.COMMA: args.append(_parse(lookahead(iter(stream)))) stream.clear() else: stream.append((token, value)) if stream: args.append(_parse(lookahead(iter(stream)))) return type_(args) if token is TokenType.NOT: next(ast) # advance the iterator to get rid of the LPAREN stream = [] # Mypy can't figure out that token is overridden inside the while loop while token is not TokenType.RPAREN: # type: ignore (token, value), _ = next(ast) stream.append((token, value)) return Not(_parse(lookahead(iter(stream)))) raise MesonBugException(f'Unhandled Cargo token: {token}') def parse(ast: _LEX_STREAM) -> IR: """Parse the tokenized list into Meson AST. :param ast: An iterable of Tokens :return: An mparser Node to be used as a conditional """ ast_i: _LEX_STREAM_AH = lookahead(iter(ast)) return _parse(ast_i) @functools.singledispatch def ir_to_meson(ir: T.Any, build: builder.Builder) -> mparser.BaseNode: raise NotImplementedError @ir_to_meson.register def _(ir: String, build: builder.Builder) -> mparser.BaseNode: return build.string(ir.value) @ir_to_meson.register def _(ir: Identifier, build: builder.Builder) -> mparser.BaseNode: host_machine = build.identifier('host_machine') if ir.value == "target_arch": return build.method('cpu_family', host_machine) elif ir.value in {"target_os", "target_family"}: return build.method('system', host_machine) elif ir.value == "target_endian": return build.method('endian', host_machine) raise MesonBugException(f"Unhandled Cargo identifier: {ir.value}") @ir_to_meson.register def _(ir: Equal, build: builder.Builder) -> mparser.BaseNode: return build.equal(ir_to_meson(ir.lhs, build), ir_to_meson(ir.rhs, build)) @ir_to_meson.register def _(ir: Not, build: builder.Builder) -> mparser.BaseNode: return build.not_(ir_to_meson(ir.value, build)) @ir_to_meson.register def _(ir: Any, build: builder.Builder) -> mparser.BaseNode: args = iter(reversed(ir.args)) last = next(args) cur = build.or_(ir_to_meson(next(args), build), ir_to_meson(last, build)) for a in args: cur = build.or_(ir_to_meson(a, build), cur) return cur @ir_to_meson.register def _(ir: All, build: builder.Builder) -> mparser.BaseNode: args = iter(reversed(ir.args)) last = next(args) cur = build.and_(ir_to_meson(next(args), build), ir_to_meson(last, build)) for a in args: cur = build.and_(ir_to_meson(a, build), cur) return cur ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0 meson-1.3.2/mesonbuild/cargo/interpreter.py0000644000175000017500000003771014562742373021226 0ustar00jpakkanejpakkane# SPDX-License-Identifier: Apache-2.0 # Copyright Ā© 2022-2023 Intel Corporation """Interpreter for converting Cargo Toml definitions to Meson AST There are some notable limits here. We don't even try to convert something with a build.rs: there's so few limits on what Cargo allows a build.rs (basically none), and no good way for us to convert them. In that case, an actual meson port will be required. """ from __future__ import annotations import dataclasses import glob import importlib import itertools import json import os import shutil import typing as T from . import builder from . import version from ..mesonlib import MesonException, Popen_safe if T.TYPE_CHECKING: from types import ModuleType from . import manifest from .. import mparser from ..environment import Environment # tomllib is present in python 3.11, before that it is a pypi module called tomli, # we try to import tomllib, then tomli, # TODO: add a fallback to toml2json? tomllib: T.Optional[ModuleType] = None toml2json: T.Optional[str] = None for t in ['tomllib', 'tomli']: try: tomllib = importlib.import_module(t) break except ImportError: pass else: # TODO: it would be better to use an Executable here, which could be looked # up in the cross file or provided by a wrap. However, that will have to be # passed in externally, since we don't have (and I don't think we should), # have access to the `Environment` for that in this module. toml2json = shutil.which('toml2json') def load_toml(filename: str) -> T.Dict[object, object]: if tomllib: with open(filename, 'rb') as f: raw = tomllib.load(f) else: if toml2json is None: raise MesonException('Could not find an implementation of tomllib, nor toml2json') p, out, err = Popen_safe([toml2json, filename]) if p.returncode != 0: raise MesonException('toml2json failed to decode output\n', err) raw = json.loads(out) if not isinstance(raw, dict): raise MesonException("Cargo.toml isn't a dictionary? How did that happen?") return raw def fixup_meson_varname(name: str) -> str: """Fixup a meson variable name :param name: The name to fix :return: the fixed name """ return name.replace('-', '_') # Pylance can figure out that these do not, in fact, overlap, but mypy can't @T.overload def _fixup_raw_mappings(d: manifest.BuildTarget) -> manifest.FixedBuildTarget: ... # type: ignore @T.overload def _fixup_raw_mappings(d: manifest.LibTarget) -> manifest.FixedLibTarget: ... # type: ignore @T.overload def _fixup_raw_mappings(d: manifest.Dependency) -> manifest.FixedDependency: ... def _fixup_raw_mappings(d: T.Union[manifest.BuildTarget, manifest.LibTarget, manifest.Dependency] ) -> T.Union[manifest.FixedBuildTarget, manifest.FixedLibTarget, manifest.FixedDependency]: """Fixup raw cargo mappings to ones more suitable for python to consume. This does the following: * replaces any `-` with `_`, cargo likes the former, but python dicts make keys with `-` in them awkward to work with * Convert Dependndency versions from the cargo format to something meson understands :param d: The mapping to fix :return: the fixed string """ raw = {fixup_meson_varname(k): v for k, v in d.items()} if 'version' in raw: assert isinstance(raw['version'], str), 'for mypy' raw['version'] = version.convert(raw['version']) return T.cast('T.Union[manifest.FixedBuildTarget, manifest.FixedLibTarget, manifest.FixedDependency]', raw) @dataclasses.dataclass class Package: """Representation of a Cargo Package entry, with defaults filled in.""" name: str version: str description: T.Optional[str] = None resolver: T.Optional[str] = None authors: T.List[str] = dataclasses.field(default_factory=list) edition: manifest.EDITION = '2015' rust_version: T.Optional[str] = None documentation: T.Optional[str] = None readme: T.Optional[str] = None homepage: T.Optional[str] = None repository: T.Optional[str] = None license: T.Optional[str] = None license_file: T.Optional[str] = None keywords: T.List[str] = dataclasses.field(default_factory=list) categories: T.List[str] = dataclasses.field(default_factory=list) workspace: T.Optional[str] = None build: T.Optional[str] = None links: T.Optional[str] = None exclude: T.List[str] = dataclasses.field(default_factory=list) include: T.List[str] = dataclasses.field(default_factory=list) publish: bool = True metadata: T.Dict[str, T.Dict[str, str]] = dataclasses.field(default_factory=dict) default_run: T.Optional[str] = None autobins: bool = True autoexamples: bool = True autotests: bool = True autobenches: bool = True @dataclasses.dataclass class Dependency: """Representation of a Cargo Dependency Entry.""" version: T.List[str] registry: T.Optional[str] = None git: T.Optional[str] = None branch: T.Optional[str] = None rev: T.Optional[str] = None path: T.Optional[str] = None optional: bool = False package: T.Optional[str] = None default_features: bool = False features: T.List[str] = dataclasses.field(default_factory=list) @classmethod def from_raw(cls, raw: manifest.DependencyV) -> Dependency: """Create a dependency from a raw cargo dictionary""" if isinstance(raw, str): return cls(version.convert(raw)) return cls(**_fixup_raw_mappings(raw)) @dataclasses.dataclass class BuildTarget: name: str crate_type: T.List[manifest.CRATE_TYPE] = dataclasses.field(default_factory=lambda: ['lib']) path: dataclasses.InitVar[T.Optional[str]] = None # https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-test-field # True for lib, bin, test test: bool = True # https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-doctest-field # True for lib doctest: bool = False # https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-bench-field # True for lib, bin, benchmark bench: bool = True # https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-doc-field # True for libraries and binaries doc: bool = False harness: bool = True edition: manifest.EDITION = '2015' required_features: T.List[str] = dataclasses.field(default_factory=list) plugin: bool = False @dataclasses.dataclass class Library(BuildTarget): """Representation of a Cargo Library Entry.""" doctest: bool = True doc: bool = True proc_macro: bool = False crate_type: T.List[manifest.CRATE_TYPE] = dataclasses.field(default_factory=lambda: ['lib']) doc_scrape_examples: bool = True @dataclasses.dataclass class Binary(BuildTarget): """Representation of a Cargo Bin Entry.""" doc: bool = True @dataclasses.dataclass class Test(BuildTarget): """Representation of a Cargo Test Entry.""" bench: bool = True @dataclasses.dataclass class Benchmark(BuildTarget): """Representation of a Cargo Benchmark Entry.""" test: bool = True @dataclasses.dataclass class Example(BuildTarget): """Representation of a Cargo Example Entry.""" crate_type: T.List[manifest.CRATE_TYPE] = dataclasses.field(default_factory=lambda: ['bin']) @dataclasses.dataclass class Manifest: """Cargo Manifest definition. Most of these values map up to the Cargo Manifest, but with default values if not provided. Cargo subprojects can contain what Meson wants to treat as multiple, interdependent, subprojects. :param subdir: the subdirectory that this cargo project is in :param path: the path within the cargo subproject. """ package: Package dependencies: T.Dict[str, Dependency] dev_dependencies: T.Dict[str, Dependency] build_dependencies: T.Dict[str, Dependency] lib: Library bin: T.List[Binary] test: T.List[Test] bench: T.List[Benchmark] example: T.List[Example] features: T.Dict[str, T.List[str]] target: T.Dict[str, T.Dict[str, Dependency]] subdir: str path: str = '' def _convert_manifest(raw_manifest: manifest.Manifest, subdir: str, path: str = '') -> Manifest: # This cast is a bit of a hack to deal with proc-macro lib = _fixup_raw_mappings(raw_manifest.get('lib', {})) # We need to set the name field if it's not set manually, # including if other fields are set in the lib section lib.setdefault('name', raw_manifest['package']['name']) pkg = T.cast('manifest.FixedPackage', {fixup_meson_varname(k): v for k, v in raw_manifest['package'].items()}) return Manifest( Package(**pkg), {k: Dependency.from_raw(v) for k, v in raw_manifest.get('dependencies', {}).items()}, {k: Dependency.from_raw(v) for k, v in raw_manifest.get('dev-dependencies', {}).items()}, {k: Dependency.from_raw(v) for k, v in raw_manifest.get('build-dependencies', {}).items()}, Library(**lib), [Binary(**_fixup_raw_mappings(b)) for b in raw_manifest.get('bin', {})], [Test(**_fixup_raw_mappings(b)) for b in raw_manifest.get('test', {})], [Benchmark(**_fixup_raw_mappings(b)) for b in raw_manifest.get('bench', {})], [Example(**_fixup_raw_mappings(b)) for b in raw_manifest.get('example', {})], raw_manifest.get('features', {}), {k: {k2: Dependency.from_raw(v2) for k2, v2 in v.get('dependencies', {}).items()} for k, v in raw_manifest.get('target', {}).items()}, subdir, path, ) def _load_manifests(subdir: str) -> T.Dict[str, Manifest]: filename = os.path.join(subdir, 'Cargo.toml') raw = load_toml(filename) manifests: T.Dict[str, Manifest] = {} raw_manifest: T.Union[manifest.Manifest, manifest.VirtualManifest] if 'package' in raw: raw_manifest = T.cast('manifest.Manifest', raw) manifest_ = _convert_manifest(raw_manifest, subdir) manifests[manifest_.package.name] = manifest_ else: raw_manifest = T.cast('manifest.VirtualManifest', raw) if 'workspace' in raw_manifest: # XXX: need to verify that python glob and cargo globbing are the # same and probably write a glob implementation. Blarg # We need to chdir here to make the glob work correctly pwd = os.getcwd() os.chdir(subdir) members: T.Iterable[str] try: members = itertools.chain.from_iterable( glob.glob(m) for m in raw_manifest['workspace']['members']) finally: os.chdir(pwd) if 'exclude' in raw_manifest['workspace']: members = (x for x in members if x not in raw_manifest['workspace']['exclude']) for m in members: filename = os.path.join(subdir, m, 'Cargo.toml') raw = load_toml(filename) raw_manifest = T.cast('manifest.Manifest', raw) man = _convert_manifest(raw_manifest, subdir, m) manifests[man.package.name] = man return manifests def _dependency_name(package_name: str) -> str: return package_name if package_name.endswith('-rs') else f'{package_name}-rs' def _dependency_varname(package_name: str) -> str: return f'{fixup_meson_varname(package_name)}_dep' def _create_project(cargo: Manifest, build: builder.Builder, env: Environment) -> T.List[mparser.BaseNode]: """Create a function call :param cargo: The Manifest to generate from :param build: The AST builder :param env: Meson environment :return: a list nodes """ args: T.List[mparser.BaseNode] = [] args.extend([ build.string(cargo.package.name), build.string('rust'), ]) kwargs: T.Dict[str, mparser.BaseNode] = { 'version': build.string(cargo.package.version), # Always assume that the generated meson is using the latest features # This will warn when when we generate deprecated code, which is helpful # for the upkeep of the module 'meson_version': build.string(f'>= {env.coredata.version}'), 'default_options': build.array([build.string(f'rust_std={cargo.package.edition}')]), } if cargo.package.license: kwargs['license'] = build.string(cargo.package.license) elif cargo.package.license_file: kwargs['license_files'] = build.string(cargo.package.license_file) return [build.function('project', args, kwargs)] def _create_dependencies(cargo: Manifest, build: builder.Builder) -> T.List[mparser.BaseNode]: ast: T.List[mparser.BaseNode] = [] for name, dep in cargo.dependencies.items(): package_name = dep.package or name kw = { 'version': build.array([build.string(s) for s in dep.version]), } ast.extend([ build.assign( build.function( 'dependency', [build.string(_dependency_name(package_name))], kw, ), _dependency_varname(package_name), ), ]) return ast def _create_lib(cargo: Manifest, build: builder.Builder, crate_type: manifest.CRATE_TYPE) -> T.List[mparser.BaseNode]: dependencies: T.List[mparser.BaseNode] = [] dependency_map: T.Dict[mparser.BaseNode, mparser.BaseNode] = {} for name, dep in cargo.dependencies.items(): package_name = dep.package or name dependencies.append(build.identifier(_dependency_varname(package_name))) if name != package_name: dependency_map[build.string(fixup_meson_varname(package_name))] = build.string(name) posargs: T.List[mparser.BaseNode] = [ build.string(fixup_meson_varname(cargo.package.name)), build.string(os.path.join('src', 'lib.rs')), ] kwargs: T.Dict[str, mparser.BaseNode] = { 'dependencies': build.array(dependencies), 'rust_dependency_map': build.dict(dependency_map), } lib: mparser.BaseNode if cargo.lib.proc_macro or crate_type == 'proc-macro': lib = build.method('proc_macro', build.identifier('rust'), posargs, kwargs) else: if crate_type in {'lib', 'rlib', 'staticlib'}: target_type = 'static_library' elif crate_type in {'dylib', 'cdylib'}: target_type = 'shared_library' else: raise MesonException(f'Unsupported crate type {crate_type}') if crate_type in {'staticlib', 'cdylib'}: kwargs['rust_abi'] = build.string('c') lib = build.function(target_type, posargs, kwargs) return [ build.assign(lib, 'lib'), build.assign( build.function( 'declare_dependency', kw={ 'link_with': build.identifier('lib'), }, ), 'dep' ), build.method( 'override_dependency', build.identifier('meson'), [ build.string(_dependency_name(cargo.package.name)), build.identifier('dep'), ], ), ] def interpret(subp_name: str, subdir: str, env: Environment) -> mparser.CodeBlockNode: package_name = subp_name[:-3] if subp_name.endswith('-rs') else subp_name manifests = _load_manifests(os.path.join(env.source_dir, subdir)) cargo = manifests.get(package_name) if not cargo: raise MesonException(f'Cargo package {package_name!r} not found in {subdir}') filename = os.path.join(cargo.subdir, cargo.path, 'Cargo.toml') build = builder.Builder(filename) ast = _create_project(cargo, build, env) ast += [build.assign(build.function('import', [build.string('rust')]), 'rust')] ast += _create_dependencies(cargo, build) # Libs are always auto-discovered and there's no other way to handle them, # which is unfortunate for reproducability if os.path.exists(os.path.join(env.source_dir, cargo.subdir, cargo.path, 'src', 'lib.rs')): for crate_type in cargo.lib.crate_type: ast.extend(_create_lib(cargo, build, crate_type)) return build.block(ast) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1687963700.0 meson-1.3.2/mesonbuild/cargo/manifest.py0000644000175000017500000001220714447044064020455 0ustar00jpakkanejpakkane# SPDX-License-Identifier: Apache-2.0 # Copyright Ā© 2022-2023 Intel Corporation """Type definitions for cargo manifest files.""" from __future__ import annotations import typing as T from typing_extensions import Literal, TypedDict, Required EDITION = Literal['2015', '2018', '2021'] CRATE_TYPE = Literal['bin', 'lib', 'dylib', 'staticlib', 'cdylib', 'rlib', 'proc-macro'] Package = TypedDict( 'Package', { 'name': Required[str], 'version': Required[str], 'authors': T.List[str], 'edition': EDITION, 'rust-version': str, 'description': str, 'readme': str, 'license': str, 'license-file': str, 'keywords': T.List[str], 'categories': T.List[str], 'workspace': str, 'build': str, 'links': str, 'include': T.List[str], 'exclude': T.List[str], 'publish': bool, 'metadata': T.Dict[str, T.Dict[str, str]], 'default-run': str, 'autobins': bool, 'autoexamples': bool, 'autotests': bool, 'autobenches': bool, }, total=False, ) """A description of the Package Dictionary.""" class FixedPackage(TypedDict, total=False): """A description of the Package Dictionary, fixed up.""" name: Required[str] version: Required[str] authors: T.List[str] edition: EDITION rust_version: str description: str readme: str license: str license_file: str keywords: T.List[str] categories: T.List[str] workspace: str build: str links: str include: T.List[str] exclude: T.List[str] publish: bool metadata: T.Dict[str, T.Dict[str, str]] default_run: str autobins: bool autoexamples: bool autotests: bool autobenches: bool class Badge(TypedDict): """An entry in the badge section.""" status: Literal['actively-developed', 'passively-developed', 'as-is', 'experimental', 'deprecated', 'none'] Dependency = TypedDict( 'Dependency', { 'version': str, 'registry': str, 'git': str, 'branch': str, 'rev': str, 'path': str, 'optional': bool, 'package': str, 'default-features': bool, 'features': T.List[str], }, total=False, ) """An entry in the *dependencies sections.""" class FixedDependency(TypedDict, total=False): """An entry in the *dependencies sections, fixed up.""" version: T.List[str] registry: str git: str branch: str rev: str path: str optional: bool package: str default_features: bool features: T.List[str] DependencyV = T.Union[Dependency, str] """A Dependency entry, either a string or a Dependency Dict.""" _BaseBuildTarget = TypedDict( '_BaseBuildTarget', { 'path': str, 'test': bool, 'doctest': bool, 'bench': bool, 'doc': bool, 'plugin': bool, 'proc-macro': bool, 'harness': bool, 'edition': EDITION, 'crate-type': T.List[CRATE_TYPE], 'required-features': T.List[str], }, total=False, ) class BuildTarget(_BaseBuildTarget, total=False): name: Required[str] class LibTarget(_BaseBuildTarget, total=False): name: str class _BaseFixedBuildTarget(TypedDict, total=False): path: str test: bool doctest: bool bench: bool doc: bool plugin: bool harness: bool edition: EDITION crate_type: T.List[CRATE_TYPE] required_features: T.List[str] class FixedBuildTarget(_BaseFixedBuildTarget, total=False): name: str class FixedLibTarget(_BaseFixedBuildTarget, total=False): name: Required[str] proc_macro: bool class Target(TypedDict): """Target entry in the Manifest File.""" dependencies: T.Dict[str, DependencyV] class Workspace(TypedDict): """The representation of a workspace. In a vritual manifest the :attribute:`members` is always present, but in a project manifest, an empty workspace may be provided, in which case the workspace is implicitly filled in by values from the path based dependencies. the :attribute:`exclude` is always optional """ members: T.List[str] exclude: T.List[str] Manifest = TypedDict( 'Manifest', { 'package': Package, 'badges': T.Dict[str, Badge], 'dependencies': T.Dict[str, DependencyV], 'dev-dependencies': T.Dict[str, DependencyV], 'build-dependencies': T.Dict[str, DependencyV], 'lib': LibTarget, 'bin': T.List[BuildTarget], 'test': T.List[BuildTarget], 'bench': T.List[BuildTarget], 'example': T.List[BuildTarget], 'features': T.Dict[str, T.List[str]], 'target': T.Dict[str, Target], 'workspace': Workspace, # TODO: patch? # TODO: replace? }, total=False, ) """The Cargo Manifest format.""" class VirtualManifest(TypedDict): """The Representation of a virtual manifest. Cargo allows a root manifest that contains only a workspace, this is called a virtual manifest. This doesn't really map 1:1 with any meson concept, except perhaps the proposed "meta project". """ workspace: Workspace ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336264.0 meson-1.3.2/mesonbuild/cargo/version.py0000644000175000017500000000755414516507010020335 0ustar00jpakkanejpakkane# SPDX-License-Identifier: Apache-2.0 # Copyright Ā© 2022-2023 Intel Corporation """Convert Cargo versions into Meson compatible ones.""" from __future__ import annotations import typing as T def convert(cargo_ver: str) -> T.List[str]: """Convert a Cargo compatible version into a Meson compatible one. :param cargo_ver: The version, as Cargo specifies :return: A list of version constraints, as Meson understands them """ # Cleanup, just for safety cargo_ver = cargo_ver.strip() cargo_vers = [c.strip() for c in cargo_ver.split(',')] out: T.List[str] = [] for ver in cargo_vers: # This covers >= and =< as well # https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#comparison-requirements if ver.startswith(('>', '<', '=')): out.append(ver) elif ver.startswith('~'): # Rust has these tilde requirements, which means that it is >= to # the version, but less than the next version # https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#tilde-requirements # we convert those into a pair of constraints v = ver[1:].split('.') out.append(f'>= {".".join(v)}') if len(v) == 3: out.append(f'< {v[0]}.{int(v[1]) + 1}.0') elif len(v) == 2: out.append(f'< {v[0]}.{int(v[1]) + 1}') else: out.append(f'< {int(v[0]) + 1}') elif '*' in ver: # Rust has astrisk requirements,, which are like 1.* == ~1 # https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#wildcard-requirements v = ver.split('.')[:-1] if v: out.append(f'>= {".".join(v)}') if len(v) == 2: out.append(f'< {v[0]}.{int(v[1]) + 1}') elif len(v) == 1: out.append(f'< {int(v[0]) + 1}') else: # a Caret version is equivalent to the default strategy # https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#caret-requirements if ver.startswith('^'): ver = ver[1:] # If there is no qualifier, then it means this or the next non-zero version # That means that if this is `1.1.0``, then we need `>= 1.1.0` && `< 2.0.0` # Or if we have `0.1.0`, then we need `>= 0.1.0` && `< 0.2.0` # Or if we have `0.1`, then we need `>= 0.1.0` && `< 0.2.0` # Or if we have `0.0.0`, then we need `< 1.0.0` # Or if we have `0.0`, then we need `< 1.0.0` # Or if we have `0`, then we need `< 1.0.0` # Or if we have `0.0.3`, then we need `>= 0.0.3` && `< 0.0.4` # https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#specifying-dependencies-from-cratesio # # this works much like the ~ versions, but in reverse. Tilde starts # at the patch version and works up, to the major version, while # bare numbers start at the major version and work down to the patch # version vers = ver.split('.') min_: T.List[str] = [] max_: T.List[str] = [] bumped = False for v_ in vers: if v_ != '0' and not bumped: min_.append(v_) max_.append(str(int(v_) + 1)) bumped = True else: min_.append(v_) if not bumped: max_.append('0') # If there is no minimum, don't emit one if set(min_) != {'0'}: out.append('>= {}'.format('.'.join(min_))) if set(max_) != {'0'}: out.append('< {}'.format('.'.join(max_))) else: out.append('< 1') return out ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.6186376 meson-1.3.2/mesonbuild/cmake/0000755000175000017500000000000014562742414016262 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/cmake/__init__.py0000644000175000017500000000254314562742363020402 0ustar00jpakkanejpakkane# 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__ = [ 'CMakeExecutor', 'CMakeExecScope', 'CMakeException', 'CMakeInterpreter', 'CMakeTarget', 'CMakeToolchain', 'CMakeTraceParser', 'TargetOptions', 'language_map', 'cmake_defines_to_args', 'check_cmake_args', 'cmake_is_debug', 'resolve_cmake_trace_targets', ] from .common import CMakeException, TargetOptions, cmake_defines_to_args, language_map, check_cmake_args, cmake_is_debug from .executor import CMakeExecutor from .interpreter import CMakeInterpreter from .toolchain import CMakeToolchain, CMakeExecScope from .traceparser import CMakeTarget, CMakeTraceParser from .tracetargets import resolve_cmake_trace_targets ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/cmake/common.py0000644000175000017500000003262014562742363020132 0ustar00jpakkanejpakkane# 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 __future__ import annotations from ..mesonlib import MesonException, OptionKey from .. import mlog from pathlib import Path import typing as T if T.TYPE_CHECKING: from ..environment import Environment from ..interpreterbase import TYPE_var language_map = { 'c': 'C', 'cpp': 'CXX', 'cuda': 'CUDA', 'objc': 'OBJC', 'objcpp': 'OBJCXX', 'cs': 'CSharp', 'java': 'Java', 'fortran': 'Fortran', 'swift': 'Swift', } backend_generator_map = { 'ninja': 'Ninja', 'xcode': 'Xcode', 'vs2010': 'Visual Studio 10 2010', 'vs2012': 'Visual Studio 11 2012', 'vs2013': 'Visual Studio 12 2013', 'vs2015': 'Visual Studio 14 2015', 'vs2017': 'Visual Studio 15 2017', 'vs2019': 'Visual Studio 16 2019', 'vs2022': 'Visual Studio 17 2022', } blacklist_cmake_defs = [ 'CMAKE_TOOLCHAIN_FILE', 'CMAKE_PROJECT_INCLUDE', 'MESON_PRELOAD_FILE', 'MESON_PS_CMAKE_CURRENT_BINARY_DIR', 'MESON_PS_CMAKE_CURRENT_SOURCE_DIR', 'MESON_PS_DELAYED_CALLS', 'MESON_PS_LOADED', 'MESON_FIND_ROOT_PATH', 'MESON_CMAKE_SYSROOT', 'MESON_PATHS_LIST', 'MESON_CMAKE_ROOT', ] def cmake_is_debug(env: 'Environment') -> bool: if OptionKey('b_vscrt') in env.coredata.options: is_debug = env.coredata.get_option(OptionKey('buildtype')) == 'debug' if env.coredata.options[OptionKey('b_vscrt')].value in {'mdd', 'mtd'}: is_debug = True return is_debug else: # Don't directly assign to is_debug to make mypy happy debug_opt = env.coredata.get_option(OptionKey('debug')) assert isinstance(debug_opt, bool) return debug_opt class CMakeException(MesonException): pass class CMakeBuildFile: def __init__(self, file: Path, is_cmake: bool, is_temp: bool) -> None: self.file = file self.is_cmake = is_cmake self.is_temp = is_temp def __repr__(self) -> str: return f'<{self.__class__.__name__}: {self.file}; cmake={self.is_cmake}; temp={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 = [r for r in res if len(r) > 0] return res def cmake_get_generator_args(env: 'Environment') -> T.List[str]: backend_name = env.coredata.get_option(OptionKey('backend')) assert isinstance(backend_name, str) assert backend_name in backend_generator_map return ['-G', backend_generator_map[backend_name]] def cmake_defines_to_args(raw: T.List[T.Dict[str, TYPE_var]], permissive: bool = False) -> T.List[str]: res: T.List[str] = [] for i in raw: for key, val in i.items(): if key in blacklist_cmake_defs: mlog.warning('Setting', mlog.bold(key), 'is not supported. See the meson docs for cross compilation support:') mlog.warning(' - URL: https://mesonbuild.com/CMake-module.html#cross-compilation') mlog.warning(' --> Ignoring this option') continue if isinstance(val, (str, int, float)): res += [f'-D{key}={val}'] elif isinstance(val, bool): val_str = 'ON' if val else 'OFF' res += [f'-D{key}={val_str}'] else: raise MesonException('Type "{}" of "{}" is not supported as for a CMake define value'.format(type(val).__name__, key)) return res # TODO: this function will become obsolete once the `cmake_args` kwarg is dropped def check_cmake_args(args: T.List[str]) -> T.List[str]: res: T.List[str] = [] dis = ['-D' + x for x in blacklist_cmake_defs] assert dis # Ensure that dis is not empty. for i in args: if any(i.startswith(x) for x in dis): mlog.warning('Setting', mlog.bold(i), 'is not supported. See the meson docs for cross compilation support:') mlog.warning(' - URL: https://mesonbuild.com/CMake-module.html#cross-compilation') mlog.warning(' --> Ignoring this option') continue res += [i] return res class CMakeInclude: def __init__(self, path: Path, isSystem: bool = False): self.path = path self.isSystem = isSystem def __repr__(self) -> str: return f'' class CMakeFileGroup: def __init__(self, data: T.Dict[str, T.Any]) -> None: self.defines: str = data.get('defines', '') self.flags = _flags_to_list(data.get('compileFlags', '')) self.is_generated: bool = data.get('isGenerated', False) self.language: str = data.get('language', 'C') self.sources = [Path(x) for x in data.get('sources', [])] # Fix the include directories self.includes: T.List[CMakeInclude] = [] for i in data.get('includePath', []): if isinstance(i, dict) and 'path' in i: isSystem = i.get('isSystem', False) assert isinstance(isSystem, bool) assert isinstance(i['path'], str) self.includes += [CMakeInclude(Path(i['path']), isSystem)] elif isinstance(i, str): self.includes += [CMakeInclude(Path(i))] 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([str(x) for x in 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.as_posix()) class CMakeTarget: def __init__(self, data: T.Dict[str, T.Any]) -> None: self.artifacts = [Path(x) for x in data.get('artifacts', [])] self.src_dir = Path(data.get('sourceDirectory', '')) self.build_dir = Path(data.get('buildDirectory', '')) self.name: str = data.get('name', '') self.full_name: str = data.get('fullName', '') self.install: bool = data.get('hasInstallRule', False) self.install_paths = [Path(x) for x in set(data.get('installPaths', []))] self.link_lang: str = 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 = Path(data.get('linkPath', '')) self.type: str = data.get('type', 'EXECUTABLE') # self.is_generator_provided: bool = data.get('isGeneratorProvided', False) self.files: T.List[CMakeFileGroup] = [] for i in data.get('fileGroups', []): self.files += [CMakeFileGroup(i)] def log(self) -> None: mlog.log('artifacts =', mlog.bold(', '.join([x.as_posix() for x in self.artifacts]))) mlog.log('src_dir =', mlog.bold(self.src_dir.as_posix())) mlog.log('build_dir =', mlog.bold(self.build_dir.as_posix())) 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([x.as_posix() for x in 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(f'Files {idx}:') with mlog.nested(): i.log() class CMakeProject: def __init__(self, data: T.Dict[str, T.Any]) -> None: self.src_dir = Path(data.get('sourceDirectory', '')) self.build_dir = Path(data.get('buildDirectory', '')) self.name: str = data.get('name', '') self.targets: T.List[CMakeTarget] = [] for i in data.get('targets', []): self.targets += [CMakeTarget(i)] def log(self) -> None: mlog.log('src_dir =', mlog.bold(self.src_dir.as_posix())) mlog.log('build_dir =', mlog.bold(self.build_dir.as_posix())) mlog.log('name =', mlog.bold(self.name)) for idx, i in enumerate(self.targets): mlog.log(f'Target {idx}:') with mlog.nested(): i.log() class CMakeConfiguration: def __init__(self, data: T.Dict[str, T.Any]) -> None: self.name: str = data.get('name', '') self.projects: T.List[CMakeProject] = [] 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(f'Project {idx}:') with mlog.nested(): i.log() class SingleTargetOptions: def __init__(self) -> None: self.opts: T.Dict[str, str] = {} self.lang_args: T.Dict[str, T.List[str]] = {} self.link_args: T.List[str] = [] self.install = 'preserve' def set_opt(self, opt: str, val: str) -> None: self.opts[opt] = val def append_args(self, lang: str, args: T.List[str]) -> None: if lang not in self.lang_args: self.lang_args[lang] = [] self.lang_args[lang] += args def append_link_args(self, args: T.List[str]) -> None: self.link_args += args def set_install(self, install: bool) -> None: self.install = 'true' if install else 'false' def get_override_options(self, initial: T.List[str]) -> T.List[str]: res: T.List[str] = [] for i in initial: opt = i[:i.find('=')] if opt not in self.opts: res += [i] res += [f'{k}={v}' for k, v in self.opts.items()] return res def get_compile_args(self, lang: str, initial: T.List[str]) -> T.List[str]: if lang in self.lang_args: return initial + self.lang_args[lang] return initial def get_link_args(self, initial: T.List[str]) -> T.List[str]: return initial + self.link_args def get_install(self, initial: bool) -> bool: return {'preserve': initial, 'true': True, 'false': False}[self.install] class TargetOptions: def __init__(self) -> None: self.global_options = SingleTargetOptions() self.target_options: T.Dict[str, SingleTargetOptions] = {} def __getitem__(self, tgt: str) -> SingleTargetOptions: if tgt not in self.target_options: self.target_options[tgt] = SingleTargetOptions() return self.target_options[tgt] def get_override_options(self, tgt: str, initial: T.List[str]) -> T.List[str]: initial = self.global_options.get_override_options(initial) if tgt in self.target_options: initial = self.target_options[tgt].get_override_options(initial) return initial def get_compile_args(self, tgt: str, lang: str, initial: T.List[str]) -> T.List[str]: initial = self.global_options.get_compile_args(lang, initial) if tgt in self.target_options: initial = self.target_options[tgt].get_compile_args(lang, initial) return initial def get_link_args(self, tgt: str, initial: T.List[str]) -> T.List[str]: initial = self.global_options.get_link_args(initial) if tgt in self.target_options: initial = self.target_options[tgt].get_link_args(initial) return initial def get_install(self, tgt: str, initial: bool) -> bool: initial = self.global_options.get_install(initial) if tgt in self.target_options: initial = self.target_options[tgt].get_install(initial) return initial ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.6186376 meson-1.3.2/mesonbuild/cmake/data/0000755000175000017500000000000014562742414017173 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665806.0 meson-1.3.2/mesonbuild/cmake/data/__init__.py0000644000175000017500000000000014253672216021271 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311580.0 meson-1.3.2/mesonbuild/cmake/data/preload.cmake0000644000175000017500000000402114031433534021607 0ustar00jpakkanejpakkaneif(MESON_PS_LOADED) return() endif() set(MESON_PS_LOADED ON) cmake_policy(PUSH) cmake_policy(SET CMP0054 NEW) # https://cmake.org/cmake/help/latest/policy/CMP0054.html # Dummy macros that have a special meaning in the meson code macro(meson_ps_execute_delayed_calls) endmacro() macro(meson_ps_reload_vars) endmacro() macro(meson_ps_disabled_function) message(WARNING "The function '${ARGV0}' is disabled in the context of CMake subprojects.\n" "This should not be an issue but may lead to compilation errors.") 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() macro(set_property) meson_ps_inspect_vars() _set_property(${ARGV}) endmacro() function(set_source_files_properties) set(FILES) set(I 0) set(PROPERTIES OFF) while(I LESS ARGC) if(NOT PROPERTIES) if("${ARGV${I}}" STREQUAL "PROPERTIES") set(PROPERTIES ON) else() list(APPEND FILES "${ARGV${I}}") endif() math(EXPR I "${I} + 1") else() set(ID_IDX ${I}) math(EXPR PROP_IDX "${ID_IDX} + 1") set(ID "${ARGV${ID_IDX}}") set(PROP "${ARGV${PROP_IDX}}") set_property(SOURCE ${FILES} PROPERTY "${ID}" "${PROP}") math(EXPR I "${I} + 2") endif() endwhile() endfunction() # Disable some functions that would mess up the CMake meson integration macro(target_precompile_headers) meson_ps_disabled_function(target_precompile_headers) endmacro() set(MESON_PS_DELAYED_CALLS add_custom_command;add_custom_target;set_property) meson_ps_reload_vars() cmake_policy(POP) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/cmake/executor.py0000644000175000017500000002576014562742363020507 0ustar00jpakkanejpakkane# 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 __future__ import annotations import subprocess as S from threading import Thread import typing as T import re import os from .. import mlog from ..mesonlib import PerMachine, Popen_safe, version_compare, is_windows, OptionKey from ..programs import find_external_program, NonExistingExternalProgram if T.TYPE_CHECKING: from pathlib import Path from ..environment import Environment from ..mesonlib import MachineChoice from ..programs import ExternalProgram TYPE_result = T.Tuple[int, T.Optional[str], T.Optional[str]] TYPE_cache_key = T.Tuple[str, T.Tuple[str, ...], str, T.FrozenSet[T.Tuple[str, str]]] 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[T.Optional[ExternalProgram]] = PerMachine(None, None) class_cmakevers: PerMachine[T.Optional[str]] = PerMachine(None, None) class_cmake_cache: T.Dict[T.Any, TYPE_result] = {} 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) self.always_capture_stderr = True self.print_cmout = False self.prefix_paths: T.List[str] = [] self.extra_cmake_args: T.List[str] = [] if self.cmakebin is 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 self.prefix_paths = self.environment.coredata.options[OptionKey('cmake_prefix_path', machine=self.for_machine)].value if self.prefix_paths: self.extra_cmake_args += ['-DCMAKE_PREFIX_PATH={}'.format(';'.join(self.prefix_paths))] def find_cmake_binary(self, environment: 'Environment', silent: bool = False) -> T.Tuple[T.Optional['ExternalProgram'], T.Optional[str]]: # Only search for CMake the first time and store the result in the class # definition if isinstance(CMakeExecutor.class_cmakebin[self.for_machine], NonExistingExternalProgram): mlog.debug(f'CMake binary for {self.for_machine} is cached as not found') return None, None elif CMakeExecutor.class_cmakebin[self.for_machine] is not None: mlog.debug(f'CMake binary for {self.for_machine} is cached.') else: assert CMakeExecutor.class_cmakebin[self.for_machine] is None mlog.debug(f'CMake binary for {self.for_machine} is not cached') for potential_cmakebin in find_external_program( environment, self.for_machine, 'cmake', 'CMake', environment.default_cmake, allow_default_for_cross=False): 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()), f'({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] = NonExistingExternalProgram() CMakeExecutor.class_cmakevers[self.for_machine] = None return None, 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(f'Did not find CMake {cmakebin.name!r}') return None try: cmd = cmakebin.get_command() p, out = Popen_safe(cmd + ['--version'])[0:2] if p.returncode != 0: mlog.warning('Found CMake {!r} but couldn\'t run it' ''.format(' '.join(cmd))) return None except FileNotFoundError: mlog.warning('We thought we found CMake {!r} but now it\'s not there. How odd!' ''.format(' '.join(cmd))) return None except PermissionError: msg = 'Found CMake {!r} but didn\'t have permissions to run it.'.format(' '.join(cmd)) if not 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.search(r'(cmake|cmake3)\s*version\s*([\d.]+)', out) if cmvers is not None: return cmvers.group(2) mlog.warning(f'We thought we found CMake {cmd!r}, but it was missing the expected ' 'version string in its output.') return None def set_exec_mode(self, print_cmout: T.Optional[bool] = None, always_capture_stderr: T.Optional[bool] = None) -> None: if print_cmout is not None: self.print_cmout = print_cmout if always_capture_stderr is not None: self.always_capture_stderr = always_capture_stderr def _cache_key(self, args: T.List[str], build_dir: Path, env: T.Optional[T.Dict[str, str]]) -> TYPE_cache_key: fenv = frozenset(env.items()) if env is not None else frozenset() targs = tuple(args) return (self.cmakebin.get_path(), targs, build_dir.as_posix(), fenv) def _call_cmout_stderr(self, args: T.List[str], build_dir: Path, env: T.Optional[T.Dict[str, str]]) -> TYPE_result: cmd = self.cmakebin.get_command() + args proc = S.Popen(cmd, stdout=S.PIPE, stderr=S.PIPE, cwd=str(build_dir), env=env) # TODO [PYTHON_37]: drop Path conversion # stdout and stderr MUST be read at the same time to avoid pipe # blocking issues. The easiest way to do this is with a separate # thread for one of the pipes. def print_stdout() -> None: while True: line = proc.stdout.readline() if not line: break mlog.log(line.decode(errors='ignore').strip('\n')) proc.stdout.close() t = Thread(target=print_stdout) t.start() try: # Read stderr line by line and log non trace lines raw_trace = '' tline_start_reg = re.compile(r'^\s*(.*\.(cmake|txt))\(([0-9]+)\):\s*(\w+)\(.*$') inside_multiline_trace = False while True: line_raw = proc.stderr.readline() if not line_raw: break line = line_raw.decode(errors='ignore') if tline_start_reg.match(line): raw_trace += line inside_multiline_trace = not line.endswith(' )\n') elif inside_multiline_trace: raw_trace += line else: mlog.warning(line.strip('\n')) finally: proc.stderr.close() t.join() proc.wait() return proc.returncode, None, raw_trace def _call_cmout(self, args: T.List[str], build_dir: Path, env: T.Optional[T.Dict[str, str]]) -> TYPE_result: cmd = self.cmakebin.get_command() + args proc = S.Popen(cmd, stdout=S.PIPE, stderr=S.STDOUT, cwd=str(build_dir), env=env) # TODO [PYTHON_37]: drop Path conversion while True: line = proc.stdout.readline() if not line: break mlog.log(line.decode(errors='ignore').strip('\n')) proc.stdout.close() proc.wait() return proc.returncode, None, None def _call_quiet(self, args: T.List[str], build_dir: Path, env: T.Optional[T.Dict[str, str]]) -> TYPE_result: build_dir.mkdir(parents=True, exist_ok=True) cmd = self.cmakebin.get_command() + args ret = S.run(cmd, env=env, cwd=str(build_dir), close_fds=False, stdout=S.PIPE, stderr=S.PIPE, universal_newlines=False) # TODO [PYTHON_37]: drop Path conversion rc = ret.returncode out = ret.stdout.decode(errors='ignore') err = ret.stderr.decode(errors='ignore') return rc, out, err def _call_impl(self, args: T.List[str], build_dir: Path, env: T.Optional[T.Dict[str, str]]) -> TYPE_result: mlog.debug(f'Calling CMake ({self.cmakebin.get_command()}) in {build_dir} with:') for i in args: mlog.debug(f' - "{i}"') if not self.print_cmout: return self._call_quiet(args, build_dir, env) else: if self.always_capture_stderr: return self._call_cmout_stderr(args, build_dir, env) else: return self._call_cmout(args, build_dir, env) def call(self, args: T.List[str], build_dir: Path, env: T.Optional[T.Dict[str, str]] = None, disable_cache: bool = False) -> TYPE_result: if env is None: env = os.environ.copy() args = args + self.extra_cmake_args if disable_cache: return self._call_impl(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_impl(args, build_dir, env) return cache[key] 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) -> T.List[str]: return self.cmakebin.get_command() def get_cmake_prefix_paths(self) -> T.List[str]: return self.prefix_paths def machine_choice(self) -> MachineChoice: return self.for_machine ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/cmake/fileapi.py0000644000175000017500000003126014562742363020252 0ustar00jpakkanejpakkane# 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 __future__ import annotations from .common import CMakeException, CMakeBuildFile, CMakeConfiguration import typing as T from .. import mlog from pathlib import Path import json import re STRIP_KEYS = ['cmake', 'reply', 'backtrace', 'backtraceGraph', 'version'] class CMakeFileAPI: def __init__(self, build_dir: Path): self.build_dir = build_dir self.api_base_dir = self.build_dir / '.cmake' / 'api' / 'v1' self.request_dir = self.api_base_dir / 'query' / 'client-meson' self.reply_dir = self.api_base_dir / 'reply' self.cmake_sources: T.List[CMakeBuildFile] = [] self.cmake_configurations: T.List[CMakeConfiguration] = [] 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: self.request_dir.mkdir(parents=True, exist_ok=True) query = { 'requests': [ {'kind': 'codemodel', 'version': {'major': 2, 'minor': 0}}, {'kind': 'cmakeFiles', 'version': {'major': 1, 'minor': 0}}, ] } query_file = self.request_dir / 'query.json' query_file.write_text(json.dumps(query, indent=2), encoding='utf-8') def load_reply(self) -> None: if not self.reply_dir.is_dir(): raise CMakeException('No response from the CMake file API') root = None reg_index = re.compile(r'^index-.*\.json$') for i in self.reply_dir.iterdir(): if reg_index.match(i.name): 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 = self.build_dir / '..' / 'fileAPI.json' debug_json = debug_json.resolve() debug_json.write_text(json.dumps(index, indent=2), encoding='utf-8') mlog.cmd_ci_include(debug_json.as_posix()) # 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: T.Dict[str, T.Any]) -> 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: T.Dict[str, T.Any]) -> T.Tuple[Path, Path]: src_dir = Path(dir_entry.get('source', '.')) bld_dir = Path(dir_entry.get('build', '.')) src_dir = src_dir if src_dir.is_absolute() else source_dir / src_dir bld_dir = bld_dir if bld_dir.is_absolute() else build_dir / bld_dir src_dir = src_dir.resolve() bld_dir = bld_dir.resolve() return src_dir, bld_dir def parse_sources(comp_group: T.Dict[str, T.Any], tgt: T.Dict[str, T.Any]) -> T.Tuple[T.List[Path], T.List[Path], 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 += [Path(src_list_raw[i]['path'])] else: src += [Path(src_list_raw[i]['path'])] idx += [i] return src, gen, idx def parse_target(tgt: T.Dict[str, T.Any]) -> T.Dict[str, T.Any]: src_dir, bld_dir = helper_parse_dir(cnf.get('paths', {})) # Parse install paths (if present) install_paths = [] if 'install' in tgt: prefix = Path(tgt['install']['prefix']['path']) install_paths = [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': [Path(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: T.Dict[str, T.Any]) -> T.Dict[str, T.Any]: # 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: T.Dict[str, T.Any]) -> None: assert 'inputs' in data assert 'paths' in data src_dir = Path(data['paths']['source']) for i in data['inputs']: path = Path(i['path']) path = path if path.is_absolute() else 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: Path) -> T.Dict[str, T.Any]: real_path = self.reply_dir / filename if not real_path.exists(): raise CMakeException(f'File "{real_path}" does not exist') data = json.loads(real_path.read_text(encoding='utf-8')) assert isinstance(data, dict) for i in data.keys(): assert isinstance(i, str) return data ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/cmake/generator.py0000644000175000017500000001463714562742363020640 0ustar00jpakkanejpakkane# 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 __future__ import annotations from .. import mesonlib from .. import mlog from .common import cmake_is_debug import typing as T if T.TYPE_CHECKING: from .traceparser import CMakeTraceParser, CMakeTarget def parse_generator_expressions( raw: str, trace: 'CMakeTraceParser', *, context_tgt: T.Optional['CMakeTarget'] = None, ) -> str: '''Parse CMake generator expressions Most generator expressions are simply ignored for simplicety, however some are required for some common use cases. ''' # Early abort if no generator expression present if '$<' not in raw: return raw out = '' i = 0 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' def target_property(arg: str) -> str: # We can't really support this since we don't have any context if ',' not in arg: if context_tgt is None: return '' return ';'.join(context_tgt.properties.get(arg, [])) args = arg.split(',') props = trace.targets[args[0]].properties.get(args[1], []) if args[0] in trace.targets else [] return ';'.join(props) def target_file(arg: str) -> str: if arg not in trace.targets: mlog.warning(f"Unable to evaluate the cmake variable '$'.") return '' tgt = trace.targets[arg] cfgs = [] cfg = '' if 'IMPORTED_CONFIGURATIONS' in tgt.properties: cfgs = [x for x in tgt.properties['IMPORTED_CONFIGURATIONS'] if x] cfg = cfgs[0] if cmake_is_debug(trace.env): if 'DEBUG' in cfgs: cfg = 'DEBUG' elif 'RELEASE' in cfgs: cfg = 'RELEASE' else: if 'RELEASE' in cfgs: cfg = 'RELEASE' if f'IMPORTED_IMPLIB_{cfg}' in tgt.properties: return ';'.join([x for x in tgt.properties[f'IMPORTED_IMPLIB_{cfg}'] if x]) elif 'IMPORTED_IMPLIB' in tgt.properties: return ';'.join([x for x in tgt.properties['IMPORTED_IMPLIB'] if x]) elif f'IMPORTED_LOCATION_{cfg}' in tgt.properties: return ';'.join([x for x in tgt.properties[f'IMPORTED_LOCATION_{cfg}'] if x]) elif 'IMPORTED_LOCATION' in tgt.properties: return ';'.join([x for x in tgt.properties['IMPORTED_LOCATION'] if x]) return '' supported: T.Dict[str, T.Callable[[str], str]] = { # 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', 'IF': lambda x: x.split(',')[1] if x.split(',')[0] == '1' else x.split(',')[2], '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: ';', # Target related expressions 'TARGET_EXISTS': lambda x: '1' if x in trace.targets else '0', 'TARGET_NAME_IF_EXISTS': lambda x: x if x in trace.targets else '', 'TARGET_PROPERTY': target_property, 'TARGET_FILE': target_file, } # Recursively evaluate generator expressions def eval_generator_expressions() -> str: nonlocal i i += 2 func = '' args = '' res = '' exp = '' # 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0 meson-1.3.2/mesonbuild/cmake/interpreter.py0000644000175000017500000015651414562742373021217 0ustar00jpakkanejpakkane# 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 __future__ import annotations from functools import lru_cache from os import environ from pathlib import Path import re import typing as T from .common import CMakeException, CMakeTarget, language_map, cmake_get_generator_args, check_cmake_args from .fileapi import CMakeFileAPI from .executor import CMakeExecutor from .toolchain import CMakeToolchain, CMakeExecScope from .traceparser import CMakeTraceParser from .tracetargets import resolve_cmake_trace_targets from .. import mlog, mesonlib from ..mesonlib import MachineChoice, OrderedSet, path_is_in_root, relative_to_if_possible, OptionKey from ..mesondata import DataFile from ..compilers.compilers import assembler_suffixes, lang_suffixes, header_suffixes, obj_suffixes, lib_suffixes, is_header from ..programs import ExternalProgram from ..coredata import FORBIDDEN_TARGET_NAMES from ..mparser import ( Token, BaseNode, CodeBlockNode, FunctionNode, ArrayNode, ArgumentNode, AssignmentNode, BooleanNode, StringNode, IdNode, IndexNode, MethodNode, NumberNode, SymbolNode, ) if T.TYPE_CHECKING: from .common import CMakeConfiguration, TargetOptions from .traceparser import CMakeGeneratorTarget from .._typing import ImmutableListProtocol from ..backend.backends import Backend from ..environment import Environment TYPE_mixed = T.Union[str, int, bool, Path, BaseNode] TYPE_mixed_list = T.Union[TYPE_mixed, T.Sequence[TYPE_mixed]] TYPE_mixed_kwargs = T.Dict[str, TYPE_mixed_list] # Disable all warnings automatically 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', 'CMP0102', ] 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) if name in FORBIDDEN_TARGET_NAMES or name.startswith('meson'): name = 'cm_' + name return name class OutputTargetMap: rm_so_version = re.compile(r'(\.[0-9]+)+$') def __init__(self, build_dir: Path): self.tgt_map: T.Dict[str, T.Union['ConverterTarget', 'ConverterCustomTarget']] = {} 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 executable(self, name: str) -> T.Optional['ConverterTarget']: tgt = self.target(name) if tgt is None or not isinstance(tgt, ConverterTarget): return None if tgt.meson_func() != 'executable': return None return tgt 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 += [f'{new_name}.{i}'] for i in candidates: keys += [self._rel_artifact_key(Path(i)), Path(i).name, self._base_artifact_key(Path(i))] return self._return_first_valid_key(keys) def generated(self, name: Path) -> T.Optional['ConverterCustomTarget']: res = self._return_first_valid_key([self._rel_generated_file_key(name), self._base_generated_file_key(name)]) assert res is None or isinstance(res, ConverterCustomTarget) return res # Utility functions to generate local keys def _rel_path(self, fname: Path) -> T.Optional[Path]: try: return fname.resolve().relative_to(self.build_dir) except ValueError: pass return None def _target_key(self, tgt_name: str) -> str: return f'__tgt_{tgt_name}__' def _rel_generated_file_key(self, fname: Path) -> T.Optional[str]: path = self._rel_path(fname) return f'__relgen_{path.as_posix()}__' if path else None def _base_generated_file_key(self, fname: Path) -> str: return f'__gen_{fname.name}__' def _rel_artifact_key(self, fname: Path) -> T.Optional[str]: path = self._rel_path(fname) return f'__relart_{path.as_posix()}__' if path else None def _base_artifact_key(self, fname: Path) -> str: return f'__art_{fname.name}__' class ConverterTarget: def __init__(self, target: CMakeTarget, env: 'Environment', for_machine: MachineChoice) -> None: self.env = env self.for_machine = for_machine 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: T.Optional[Path] = None self.link_libraries = target.link_libraries self.link_flags = target.link_flags + target.link_lang_flags self.depends_raw: T.List[str] = [] self.depends: T.List[T.Union[ConverterTarget, ConverterCustomTarget]] = [] if target.install_paths: self.install_dir = target.install_paths[0] self.languages: T.Set[str] = set() self.sources: T.List[Path] = [] self.generated: T.List[Path] = [] self.generated_ctgt: T.List[CustomTargetReference] = [] self.includes: T.List[Path] = [] self.sys_includes: T.List[Path] = [] self.link_with: T.List[T.Union[ConverterTarget, ConverterCustomTarget]] = [] self.object_libs: T.List[ConverterTarget] = [] self.compile_opts: T.Dict[str, T.List[str]] = {} self.public_compile_opts: T.List[str] = [] self.pie = False # Project default override options (c_std, cpp_std, etc.) self.override_options: T.List[str] = [] # Convert the target name to a valid meson target name self.name = _sanitize_cmake_name(self.name) self.generated_raw: T.List[Path] = [] for i in target.files: languages: T.Set[str] = set() src_suffixes: T.Set[str] = set() # Insert suffixes for j in i.sources: if not j.suffix: continue src_suffixes.add(j.suffix[1:]) # Determine the meson language(s) # Extract the default language from the explicit CMake field lang_cmake_to_meson = {val.lower(): key for key, val in language_map.items()} languages.add(lang_cmake_to_meson.get(i.language.lower(), 'c')) # Determine missing languages from the source suffixes for sfx in src_suffixes: for key, val in lang_suffixes.items(): if sfx in val: languages.add(key) break # Register the new languages and initialize the compile opts array for lang in languages: self.languages.add(lang) if lang not in self.compile_opts: self.compile_opts[lang] = [] # Add arguments, but avoid duplicates args = i.flags args += [f'-D{x}' for x in i.defines] for lang in languages: 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.path not in self.includes and not x.isSystem] self.sys_includes += [x.path for x in i.includes if x.path not in self.sys_includes and x.isSystem] # Add sources to the right array if i.is_generated: self.generated_raw += i.sources else: self.sources += i.sources def __repr__(self) -> str: return f'<{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: Path, subdir: Path, install_prefix: Path, trace: CMakeTraceParser) -> None: # Detect setting the C and C++ standard and do additional compiler args manipulation for i in ['c', 'cpp']: if i not in self.compile_opts: continue temp: T.List[str] = [] for j in self.compile_opts[i]: m = ConverterTarget.std_regex.match(j) ctgt = output_target_map.generated(Path(j)) if m: std = m.group(2) supported = self._all_lang_stds(i) if std not in supported: mlog.warning( 'Unknown {0}_std "{1}" -> Ignoring. Try setting the project-' 'level {0}_std if build errors occur. Known ' '{0}_stds are: {2}'.format(i, std, ' '.join(supported)), once=True ) continue self.override_options += [f'{i}_std={std}'] elif j in {'-fPIC', '-fpic', '-fPIE', '-fpie'}: self.pie = True elif isinstance(ctgt, ConverterCustomTarget): # Sometimes projects pass generated source files as compiler # flags. Add these as generated sources to ensure that the # corresponding custom target is run.2 self.generated_raw += [Path(j)] temp += [j] 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 rtgt = resolve_cmake_trace_targets(self.cmake_name, trace, self.env) self.includes += [Path(x) for x in rtgt.include_directories] self.link_flags += rtgt.link_flags self.public_compile_opts += rtgt.public_compile_opts self.link_libraries += rtgt.libraries 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 Path(i).is_absolute(): 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(assembler_suffixes) + list(header_suffixes) + list(obj_suffixes) for i in self.languages: supported += list(lang_suffixes[i]) supported = [f'.{x}' for x in supported] self.sources = [x for x in self.sources if any(x.name.endswith(y) for y in supported)] self.generated_raw = [x for x in self.generated_raw if any(x.name.endswith(y) for y in supported)] # Make paths relative def rel_path(x: Path, is_header: bool, is_generated: bool) -> T.Optional[Path]: if not x.is_absolute(): x = self.src_dir / x x = x.resolve() assert x.is_absolute() if not x.exists() and not any(x.name.endswith(y) for y in obj_suffixes) and not is_generated: if path_is_in_root(x, Path(self.env.get_build_dir()), resolve=True): x.mkdir(parents=True, exist_ok=True) return x.relative_to(Path(self.env.get_build_dir()) / subdir) else: mlog.warning('CMake: path', mlog.bold(x.as_posix()), 'does not exist.') mlog.warning(' --> Ignoring. This can lead to build errors.') return None if x in trace.explicit_headers: return None if ( path_is_in_root(x, Path(self.env.get_source_dir())) and not ( path_is_in_root(x, root_src_dir) or path_is_in_root(x, Path(self.env.get_build_dir())) ) ): mlog.warning('CMake: path', mlog.bold(x.as_posix()), 'is inside the root project but', mlog.bold('not'), 'inside the subproject.') mlog.warning(' --> Ignoring. This can lead to build errors.') return None if path_is_in_root(x, Path(self.env.get_build_dir())) and is_header: return x.relative_to(Path(self.env.get_build_dir()) / subdir) if path_is_in_root(x, root_src_dir): return x.relative_to(root_src_dir) return x build_dir_rel = self.build_dir.relative_to(Path(self.env.get_build_dir()) / subdir) self.generated_raw = [rel_path(x, False, True) for x in self.generated_raw] self.includes = list(OrderedSet([rel_path(x, True, False) for x in OrderedSet(self.includes)] + [build_dir_rel])) self.sys_includes = list(OrderedSet([rel_path(x, True, False) for x in OrderedSet(self.sys_includes)])) self.sources = [rel_path(x, False, False) for x in self.sources] # Resolve custom targets for gen_file in self.generated_raw: ctgt = output_target_map.generated(gen_file) if ctgt: assert isinstance(ctgt, ConverterCustomTarget) ref = ctgt.get_ref(gen_file) assert isinstance(ref, CustomTargetReference) and ref.valid() self.generated_ctgt += [ref] elif gen_file is not None: self.generated += [gen_file] # 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] # Make sure '.' is always in the include directories if Path('.') not in self.includes: self.includes += [Path('.')] # make install dir relative to the install prefix if self.install_dir and self.install_dir.is_absolute(): if path_is_in_root(self.install_dir, install_prefix): self.install_dir = self.install_dir.relative_to(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 OSX frameworks def handle_frameworks(flags: T.List[str]) -> T.List[str]: res: T.List[str] = [] for i in flags: p = Path(i) if not p.exists() or not p.name.endswith('.framework'): res += [i] continue res += ['-framework', p.stem] return res self.link_libraries = handle_frameworks(self.link_libraries) self.link_flags = handle_frameworks(self.link_flags) # Handle explicit CMake add_dependency() calls for i in self.depends_raw: dep_tgt = output_target_map.target(i) if dep_tgt: self.depends.append(dep_tgt) def process_object_libs(self, obj_target_list: T.List['ConverterTarget'], linker_workaround: bool) -> None: # Try to detect the object library(s) from the generated input sources temp = [x for x in self.generated if any(x.name.endswith('.' + y) for y in obj_suffixes)] stem = [x.stem 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.name for x in i.sources + i.generated] for j in stem: # 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] 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 += [f'{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(OrderedSet(self.includes)) self.object_libs += [i] break # Filter out object files from the sources self.generated = [x for x in self.generated if not any(x.name.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.generated_ctgt += tgt.generated_ctgt self.includes = list(OrderedSet(self.includes)) self.sources = list(OrderedSet(self.sources)) self.generated = list(OrderedSet(self.generated)) self.generated_ctgt = list(OrderedSet(self.generated_ctgt)) # 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) -> 'ImmutableListProtocol[str]': suffixes: T.List[str] = [] for exts in lang_suffixes.values(): suffixes.extend(exts) return suffixes @lru_cache(maxsize=None) def _all_lang_stds(self, lang: str) -> 'ImmutableListProtocol[str]': try: res = self.env.coredata.options[OptionKey('std', machine=MachineChoice.BUILD, lang=lang)].choices except KeyError: return [] # TODO: Get rid of this once we have proper typing for options assert isinstance(res, list) for i in res: assert isinstance(i, str) return res def process_inter_target_dependencies(self) -> None: # 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(OrderedSet(new_deps)) def cleanup_dependencies(self) -> None: # 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), f'({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.as_posix() if self.install_dir else '')) 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(' -- generated_ctgt: ', mlog.bold(str(self.generated_ctgt))) 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) -> None: self.ctgt = ctgt self.index = index def __repr__(self) -> str: if self.valid(): return '<{}: {} [{}]>'.format(self.__class__.__name__, self.ctgt.name, self.ctgt.outputs[self.index]) else: return f'<{self.__class__.__name__}: INVALID REFERENCE>' 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 out_counter = 0 def __init__(self, target: CMakeGeneratorTarget, env: 'Environment', for_machine: MachineChoice) -> None: 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 = f'custom_tgt_{ConverterCustomTarget.tgt_counter}' ConverterCustomTarget.tgt_counter += 1 self.cmake_name = str(self.name) self.original_outputs = list(target.outputs) self.outputs = [x.name for x in self.original_outputs] self.conflict_map: T.Dict[str, str] = {} self.command: T.List[T.List[T.Union[str, ConverterTarget]]] = [] self.working_dir = target.working_dir self.depends_raw = target.depends self.inputs: T.List[T.Union[str, CustomTargetReference]] = [] self.depends: T.List[T.Union[ConverterTarget, ConverterCustomTarget]] = [] self.current_bin_dir = target.current_bin_dir self.current_src_dir = target.current_src_dir self.env = env self.for_machine = for_machine self._raw_target = target # Convert the target name to a valid meson target name self.name = _sanitize_cmake_name(self.name) def __repr__(self) -> str: return f'<{self.__class__.__name__}: {self.name} {self.outputs}>' def postprocess(self, output_target_map: OutputTargetMap, root_src_dir: Path, all_outputs: T.List[str], trace: CMakeTraceParser) -> None: # Default the working directory to ${CMAKE_CURRENT_BINARY_DIR} if self.working_dir is None: self.working_dir = self.current_bin_dir # relative paths in the working directory are always relative # to ${CMAKE_CURRENT_BINARY_DIR} if not self.working_dir.is_absolute(): self.working_dir = self.current_bin_dir / self.working_dir # 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(x) 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: T.List[str] = [] for i in self.outputs: if i in all_outputs: old = str(i) i = f'c{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: T.List[T.List[T.Union[str, ConverterTarget]]] = [] for curr_cmd in self._raw_target.command: assert isinstance(curr_cmd, list) assert curr_cmd[0] != '', "An empty string is not a valid executable" cmd: T.List[T.Union[str, ConverterTarget]] = [] for j in curr_cmd: if not j: continue target = output_target_map.executable(j) if target: # When cross compiling, binaries have to be executed with an exe_wrapper (for instance wine for mingw-w64) if self.env.exe_wrapper is not None and self.env.properties[self.for_machine].get_cmake_use_exe_wrapper(): assert isinstance(self.env.exe_wrapper, ExternalProgram) cmd += self.env.exe_wrapper.get_command() cmd += [target] continue elif j in trace.targets: trace_tgt = trace.targets[j] if trace_tgt.type == 'EXECUTABLE' and 'IMPORTED_LOCATION' in trace_tgt.properties: cmd += trace_tgt.properties['IMPORTED_LOCATION'] continue mlog.debug(f'CMake: Found invalid CMake target "{j}" --> ignoring \n{trace_tgt}') # Fallthrough on error cmd += [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 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(raw) rel_to_root = None try: rel_to_root = raw.relative_to(root_src_dir) 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).is_file(): self.inputs += [(self.current_src_dir / raw).relative_to(root_src_dir).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: ctgt_ref = gen.get_ref(raw) assert ctgt_ref is not None self.inputs += [ctgt_ref] def process_inter_target_dependencies(self) -> None: # 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(OrderedSet(new_deps)) def get_ref(self, fname: Path) -> T.Optional[CustomTargetReference]: name = fname.name try: if name in self.conflict_map: name = self.conflict_map[name] idx = self.outputs.index(name) return CustomTargetReference(self, idx) except ValueError: return None def log(self) -> None: mlog.log('Custom Target', mlog.bold(self.name), f'({self.cmake_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 CMakeInterpreter: def __init__(self, subdir: Path, install_prefix: Path, env: 'Environment', backend: 'Backend'): self.subdir = subdir self.src_dir = Path(env.get_source_dir(), subdir) self.build_dir_rel = subdir / '__CMake_build' self.build_dir = Path(env.get_build_dir()) / self.build_dir_rel self.install_prefix = install_prefix self.env = env self.for_machine = MachineChoice.HOST # TODO make parameter self.backend_name = backend.name self.linkers: T.Set[str] = set() self.fileapi = CMakeFileAPI(self.build_dir) # Raw CMake results self.bs_files: T.List[Path] = [] self.codemodel_configs: T.Optional[T.List[CMakeConfiguration]] = None self.cmake_stderr: T.Optional[str] = None # Analysed data self.project_name = '' self.languages: T.List[str] = [] self.targets: T.List[ConverterTarget] = [] self.custom_targets: T.List[ConverterCustomTarget] = [] self.trace: CMakeTraceParser self.output_target_map = OutputTargetMap(self.build_dir) # Generated meson data self.generated_targets: T.Dict[str, T.Dict[str, T.Optional[str]]] = {} self.internal_name_map: T.Dict[str, str] = {} # Do some special handling for object libraries for certain configurations self._object_lib_workaround = False if self.backend_name.startswith('vs'): for comp in self.env.coredata.compilers[self.for_machine].values(): if comp.get_linker_id() == 'link': self._object_lib_workaround = True break def configure(self, extra_cmake_options: T.List[str]) -> CMakeExecutor: # Find CMake # TODO: Using MachineChoice.BUILD should always be correct here, but also evaluate the use of self.for_machine cmake_exe = CMakeExecutor(self.env, '>=3.14', MachineChoice.BUILD) if not cmake_exe.found(): raise CMakeException('Unable to find CMake') self.trace = CMakeTraceParser(cmake_exe.version(), self.build_dir, self.env, permissive=True) preload_file = DataFile('cmake/data/preload.cmake').write_to_private(self.env) toolchain = CMakeToolchain(cmake_exe, self.env, self.for_machine, CMakeExecScope.SUBPROJECT, self.build_dir, preload_file) toolchain_file = toolchain.write() # TODO: drop this check once the deprecated `cmake_args` kwarg is removed extra_cmake_options = check_cmake_args(extra_cmake_options) cmake_args = [] cmake_args += cmake_get_generator_args(self.env) cmake_args += [f'-DCMAKE_INSTALL_PREFIX={self.install_prefix}'] cmake_args += extra_cmake_options trace_args = self.trace.trace_args() cmcmp_args = [f'-DCMAKE_POLICY_WARNING_{x}=OFF' for x in disable_policy_warnings] self.fileapi.setup_request() # 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 CMake with:'), ' '.join(cmake_args)) mlog.log(mlog.bold(' - build directory: '), self.build_dir.as_posix()) mlog.log(mlog.bold(' - source directory: '), self.src_dir.as_posix()) mlog.log(mlog.bold(' - toolchain file: '), toolchain_file.as_posix()) mlog.log(mlog.bold(' - preload file: '), preload_file.as_posix()) mlog.log(mlog.bold(' - trace args: '), ' '.join(trace_args)) mlog.log(mlog.bold(' - disabled policy warnings:'), '[{}]'.format(', '.join(disable_policy_warnings))) mlog.log() self.build_dir.mkdir(parents=True, exist_ok=True) os_env = environ.copy() os_env['LC_ALL'] = 'C' final_args = cmake_args + trace_args + cmcmp_args + toolchain.get_cmake_args() + [self.src_dir.as_posix()] cmake_exe.set_exec_mode(print_cmout=True, always_capture_stderr=self.trace.requires_stderr()) rc, _, self.cmake_stderr = cmake_exe.call(final_args, self.build_dir, env=os_env, disable_cache=True) mlog.log() h = mlog.green('SUCCEEDED') if rc == 0 else mlog.red('FAILED') mlog.log('CMake configuration:', h) if rc != 0: # get the last CMake error - We only need the message function for this: self.trace.functions = {'message': self.trace.functions['message']} self.trace.parse(self.cmake_stderr) error = f': {self.trace.errors[-1]}' if self.trace.errors else '' raise CMakeException(f'Failed to configure the CMake subproject{error}') return cmake_exe def initialise(self, extra_cmake_options: T.List[str]) -> None: # Configure the CMake project to generate the file API data self.configure(extra_cmake_options) # 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 = [relative_to_if_possible(x, Path(self.env.get_source_dir())) for x in self.bs_files] self.bs_files = [x for x in self.bs_files if not path_is_in_root(x, Path(self.env.get_build_dir()), resolve=True)] self.bs_files = list(OrderedSet(self.bs_files)) # Load the codemodel configurations self.codemodel_configs = self.fileapi.get_cmake_configurations() 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 = [] # Parse the trace self.trace.parse(self.cmake_stderr) # Find all targets added_target_names: T.List[str] = [] for i_0 in self.codemodel_configs: for j_0 in i_0.projects: if not self.project_name: self.project_name = j_0.name for k_0 in j_0.targets: # Avoid duplicate targets from different configurations and known # dummy CMake internal target types if k_0.type not in skip_targets and k_0.name not in added_target_names: added_target_names += [k_0.name] self.targets += [ConverterTarget(k_0, self.env, self.for_machine)] # 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_1 in self.trace.targets.values(): if i_1.type != 'INTERFACE' or i_1.name in api_target_name_list or i_1.imported: continue dummy = CMakeTarget({ 'name': i_1.name, 'type': 'INTERFACE_LIBRARY', 'sourceDirectory': self.src_dir, 'buildDirectory': self.build_dir, }) self.targets += [ConverterTarget(dummy, self.env, self.for_machine)] for i_2 in self.trace.custom_targets: self.custom_targets += [ConverterCustomTarget(i_2, self.env, self.for_machine)] # generate the output_target_map for i_3 in [*self.targets, *self.custom_targets]: assert isinstance(i_3, (ConverterTarget, ConverterCustomTarget)) self.output_target_map.add(i_3) # First pass: Basic target cleanup object_libs = [] custom_target_outputs: T.List[str] = [] for ctgt in self.custom_targets: ctgt.postprocess(self.output_target_map, self.src_dir, custom_target_outputs, self.trace) for tgt in self.targets: tgt.postprocess(self.output_target_map, self.src_dir, self.subdir, self.install_prefix, self.trace) if tgt.type == 'OBJECT_LIBRARY': object_libs += [tgt] self.languages += [x for x in tgt.languages if x not in self.languages] # Second pass: Detect object library dependencies for tgt in self.targets: tgt.process_object_libs(object_libs, self._object_lib_workaround) # Third pass: Reassign dependencies to avoid some loops for tgt in self.targets: tgt.process_inter_target_dependencies() for ctgt in self.custom_targets: ctgt.process_inter_target_dependencies() # Fourth pass: Remove rassigned dependencies for tgt in self.targets: tgt.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, options: TargetOptions) -> CodeBlockNode: if not self.project_name: raise CMakeException('CMakeInterpreter was not analysed') def token(tid: str = 'string', val: TYPE_mixed = '') -> Token: return Token(tid, self.subdir.as_posix(), 0, 0, 0, None, val) def symbol(val: str) -> SymbolNode: return SymbolNode(token('', val)) def string(value: str) -> StringNode: return StringNode(token(val=value), escape=False) def id_node(value: str) -> IdNode: return IdNode(token(val=value)) def number(value: int) -> NumberNode: return NumberNode(token(val=str(value))) def nodeify(value: TYPE_mixed_list) -> BaseNode: if isinstance(value, str): return string(value) if isinstance(value, Path): return string(value.as_posix()) elif isinstance(value, bool): return BooleanNode(token(val=value)) elif isinstance(value, int): return number(value) elif isinstance(value, list): return array(value) elif isinstance(value, BaseNode): return value raise RuntimeError('invalid type of value: {} ({})'.format(type(value).__name__, str(value))) def indexed(node: BaseNode, index: int) -> IndexNode: return IndexNode(node, symbol('['), nodeify(index), symbol(']')) def array(elements: TYPE_mixed_list) -> 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(symbol('['), args, symbol(']')) def function(name: str, args: T.Optional[TYPE_mixed_list] = None, kwargs: T.Optional[TYPE_mixed_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): assert isinstance(args, (str, int, bool, Path, BaseNode)) args = [args] args_n.arguments = [nodeify(x) for x in args if x is not None] args_n.kwargs = {id_node(k): nodeify(v) for k, v in kwargs.items() if v is not None} func_n = FunctionNode(id_node(name), symbol('('), args_n, symbol(')')) return func_n def method(obj: BaseNode, name: str, args: T.Optional[TYPE_mixed_list] = None, kwargs: T.Optional[TYPE_mixed_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): assert isinstance(args, (str, int, bool, Path, BaseNode)) args = [args] args_n.arguments = [nodeify(x) for x in args if x is not None] args_n.kwargs = {id_node(k): nodeify(v) for k, v in kwargs.items() if v is not None} return MethodNode(obj, symbol('.'), id_node(name), symbol('('), args_n, symbol(')')) def assign(var_name: str, value: BaseNode) -> AssignmentNode: return AssignmentNode(id_node(var_name), symbol('='), 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 # Add the targets processing: T.List[str] = [] processed: T.Dict[str, T.Dict[str, T.Optional[str]]] = {} name_map: T.Dict[str, str] = {} 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) -> T.Union[IdNode, IndexNode]: 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) -> None: detect_cycle(tgt) # First handle inter target dependencies link_with: T.List[IdNode] = [] objec_libs: T.List[IdNode] = [] sources: T.List[Path] = [] generated: T.List[T.Union[IdNode, IndexNode]] = [] generated_filenames: T.List[str] = [] custom_targets: T.List[ConverterCustomTarget] = [] dependencies: T.List[IdNode] = [] 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 sources += tgt.sources sources += tgt.generated for ctgt_ref in tgt.generated_ctgt: ctgt = ctgt_ref.ctgt if ctgt.name not in processed: process_custom_target(ctgt) generated += [resolve_ctgt_ref(ctgt_ref)] generated_filenames += [ctgt_ref.filename()] if ctgt not in custom_targets: custom_targets += [ctgt] # 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 ctgt in custom_targets: for j in ctgt.outputs: if not is_header(j) or j in generated_filenames: continue generated += [resolve_ctgt_ref(ctgt.get_ref(Path(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(f'Unknown target type "{tgt.type}"') # Determine the variable names inc_var = f'{tgt.name}_inc' dir_var = f'{tgt.name}_dir' sys_var = f'{tgt.name}_sys' src_var = f'{tgt.name}_src' dep_var = f'{tgt.name}_dep' tgt_var = tgt.name install_tgt = options.get_install(tgt.cmake_name, tgt.install) # Generate target kwargs tgt_kwargs: TYPE_mixed_kwargs = { 'build_by_default': install_tgt, 'link_args': options.get_link_args(tgt.cmake_name, tgt.link_flags + tgt.link_libraries), 'link_with': link_with, 'include_directories': id_node(inc_var), 'install': install_tgt, 'override_options': options.get_override_options(tgt.cmake_name, tgt.override_options), 'objects': [method(x, 'extract_all_objects') for x in objec_libs], } # Only set if installed and only override if it is set if install_tgt and tgt.install_dir: tgt_kwargs['install_dir'] = tgt.install_dir # Handle compiler args for key, val in tgt.compile_opts.items(): tgt_kwargs[f'{key}_args'] = options.get_compile_args(tgt.cmake_name, 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: TYPE_mixed_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] elif tgt_func == 'shared_module': del dep_kwargs['link_with'] 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 def resolve_source(x: T.Union[str, ConverterTarget, ConverterCustomTarget, CustomTargetReference]) -> T.Union[str, IdNode, IndexNode]: 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: T.List[T.Union[str, IdNode, IndexNode]] = [] command += mesonlib.get_meson_command() command += ['--internal', 'cmake_run_ctgt'] command += ['-o', '@OUTPUT@'] if tgt.original_outputs: command += ['-O'] + [x.as_posix() for x in tgt.original_outputs] command += ['-d', tgt.working_dir.as_posix()] # Generate the commands. Subcommands are separated by ';;;' for cmd in tgt.command: command += [resolve_source(x) for x in cmd] + [';;;'] tgt_kwargs: TYPE_mixed_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 ctgt in self.custom_targets: if ctgt.name not in processed: process_custom_target(ctgt) for tgt in self.targets: if tgt.name not in processed: process_target(tgt) 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()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/cmake/toolchain.py0000644000175000017500000002356314562742363020630 0ustar00jpakkanejpakkane# Copyright 2020 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 __future__ import annotations from pathlib import Path from .traceparser import CMakeTraceParser from ..envconfig import CMakeSkipCompilerTest from .common import language_map, cmake_get_generator_args from .. import mlog import shutil import typing as T from enum import Enum from textwrap import dedent if T.TYPE_CHECKING: from .executor import CMakeExecutor from ..environment import Environment from ..compilers import Compiler from ..mesonlib import MachineChoice class CMakeExecScope(Enum): SUBPROJECT = 'subproject' DEPENDENCY = 'dependency' class CMakeToolchain: def __init__(self, cmakebin: 'CMakeExecutor', env: 'Environment', for_machine: MachineChoice, exec_scope: CMakeExecScope, build_dir: Path, preload_file: T.Optional[Path] = None) -> None: self.env = env self.cmakebin = cmakebin self.for_machine = for_machine self.exec_scope = exec_scope self.preload_file = preload_file self.build_dir = build_dir self.build_dir = self.build_dir.resolve() self.toolchain_file = build_dir / 'CMakeMesonToolchainFile.cmake' self.cmcache_file = build_dir / 'CMakeCache.txt' self.minfo = self.env.machines[self.for_machine] self.properties = self.env.properties[self.for_machine] self.compilers = self.env.coredata.compilers[self.for_machine] self.cmakevars = self.env.cmakevars[self.for_machine] self.cmakestate = self.env.coredata.cmake_cache[self.for_machine] self.variables = self.get_defaults() self.variables.update(self.cmakevars.get_variables()) # Determine whether CMake the compiler test should be skipped skip_status = self.properties.get_cmake_skip_compiler_test() self.skip_check = skip_status == CMakeSkipCompilerTest.ALWAYS if skip_status == CMakeSkipCompilerTest.DEP_ONLY and self.exec_scope == CMakeExecScope.DEPENDENCY: self.skip_check = True if not self.properties.get_cmake_defaults(): self.skip_check = False assert self.toolchain_file.is_absolute() def write(self) -> Path: if not self.toolchain_file.parent.exists(): self.toolchain_file.parent.mkdir(parents=True) self.toolchain_file.write_text(self.generate(), encoding='utf-8') self.cmcache_file.write_text(self.generate_cache(), encoding='utf-8') mlog.cmd_ci_include(self.toolchain_file.as_posix()) return self.toolchain_file def get_cmake_args(self) -> T.List[str]: args = ['-DCMAKE_TOOLCHAIN_FILE=' + self.toolchain_file.as_posix()] if self.preload_file is not None: args += ['-DMESON_PRELOAD_FILE=' + self.preload_file.as_posix()] return args @staticmethod def _print_vars(vars: T.Dict[str, T.List[str]]) -> str: res = '' for key, value in vars.items(): res += 'set(' + key for i in value: res += f' "{i}"' res += ')\n' return res def generate(self) -> str: res = dedent('''\ ###################################### ### AUTOMATICALLY GENERATED FILE ### ###################################### # This file was generated from the configuration in the # relevant meson machine file. See the meson documentation # https://mesonbuild.com/Machine-files.html for more information if(DEFINED MESON_PRELOAD_FILE) include("${MESON_PRELOAD_FILE}") endif() ''') # Escape all \ in the values for key, value in self.variables.items(): self.variables[key] = [x.replace('\\', '/') for x in value] # Set compiler if self.skip_check: self.update_cmake_compiler_state() res += '# CMake compiler state variables\n' for lang, vars in self.cmakestate: res += f'# -- Variables for language {lang}\n' res += self._print_vars(vars) res += '\n' res += '\n' # Set variables from the current machine config res += '# Variables from meson\n' res += self._print_vars(self.variables) res += '\n' # Add the user provided toolchain file user_file = self.properties.get_cmake_toolchain_file() if user_file is not None: res += dedent(''' # Load the CMake toolchain file specified by the user include("{}") '''.format(user_file.as_posix())) return res def generate_cache(self) -> str: if not self.skip_check: return '' res = '' for name, v in self.cmakestate.cmake_cache.items(): res += f'{name}:{v.type}={";".join(v.value)}\n' return res def get_defaults(self) -> T.Dict[str, T.List[str]]: defaults: T.Dict[str, T.List[str]] = {} # Do nothing if the user does not want automatic defaults if not self.properties.get_cmake_defaults(): return defaults # Best effort to map the meson system name to CMAKE_SYSTEM_NAME, which # is not trivial since CMake lacks a list of all supported # CMAKE_SYSTEM_NAME values. SYSTEM_MAP: T.Dict[str, str] = { 'android': 'Android', 'linux': 'Linux', 'windows': 'Windows', 'freebsd': 'FreeBSD', 'darwin': 'Darwin', } # Only set these in a cross build. Otherwise CMake will trip up in native # builds and thing they are cross (which causes TRY_RUN() to break) if self.env.is_cross_build(when_building_for=self.for_machine): defaults['CMAKE_SYSTEM_NAME'] = [SYSTEM_MAP.get(self.minfo.system, self.minfo.system)] defaults['CMAKE_SYSTEM_PROCESSOR'] = [self.minfo.cpu_family] defaults['CMAKE_SIZEOF_VOID_P'] = ['8' if self.minfo.is_64_bit else '4'] sys_root = self.properties.get_sys_root() if sys_root: defaults['CMAKE_SYSROOT'] = [sys_root] def make_abs(exe: str) -> str: if Path(exe).is_absolute(): return exe p = shutil.which(exe) if p is None: return exe return p # Set the compiler variables for lang, comp_obj in self.compilers.items(): prefix = 'CMAKE_{}_'.format(language_map.get(lang, lang.upper())) exe_list = comp_obj.get_exelist() if not exe_list: continue if len(exe_list) >= 2 and not self.is_cmdline_option(comp_obj, exe_list[1]): defaults[prefix + 'COMPILER_LAUNCHER'] = [make_abs(exe_list[0])] exe_list = exe_list[1:] exe_list[0] = make_abs(exe_list[0]) defaults[prefix + 'COMPILER'] = exe_list if comp_obj.get_id() == 'clang-cl': defaults['CMAKE_LINKER'] = comp_obj.get_linker_exelist() return defaults @staticmethod def is_cmdline_option(compiler: 'Compiler', arg: str) -> bool: if compiler.get_argument_syntax() == 'msvc': return arg.startswith('/') else: return arg.startswith('-') def update_cmake_compiler_state(self) -> None: # Check if all variables are already cached if self.cmakestate.languages.issuperset(self.compilers.keys()): return # Generate the CMakeLists.txt mlog.debug('CMake Toolchain: Calling CMake once to generate the compiler state') languages = list(self.compilers.keys()) lang_ids = [language_map.get(x, x.upper()) for x in languages] cmake_content = dedent(f''' cmake_minimum_required(VERSION 3.7) project(CompInfo {' '.join(lang_ids)}) ''') build_dir = Path(self.env.scratch_dir) / '__CMake_compiler_info__' build_dir.mkdir(parents=True, exist_ok=True) cmake_file = build_dir / 'CMakeLists.txt' cmake_file.write_text(cmake_content, encoding='utf-8') # Generate the temporary toolchain file temp_toolchain_file = build_dir / 'CMakeMesonTempToolchainFile.cmake' temp_toolchain_file.write_text(CMakeToolchain._print_vars(self.variables), encoding='utf-8') # Configure trace = CMakeTraceParser(self.cmakebin.version(), build_dir, self.env) self.cmakebin.set_exec_mode(print_cmout=False, always_capture_stderr=trace.requires_stderr()) cmake_args = [] cmake_args += trace.trace_args() cmake_args += cmake_get_generator_args(self.env) cmake_args += [f'-DCMAKE_TOOLCHAIN_FILE={temp_toolchain_file.as_posix()}', '.'] rc, _, raw_trace = self.cmakebin.call(cmake_args, build_dir=build_dir, disable_cache=True) if rc != 0: mlog.warning('CMake Toolchain: Failed to determine CMake compilers state') return # Parse output trace.parse(raw_trace) self.cmakestate.cmake_cache = {**trace.cache} vars_by_file = {k.name: v for (k, v) in trace.vars_by_file.items()} for lang in languages: lang_cmake = language_map.get(lang, lang.upper()) file_name = f'CMake{lang_cmake}Compiler.cmake' vars = vars_by_file.setdefault(file_name, {}) vars[f'CMAKE_{lang_cmake}_COMPILER_FORCED'] = ['1'] self.cmakestate.update(lang, vars) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/cmake/traceparser.py0000644000175000017500000010217514562742363021160 0ustar00jpakkanejpakkane# 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 __future__ import annotations from .common import CMakeException from .generator import parse_generator_expressions from .. import mlog from ..mesonlib import version_compare import typing as T from pathlib import Path from functools import lru_cache import re import json import textwrap if T.TYPE_CHECKING: from ..environment import Environment class CMakeTraceLine: def __init__(self, file_str: str, line: int, func: str, args: T.List[str]) -> None: self.file = CMakeTraceLine._to_path(file_str) self.line = line self.func = func.lower() self.args = args @staticmethod @lru_cache(maxsize=None) def _to_path(file_str: str) -> Path: return Path(file_str) def __repr__(self) -> str: s = 'CMake TRACE: {0}:{1} {2}({3})' return s.format(self.file, self.line, self.func, self.args) class CMakeCacheEntry(T.NamedTuple): value: T.List[str] type: str class CMakeTarget: def __init__( self, name: str, target_type: str, properties: T.Optional[T.Dict[str, T.List[str]]] = 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: T.List[str] = [] self.current_bin_dir: T.Optional[Path] = None self.current_src_dir: T.Optional[Path] = None def __repr__(self) -> str: 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] assert all(';' not in x for x in self.properties[key]) class CMakeGeneratorTarget(CMakeTarget): def __init__(self, name: str) -> None: super().__init__(name, 'CUSTOM', {}) self.outputs: T.List[Path] = [] self._outputs_str: T.List[str] = [] self.command: T.List[T.List[str]] = [] self.working_dir: T.Optional[Path] = None class CMakeTraceParser: def __init__(self, cmake_version: str, build_dir: Path, env: 'Environment', permissive: bool = True) -> None: self.vars: T.Dict[str, T.List[str]] = {} self.vars_by_file: T.Dict[Path, T.Dict[str, T.List[str]]] = {} self.targets: T.Dict[str, CMakeTarget] = {} self.cache: T.Dict[str, CMakeCacheEntry] = {} self.explicit_headers: T.Set[Path] = set() # T.List of targes that were added with add_custom_command to generate files self.custom_targets: T.List[CMakeGeneratorTarget] = [] self.env = env self.permissive = permissive self.cmake_version = cmake_version self.trace_file = 'cmake_trace.txt' self.trace_file_path = build_dir / self.trace_file self.trace_format = 'json-v1' if version_compare(cmake_version, '>=3.17') else 'human' self.errors: T.List[str] = [] # 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: T.List[str] = [] self.stored_commands: T.List[CMakeTraceLine] = [] # All supported functions self.functions: T.Dict[str, T.Callable[[CMakeTraceLine], None]] = { '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, 'message': self._cmake_message, # 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, 'meson_ps_disabled_function': self._meson_ps_disabled_function, } if version_compare(self.cmake_version, '<3.17.0'): mlog.deprecation(textwrap.dedent(f'''\ CMake support for versions <3.17 is deprecated since Meson 0.62.0. | | However, Meson was only able to find CMake {self.cmake_version}. | | Support for all CMake versions below 3.17.0 will be removed once | newer CMake versions are more widely adopted. If you encounter | any errors please try upgrading CMake to a newer version first. '''), once=True) def trace_args(self) -> T.List[str]: arg_map = { 'human': ['--trace', '--trace-expand'], 'json-v1': ['--trace-expand', '--trace-format=json-v1'], } base_args = ['--no-warn-unused-cli'] if not self.requires_stderr(): base_args += [f'--trace-redirect={self.trace_file}'] return arg_map[self.trace_format] + base_args def requires_stderr(self) -> bool: return version_compare(self.cmake_version, '<3.16') def parse(self, trace: T.Optional[str] = None) -> None: # First load the trace (if required) if not self.requires_stderr(): if not self.trace_file_path.exists and not self.trace_file_path.is_file(): raise CMakeException(f'CMake: Trace file "{self.trace_file_path!s}" not found') trace = self.trace_file_path.read_text(errors='ignore', encoding='utf-8') if not trace: raise CMakeException('CMake: The CMake trace was not provided or is empty') # Second parse the trace lexer1 = None if self.trace_format == 'human': lexer1 = self._lex_trace_human(trace) elif self.trace_format == 'json-v1': lexer1 = self._lex_trace_json(trace) else: raise CMakeException(f'CMake: Internal error: Invalid trace format {self.trace_format}. Expected [human, json-v1]') # 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) # Evaluate generator expressions strlist_gen: T.Callable[[T.List[str]], T.List[str]] = lambda strlist: parse_generator_expressions(';'.join(strlist), self).split(';') if strlist else [] pathlist_gen: T.Callable[[T.List[str]], T.List[Path]] = lambda strlist: [Path(x) for x in parse_generator_expressions(';'.join(strlist), self).split(';')] if strlist else [] self.vars = {k: strlist_gen(v) for k, v in self.vars.items()} self.vars_by_file = { p: {k: strlist_gen(v) for k, v in d.items()} for p, d in self.vars_by_file.items() } self.explicit_headers = {Path(parse_generator_expressions(str(x), self)) for x in self.explicit_headers} self.cache = { k: CMakeCacheEntry( strlist_gen(v.value), v.type ) for k, v in self.cache.items() } for tgt in self.targets.values(): tgtlist_gen: T.Callable[[T.List[str], CMakeTarget], T.List[str]] = lambda strlist, t: parse_generator_expressions(';'.join(strlist), self, context_tgt=t).split(';') if strlist else [] tgt.name = parse_generator_expressions(tgt.name, self, context_tgt=tgt) tgt.type = parse_generator_expressions(tgt.type, self, context_tgt=tgt) tgt.properties = { k: tgtlist_gen(v, tgt) for k, v in tgt.properties.items() } if tgt.properties is not None else None tgt.depends = tgtlist_gen(tgt.depends, tgt) for ctgt in self.custom_targets: ctgt.outputs = pathlist_gen(ctgt._outputs_str) temp = ctgt.command ctgt.command = [strlist_gen(x) for x in ctgt.command] for command, src in zip(ctgt.command, temp): if command[0] == "": raise CMakeException( "We evaluated the cmake variable '{}' to an empty string, which is not a valid path to an executable.".format(src[0]) ) ctgt.working_dir = Path(parse_generator_expressions(str(ctgt.working_dir), self)) if ctgt.working_dir is not None else None # 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 _str_to_bool(self, expr: T.Union[str, T.List[str]]) -> bool: if not expr: return False if isinstance(expr, list): expr_str = expr[0] else: expr_str = expr expr_str = expr_str.upper() return expr_str not in ['0', 'OFF', 'NO', 'FALSE', 'N', 'IGNORE'] and not expr_str.endswith('NOTFOUND') def var_to_bool(self, var: str) -> bool: return self._str_to_bool(self.vars.get(var, [])) 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(f'CMake trace warning: {function}() {error}\n{tline}') return None raise CMakeException(f'CMake: {function}() {error}\n{tline}') def _cmake_set(self, tline: CMakeTraceLine) -> None: """Handler for the CMake set() function in all varieties. 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 cache_type = None cache_force = 'FORCE' in tline.args try: cache_idx = tline.args.index('CACHE') cache_type = tline.args[cache_idx + 1] except (ValueError, IndexError): pass # 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) # Write to the CMake cache instead if cache_type: # Honor how the CMake FORCE parameter works if identifier not in self.cache or cache_force: self.cache[identifier] = CMakeCacheEntry(value.split(';'), cache_type) if not value: # Same as unset if identifier in self.vars: del self.vars[identifier] else: self.vars[identifier] = value.split(';') self.vars_by_file.setdefault(tline.file, {})[identifier] = value.split(';') def _cmake_unset(self, tline: CMakeTraceLine) -> None: # 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) -> None: # 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 is_imported = True 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', {}, tline=tline, imported=is_imported) def _cmake_add_library(self, tline: CMakeTraceLine) -> None: # 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: T.Optional[str] = None) -> None: # DOC: https://cmake.org/cmake/help/latest/command/add_custom_command.html args = self._flatten_args(list(tline.args)) # Commands can be passed as ';' separated lists 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_str += [key] def handle_command(key: str, target: CMakeGeneratorTarget) -> None: if key == 'ARGS': return target.command[-1] += [key] def handle_depends(key: str, target: CMakeGeneratorTarget) -> None: target.depends += [key] working_dir = None def handle_working_dir(key: str, target: CMakeGeneratorTarget) -> None: nonlocal working_dir if working_dir is None: working_dir = key else: working_dir += ' ' 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) cbinary_dir = self.var_to_str('MESON_PS_CMAKE_CURRENT_BINARY_DIR') csource_dir = self.var_to_str('MESON_PS_CMAKE_CURRENT_SOURCE_DIR') target.working_dir = Path(working_dir) if working_dir else None target.current_bin_dir = Path(cbinary_dir) if cbinary_dir else None target.current_src_dir = Path(csource_dir) if csource_dir else None target._outputs_str = self._guess_files(target._outputs_str) 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) -> None: # 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) scope = args.pop(0) 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 in {'APPEND', 'APPEND_STRING'}: append = True continue if curr == 'PROPERTY': break targets += curr.split(';') if not args: return self._gen_exception('set_property', 'failed 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) if self.trace_format == 'human': value = ' '.join(args).split(';') else: value = [y for x in args for y in x.split(';')] if not value: return def do_target(t: str) -> None: if t not in self.targets: return self._gen_exception('set_property', f'TARGET {t} not found', tline) tgt = self.targets[t] if identifier not in tgt.properties: tgt.properties[identifier] = [] if append: tgt.properties[identifier] += value else: tgt.properties[identifier] = value def do_source(src: str) -> None: if identifier != 'HEADER_FILE_ONLY' or not self._str_to_bool(value): return current_src_dir = self.var_to_str('MESON_PS_CMAKE_CURRENT_SOURCE_DIR') if not current_src_dir: mlog.warning(textwrap.dedent('''\ CMake trace: set_property(SOURCE) called before the preload script was loaded. Unable to determine CMAKE_CURRENT_SOURCE_DIR. This can lead to build errors. ''')) current_src_dir = '.' cur_p = Path(current_src_dir) src_p = Path(src) if not src_p.is_absolute(): src_p = cur_p / src_p self.explicit_headers.add(src_p) if scope == 'TARGET': for i in targets: do_target(i) elif scope == 'SOURCE': files = self._guess_files(targets) for i in files: do_source(i) 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 reconstitute 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 # synchronization for cmake changes. # # With the JSON output format, introduced in CMake 3.17, spaces are # handled properly and we don't have to do either options arglist: T.List[T.Tuple[str, T.List[str]]] = [] if self.trace_format == 'human': name = args.pop(0) values: T.List[str] = [] 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(';'))) else: arglist = [(x[0], x[1].split(';')) for x in zip(args[::2], args[1::2])] for name, value in arglist: for i in targets: if i not in self.targets: return self._gen_exception('set_target_properties', f'TARGET {i} not found', 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 _cmake_message(self, tline: CMakeTraceLine) -> None: # DOC: https://cmake.org/cmake/help/latest/command/message.html args = list(tline.args) if len(args) < 1: return self._gen_exception('message', 'takes at least 1 argument', tline) if args[0].upper().strip() not in ['FATAL_ERROR', 'SEND_ERROR']: return self.errors += [' '.join(args[1:])] 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) -> None: 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, f'TARGET {target} not found', 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.split(';') if mode in {'PUBLIC', 'PRIVATE', 'LINK_PRIVATE'}: private += i.split(';') 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 j in [(private_prop, private), (interface_prop, interface)]: if not j[0] in self.targets[target].properties: self.targets[target].properties[j[0]] = [] self.targets[target].properties[j[0]] += j[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 _meson_ps_disabled_function(self, tline: CMakeTraceLine) -> None: args = list(tline.args) if not args: mlog.error('Invalid preload.cmake script! At least one argument to `meson_ps_disabled_function` is expected') return mlog.warning(f'The CMake function "{args[0]}" was disabled to avoid compatibility issues with Meson.') def _lex_trace_human(self, trace: str) -> T.Generator[CMakeTraceLine, None, None]: # 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) argl = args.split(' ') argl = [a.strip() for a in argl] yield CMakeTraceLine(file, int(line), func, argl) def _lex_trace_json(self, trace: str) -> T.Generator[CMakeTraceLine, None, None]: lines = trace.splitlines(keepends=False) lines.pop(0) # The first line is the version for i in lines: data = json.loads(i) assert isinstance(data['file'], str) assert isinstance(data['line'], int) assert isinstance(data['cmd'], str) assert isinstance(data['args'], list) args = data['args'] for j in args: assert isinstance(j, str) yield CMakeTraceLine(data['file'], data['line'], data['cmd'], args) def _flatten_args(self, args: T.List[str]) -> T.List[str]: # Split lists in arguments res: T.List[str] = [] for i in args: res += i.split(';') return res def _guess_files(self, broken_list: T.List[str]) -> T.List[str]: # Nothing has to be done for newer formats if self.trace_format != 'human': return broken_list # 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: T.List[str] = [] curr_str: T.Optional[str] = None path_found = False for i in broken_list: if curr_str is None: curr_str = i path_found = False elif Path(curr_str).is_file(): # Abort concatenation if curr_str is an existing file fixed_list += [curr_str] curr_str = i path_found = False elif not reg_start.match(curr_str): # Abort concatenation if curr_str no longer matches the regex fixed_list += [curr_str] curr_str = i path_found = False elif reg_end.match(i): # File detected curr_str = f'{curr_str} {i}' fixed_list += [curr_str] curr_str = None path_found = False elif Path(f'{curr_str} {i}').exists(): # Path detected curr_str = f'{curr_str} {i}' path_found = True elif path_found: # Add path to fixed_list after ensuring the whole path is in curr_str fixed_list += [curr_str] curr_str = i path_found = False else: curr_str = f'{curr_str} {i}' path_found = False if curr_str: fixed_list += [curr_str] return fixed_list ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/cmake/tracetargets.py0000644000175000017500000001173714562742363021340 0ustar00jpakkanejpakkane# SPDX-License-Identifer: Apache-2.0 # Copyright 2021 The Meson development team from __future__ import annotations from .common import cmake_is_debug from .. import mlog from pathlib import Path import re import typing as T if T.TYPE_CHECKING: from .traceparser import CMakeTraceParser from ..environment import Environment from ..compilers import Compiler from ..dependencies import MissingCompiler class ResolvedTarget: def __init__(self) -> None: self.include_directories: T.List[str] = [] self.link_flags: T.List[str] = [] self.public_compile_opts: T.List[str] = [] self.libraries: T.List[str] = [] def resolve_cmake_trace_targets(target_name: str, trace: 'CMakeTraceParser', env: 'Environment', *, clib_compiler: T.Union['MissingCompiler', 'Compiler'] = None, not_found_warning: T.Callable[[str], None] = lambda x: None) -> ResolvedTarget: res = ResolvedTarget() targets = [target_name] # recognise arguments we should pass directly to the linker reg_is_lib = re.compile(r'^(-l[a-zA-Z0-9_]+|-l?pthread)$') reg_is_maybe_bare_lib = re.compile(r'^[a-zA-Z0-9_]+$') is_debug = cmake_is_debug(env) processed_targets: T.List[str] = [] while len(targets) > 0: curr = targets.pop(0) # Skip already processed targets if curr in processed_targets: continue if curr not in trace.targets: if reg_is_lib.match(curr): res.libraries += [curr] elif Path(curr).is_absolute() and Path(curr).exists(): res.libraries += [curr] elif reg_is_maybe_bare_lib.match(curr) and clib_compiler: # CMake library dependencies can be passed as bare library names, # CMake brute-forces a combination of prefix/suffix combinations to find the # right library. Assume any bare argument passed which is not also a CMake # target must be a system library we should try to link against. flib = clib_compiler.find_library(curr, env, []) if flib is not None: res.libraries += flib else: not_found_warning(curr) else: not_found_warning(curr) continue tgt = trace.targets[curr] cfgs = [] cfg = '' mlog.debug(tgt) if 'INTERFACE_INCLUDE_DIRECTORIES' in tgt.properties: res.include_directories += [x for x in tgt.properties['INTERFACE_INCLUDE_DIRECTORIES'] if x] if 'INTERFACE_LINK_OPTIONS' in tgt.properties: res.link_flags += [x for x in tgt.properties['INTERFACE_LINK_OPTIONS'] if x] if 'INTERFACE_COMPILE_DEFINITIONS' in tgt.properties: res.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: res.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 is_debug: if 'DEBUG' in cfgs: cfg = 'DEBUG' elif 'RELEASE' in cfgs: cfg = 'RELEASE' else: if 'RELEASE' in cfgs: cfg = 'RELEASE' if f'IMPORTED_IMPLIB_{cfg}' in tgt.properties: res.libraries += [x for x in tgt.properties[f'IMPORTED_IMPLIB_{cfg}'] if x] elif 'IMPORTED_IMPLIB' in tgt.properties: res.libraries += [x for x in tgt.properties['IMPORTED_IMPLIB'] if x] elif f'IMPORTED_LOCATION_{cfg}' in tgt.properties: res.libraries += [x for x in tgt.properties[f'IMPORTED_LOCATION_{cfg}'] if x] elif 'IMPORTED_LOCATION' in tgt.properties: res.libraries += [x for x in tgt.properties['IMPORTED_LOCATION'] if x] if 'LINK_LIBRARIES' in tgt.properties: targets += [x for x in tgt.properties['LINK_LIBRARIES'] if x] if 'INTERFACE_LINK_LIBRARIES' in tgt.properties: targets += [x for x in tgt.properties['INTERFACE_LINK_LIBRARIES'] if x] if f'IMPORTED_LINK_DEPENDENT_LIBRARIES_{cfg}' in tgt.properties: targets += [x for x in tgt.properties[f'IMPORTED_LINK_DEPENDENT_LIBRARIES_{cfg}'] if x] elif 'IMPORTED_LINK_DEPENDENT_LIBRARIES' in tgt.properties: targets += [x for x in tgt.properties['IMPORTED_LINK_DEPENDENT_LIBRARIES'] if x] processed_targets += [curr] res.include_directories = sorted(set(res.include_directories)) res.link_flags = sorted(set(res.link_flags)) res.public_compile_opts = sorted(set(res.public_compile_opts)) res.libraries = sorted(set(res.libraries)) return res ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.642638 meson-1.3.2/mesonbuild/compilers/0000755000175000017500000000000014562742414017177 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/compilers/__init__.py0000644000175000017500000000456414562742363021324 0ustar00jpakkanejpakkane# 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', 'RunResult', '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', 'is_known_suffix', 'lang_suffixes', 'LANGUAGES_USING_LDFLAGS', 'sort_clink', 'SUFFIX_TO_LANG', 'compiler_from_language', 'detect_compiler_for', 'detect_static_linker', 'detect_c_compiler', 'detect_cpp_compiler', 'detect_cuda_compiler', 'detect_fortran_compiler', 'detect_objc_compiler', 'detect_objcpp_compiler', 'detect_java_compiler', 'detect_cs_compiler', 'detect_vala_compiler', 'detect_rust_compiler', 'detect_d_compiler', 'detect_swift_compiler', ] # Bring symbols from each module into compilers sub-package namespace from .compilers import ( Compiler, RunResult, 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, is_known_suffix, lang_suffixes, LANGUAGES_USING_LDFLAGS, sort_clink, SUFFIX_TO_LANG, ) from .detect import ( compiler_from_language, detect_compiler_for, detect_static_linker, detect_c_compiler, detect_cpp_compiler, detect_cuda_compiler, detect_objc_compiler, detect_objcpp_compiler, detect_fortran_compiler, detect_java_compiler, detect_cs_compiler, detect_vala_compiler, detect_rust_compiler, detect_d_compiler, detect_swift_compiler, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/compilers/asm.py0000644000175000017500000002615014562742363020340 0ustar00jpakkanejpakkanefrom __future__ import annotations import os import typing as T from ..mesonlib import EnvironmentException, OptionKey, get_meson_command from .compilers import Compiler from .mixins.metrowerks import MetrowerksCompiler, mwasmarm_instruction_set_args, mwasmeppc_instruction_set_args if T.TYPE_CHECKING: from ..environment import Environment from ..linkers.linkers import DynamicLinker from ..mesonlib import MachineChoice from ..envconfig import MachineInfo nasm_optimization_args: T.Dict[str, T.List[str]] = { 'plain': [], '0': ['-O0'], 'g': ['-O0'], '1': ['-O1'], '2': ['-Ox'], '3': ['-Ox'], 's': ['-Ox'], } class NasmCompiler(Compiler): language = 'nasm' id = 'nasm' # https://learn.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features crt_args: T.Dict[str, T.List[str]] = { 'none': [], 'md': ['/DEFAULTLIB:ucrt.lib', '/DEFAULTLIB:vcruntime.lib', '/DEFAULTLIB:msvcrt.lib'], 'mdd': ['/DEFAULTLIB:ucrtd.lib', '/DEFAULTLIB:vcruntimed.lib', '/DEFAULTLIB:msvcrtd.lib'], 'mt': ['/DEFAULTLIB:libucrt.lib', '/DEFAULTLIB:libvcruntime.lib', '/DEFAULTLIB:libcmt.lib'], 'mtd': ['/DEFAULTLIB:libucrtd.lib', '/DEFAULTLIB:libvcruntimed.lib', '/DEFAULTLIB:libcmtd.lib'], } def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: 'MachineChoice', info: 'MachineInfo', linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None, is_cross: bool = False): super().__init__(ccache, exelist, version, for_machine, info, linker, full_version, is_cross) if 'link' in self.linker.id: self.base_options.add(OptionKey('b_vscrt')) def needs_static_linker(self) -> bool: return True def get_always_args(self) -> T.List[str]: cpu = '64' if self.info.is_64_bit else '32' if self.info.is_windows() or self.info.is_cygwin(): plat = 'win' define = f'WIN{cpu}' elif self.info.is_darwin(): plat = 'macho' define = 'MACHO' else: plat = 'elf' define = 'ELF' args = ['-f', f'{plat}{cpu}', f'-D{define}'] if self.info.is_64_bit: args.append('-D__x86_64__') return args def get_werror_args(self) -> T.List[str]: return ['-Werror'] def get_output_args(self, outputname: str) -> T.List[str]: return ['-o', outputname] def unix_args_to_native(self, args: T.List[str]) -> T.List[str]: outargs: T.List[str] = [] for arg in args: if arg == '-pthread': continue outargs.append(arg) return outargs def get_optimization_args(self, optimization_level: str) -> T.List[str]: return nasm_optimization_args[optimization_level] def get_debug_args(self, is_debug: bool) -> T.List[str]: if is_debug: if self.info.is_windows(): return [] return ['-g', '-F', 'dwarf'] return [] def get_depfile_suffix(self) -> str: return 'd' def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: return ['-MD', outfile, '-MQ', outtarget] def sanity_check(self, work_dir: str, environment: 'Environment') -> None: if self.info.cpu_family not in {'x86', 'x86_64'}: raise EnvironmentException(f'ASM compiler {self.id!r} does not support {self.info.cpu_family} CPU family') def get_buildtype_args(self, buildtype: str) -> T.List[str]: # FIXME: Not implemented return [] def get_pic_args(self) -> T.List[str]: return [] def get_include_args(self, path: str, is_system: bool) -> T.List[str]: if not path: path = '.' 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': parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:])) return parameter_list def get_crt_compile_args(self, crt_val: str, buildtype: str) -> T.List[str]: return [] # Linking ASM-only objects into an executable or DLL # require this, otherwise it'll fail to find # _WinMain or _DllMainCRTStartup. def get_crt_link_args(self, crt_val: str, buildtype: str) -> T.List[str]: if not self.info.is_windows(): return [] return self.crt_args[self.get_crt_val(crt_val, buildtype)] class YasmCompiler(NasmCompiler): id = 'yasm' def get_optimization_args(self, optimization_level: str) -> T.List[str]: # Yasm is incompatible with Nasm optimization flags. return [] def get_exelist(self, ccache: bool = True) -> T.List[str]: # Wrap yasm executable with an internal script that will write depfile. exelist = super().get_exelist(ccache) return get_meson_command() + ['--internal', 'yasm'] + exelist def get_debug_args(self, is_debug: bool) -> T.List[str]: if is_debug: if self.info.is_windows(): return ['-g', 'null'] return ['-g', 'dwarf2'] return [] def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: return ['--depfile', outfile] # https://learn.microsoft.com/en-us/cpp/assembler/masm/ml-and-ml64-command-line-reference class MasmCompiler(Compiler): language = 'masm' id = 'ml' def get_compile_only_args(self) -> T.List[str]: return ['/c'] def get_argument_syntax(self) -> str: return 'msvc' def needs_static_linker(self) -> bool: return True def get_always_args(self) -> T.List[str]: return ['/nologo'] def get_werror_args(self) -> T.List[str]: return ['/WX'] def get_output_args(self, outputname: str) -> T.List[str]: return ['/Fo', outputname] def get_optimization_args(self, optimization_level: str) -> T.List[str]: return [] def get_debug_args(self, is_debug: bool) -> T.List[str]: if is_debug: return ['/Zi'] return [] def sanity_check(self, work_dir: str, environment: 'Environment') -> None: if self.info.cpu_family not in {'x86', 'x86_64'}: raise EnvironmentException(f'ASM compiler {self.id!r} does not support {self.info.cpu_family} CPU family') def get_buildtype_args(self, buildtype: str) -> T.List[str]: # FIXME: Not implemented return [] def get_pic_args(self) -> T.List[str]: return [] def get_include_args(self, path: str, is_system: bool) -> T.List[str]: if not path: path = '.' 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:])) return parameter_list def get_crt_compile_args(self, crt_val: str, buildtype: str) -> T.List[str]: return [] def depfile_for_object(self, objfile: str) -> T.Optional[str]: return None # https://learn.microsoft.com/en-us/cpp/assembler/arm/arm-assembler-command-line-reference class MasmARMCompiler(Compiler): language = 'masm' id = 'armasm' def needs_static_linker(self) -> bool: return True def get_always_args(self) -> T.List[str]: return ['-nologo'] def get_werror_args(self) -> T.List[str]: return [] def get_output_args(self, outputname: str) -> T.List[str]: return ['-o', outputname] def get_optimization_args(self, optimization_level: str) -> T.List[str]: return [] def get_debug_args(self, is_debug: bool) -> T.List[str]: if is_debug: return ['-g'] return [] def sanity_check(self, work_dir: str, environment: 'Environment') -> None: if self.info.cpu_family not in {'arm', 'aarch64'}: raise EnvironmentException(f'ASM compiler {self.id!r} does not support {self.info.cpu_family} CPU family') def get_buildtype_args(self, buildtype: str) -> T.List[str]: # FIXME: Not implemented return [] def get_pic_args(self) -> T.List[str]: return [] def get_include_args(self, path: str, is_system: bool) -> T.List[str]: if not path: path = '.' 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': parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:])) return parameter_list def get_crt_compile_args(self, crt_val: str, buildtype: str) -> T.List[str]: return [] def depfile_for_object(self, objfile: str) -> T.Optional[str]: return None class MetrowerksAsmCompiler(MetrowerksCompiler, Compiler): language = 'nasm' def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: 'MachineChoice', info: 'MachineInfo', linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None, is_cross: bool = False): Compiler.__init__(self, ccache, exelist, version, for_machine, info, linker, full_version, is_cross) MetrowerksCompiler.__init__(self) self.warn_args: T.Dict[str, T.List[str]] = { '0': [], '1': [], '2': [], '3': [], 'everything': []} self.can_compile_suffixes.add('s') def get_crt_compile_args(self, crt_val: str, buildtype: str) -> T.List[str]: return [] def get_optimization_args(self, optimization_level: str) -> T.List[str]: return [] def get_pic_args(self) -> T.List[str]: return [] def needs_static_linker(self) -> bool: return True class MetrowerksAsmCompilerARM(MetrowerksAsmCompiler): id = 'mwasmarm' def get_instruction_set_args(self, instruction_set: str) -> T.Optional[T.List[str]]: return mwasmarm_instruction_set_args.get(instruction_set, None) def sanity_check(self, work_dir: str, environment: 'Environment') -> None: if self.info.cpu_family not in {'arm'}: raise EnvironmentException(f'ASM compiler {self.id!r} does not support {self.info.cpu_family} CPU family') class MetrowerksAsmCompilerEmbeddedPowerPC(MetrowerksAsmCompiler): id = 'mwasmeppc' def get_instruction_set_args(self, instruction_set: str) -> T.Optional[T.List[str]]: return mwasmeppc_instruction_set_args.get(instruction_set, None) def sanity_check(self, work_dir: str, environment: 'Environment') -> None: if self.info.cpu_family not in {'ppc'}: raise EnvironmentException(f'ASM compiler {self.id!r} does not support {self.info.cpu_family} CPU family') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/compilers/c.py0000644000175000017500000010512514562742363020002 0ustar00jpakkanejpakkane# Copyright 2012-2020 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 __future__ import annotations import os.path import typing as T from .. import coredata from .. import mlog from ..mesonlib import MesonException, version_compare, OptionKey from .c_function_attributes import C_FUNC_ATTRIBUTES from .mixins.clike import CLikeCompiler from .mixins.ccrx import CcrxCompiler from .mixins.xc16 import Xc16Compiler from .mixins.compcert import CompCertCompiler from .mixins.ti import TICompiler from .mixins.arm import ArmCompiler, ArmclangCompiler from .mixins.visualstudio import MSVCCompiler, ClangClCompiler from .mixins.gnu import GnuCompiler from .mixins.gnu import gnu_common_warning_args, gnu_c_warning_args from .mixins.intel import IntelGnuLikeCompiler, IntelVisualStudioLikeCompiler from .mixins.clang import ClangCompiler from .mixins.elbrus import ElbrusCompiler from .mixins.pgi import PGICompiler from .mixins.emscripten import EmscriptenMixin from .mixins.metrowerks import MetrowerksCompiler from .mixins.metrowerks import mwccarm_instruction_set_args, mwcceppc_instruction_set_args from .compilers import ( gnu_winlibs, msvc_winlibs, Compiler, ) if T.TYPE_CHECKING: from ..coredata import MutableKeyedOptionDictType, KeyedOptionDictType from ..dependencies import Dependency from ..envconfig import MachineInfo from ..environment import Environment from ..linkers.linkers import DynamicLinker from ..mesonlib import MachineChoice from ..programs import ExternalProgram from .compilers import CompileCheckMode CompilerMixinBase = Compiler else: CompilerMixinBase = object _ALL_STDS = ['c89', 'c9x', 'c90', 'c99', 'c1x', 'c11', 'c17', 'c18', 'c2x'] _ALL_STDS += [f'gnu{std[1:]}' for std in _ALL_STDS] _ALL_STDS += ['iso9899:1990', 'iso9899:199409', 'iso9899:1999', 'iso9899:2011', 'iso9899:2017', 'iso9899:2018'] class CCompiler(CLikeCompiler, Compiler): def attribute_check_func(self, name: str) -> str: try: return C_FUNC_ATTRIBUTES[name] except KeyError: raise MesonException(f'Unknown function attribute "{name}"') language = 'c' def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): # If a child ObjC or CPP class has already set it, don't set it ourselves Compiler.__init__(self, ccache, exelist, version, for_machine, info, is_cross=is_cross, full_version=full_version, linker=linker) CLikeCompiler.__init__(self, exe_wrapper) def get_no_stdinc_args(self) -> T.List[str]: return ['-nostdinc'] def sanity_check(self, work_dir: str, environment: 'Environment') -> None: 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: str, symbol: str, prefix: str, env: 'Environment', *, extra_args: T.Union[None, T.List[str], T.Callable[['CompileCheckMode'], T.List[str]]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: 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_options(self) -> 'MutableKeyedOptionDictType': opts = super().get_options() key = OptionKey('std', machine=self.for_machine, lang=self.language) opts.update({ key: coredata.UserStdOption('C', _ALL_STDS), }) return opts class _ClangCStds(CompilerMixinBase): """Mixin class for clang based compilers for setting C standards. This is used by both ClangCCompiler and ClangClCompiler, as they share the same versions """ _C17_VERSION = '>=6.0.0' _C18_VERSION = '>=8.0.0' _C2X_VERSION = '>=9.0.0' def get_options(self) -> 'MutableKeyedOptionDictType': opts = super().get_options() stds = ['c89', 'c99', 'c11'] # 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): stds += ['c17'] if version_compare(self.version, self._C18_VERSION): stds += ['c18'] if version_compare(self.version, self._C2X_VERSION): stds += ['c2x'] std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(stds, gnu=True) return opts class ClangCCompiler(_ClangCStds, ClangCompiler, CCompiler): def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, defines: T.Optional[T.Dict[str, str]] = None, full_version: T.Optional[str] = None): CCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) ClangCompiler.__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'], 'everything': ['-Weverything']} def get_options(self) -> 'MutableKeyedOptionDictType': opts = super().get_options() if self.info.is_windows() or self.info.is_cygwin(): opts.update({ OptionKey('winlibs', machine=self.for_machine, lang=self.language): coredata.UserArrayOption( 'Standard Win libraries to link against', gnu_winlibs, ), }) return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] std = options[OptionKey('std', machine=self.for_machine, lang=self.language)] if std.value != 'none': args.append('-std=' + std.value) return args def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: if self.info.is_windows() or self.info.is_cygwin(): # without a typedict mypy can't understand this. libs = options[OptionKey('winlibs', machine=self.for_machine, lang=self.language)].value.copy() assert isinstance(libs, list) for l in libs: assert isinstance(l, str) return libs return [] class ArmLtdClangCCompiler(ClangCCompiler): id = 'armltdclang' 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' _C2X_VERSION = '>=11.0.0' class EmscriptenCCompiler(EmscriptenMixin, ClangCCompiler): id = 'emscripten' def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, defines: T.Optional[T.Dict[str, str]] = None, full_version: T.Optional[str] = None): if not is_cross: raise MesonException('Emscripten compiler can only be used for cross compilation.') if not version_compare(version, '>=1.39.19'): raise MesonException('Meson requires Emscripten >= 1.39.19') ClangCCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper=exe_wrapper, linker=linker, defines=defines, full_version=full_version) class ArmclangCCompiler(ArmclangCompiler, CCompiler): ''' Keil armclang ''' def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) 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'], 'everything': ['-Weverything']} def get_options(self) -> 'MutableKeyedOptionDictType': opts = CCompiler.get_options(self) std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(['c90', 'c99', 'c11'], gnu=True) return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] std = options[OptionKey('std', machine=self.for_machine, lang=self.language)] if std.value != 'none': args.append('-std=' + std.value) return args def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return [] class GnuCCompiler(GnuCompiler, CCompiler): _C18_VERSION = '>=8.0.0' _C2X_VERSION = '>=9.0.0' _INVALID_PCH_VERSION = ">=3.4.0" def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, defines: T.Optional[T.Dict[str, str]] = None, full_version: T.Optional[str] = None): CCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) GnuCompiler.__init__(self, defines) default_warn_args = ['-Wall'] if version_compare(self.version, self._INVALID_PCH_VERSION): default_warn_args += ['-Winvalid-pch'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic'], 'everything': (default_warn_args + ['-Wextra', '-Wpedantic'] + self.supported_warn_args(gnu_common_warning_args) + self.supported_warn_args(gnu_c_warning_args))} def get_options(self) -> 'MutableKeyedOptionDictType': opts = CCompiler.get_options(self) stds = ['c89', 'c99', 'c11'] if version_compare(self.version, self._C18_VERSION): stds += ['c17', 'c18'] if version_compare(self.version, self._C2X_VERSION): stds += ['c2x'] key = OptionKey('std', machine=self.for_machine, lang=self.language) std_opt = opts[key] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(stds, gnu=True) if self.info.is_windows() or self.info.is_cygwin(): opts.update({ key.evolve('winlibs'): coredata.UserArrayOption( 'Standard Win libraries to link against', gnu_winlibs, ), }) return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] std = options[OptionKey('std', lang=self.language, machine=self.for_machine)] if std.value != 'none': args.append('-std=' + std.value) return args def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: if self.info.is_windows() or self.info.is_cygwin(): # without a typeddict mypy can't figure this out libs: T.List[str] = options[OptionKey('winlibs', lang=self.language, machine=self.for_machine)].value.copy() assert isinstance(libs, list) for l in libs: assert isinstance(l, str) return libs return [] def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: return ['-fpch-preprocess', '-include', os.path.basename(header)] class PGICCompiler(PGICompiler, CCompiler): def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) PGICompiler.__init__(self) class NvidiaHPC_CCompiler(PGICompiler, CCompiler): id = 'nvidia_hpc' def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) PGICompiler.__init__(self) class ElbrusCCompiler(ElbrusCompiler, CCompiler): def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, defines: T.Optional[T.Dict[str, str]] = None, full_version: T.Optional[str] = None): CCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) ElbrusCompiler.__init__(self) def get_options(self) -> 'MutableKeyedOptionDictType': opts = CCompiler.get_options(self) stds = ['c89', 'c9x', 'c99', 'gnu89', 'gnu9x', 'gnu99'] stds += ['iso9899:1990', 'iso9899:199409', 'iso9899:1999'] if version_compare(self.version, '>=1.20.00'): stds += ['c11', 'gnu11'] if version_compare(self.version, '>=1.21.00') and version_compare(self.version, '<1.22.00'): stds += ['c90', 'c1x', 'gnu90', 'gnu1x', 'iso9899:2011'] if version_compare(self.version, '>=1.23.00'): stds += ['c90', 'c1x', 'gnu90', 'gnu1x', 'iso9899:2011'] if version_compare(self.version, '>=1.26.00'): stds += ['c17', 'c18', 'iso9899:2017', 'iso9899:2018', 'gnu17', 'gnu18'] std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(stds) 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: str, prefix: str, env: 'Environment', *, extra_args: T.Optional[T.List[str]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: 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, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) IntelGnuLikeCompiler.__init__(self) self.lang_header = 'c-header' default_warn_args = ['-Wall', '-w3'] self.warn_args = {'0': [], '1': default_warn_args + ['-diag-disable:remark'], '2': default_warn_args + ['-Wextra', '-diag-disable:remark'], '3': default_warn_args + ['-Wextra', '-diag-disable:remark'], 'everything': default_warn_args + ['-Wextra']} def get_options(self) -> 'MutableKeyedOptionDictType': opts = CCompiler.get_options(self) stds = ['c89', 'c99'] if version_compare(self.version, '>=16.0.0'): stds += ['c11'] std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(stds, gnu=True) return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] std = options[OptionKey('std', machine=self.for_machine, lang=self.language)] if std.value != 'none': args.append('-std=' + std.value) return args class IntelLLVMCCompiler(ClangCCompiler): id = 'intel-llvm' class VisualStudioLikeCCompilerMixin(CompilerMixinBase): """Shared methods that apply to MSVC-like C compilers.""" def get_options(self) -> 'MutableKeyedOptionDictType': opts = super().get_options() opts.update({ OptionKey('winlibs', machine=self.for_machine, lang=self.language): coredata.UserArrayOption( 'Windows libs to link against.', msvc_winlibs, ), }) return opts def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: # need a TypeDict to make this work key = OptionKey('winlibs', machine=self.for_machine, lang=self.language) libs = options[key].value.copy() assert isinstance(libs, list) for l in libs: assert isinstance(l, str) return libs class VisualStudioCCompiler(MSVCCompiler, VisualStudioLikeCCompilerMixin, CCompiler): _C11_VERSION = '>=19.28' _C17_VERSION = '>=19.28' def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', target: str, exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) MSVCCompiler.__init__(self, target) def get_options(self) -> 'MutableKeyedOptionDictType': opts = super().get_options() stds = ['c89', 'c99'] if version_compare(self.version, self._C11_VERSION): stds += ['c11'] if version_compare(self.version, self._C17_VERSION): stds += ['c17', 'c18'] std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(stds, gnu=True, gnu_deprecated=True) return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] std = options[OptionKey('std', machine=self.for_machine, lang=self.language)] # As of MVSC 16.8, /std:c11 and /std:c17 are the only valid C standard options. if std.value in {'c11'}: args.append('/std:c11') elif std.value in {'c17', 'c18'}: args.append('/std:c17') return args class ClangClCCompiler(_ClangCStds, ClangClCompiler, VisualStudioLikeCCompilerMixin, CCompiler): def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', target: str, exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CCompiler.__init__(self, [], exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) ClangClCompiler.__init__(self, target) def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: key = OptionKey('std', machine=self.for_machine, lang=self.language) std = options[key].value if std != "none": return [f'/clang:-std={std}'] return [] class IntelClCCompiler(IntelVisualStudioLikeCompiler, VisualStudioLikeCCompilerMixin, CCompiler): """Intel "ICL" compiler abstraction.""" def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', target: str, exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CCompiler.__init__(self, [], exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) IntelVisualStudioLikeCompiler.__init__(self, target) def get_options(self) -> 'MutableKeyedOptionDictType': opts = super().get_options() std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(['c89', 'c99', 'c11']) return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] key = OptionKey('std', machine=self.for_machine, lang=self.language) std = options[key] if std.value == 'c89': mlog.log("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 IntelLLVMClCCompiler(IntelClCCompiler): id = 'intel-llvm-cl' class ArmCCompiler(ArmCompiler, CCompiler): def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) ArmCompiler.__init__(self) def get_options(self) -> 'MutableKeyedOptionDictType': opts = CCompiler.get_options(self) std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(['c89', 'c99', 'c11']) return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] key = OptionKey('std', machine=self.for_machine, lang=self.language) std = options[key] if std.value != 'none': args.append('--' + std.value) return args class CcrxCCompiler(CcrxCompiler, CCompiler): def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) CcrxCompiler.__init__(self) # Override CCompiler.get_always_args def get_always_args(self) -> T.List[str]: return ['-nologo'] def get_options(self) -> 'MutableKeyedOptionDictType': opts = CCompiler.get_options(self) std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(['c89', 'c99']) return opts def get_no_stdinc_args(self) -> T.List[str]: return [] def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] key = OptionKey('std', machine=self.for_machine, lang=self.language) std = options[key] if std.value == 'c89': args.append('-lang=c') elif std.value == 'c99': args.append('-lang=c99') return args def get_compile_only_args(self) -> T.List[str]: return [] def get_no_optimization_args(self) -> T.List[str]: return ['-optimize=0'] def get_output_args(self, target: str) -> T.List[str]: return [f'-output=obj={target}'] def get_werror_args(self) -> T.List[str]: return ['-change_message=error'] def get_include_args(self, path: str, is_system: bool) -> T.List[str]: if path == '': path = '.' return ['-include=' + path] class Xc16CCompiler(Xc16Compiler, CCompiler): def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) Xc16Compiler.__init__(self) def get_options(self) -> 'MutableKeyedOptionDictType': opts = CCompiler.get_options(self) std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(['c89', 'c99'], gnu=True) return opts def get_no_stdinc_args(self) -> T.List[str]: return [] def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] key = OptionKey('std', machine=self.for_machine, lang=self.language) std = options[key] if std.value != 'none': args.append('-ansi') args.append('-std=' + std.value) return args def get_compile_only_args(self) -> T.List[str]: return [] def get_no_optimization_args(self) -> T.List[str]: return ['-O0'] def get_output_args(self, target: str) -> T.List[str]: return [f'-o{target}'] def get_werror_args(self) -> T.List[str]: return ['-change_message=error'] def get_include_args(self, path: str, is_system: bool) -> T.List[str]: if path == '': path = '.' return ['-I' + path] class CompCertCCompiler(CompCertCompiler, CCompiler): def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) CompCertCompiler.__init__(self) def get_options(self) -> 'MutableKeyedOptionDictType': opts = CCompiler.get_options(self) std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(['c89', 'c99']) return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return [] def get_no_optimization_args(self) -> T.List[str]: return ['-O0'] def get_output_args(self, target: str) -> T.List[str]: return [f'-o{target}'] def get_werror_args(self) -> T.List[str]: return ['-Werror'] def get_include_args(self, path: str, is_system: bool) -> T.List[str]: if path == '': path = '.' return ['-I' + path] class TICCompiler(TICompiler, CCompiler): def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) TICompiler.__init__(self) # Override CCompiler.get_always_args def get_always_args(self) -> T.List[str]: return [] def get_options(self) -> 'MutableKeyedOptionDictType': opts = CCompiler.get_options(self) std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(['c89', 'c99', 'c11']) return opts def get_no_stdinc_args(self) -> T.List[str]: return [] def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] key = OptionKey('std', machine=self.for_machine, lang=self.language) std = options[key] if std.value != 'none': args.append('--' + std.value) return args class C2000CCompiler(TICCompiler): # Required for backwards compat with projects created before ti-cgt support existed id = 'c2000' class MetrowerksCCompilerARM(MetrowerksCompiler, CCompiler): id = 'mwccarm' def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) MetrowerksCompiler.__init__(self) def get_instruction_set_args(self, instruction_set: str) -> T.Optional[T.List[str]]: return mwccarm_instruction_set_args.get(instruction_set, None) def get_options(self) -> 'MutableKeyedOptionDictType': opts = CCompiler.get_options(self) c_stds = ['c99'] opts[OptionKey('std', machine=self.for_machine, lang=self.language)].choices = ['none'] + c_stds return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] std = options[OptionKey('std', machine=self.for_machine, lang=self.language)] if std.value != 'none': args.append('-lang') args.append(std.value) return args class MetrowerksCCompilerEmbeddedPowerPC(MetrowerksCompiler, CCompiler): id = 'mwcceppc' def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) MetrowerksCompiler.__init__(self) def get_instruction_set_args(self, instruction_set: str) -> T.Optional[T.List[str]]: return mwcceppc_instruction_set_args.get(instruction_set, None) def get_options(self) -> 'MutableKeyedOptionDictType': opts = CCompiler.get_options(self) c_stds = ['c99'] opts[OptionKey('std', machine=self.for_machine, lang=self.language)].choices = ['none'] + c_stds return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] std = options[OptionKey('std', machine=self.for_machine, lang=self.language)] if std.value != 'none': args.append('-lang ' + std.value) return args ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1699217691.0 meson-1.3.2/mesonbuild/compilers/c_function_attributes.py0000644000175000017500000001275014522000433024133 0ustar00jpakkanejpakkane# 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)));', 'force_align_arg_pointer': '__attribute__((force_align_arg_pointer)) int foo(void) { return 0; }', '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));', 'section': ''' #if defined(__APPLE__) && defined(__MACH__) extern int foo __attribute__((section("__BAR,__bar"))); #else extern int foo __attribute__((section(".bar"))); #endif''', 'sentinel': 'int foo(const char *bar, ...) __attribute__((sentinel));', 'unused': 'int foo(void) __attribute__((unused));', 'used': 'int foo(void) __attribute__((used));', 'vector_size': '__attribute__((vector_size(32))); int foo(void) { return 0; }', 'visibility': ''' int foo_def(void) __attribute__((visibility("default"))); int foo_def(void) { return 0; } int foo_hid(void) __attribute__((visibility("hidden"))); int foo_hid(void) { return 0; } int foo_int(void) __attribute__((visibility("internal"))); int foo_int(void) { return 0; }''', 'visibility:default': 'int foo(void) __attribute__((visibility("default"))); int foo(void) { return 0; }', 'visibility:hidden': 'int foo(void) __attribute__((visibility("hidden"))); int foo(void) { return 0; }', 'visibility:internal': 'int foo(void) __attribute__((visibility("internal"))); int foo(void) { return 0; }', 'visibility:protected': 'int foo(void) __attribute__((visibility("protected"))); int foo(void) { return 0; }', '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")));''', 'retain': '__attribute__((retain)) int x;', } 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")));'), } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/compilers/compilers.py0000644000175000017500000016403714562742363021564 0ustar00jpakkanejpakkane# Copyright 2012-2022 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 __future__ import annotations import abc import contextlib, os.path, re import enum import itertools import typing as T from functools import lru_cache from .. import coredata from .. import mlog from .. import mesonlib from ..mesonlib import ( HoldableObject, EnvironmentException, MesonException, Popen_safe_logged, LibType, TemporaryDirectoryWinProof, OptionKey, ) from ..arglist import CompilerArgs if T.TYPE_CHECKING: from ..build import BuildTarget, DFeatures from ..coredata import MutableKeyedOptionDictType, KeyedOptionDictType from ..envconfig import MachineInfo from ..environment import Environment from ..linkers import RSPFileSyntax from ..linkers.linkers import DynamicLinker from ..mesonlib import MachineChoice from ..dependencies import Dependency CompilerType = T.TypeVar('CompilerType', bound='Compiler') _T = T.TypeVar('_T') """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 detect.py.""" header_suffixes = {'h', 'hh', 'hpp', 'hxx', 'H', 'ipp', 'moc', 'vapi', 'di'} obj_suffixes = {'o', 'obj', 'res'} # To the emscripten compiler, .js files are libraries lib_suffixes = {'a', 'lib', 'dll', 'dll.a', 'dylib', 'so', 'js'} # 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. # First suffix is the language's default. lang_suffixes = { 'c': ('c',), 'cpp': ('cpp', 'cc', 'cxx', 'c++', 'hh', 'hpp', 'ipp', 'hxx', 'ino', 'ixx', 'C'), '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',), 'cython': ('pyx', ), 'nasm': ('asm',), 'masm': ('masm',), } all_languages = lang_suffixes.keys() c_cpp_suffixes = {'h'} cpp_suffixes = set(lang_suffixes['cpp']) | c_cpp_suffixes c_suffixes = set(lang_suffixes['c']) | c_cpp_suffixes assembler_suffixes = {'s', 'S', 'sx', 'asm', 'masm'} llvm_ir_suffixes = {'ll'} all_suffixes = set(itertools.chain(*lang_suffixes.values(), assembler_suffixes, llvm_ir_suffixes, c_cpp_suffixes)) source_suffixes = all_suffixes - header_suffixes # List of languages that by default consume and output libraries following the # C ABI; these can generally be used interchangeably # This must be sorted, see sort_clink(). clib_langs = ('objcpp', 'cpp', 'objc', 'c', 'nasm', '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() # This must be sorted, see sort_clink(). clink_langs = ('d', 'cuda') + clib_langs SUFFIX_TO_LANG = dict(itertools.chain(*( [(suffix, lang) for suffix in v] for lang, v in lang_suffixes.items()))) # Languages that should use LDFLAGS arguments when linking. LANGUAGES_USING_LDFLAGS = {'objcpp', 'cpp', 'objc', 'c', 'fortran', 'd', 'cuda'} # Languages that should use CPPFLAGS arguments when linking. LANGUAGES_USING_CPPFLAGS = {'c', 'cpp', 'objc', 'objcpp'} soregex = re.compile(r'.*\.so(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?$') # Environment variables that each lang uses. CFLAGS_MAPPING: T.Mapping[str, str] = { 'c': 'CFLAGS', 'cpp': 'CXXFLAGS', 'cuda': 'CUFLAGS', 'objc': 'OBJCFLAGS', 'objcpp': 'OBJCXXFLAGS', 'fortran': 'FFLAGS', 'd': 'DFLAGS', 'vala': 'VALAFLAGS', 'rust': 'RUSTFLAGS', 'cython': 'CYTHONFLAGS', 'cs': 'CSFLAGS', # This one might not be standard. } # All these are only for C-linkable languages; see `clink_langs` above. def sort_clink(lang: str) -> int: ''' 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: 'mesonlib.FileOrString') -> bool: if isinstance(fname, mesonlib.File): fname = fname.fname suffix = fname.split('.')[-1] return suffix in header_suffixes def is_source_suffix(suffix: str) -> bool: return suffix in source_suffixes def is_source(fname: 'mesonlib.FileOrString') -> bool: if isinstance(fname, mesonlib.File): fname = fname.fname suffix = fname.split('.')[-1].lower() return is_source_suffix(suffix) def is_assembly(fname: 'mesonlib.FileOrString') -> bool: if isinstance(fname, mesonlib.File): fname = fname.fname suffix = fname.split('.')[-1] return suffix in assembler_suffixes def is_llvm_ir(fname: 'mesonlib.FileOrString') -> bool: if isinstance(fname, mesonlib.File): fname = fname.fname suffix = fname.split('.')[-1] return suffix in llvm_ir_suffixes @lru_cache(maxsize=None) def cached_by_name(fname: 'mesonlib.FileOrString') -> bool: suffix = fname.split('.')[-1] return suffix in obj_suffixes def is_object(fname: 'mesonlib.FileOrString') -> bool: if isinstance(fname, mesonlib.File): fname = fname.fname return cached_by_name(fname) def is_library(fname: 'mesonlib.FileOrString') -> bool: if isinstance(fname, mesonlib.File): fname = fname.fname if soregex.match(fname): return True suffix = fname.split('.')[-1] return suffix in lib_suffixes def is_known_suffix(fname: 'mesonlib.FileOrString') -> bool: if isinstance(fname, mesonlib.File): fname = fname.fname suffix = fname.split('.')[-1] return suffix in all_suffixes class CompileCheckMode(enum.Enum): PREPROCESS = 'preprocess' COMPILE = 'compile' LINK = 'link' cuda_buildtype_args: T.Dict[str, T.List[str]] = { 'plain': [], 'debug': ['-g', '-G'], 'debugoptimized': ['-g', '-lineinfo'], 'release': [], 'minsize': [], 'custom': [], } java_buildtype_args: T.Dict[str, T.List[str]] = { 'plain': [], 'debug': ['-g'], 'debugoptimized': ['-g'], 'release': [], 'minsize': [], 'custom': [], } rust_buildtype_args: T.Dict[str, T.List[str]] = { 'plain': [], 'debug': [], 'debugoptimized': [], 'release': [], 'minsize': [], 'custom': [], } d_gdc_buildtype_args: T.Dict[str, T.List[str]] = { 'plain': [], 'debug': [], 'debugoptimized': ['-finline-functions'], 'release': ['-finline-functions'], 'minsize': [], 'custom': [], } d_ldc_buildtype_args: T.Dict[str, T.List[str]] = { 'plain': [], 'debug': [], 'debugoptimized': ['-enable-inlining', '-Hkeep-all-bodies'], 'release': ['-enable-inlining', '-Hkeep-all-bodies'], 'minsize': [], 'custom': [], } d_dmd_buildtype_args: T.Dict[str, T.List[str]] = { 'plain': [], 'debug': [], 'debugoptimized': ['-inline'], 'release': ['-inline'], 'minsize': [], 'custom': [], } mono_buildtype_args: T.Dict[str, T.List[str]] = { 'plain': [], 'debug': [], 'debugoptimized': ['-optimize+'], 'release': ['-optimize+'], 'minsize': [], 'custom': [], } swift_buildtype_args: T.Dict[str, T.List[str]] = { '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: T.Dict[str, T.List[str]] = { 'plain': [], '0': [], 'g': [], '1': ['-O1'], '2': ['-O2'], '3': ['-O3'], 's': ['-Os'], } cuda_optimization_args: T.Dict[str, T.List[str]] = { 'plain': [], '0': [], 'g': ['-O0'], '1': ['-O1'], '2': ['-O2'], '3': ['-O3'], 's': ['-O3'] } cuda_debug_args: T.Dict[bool, T.List[str]] = { False: [], True: ['-g'] } clike_debug_args: T.Dict[bool, T.List[str]] = { False: [], True: ['-g'] } MSCRT_VALS = ['none', 'md', 'mdd', 'mt', 'mtd'] base_options: 'KeyedOptionDictType' = { OptionKey('b_pch'): coredata.UserBooleanOption('Use precompiled headers', True), OptionKey('b_lto'): coredata.UserBooleanOption('Use link time optimization', False), OptionKey('b_lto_threads'): coredata.UserIntegerOption('Use multiple threads for Link Time Optimization', (None, None, 0)), OptionKey('b_lto_mode'): coredata.UserComboOption('Select between different LTO modes.', ['default', 'thin'], 'default'), OptionKey('b_thinlto_cache'): coredata.UserBooleanOption('Use LLVM ThinLTO caching for faster incremental builds', False), OptionKey('b_thinlto_cache_dir'): coredata.UserStringOption('Directory to store ThinLTO cache objects', ''), OptionKey('b_sanitize'): coredata.UserComboOption('Code sanitizer to use', ['none', 'address', 'thread', 'undefined', 'memory', 'leak', 'address,undefined'], 'none'), OptionKey('b_lundef'): coredata.UserBooleanOption('Use -Wl,--no-undefined when linking', True), OptionKey('b_asneeded'): coredata.UserBooleanOption('Use -Wl,--as-needed when linking', True), OptionKey('b_pgo'): coredata.UserComboOption('Use profile guided optimization', ['off', 'generate', 'use'], 'off'), OptionKey('b_coverage'): coredata.UserBooleanOption('Enable coverage tracking.', False), OptionKey('b_colorout'): coredata.UserComboOption('Use colored output', ['auto', 'always', 'never'], 'always'), OptionKey('b_ndebug'): coredata.UserComboOption('Disable asserts', ['true', 'false', 'if-release'], 'false'), OptionKey('b_staticpic'): coredata.UserBooleanOption('Build static libraries as position independent', True), OptionKey('b_pie'): coredata.UserBooleanOption('Build executables as position independent', False), OptionKey('b_bitcode'): coredata.UserBooleanOption('Generate and embed bitcode (only macOS/iOS/tvOS)', False), OptionKey('b_vscrt'): coredata.UserComboOption('VS run-time library type to use.', MSCRT_VALS + ['from_buildtype', 'static_from_buildtype'], 'from_buildtype'), } def option_enabled(boptions: T.Set[OptionKey], options: 'KeyedOptionDictType', option: OptionKey) -> bool: try: if option not in boptions: return False ret = options[option].value assert isinstance(ret, bool), 'must return bool' # could also be str return ret except KeyError: return False def get_option_value(options: 'KeyedOptionDictType', opt: OptionKey, fallback: '_T') -> '_T': """Get the value of an option, or the fallback value.""" try: v: '_T' = options[opt].value except KeyError: return fallback assert isinstance(v, type(fallback)), f'Should have {type(fallback)!r} but was {type(v)!r}' # Mypy doesn't understand that the above assert ensures that v is type _T return v def are_asserts_disabled(options: KeyedOptionDictType) -> bool: """Should debug assertions be disabled :param options: OptionDictionary :return: whether to disable assertions or not """ return (options[OptionKey('b_ndebug')].value == 'true' or (options[OptionKey('b_ndebug')].value == 'if-release' and options[OptionKey('buildtype')].value in {'release', 'plain'})) def get_base_compile_args(options: 'KeyedOptionDictType', compiler: 'Compiler') -> T.List[str]: args: T.List[str] = [] try: if options[OptionKey('b_lto')].value: args.extend(compiler.get_lto_compile_args( threads=get_option_value(options, OptionKey('b_lto_threads'), 0), mode=get_option_value(options, OptionKey('b_lto_mode'), 'default'))) except KeyError: pass try: args += compiler.get_colorout_args(options[OptionKey('b_colorout')].value) except KeyError: pass try: args += compiler.sanitizer_compile_args(options[OptionKey('b_sanitize')].value) except KeyError: pass try: pgo_val = options[OptionKey('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[OptionKey('b_coverage')].value: args += compiler.get_coverage_args() except KeyError: pass try: args += compiler.get_assert_args(are_asserts_disabled(options)) except KeyError: pass # This does not need a try...except if option_enabled(compiler.base_options, options, OptionKey('b_bitcode')): args.append('-fembed-bitcode') try: crt_val = options[OptionKey('b_vscrt')].value buildtype = options[OptionKey('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: 'KeyedOptionDictType', linker: 'Compiler', is_shared_module: bool, build_dir: str) -> T.List[str]: args: T.List[str] = [] try: if options[OptionKey('b_lto')].value: thinlto_cache_dir = None if get_option_value(options, OptionKey('b_thinlto_cache'), False): thinlto_cache_dir = get_option_value(options, OptionKey('b_thinlto_cache_dir'), '') if thinlto_cache_dir == '': thinlto_cache_dir = os.path.join(build_dir, 'meson-private', 'thinlto-cache') args.extend(linker.get_lto_link_args( threads=get_option_value(options, OptionKey('b_lto_threads'), 0), mode=get_option_value(options, OptionKey('b_lto_mode'), 'default'), thinlto_cache_dir=thinlto_cache_dir)) except KeyError: pass try: args += linker.sanitizer_link_args(options[OptionKey('b_sanitize')].value) except KeyError: pass try: pgo_val = options[OptionKey('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[OptionKey('b_coverage')].value: args += linker.get_coverage_link_args() except KeyError: pass as_needed = option_enabled(linker.base_options, options, OptionKey('b_asneeded')) bitcode = option_enabled(linker.base_options, options, OptionKey('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 -undefined # arguments or -headerpad_max_install_names when bitcode is enabled if not bitcode: args.extend(linker.headerpad_args()) if (not is_shared_module and option_enabled(linker.base_options, options, OptionKey('b_lundef'))): args.extend(linker.no_undefined_link_args()) else: args.extend(linker.get_allow_undefined_link_args()) try: crt_val = options[OptionKey('b_vscrt')].value buildtype = options[OptionKey('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(HoldableObject): def __init__(self, compiled: bool, returncode: int = 999, stdout: str = 'UNDEFINED', stderr: str = 'UNDEFINED', cached: bool = False): self.compiled = compiled self.returncode = returncode self.stdout = stdout self.stderr = stderr self.cached = cached class CompileResult(HoldableObject): """The result of Compiler.compiles (and friends).""" def __init__(self, stdo: T.Optional[str] = None, stde: T.Optional[str] = None, command: T.Optional[T.List[str]] = None, returncode: int = 999, input_name: T.Optional[str] = None, output_name: T.Optional[str] = None, cached: bool = False): self.stdout = stdo self.stderr = stde self.input_name = input_name self.output_name = output_name self.command = command or [] self.cached = cached self.returncode = returncode class Compiler(HoldableObject, metaclass=abc.ABCMeta): # Libraries to ignore in find_library() since they are provided by the # compiler or the C library. Currently only used for MSVC. ignore_libs: T.List[str] = [] # Libraries that are internal compiler implementations, and must not be # manually searched. internal_libs: T.List[str] = [] LINKER_PREFIX: T.Union[None, str, T.List[str]] = None INVOKES_LINKER = True language: str id: str warn_args: T.Dict[str, T.List[str]] mode = 'COMPILER' def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, info: 'MachineInfo', linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None, is_cross: bool = False): self.exelist = ccache + exelist self.exelist_no_ccache = exelist # 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: T.Set[str] = set(self.file_suffixes) self.default_suffix = self.file_suffixes[0] self.version = version self.full_version = full_version self.for_machine = for_machine self.base_options: T.Set[OptionKey] = set() self.linker = linker self.info = info self.is_cross = is_cross self.modes: T.List[Compiler] = [] def __repr__(self) -> str: repr_str = "<{0}: v{1} `{2}`>" return repr_str.format(self.__class__.__name__, self.version, ' '.join(self.exelist)) @lru_cache(maxsize=None) def can_compile(self, src: 'mesonlib.FileOrString') -> bool: if isinstance(src, mesonlib.File): src = src.fname suffix = os.path.splitext(src)[1] if suffix != '.C': suffix = suffix.lower() return bool(suffix) and suffix[1:] in self.can_compile_suffixes def get_id(self) -> str: return self.id def get_modes(self) -> T.List[Compiler]: return self.modes 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: str, prefix: str, env: 'Environment', extra_args: T.Union[T.List[str], T.Callable[[CompileCheckMode], T.List[str]]], dependencies: T.List['Dependency'], disable_cache: bool = False) -> T.Tuple[str, bool]: raise EnvironmentException('%s does not support get_define ' % self.get_id()) def compute_int(self, expression: str, low: T.Optional[int], high: T.Optional[int], guess: T.Optional[int], prefix: str, env: 'Environment', *, extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]], dependencies: T.Optional[T.List['Dependency']]) -> int: raise EnvironmentException('%s does not support compute_int ' % self.get_id()) def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], build_dir: str) -> T.List[str]: raise EnvironmentException('%s does not support compute_parameters_with_absolute_paths ' % self.get_id()) def has_members(self, typename: str, membernames: T.List[str], prefix: str, env: 'Environment', *, extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: raise EnvironmentException('%s does not support has_member(s) ' % self.get_id()) def has_type(self, typename: str, prefix: str, env: 'Environment', extra_args: T.Union[T.List[str], T.Callable[[CompileCheckMode], T.List[str]]], *, dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: raise EnvironmentException('%s does not support has_type ' % self.get_id()) def symbols_have_underscore_prefix(self, env: 'Environment') -> bool: raise EnvironmentException('%s does not support symbols_have_underscore_prefix ' % self.get_id()) def get_exelist(self, ccache: bool = True) -> T.List[str]: return self.exelist.copy() if ccache else self.exelist_no_ccache.copy() def get_linker_exelist(self) -> T.List[str]: return self.linker.get_exelist() if self.linker else self.get_exelist() @abc.abstractmethod def get_output_args(self, outputname: str) -> T.List[str]: pass def get_linker_output_args(self, outputname: str) -> T.List[str]: return self.linker.get_output_args(outputname) def get_linker_search_args(self, dirname: str) -> T.List[str]: return self.linker.get_search_args(dirname) def get_builtin_define(self, define: str) -> T.Optional[str]: raise EnvironmentException('%s does not support get_builtin_define.' % self.id) def has_builtin_define(self, define: str) -> bool: raise EnvironmentException('%s does not support has_builtin_define.' % self.id) def get_always_args(self) -> T.List[str]: 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) -> T.List[str]: return self.linker.get_always_args() def get_linker_lib_prefix(self) -> str: return self.linker.get_lib_prefix() def gen_import_library_args(self, implibname: str) -> T.List[str]: """ Used only on Windows for libraries that need an import library. This currently means C, C++, Fortran. """ return [] def get_options(self) -> 'MutableKeyedOptionDictType': return {} def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return [] def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return self.linker.get_option_args(options) def check_header(self, hname: str, prefix: str, env: 'Environment', *, extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: """Check that header is usable. Returns a two item tuple of bools. The first bool is whether the check succeeded, the second is whether the result was cached (True) or run fresh (False). """ raise EnvironmentException('Language %s does not support header checks.' % self.get_display_language()) def has_header(self, hname: str, prefix: str, env: 'Environment', *, extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None, dependencies: T.Optional[T.List['Dependency']] = None, disable_cache: bool = False) -> T.Tuple[bool, bool]: """Check that header is exists. This check will return true if the file exists, even if it contains: ```c # error "You thought you could use this, LOLZ!" ``` Use check_header if your header only works in some cases. Returns a two item tuple of bools. The first bool is whether the check succeeded, the second is whether the result was cached (True) or run fresh (False). """ raise EnvironmentException('Language %s does not support header checks.' % self.get_display_language()) def has_header_symbol(self, hname: str, symbol: str, prefix: str, env: 'Environment', *, extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: raise EnvironmentException('Language %s does not support header symbol checks.' % self.get_display_language()) def run(self, code: 'mesonlib.FileOrString', env: 'Environment', *, extra_args: T.Union[T.List[str], T.Callable[[CompileCheckMode], T.List[str]], None] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> RunResult: raise EnvironmentException('Language %s does not support run checks.' % self.get_display_language()) # Caching run() in general seems too risky (no way to know what the program # depends on), but some callers know more about the programs they intend to # run. # For now we just accept code as a string, as that's what internal callers # need anyway. If we wanted to accept files, the cache key would need to # include mtime. def cached_run(self, code: str, env: 'Environment', *, extra_args: T.Union[T.List[str], T.Callable[[CompileCheckMode], T.List[str]], None] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> RunResult: run_check_cache = env.coredata.run_check_cache args = self.build_wrapper_args(env, extra_args, dependencies, CompileCheckMode('link')) key = (code, tuple(args)) if key in run_check_cache: p = run_check_cache[key] p.cached = True mlog.debug('Using cached run result:') mlog.debug('Code:\n', code) mlog.debug('Args:\n', extra_args) mlog.debug('Cached run returncode:\n', p.returncode) mlog.debug('Cached run stdout:\n', p.stdout) mlog.debug('Cached run stderr:\n', p.stderr) else: p = self.run(code, env, extra_args=extra_args, dependencies=dependencies) run_check_cache[key] = p return p def sizeof(self, typename: str, prefix: str, env: 'Environment', *, extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[int, bool]: raise EnvironmentException('Language %s does not support sizeof checks.' % self.get_display_language()) def alignment(self, typename: str, prefix: str, env: 'Environment', *, extra_args: T.Optional[T.List[str]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[int, bool]: raise EnvironmentException('Language %s does not support alignment checks.' % self.get_display_language()) 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) -> T.Tuple[bool, bool]: """See if a function exists. Returns a two item tuple of bools. The first bool is whether the check succeeded, the second is whether the result was cached (True) or run fresh (False). """ raise EnvironmentException('Language %s does not support function checks.' % self.get_display_language()) @classmethod def _unix_args_to_native(cls, args: T.List[str], info: MachineInfo) -> T.List[str]: "Always returns a copy that can be independently mutated" return args.copy() def unix_args_to_native(self, args: T.List[str]) -> T.List[str]: return self._unix_args_to_native(args, self.info) @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.copy() def find_library(self, libname: str, env: 'Environment', extra_dirs: T.List[str], libtype: LibType = LibType.PREFER_SHARED, lib_prefix_warning: bool = True) -> T.Optional[T.List[str]]: raise EnvironmentException(f'Language {self.get_display_language()} does not support library finding.') def get_library_naming(self, env: 'Environment', libtype: LibType, strict: bool = False) -> T.Optional[T.Tuple[str, ...]]: raise EnvironmentException( 'Language {} does not support get_library_naming.'.format( self.get_display_language())) def get_program_dirs(self, env: 'Environment') -> T.List[str]: return [] def has_multi_arguments(self, args: T.List[str], env: 'Environment') -> 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: str, mode: CompileCheckMode) -> str: assert mode != CompileCheckMode.PREPROCESS, 'In pre-processor mode, the output is sent to stdout and discarded' # Extension only matters if running results; '.exe' is # guaranteed to be executable on every platform. if mode == CompileCheckMode.LINK: suffix = 'exe' else: suffix = 'obj' return os.path.join(dirname, 'output.' + suffix) def get_compiler_args_for_mode(self, mode: CompileCheckMode) -> T.List[str]: args: T.List[str] = [] args += self.get_always_args() if mode is CompileCheckMode.COMPILE: args += self.get_compile_only_args() elif mode is CompileCheckMode.PREPROCESS: args += self.get_preprocess_only_args() else: assert mode is CompileCheckMode.LINK return args def compiler_args(self, args: T.Optional[T.Iterable[str]] = None) -> CompilerArgs: """Return an appropriate CompilerArgs instance for this class.""" return CompilerArgs(self, args) @contextlib.contextmanager def compile(self, code: 'mesonlib.FileOrString', extra_args: T.Union[None, CompilerArgs, T.List[str]] = None, *, mode: CompileCheckMode = CompileCheckMode.LINK, want_output: bool = False, temp_dir: T.Optional[str] = None) -> T.Iterator[T.Optional[CompileResult]]: # TODO: there isn't really any reason for this to be a contextmanager if mode == CompileCheckMode.PREPROCESS: assert not want_output, 'In pre-processor mode, the output is sent to stdout and discarded' if extra_args is None: extra_args = [] with TemporaryDirectoryWinProof(dir=temp_dir) as tmpdirname: no_ccache = False if isinstance(code, str): srcname = os.path.join(tmpdirname, 'testfile.' + self.default_suffix) with open(srcname, 'w', encoding='utf-8') as ofile: ofile.write(code) # ccache would result in a cache miss no_ccache = True contents = code else: srcname = code.fname if not is_object(code.fname): with open(code.fname, encoding='utf-8') as f: contents = f.read() else: contents = '' # Construct the compiler command-line commands = self.compiler_args() commands.append(srcname) # Preprocess mode outputs to stdout, so no output args if mode != CompileCheckMode.PREPROCESS: output = self._get_compile_output(tmpdirname, mode) commands += self.get_output_args(output) commands.extend(self.get_compiler_args_for_mode(CompileCheckMode(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. if extra_args: commands += extra_args # Generate full command-line with the exelist command_list = self.get_exelist(ccache=not no_ccache) + commands.to_native() mlog.debug('Running compile:') mlog.debug('Working directory: ', tmpdirname) mlog.debug('Code:\n', contents) os_env = os.environ.copy() os_env['LC_ALL'] = 'C' if no_ccache: os_env['CCACHE_DISABLE'] = '1' p, stdo, stde = Popen_safe_logged(command_list, msg='Command line', cwd=tmpdirname, env=os_env) result = CompileResult(stdo, stde, command_list, p.returncode, input_name=srcname) if want_output: result.output_name = output yield result @contextlib.contextmanager def cached_compile(self, code: 'mesonlib.FileOrString', cdata: coredata.CoreData, *, extra_args: T.Union[None, T.List[str], CompilerArgs] = None, mode: CompileCheckMode = CompileCheckMode.LINK, temp_dir: T.Optional[str] = None) -> T.Iterator[T.Optional[CompileResult]]: # TODO: There's isn't really any reason for this to be a context manager # Calculate the key textra_args: T.Tuple[str, ...] = tuple(extra_args) if extra_args is not None else tuple() key: coredata.CompilerCheckCacheKey = (tuple(self.exelist), self.version, code, textra_args, mode) # Check if not cached, and generate, otherwise get from the cache if key in cdata.compiler_check_cache: p = cdata.compiler_check_cache[key] p.cached = True mlog.debug('Using cached compile:') mlog.debug('Cached command line: ', ' '.join(p.command), '\n') mlog.debug('Code:\n', code) mlog.debug('Cached compiler stdout:\n', p.stdout) mlog.debug('Cached compiler stderr:\n', p.stderr) yield p else: with self.compile(code, extra_args=extra_args, mode=mode, want_output=False, temp_dir=temp_dir) as p: cdata.compiler_check_cache[key] = p yield p def get_colorout_args(self, colortype: str) -> T.List[str]: # TODO: colortype can probably be an emum 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: str, pch: bool = False) -> T.List[str]: return [] def get_link_debugfile_name(self, targetfile: str) -> T.Optional[str]: return self.linker.get_debugfile_name(targetfile) 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: 'KeyedOptionDictType') -> 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() def get_instruction_set_args(self, instruction_set: str) -> T.Optional[T.List[str]]: """Compiler arguments needed to enable the given instruction set. Return type ay be an empty list meaning nothing needed or None meaning the given set is not supported. """ return None def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, rpath_paths: T.Tuple[str, ...], build_rpath: str, install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: return self.linker.build_rpath_args( env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath) def get_archive_name(self, filename: str) -> str: return self.linker.get_archive_name(filename) def get_command_to_archive_shlib(self) -> T.List[str]: if not self.linker: return [] return self.linker.get_command_to_archive_shlib() def thread_flags(self, env: 'Environment') -> T.List[str]: return [] def thread_link_flags(self, env: 'Environment') -> T.List[str]: return self.linker.thread_flags(env) def openmp_flags(self) -> T.List[str]: raise EnvironmentException('Language %s does not support OpenMP flags.' % self.get_display_language()) def openmp_link_flags(self) -> T.List[str]: return self.openmp_flags() def language_stdlib_only_link_flags(self, env: 'Environment') -> T.List[str]: return [] def gnu_symbol_visibility_args(self, vistype: str) -> T.List[str]: return [] def get_win_subsystem_args(self, value: str) -> T.List[str]: # By default the dynamic linker is going to return an empty # array in case it either doesn't support Windows subsystems # or does not target Windows return self.linker.get_win_subsystem_args(value) def has_func_attribute(self, name: str, env: 'Environment') -> T.Tuple[bool, bool]: raise EnvironmentException( f'Language {self.get_display_language()} does not support function attributes.') def get_pic_args(self) -> T.List[str]: m = 'Language {} does not support position-independent code' raise EnvironmentException(m.format(self.get_display_language())) def get_pie_args(self) -> T.List[str]: 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) -> str: """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) -> T.List[str]: raise EnvironmentException( '%s does not support get_profile_generate_args ' % self.get_id()) def get_profile_use_args(self) -> T.List[str]: raise EnvironmentException( '%s does not support get_profile_use_args ' % self.get_id()) def remove_linkerlike_args(self, args: T.List[str]) -> T.List[str]: rm_exact = ('-headerpad_max_install_names',) rm_prefixes = ('-Wl,', '-L',) rm_next = ('-L', '-framework',) ret: T.List[str] = [] 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, *, threads: int = 0, mode: str = 'default') -> T.List[str]: return [] def get_lto_link_args(self, *, threads: int = 0, mode: str = 'default', thinlto_cache_dir: T.Optional[str] = None) -> 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 headerpad_args(self) -> T.List[str]: return self.linker.headerpad_args() def bitcode_args(self) -> T.List[str]: return self.linker.bitcode_args() def get_buildtype_args(self, buildtype: str) -> T.List[str]: raise EnvironmentException(f'{self.id} does not implement get_buildtype_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]) -> T.List[str]: return self.linker.get_soname_args( env, prefix, shlib_name, suffix, soversion, darwin_versions) def get_target_link_args(self, target: 'BuildTarget') -> T.List[str]: return target.link_args def get_dependency_compile_args(self, dep: 'Dependency') -> T.List[str]: return dep.get_compile_args() def get_dependency_link_args(self, dep: 'Dependency') -> T.List[str]: return dep.get_link_args() @classmethod def use_linker_args(cls, linker: str, version: str) -> T.List[str]: """Get a list of arguments to pass to the compiler to set the linker. """ return [] def get_coverage_args(self) -> T.List[str]: return [] def get_coverage_link_args(self) -> T.List[str]: return self.linker.get_coverage_args() def get_assert_args(self, disable: bool) -> T.List[str]: """Get arguments to enable or disable assertion. :param disable: Whether to disable assertions :return: A list of string arguments for this compiler """ return [] def get_crt_val(self, crt_val: str, buildtype: str) -> str: if crt_val in MSCRT_VALS: return crt_val assert crt_val in {'from_buildtype', 'static_from_buildtype'} dbg = 'mdd' rel = 'md' if crt_val == 'static_from_buildtype': dbg = 'mtd' rel = 'mt' # Match what build type flags used to do. if buildtype == 'plain': return 'none' elif buildtype == 'debug': return dbg elif buildtype in {'debugoptimized', 'release', 'minsize'}: return rel else: assert buildtype == 'custom' raise EnvironmentException('Requested C runtime based on buildtype, but buildtype is "custom".') def get_crt_compile_args(self, crt_val: str, buildtype: str) -> T.List[str]: raise EnvironmentException('This compiler does not support Windows CRT selection') def get_crt_link_args(self, crt_val: str, buildtype: str) -> T.List[str]: raise EnvironmentException('This compiler does not support Windows CRT selection') def get_compile_only_args(self) -> T.List[str]: return [] def get_preprocess_only_args(self) -> T.List[str]: raise EnvironmentException('This compiler does not have a preprocessor') def get_preprocess_to_file_args(self) -> T.List[str]: return self.get_preprocess_only_args() def get_default_include_dirs(self) -> T.List[str]: # TODO: This is a candidate for returning an immutable list return [] def get_largefile_args(self) -> T.List[str]: '''Enable transparent large-file-support for 32-bit UNIX systems''' if not (self.get_argument_syntax() == 'msvc' or self.info.is_darwin()): # Enable large-file support unconditionally on all platforms other # than macOS and MSVC. macOS is now 64-bit-only so it doesn't # need anything special, and MSVC 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_library_dirs(self, env: 'Environment', elf_class: T.Optional[int] = None) -> T.List[str]: return [] def get_return_value(self, fname: str, rtype: str, prefix: str, env: 'Environment', extra_args: T.Optional[T.List[str]], dependencies: T.Optional[T.List['Dependency']]) -> T.Union[str, int]: raise EnvironmentException(f'{self.id} does not support get_return_value') def find_framework(self, name: str, env: 'Environment', extra_dirs: T.List[str], allow_system: bool = True) -> T.Optional[T.List[str]]: raise EnvironmentException(f'{self.id} does not support find_framework') def find_framework_paths(self, env: 'Environment') -> T.List[str]: raise EnvironmentException(f'{self.id} does not support find_framework_paths') def attribute_check_func(self, name: str) -> str: raise EnvironmentException(f'{self.id} does not support attribute checks') def get_pch_suffix(self) -> str: raise EnvironmentException(f'{self.id} does not support pre compiled headers') def get_pch_name(self, name: str) -> str: raise EnvironmentException(f'{self.id} does not support pre compiled headers') def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: raise EnvironmentException(f'{self.id} does not support pre compiled headers') def get_has_func_attribute_extra_args(self, name: str) -> T.List[str]: raise EnvironmentException(f'{self.id} does not support function attributes') def name_string(self) -> str: return ' '.join(self.exelist) @abc.abstractmethod def sanity_check(self, work_dir: str, environment: 'Environment') -> None: """Check that this compiler actually works. This should provide a simple compile/link test. Something as simple as: ```python main(): return 0 ``` is good enough here. """ def split_shlib_to_parts(self, fname: str) -> T.Tuple[T.Optional[str], str]: return None, fname def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: return [] def get_std_exe_link_args(self) -> T.List[str]: # TODO: is this a linker property? return [] def get_include_args(self, path: str, is_system: bool) -> T.List[str]: return [] def depfile_for_object(self, objfile: str) -> T.Optional[str]: return objfile + '.' + self.get_depfile_suffix() def get_depfile_suffix(self) -> str: raise EnvironmentException(f'{self.id} does not implement get_depfile_suffix') def get_no_stdinc_args(self) -> T.List[str]: """Arguments to turn off default inclusion of standard libraries.""" return [] def get_warn_args(self, level: str) -> T.List[str]: return [] def get_werror_args(self) -> T.List[str]: return [] @abc.abstractmethod def get_optimization_args(self, optimization_level: str) -> T.List[str]: pass def get_module_incdir_args(self) -> T.Tuple[str, ...]: raise EnvironmentException(f'{self.id} does not implement get_module_incdir_args') def get_module_outdir_args(self, path: str) -> T.List[str]: raise EnvironmentException(f'{self.id} does not implement get_module_outdir_args') def module_name_to_filename(self, module_name: str) -> str: raise EnvironmentException(f'{self.id} does not implement module_name_to_filename') def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: """Arguments to pass the compiler and/or linker for checks. The default implementation turns off optimizations. Examples of things that go here: - extra arguments for error checking - Arguments required to make the compiler exit with a non-zero status when something is wrong. """ return self.get_no_optimization_args() def get_no_optimization_args(self) -> T.List[str]: """Arguments to the compiler to turn off all optimizations.""" return [] def build_wrapper_args(self, env: 'Environment', extra_args: T.Union[None, CompilerArgs, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]], dependencies: T.Optional[T.List['Dependency']], mode: CompileCheckMode = CompileCheckMode.COMPILE) -> CompilerArgs: """Arguments to pass the build_wrapper helper. This generally needs to be set on a per-language basis. It provides a hook for languages to handle dependencies and extra args. The base implementation handles the most common cases, namely adding the check_arguments, unwrapping dependencies, and appending extra args. """ if callable(extra_args): extra_args = extra_args(mode) if extra_args is None: extra_args = [] if dependencies is None: dependencies = [] # Collect compiler arguments args = self.compiler_args(self.get_compiler_check_args(mode)) for d in dependencies: # Add compile flags needed by dependencies args += d.get_compile_args() if mode is CompileCheckMode.LINK: # Add link flags needed to find dependencies args += d.get_link_args() if mode is CompileCheckMode.COMPILE: # Add DFLAGS from the env args += env.coredata.get_external_args(self.for_machine, self.language) elif mode is CompileCheckMode.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 @contextlib.contextmanager def _build_wrapper(self, code: 'mesonlib.FileOrString', env: 'Environment', extra_args: T.Union[None, CompilerArgs, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None, dependencies: T.Optional[T.List['Dependency']] = None, mode: CompileCheckMode = CompileCheckMode.COMPILE, want_output: bool = False, disable_cache: bool = False) -> T.Iterator[T.Optional[CompileResult]]: """Helper for getting a cached value when possible. This method isn't meant to be called externally, it's mean to be wrapped by other methods like compiles() and links(). """ args = self.build_wrapper_args(env, extra_args, dependencies, mode) if disable_cache or want_output: with self.compile(code, extra_args=args, mode=mode, want_output=want_output, temp_dir=env.scratch_dir) as r: yield r else: with self.cached_compile(code, env.coredata, extra_args=args, mode=mode, temp_dir=env.scratch_dir) as r: yield r def compiles(self, code: 'mesonlib.FileOrString', env: 'Environment', *, extra_args: T.Union[None, T.List[str], CompilerArgs, T.Callable[[CompileCheckMode], T.List[str]]] = None, dependencies: T.Optional[T.List['Dependency']] = None, mode: CompileCheckMode = CompileCheckMode.COMPILE, disable_cache: bool = False) -> T.Tuple[bool, bool]: with self._build_wrapper(code, env, extra_args, dependencies, mode, disable_cache=disable_cache) as p: return p.returncode == 0, p.cached def links(self, code: 'mesonlib.FileOrString', env: 'Environment', *, compiler: T.Optional['Compiler'] = None, extra_args: T.Union[None, T.List[str], CompilerArgs, T.Callable[[CompileCheckMode], T.List[str]]] = None, dependencies: T.Optional[T.List['Dependency']] = None, disable_cache: bool = False) -> T.Tuple[bool, bool]: if compiler: with compiler._build_wrapper(code, env, dependencies=dependencies, want_output=True) as r: objfile = mesonlib.File.from_absolute_file(r.output_name) return self.compiles(objfile, env, extra_args=extra_args, dependencies=dependencies, mode=CompileCheckMode.LINK, disable_cache=True) return self.compiles(code, env, extra_args=extra_args, dependencies=dependencies, mode=CompileCheckMode.LINK, disable_cache=disable_cache) def get_feature_args(self, kwargs: DFeatures, build_to_src: str) -> T.List[str]: """Used by D for extra language features.""" # TODO: using a TypeDict here would improve this raise EnvironmentException(f'{self.id} does not implement get_feature_args') def get_prelink_args(self, prelink_name: str, obj_list: T.List[str]) -> T.List[str]: raise EnvironmentException(f'{self.id} does not know how to do prelinking.') def rsp_file_syntax(self) -> 'RSPFileSyntax': """The format of the RSP file that this compiler supports. If `self.can_linker_accept_rsp()` returns True, then this needs to be implemented """ return self.linker.rsp_file_syntax() def get_debug_args(self, is_debug: bool) -> T.List[str]: """Arguments required for a debug build.""" return [] def get_no_warn_args(self) -> T.List[str]: """Arguments to completely disable warnings.""" return [] def needs_static_linker(self) -> bool: raise NotImplementedError(f'There is no static linker for {self.language}') def get_preprocessor(self) -> Compiler: """Get compiler's preprocessor. """ raise EnvironmentException(f'{self.get_id()} does not support preprocessor') def get_global_options(lang: str, comp: T.Type[Compiler], for_machine: MachineChoice, env: 'Environment') -> 'KeyedOptionDictType': """Retrieve options that apply to all compilers for a given language.""" description = f'Extra arguments passed to the {lang}' argkey = OptionKey('args', lang=lang, machine=for_machine) largkey = argkey.evolve('link_args') envkey = argkey.evolve('env_args') comp_key = argkey if argkey in env.options else envkey comp_options = env.options.get(comp_key, []) link_options = env.options.get(largkey, []) cargs = coredata.UserArrayOption( description + ' compiler', comp_options, split_args=True, allow_dups=True) largs = coredata.UserArrayOption( description + ' linker', link_options, split_args=True, allow_dups=True) if comp.INVOKES_LINKER and comp_key == envkey: # If the compiler acts as a linker driver, and we're using the # environment variable flags for both the compiler and linker # arguments, then put the compiler flags in the linker flags as well. # This is how autotools works, and the env vars feature is for # autotools compatibility. largs.extend_value(comp_options) opts: 'KeyedOptionDictType' = {argkey: cargs, largkey: largs} return opts ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/compilers/cpp.py0000644000175000017500000012653414562742363020351 0ustar00jpakkanejpakkane# 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 __future__ import annotations import copy import functools import os.path import typing as T from .. import coredata from .. import mlog from ..mesonlib import MesonException, version_compare, OptionKey from .compilers import ( gnu_winlibs, msvc_winlibs, Compiler, CompileCheckMode, ) from .c_function_attributes import CXX_FUNC_ATTRIBUTES, C_FUNC_ATTRIBUTES from .mixins.clike import CLikeCompiler from .mixins.ccrx import CcrxCompiler from .mixins.ti import TICompiler from .mixins.arm import ArmCompiler, ArmclangCompiler from .mixins.visualstudio import MSVCCompiler, ClangClCompiler from .mixins.gnu import GnuCompiler, gnu_common_warning_args, gnu_cpp_warning_args from .mixins.intel import IntelGnuLikeCompiler, IntelVisualStudioLikeCompiler from .mixins.clang import ClangCompiler from .mixins.elbrus import ElbrusCompiler from .mixins.pgi import PGICompiler from .mixins.emscripten import EmscriptenMixin from .mixins.metrowerks import MetrowerksCompiler from .mixins.metrowerks import mwccarm_instruction_set_args, mwcceppc_instruction_set_args if T.TYPE_CHECKING: from ..coredata import MutableKeyedOptionDictType, KeyedOptionDictType from ..dependencies import Dependency from ..envconfig import MachineInfo from ..environment import Environment from ..linkers.linkers import DynamicLinker from ..mesonlib import MachineChoice from ..programs import ExternalProgram CompilerMixinBase = CLikeCompiler else: CompilerMixinBase = object _ALL_STDS = ['c++98', 'c++0x', 'c++03', 'c++1y', 'c++1z', 'c++11', 'c++14', 'c++17', 'c++2a', 'c++20', 'c++23', 'c++26'] _ALL_STDS += [f'gnu{std[1:]}' for std in _ALL_STDS] _ALL_STDS += ['vc++11', 'vc++14', 'vc++17', 'vc++20', 'vc++latest', 'c++latest'] def non_msvc_eh_options(eh: str, args: T.List[str]) -> None: if eh == 'none': args.append('-fno-exceptions') elif eh in {'s', 'c'}: mlog.warning(f'non-MSVC compilers do not support {eh} exception handling. ' 'You may want to set eh to \'default\'.', fatal=False) class CPPCompiler(CLikeCompiler, Compiler): def attribute_check_func(self, name: str) -> str: try: return CXX_FUNC_ATTRIBUTES.get(name, C_FUNC_ATTRIBUTES[name]) except KeyError: raise MesonException(f'Unknown function attribute "{name}"') language = 'cpp' def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): # If a child ObjCPP class has already set it, don't set it ourselves Compiler.__init__(self, ccache, exelist, version, for_machine, info, is_cross=is_cross, linker=linker, full_version=full_version) CLikeCompiler.__init__(self, exe_wrapper) @classmethod def get_display_language(cls) -> str: return 'C++' def get_no_stdinc_args(self) -> T.List[str]: return ['-nostdinc++'] def get_no_stdlib_link_args(self) -> T.List[str]: return ['-nostdlib++'] def sanity_check(self, work_dir: str, environment: 'Environment') -> None: 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, mode: CompileCheckMode) -> T.List[str]: # -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(mode) + ['-fpermissive'] def has_header_symbol(self, hname: str, symbol: str, prefix: str, env: 'Environment', *, extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: # 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 = [] t = f'''{prefix} #include <{hname}> using {symbol}; int main(void) {{ return 0; }}''' return self.compiles(t, env, extra_args=extra_args, dependencies=dependencies) def _test_cpp_std_arg(self, cpp_std_value: str) -> bool: # 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=CompileCheckMode.COMPILE) as p: if p.returncode == 0: mlog.debug(f'Compiler accepts {cpp_std_value}:', 'YES') return True else: mlog.debug(f'Compiler accepts {cpp_std_value}:', 'NO') return False @functools.lru_cache() def _find_best_cpp_std(self, cpp_std: str) -> str: # 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', 'c++20': 'c++2a', 'gnu++20': 'gnu++2a', 'c++23': 'c++2b', 'gnu++23': 'gnu++2b', 'c++26': 'c++2c', 'gnu++26': 'gnu++2c', } # Currently, remapping is only supported for Clang, Elbrus and GCC assert self.id in frozenset(['clang', 'lcc', 'gcc', 'emscripten', 'armltdclang', 'intel-llvm']) 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(f'C++ Compiler does not support -std={cpp_std}') def get_options(self) -> 'MutableKeyedOptionDictType': opts = super().get_options() key = OptionKey('std', machine=self.for_machine, lang=self.language) opts.update({ key: coredata.UserStdOption('C++', _ALL_STDS), }) return opts class _StdCPPLibMixin(CompilerMixinBase): """Detect whether to use libc++ or libstdc++.""" @functools.lru_cache(None) def language_stdlib_only_link_flags(self, env: Environment) -> T.List[str]: """Detect the C++ stdlib and default search dirs As an optimization, this method will cache the value, to avoid building the same values over and over :param env: An Environment object :raises MesonException: If a stdlib cannot be determined """ # We need to apply the search prefix here, as these link arguments may # be passed to a different compiler with a different set of default # search paths, such as when using Clang for C/C++ and gfortran for # fortran. search_dirs = [f'-L{d}' for d in self.get_compiler_dirs(env, 'libraries')] machine = env.machines[self.for_machine] assert machine is not None, 'for mypy' # We need to determine whether to use libc++ or libstdc++. We can't # really know the answer in most cases, only the most likely answer, # because a user can install things themselves or build custom images. search_order: T.List[str] = [] if machine.system in {'android', 'darwin', 'dragonfly', 'freebsd', 'netbsd', 'openbsd'}: search_order = ['c++', 'stdc++'] else: search_order = ['stdc++', 'c++'] for lib in search_order: if self.find_library(lib, env, []) is not None: return search_dirs + [f'-l{lib}'] # TODO: maybe a bug exception? raise MesonException('Could not detect either libc++ or libstdc++ as your C++ stdlib implementation.') class ClangCPPCompiler(_StdCPPLibMixin, ClangCompiler, CPPCompiler): _CPP23_VERSION = '>=12.0.0' _CPP26_VERSION = '>=17.0.0' def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, defines: T.Optional[T.Dict[str, str]] = None, full_version: T.Optional[str] = None): CPPCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) ClangCompiler.__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'], 'everything': ['-Weverything']} def get_options(self) -> 'MutableKeyedOptionDictType': opts = CPPCompiler.get_options(self) key = OptionKey('key', machine=self.for_machine, lang=self.language) opts.update({ key.evolve('eh'): coredata.UserComboOption( 'C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default', ), key.evolve('rtti'): coredata.UserBooleanOption('Enable RTTI', True), }) cppstd_choices = [ 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'c++1z', 'c++2a', 'c++20', ] if version_compare(self.version, self._CPP23_VERSION): cppstd_choices.append('c++23') if version_compare(self.version, self._CPP26_VERSION): cppstd_choices.append('c++26') std_opt = opts[key.evolve('std')] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(cppstd_choices, gnu=True) if self.info.is_windows() or self.info.is_cygwin(): opts.update({ key.evolve('winlibs'): coredata.UserArrayOption( 'Standard Win libraries to link against', gnu_winlibs, ), }) return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = OptionKey('std', machine=self.for_machine, lang=self.language) std = options[key] if std.value != 'none': args.append(self._find_best_cpp_std(std.value)) non_msvc_eh_options(options[key.evolve('eh')].value, args) if not options[key.evolve('rtti')].value: args.append('-fno-rtti') return args def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: if self.info.is_windows() or self.info.is_cygwin(): # without a typedict mypy can't understand this. key = OptionKey('winlibs', machine=self.for_machine, lang=self.language) libs = options[key].value.copy() assert isinstance(libs, list) for l in libs: assert isinstance(l, str) return libs return [] class ArmLtdClangCPPCompiler(ClangCPPCompiler): id = 'armltdclang' class AppleClangCPPCompiler(ClangCPPCompiler): _CPP23_VERSION = '>=13.0.0' # TODO: We don't know which XCode version will include LLVM 17 yet, so # use something absurd. _CPP26_VERSION = '>=99.0.0' class EmscriptenCPPCompiler(EmscriptenMixin, ClangCPPCompiler): id = 'emscripten' def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, defines: T.Optional[T.Dict[str, str]] = None, full_version: T.Optional[str] = None): if not is_cross: raise MesonException('Emscripten compiler can only be used for cross compilation.') if not version_compare(version, '>=1.39.19'): raise MesonException('Meson requires Emscripten >= 1.39.19') ClangCPPCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper=exe_wrapper, linker=linker, defines=defines, full_version=full_version) def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = OptionKey('std', machine=self.for_machine, lang=self.language) std = options[key] if std.value != 'none': args.append(self._find_best_cpp_std(std.value)) return args class ArmclangCPPCompiler(ArmclangCompiler, CPPCompiler): ''' Keil armclang ''' def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CPPCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) 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'], 'everything': ['-Weverything']} def get_options(self) -> 'MutableKeyedOptionDictType': opts = CPPCompiler.get_options(self) key = OptionKey('std', machine=self.for_machine, lang=self.language) opts.update({ key.evolve('eh'): coredata.UserComboOption( 'C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default', ), }) std_opt = opts[key] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(['c++98', 'c++03', 'c++11', 'c++14', 'c++17'], gnu=True) return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = OptionKey('std', machine=self.for_machine, lang=self.language) std = options[key] if std.value != 'none': args.append('-std=' + std.value) non_msvc_eh_options(options[key.evolve('eh')].value, args) return args def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return [] class GnuCPPCompiler(_StdCPPLibMixin, GnuCompiler, CPPCompiler): def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, defines: T.Optional[T.Dict[str, str]] = None, full_version: T.Optional[str] = None): CPPCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) 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'], 'everything': (default_warn_args + ['-Wextra', '-Wpedantic'] + self.supported_warn_args(gnu_common_warning_args) + self.supported_warn_args(gnu_cpp_warning_args))} def get_options(self) -> 'MutableKeyedOptionDictType': key = OptionKey('std', machine=self.for_machine, lang=self.language) opts = CPPCompiler.get_options(self) opts.update({ key.evolve('eh'): coredata.UserComboOption( 'C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default', ), key.evolve('rtti'): coredata.UserBooleanOption('Enable RTTI', True), key.evolve('debugstl'): coredata.UserBooleanOption( 'STL debug mode', False, ) }) cppstd_choices = [ 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'c++1z', 'c++2a', 'c++20', ] if version_compare(self.version, '>=11.0.0'): cppstd_choices.append('c++23') if version_compare(self.version, '>=14.0.0'): cppstd_choices.append('c++26') std_opt = opts[key] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(cppstd_choices, gnu=True) if self.info.is_windows() or self.info.is_cygwin(): opts.update({ key.evolve('winlibs'): coredata.UserArrayOption( 'Standard Win libraries to link against', gnu_winlibs, ), }) return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = OptionKey('std', machine=self.for_machine, lang=self.language) std = options[key] if std.value != 'none': args.append(self._find_best_cpp_std(std.value)) non_msvc_eh_options(options[key.evolve('eh')].value, args) if not options[key.evolve('rtti')].value: args.append('-fno-rtti') if options[key.evolve('debugstl')].value: args.append('-D_GLIBCXX_DEBUG=1') return args def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: if self.info.is_windows() or self.info.is_cygwin(): # without a typedict mypy can't understand this. key = OptionKey('winlibs', machine=self.for_machine, lang=self.language) libs = options[key].value.copy() assert isinstance(libs, list) for l in libs: assert isinstance(l, str) return libs return [] def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: return ['-fpch-preprocess', '-include', os.path.basename(header)] class PGICPPCompiler(PGICompiler, CPPCompiler): def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CPPCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) PGICompiler.__init__(self) class NvidiaHPC_CPPCompiler(PGICompiler, CPPCompiler): id = 'nvidia_hpc' def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CPPCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) PGICompiler.__init__(self) class ElbrusCPPCompiler(ElbrusCompiler, CPPCompiler): def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, defines: T.Optional[T.Dict[str, str]] = None, full_version: T.Optional[str] = None): CPPCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) ElbrusCompiler.__init__(self) def get_options(self) -> 'MutableKeyedOptionDictType': opts = CPPCompiler.get_options(self) cpp_stds = ['c++98'] if version_compare(self.version, '>=1.20.00'): cpp_stds += ['c++03', 'c++0x', 'c++11'] if version_compare(self.version, '>=1.21.00') and version_compare(self.version, '<1.22.00'): cpp_stds += ['c++14', 'c++1y'] if version_compare(self.version, '>=1.22.00'): cpp_stds += ['c++14'] if version_compare(self.version, '>=1.23.00'): cpp_stds += ['c++1y'] if version_compare(self.version, '>=1.24.00'): cpp_stds += ['c++1z', 'c++17'] if version_compare(self.version, '>=1.25.00'): cpp_stds += ['c++2a'] if version_compare(self.version, '>=1.26.00'): cpp_stds += ['c++20'] key = OptionKey('std', machine=self.for_machine, lang=self.language) opts.update({ key.evolve('eh'): coredata.UserComboOption( 'C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default', ), key.evolve('debugstl'): coredata.UserBooleanOption( 'STL debug mode', False, ), }) std_opt = opts[key] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(cpp_stds, gnu=True) 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: str, prefix: str, env: 'Environment', *, extra_args: T.Optional[T.List[str]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: 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: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = OptionKey('std', machine=self.for_machine, lang=self.language) std = options[key] if std.value != 'none': args.append(self._find_best_cpp_std(std.value)) non_msvc_eh_options(options[key.evolve('eh')].value, args) if options[key.evolve('debugstl')].value: args.append('-D_GLIBCXX_DEBUG=1') return args class IntelCPPCompiler(IntelGnuLikeCompiler, CPPCompiler): def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CPPCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) IntelGnuLikeCompiler.__init__(self) self.lang_header = 'c++-header' default_warn_args = ['-Wall', '-w3', '-Wpch-messages'] self.warn_args = {'0': [], '1': default_warn_args + ['-diag-disable:remark'], '2': default_warn_args + ['-Wextra', '-diag-disable:remark'], '3': default_warn_args + ['-Wextra', '-diag-disable:remark'], 'everything': default_warn_args + ['-Wextra']} def get_options(self) -> 'MutableKeyedOptionDictType': 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'] if version_compare(self.version, '>=19.1.0'): c_stds += ['c++2a'] g_stds += ['gnu++2a'] key = OptionKey('std', machine=self.for_machine, lang=self.language) opts.update({ key.evolve('eh'): coredata.UserComboOption( 'C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default', ), key.evolve('rtti'): coredata.UserBooleanOption('Enable RTTI', True), key.evolve('debugstl'): coredata.UserBooleanOption('STL debug mode', False), }) std_opt = opts[key] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(c_stds + g_stds) return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = OptionKey('std', machine=self.for_machine, lang=self.language) std = options[key] 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[key.evolve('eh')].value == 'none': args.append('-fno-exceptions') if not options[key.evolve('rtti')].value: args.append('-fno-rtti') if options[key.evolve('debugstl')].value: args.append('-D_GLIBCXX_DEBUG=1') return args def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return [] class IntelLLVMCPPCompiler(ClangCPPCompiler): id = 'intel-llvm' class VisualStudioLikeCPPCompilerMixin(CompilerMixinBase): """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++20': (True, 20), 'vc++latest': (True, "latest"), 'c++11': (False, 11), 'c++14': (False, 14), 'c++17': (False, 17), 'c++20': (False, 20), 'c++latest': (False, "latest"), } def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: # need a typeddict for this key = OptionKey('winlibs', machine=self.for_machine, lang=self.language) return T.cast('T.List[str]', options[key].value[:]) def _get_options_impl(self, opts: 'MutableKeyedOptionDictType', cpp_stds: T.List[str]) -> 'MutableKeyedOptionDictType': key = OptionKey('std', machine=self.for_machine, lang=self.language) opts.update({ key.evolve('eh'): coredata.UserComboOption( 'C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default', ), key.evolve('rtti'): coredata.UserBooleanOption('Enable RTTI', True), key.evolve('winlibs'): coredata.UserArrayOption( 'Windows libs to link against.', msvc_winlibs, ), }) std_opt = opts[key] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(cpp_stds) return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = OptionKey('std', machine=self.for_machine, lang=self.language) eh = options[key.evolve('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[key.evolve('rtti')].value: args.append('/GR-') permissive, ver = self.VC_VERSION_MAP[options[key].value] if ver is not None: args.append(f'/std:c++{ver}') if not permissive: args.append('/permissive-') return args def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: # XXX: this is a hack because so much GnuLike stuff is in the base CPPCompiler class. return Compiler.get_compiler_check_args(self, mode) class CPP11AsCPP14Mixin(CompilerMixinBase): """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: 'KeyedOptionDictType') -> T.List[str]: # 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. key = OptionKey('std', machine=self.for_machine, lang=self.language) if options[key].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, fatal=False) # 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[key].value == 'vc++11': options[key].value = 'vc++14' else: options[key].value = 'c++14' return super().get_option_compile_args(options) class VisualStudioCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixin, MSVCCompiler, CPPCompiler): id = 'msvc' def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', target: str, exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CPPCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) MSVCCompiler.__init__(self, target) # By default, MSVC has a broken __cplusplus define that pretends to be c++98: # https://docs.microsoft.com/en-us/cpp/build/reference/zc-cplusplus?view=msvc-160 # Pass the flag to enable a truthful define, if possible. if version_compare(self.version, '>= 19.14.26428'): self.always_args = self.always_args + ['/Zc:__cplusplus'] def get_options(self) -> 'MutableKeyedOptionDictType': 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']) if version_compare(self.version, '>=19.29'): cpp_stds.extend(['c++20', 'vc++20']) return self._get_options_impl(super().get_options(), cpp_stds) def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: key = OptionKey('std', machine=self.for_machine, lang=self.language) if options[key].value != 'none' and version_compare(self.version, '<19.00.24210'): mlog.warning('This version of MSVC does not support cpp_std arguments', fatal=False) options = copy.copy(options) options[key].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, ClangClCompiler, CPPCompiler): id = 'clang-cl' def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', target: str, exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CPPCompiler.__init__(self, [], exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) ClangClCompiler.__init__(self, target) def get_options(self) -> 'MutableKeyedOptionDictType': cpp_stds = ['none', 'c++11', 'vc++11', 'c++14', 'vc++14', 'c++17', 'vc++17', 'c++20', 'vc++20', 'c++latest'] return self._get_options_impl(super().get_options(), cpp_stds) class IntelClCPPCompiler(VisualStudioLikeCPPCompilerMixin, IntelVisualStudioLikeCompiler, CPPCompiler): def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', target: str, exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CPPCompiler.__init__(self, [], exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) IntelVisualStudioLikeCompiler.__init__(self, target) def get_options(self) -> 'MutableKeyedOptionDictType': # 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) def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: # XXX: this is a hack because so much GnuLike stuff is in the base CPPCompiler class. return IntelVisualStudioLikeCompiler.get_compiler_check_args(self, mode) class IntelLLVMClCPPCompiler(IntelClCPPCompiler): id = 'intel-llvm-cl' class ArmCPPCompiler(ArmCompiler, CPPCompiler): def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CPPCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) ArmCompiler.__init__(self) def get_options(self) -> 'MutableKeyedOptionDictType': opts = CPPCompiler.get_options(self) std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(['c++03', 'c++11']) return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = OptionKey('std', machine=self.for_machine, lang=self.language) std = options[key] 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: 'KeyedOptionDictType') -> T.List[str]: return [] def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: return [] class CcrxCPPCompiler(CcrxCompiler, CPPCompiler): def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CPPCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) CcrxCompiler.__init__(self) # Override CCompiler.get_always_args def get_always_args(self) -> T.List[str]: return ['-nologo', '-lang=cpp'] def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return [] def get_compile_only_args(self) -> T.List[str]: return [] def get_output_args(self, outputname: str) -> T.List[str]: return [f'-output=obj={outputname}'] def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return [] def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: return [] class TICPPCompiler(TICompiler, CPPCompiler): def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CPPCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) TICompiler.__init__(self) def get_options(self) -> 'MutableKeyedOptionDictType': opts = CPPCompiler.get_options(self) std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(['c++03']) return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = OptionKey('std', machine=self.for_machine, lang=self.language) std = options[key] if std.value != 'none': args.append('--' + std.value) return args def get_always_args(self) -> T.List[str]: return [] def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return [] class C2000CPPCompiler(TICPPCompiler): # Required for backwards compat with projects created before ti-cgt support existed id = 'c2000' class MetrowerksCPPCompilerARM(MetrowerksCompiler, CPPCompiler): id = 'mwccarm' def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CPPCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) MetrowerksCompiler.__init__(self) def get_instruction_set_args(self, instruction_set: str) -> T.Optional[T.List[str]]: return mwccarm_instruction_set_args.get(instruction_set, None) def get_options(self) -> 'MutableKeyedOptionDictType': opts = CPPCompiler.get_options(self) key = OptionKey('std', machine=self.for_machine, lang=self.language) opts[key].choices = ['none'] return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] std = options[OptionKey('std', machine=self.for_machine, lang=self.language)] if std.value != 'none': args.append('-lang') args.append(std.value) return args class MetrowerksCPPCompilerEmbeddedPowerPC(MetrowerksCompiler, CPPCompiler): id = 'mwcceppc' def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): CPPCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) MetrowerksCompiler.__init__(self) def get_instruction_set_args(self, instruction_set: str) -> T.Optional[T.List[str]]: return mwcceppc_instruction_set_args.get(instruction_set, None) def get_options(self) -> 'MutableKeyedOptionDictType': opts = CPPCompiler.get_options(self) key = OptionKey('std', machine=self.for_machine, lang=self.language) opts[key].choices = ['none'] return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] std = options[OptionKey('std', machine=self.for_machine, lang=self.language)] if std.value != 'none': args.append('-lang ' + std.value) return args ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/compilers/cs.py0000644000175000017500000001216414562742363020165 0ustar00jpakkanejpakkane# 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 __future__ import annotations import os.path, subprocess import textwrap import typing as T from ..mesonlib import EnvironmentException from ..linkers import RSPFileSyntax from .compilers import Compiler, mono_buildtype_args from .mixins.islinker import BasicLinkerIsCompilerMixin if T.TYPE_CHECKING: from ..envconfig import MachineInfo from ..environment import Environment from ..mesonlib import MachineChoice cs_optimization_args: T.Dict[str, T.List[str]] = { 'plain': [], '0': [], 'g': [], '1': ['-optimize+'], '2': ['-optimize+'], '3': ['-optimize+'], 's': ['-optimize+'], } class CsCompiler(BasicLinkerIsCompilerMixin, Compiler): language = 'cs' def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, info: 'MachineInfo', runner: T.Optional[str] = None): super().__init__([], exelist, version, for_machine, info) self.runner = runner @classmethod def get_display_language(cls) -> str: return 'C sharp' def get_always_args(self) -> T.List[str]: return ['/nologo'] def get_linker_always_args(self) -> T.List[str]: return ['/nologo'] def get_output_args(self, fname: str) -> T.List[str]: return ['-out:' + fname] def get_link_args(self, fname: str) -> T.List[str]: return ['-r:' + fname] def get_werror_args(self) -> T.List[str]: return ['-warnaserror'] def get_pic_args(self) -> T.List[str]: 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] == '-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 get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: return [] def get_pch_name(self, header_name: str) -> str: return '' def sanity_check(self, work_dir: str, environment: 'Environment') -> None: src = 'sanity.cs' obj = 'sanity.exe' source_name = os.path.join(work_dir, src) with open(source_name, 'w', encoding='utf-8') as ofile: ofile.write(textwrap.dedent(''' 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('C# compiler %s cannot 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) -> bool: return False def get_buildtype_args(self, buildtype: str) -> T.List[str]: return mono_buildtype_args[buildtype] def get_debug_args(self, is_debug: bool) -> T.List[str]: return ['-debug'] if is_debug else [] def get_optimization_args(self, optimization_level: str) -> T.List[str]: return cs_optimization_args[optimization_level] class MonoCompiler(CsCompiler): id = 'mono' def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, info: 'MachineInfo'): super().__init__(exelist, version, for_machine, info, runner='mono') def rsp_file_syntax(self) -> 'RSPFileSyntax': return RSPFileSyntax.GCC class VisualStudioCsCompiler(CsCompiler): id = 'csc' def get_buildtype_args(self, buildtype: str) -> T.List[str]: 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 def rsp_file_syntax(self) -> 'RSPFileSyntax': return RSPFileSyntax.MSVC ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/compilers/cuda.py0000644000175000017500000012173714562742363020503 0ustar00jpakkanejpakkane# 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 __future__ import annotations import enum import os.path import string import typing as T from .. import coredata from .. import mlog from ..mesonlib import ( EnvironmentException, Popen_safe, is_windows, LibType, OptionKey, version_compare, ) from .compilers import (Compiler, cuda_buildtype_args, cuda_optimization_args, cuda_debug_args) if T.TYPE_CHECKING: from .compilers import CompileCheckMode from ..build import BuildTarget from ..coredata import MutableKeyedOptionDictType, KeyedOptionDictType from ..dependencies import Dependency from ..environment import Environment # noqa: F401 from ..envconfig import MachineInfo from ..linkers.linkers import DynamicLinker from ..mesonlib import MachineChoice from ..programs import ExternalProgram class _Phase(enum.Enum): COMPILER = 'compiler' LINKER = 'linker' class CudaCompiler(Compiler): LINKER_PREFIX = '-Xlinker=' language = 'cuda' # NVCC flags taking no arguments. _FLAG_PASSTHRU_NOARGS = { # NVCC --long-option, NVCC -short-option CUDA Toolkit 11.2.1 Reference '--objdir-as-tempdir', '-objtemp', # 4.2.1.2 '--generate-dependency-targets', '-MP', # 4.2.1.12 '--allow-unsupported-compiler', '-allow-unsupported-compiler', # 4.2.1.14 '--link', # 4.2.2.1 '--lib', '-lib', # 4.2.2.2 '--device-link', '-dlink', # 4.2.2.3 '--device-c', '-dc', # 4.2.2.4 '--device-w', '-dw', # 4.2.2.5 '--cuda', '-cuda', # 4.2.2.6 '--compile', '-c', # 4.2.2.7 '--fatbin', '-fatbin', # 4.2.2.8 '--cubin', '-cubin', # 4.2.2.9 '--ptx', '-ptx', # 4.2.2.10 '--preprocess', '-E', # 4.2.2.11 '--generate-dependencies', '-M', # 4.2.2.12 '--generate-nonsystem-dependencies', '-MM', # 4.2.2.13 '--generate-dependencies-with-compile', '-MD', # 4.2.2.14 '--generate-nonsystem-dependencies-with-compile', '-MMD', # 4.2.2.15 '--run', # 4.2.2.16 '--profile', '-pg', # 4.2.3.1 '--debug', '-g', # 4.2.3.2 '--device-debug', '-G', # 4.2.3.3 '--extensible-whole-program', '-ewp', # 4.2.3.4 '--generate-line-info', '-lineinfo', # 4.2.3.5 '--dlink-time-opt', '-dlto', # 4.2.3.8 '--no-exceptions', '-noeh', # 4.2.3.11 '--shared', '-shared', # 4.2.3.12 '--no-host-device-initializer-list', '-nohdinitlist', # 4.2.3.15 '--expt-relaxed-constexpr', '-expt-relaxed-constexpr', # 4.2.3.16 '--extended-lambda', '-extended-lambda', # 4.2.3.17 '--expt-extended-lambda', '-expt-extended-lambda', # 4.2.3.18 '--m32', '-m32', # 4.2.3.20 '--m64', '-m64', # 4.2.3.21 '--forward-unknown-to-host-compiler', '-forward-unknown-to-host-compiler', # 4.2.5.1 '--forward-unknown-to-host-linker', '-forward-unknown-to-host-linker', # 4.2.5.2 '--dont-use-profile', '-noprof', # 4.2.5.3 '--dryrun', '-dryrun', # 4.2.5.5 '--verbose', '-v', # 4.2.5.6 '--keep', '-keep', # 4.2.5.7 '--save-temps', '-save-temps', # 4.2.5.9 '--clean-targets', '-clean', # 4.2.5.10 '--no-align-double', # 4.2.5.16 '--no-device-link', '-nodlink', # 4.2.5.17 '--allow-unsupported-compiler', '-allow-unsupported-compiler', # 4.2.5.18 '--use_fast_math', '-use_fast_math', # 4.2.7.7 '--extra-device-vectorization', '-extra-device-vectorization', # 4.2.7.12 '--compile-as-tools-patch', '-astoolspatch', # 4.2.7.13 '--keep-device-functions', '-keep-device-functions', # 4.2.7.14 '--disable-warnings', '-w', # 4.2.8.1 '--source-in-ptx', '-src-in-ptx', # 4.2.8.2 '--restrict', '-restrict', # 4.2.8.3 '--Wno-deprecated-gpu-targets', '-Wno-deprecated-gpu-targets', # 4.2.8.4 '--Wno-deprecated-declarations', '-Wno-deprecated-declarations', # 4.2.8.5 '--Wreorder', '-Wreorder', # 4.2.8.6 '--Wdefault-stream-launch', '-Wdefault-stream-launch', # 4.2.8.7 '--Wext-lambda-captures-this', '-Wext-lambda-captures-this', # 4.2.8.8 '--display-error-number', '-err-no', # 4.2.8.10 '--resource-usage', '-res-usage', # 4.2.8.14 '--help', '-h', # 4.2.8.15 '--version', '-V', # 4.2.8.16 '--list-gpu-code', '-code-ls', # 4.2.8.20 '--list-gpu-arch', '-arch-ls', # 4.2.8.21 } # Dictionary of NVCC flags taking either one argument or a comma-separated list. # Maps --long to -short options, because the short options are more GCC-like. _FLAG_LONG2SHORT_WITHARGS = { '--output-file': '-o', # 4.2.1.1 '--pre-include': '-include', # 4.2.1.3 '--library': '-l', # 4.2.1.4 '--define-macro': '-D', # 4.2.1.5 '--undefine-macro': '-U', # 4.2.1.6 '--include-path': '-I', # 4.2.1.7 '--system-include': '-isystem', # 4.2.1.8 '--library-path': '-L', # 4.2.1.9 '--output-directory': '-odir', # 4.2.1.10 '--dependency-output': '-MF', # 4.2.1.11 '--compiler-bindir': '-ccbin', # 4.2.1.13 '--archiver-binary': '-arbin', # 4.2.1.15 '--cudart': '-cudart', # 4.2.1.16 '--cudadevrt': '-cudadevrt', # 4.2.1.17 '--libdevice-directory': '-ldir', # 4.2.1.18 '--target-directory': '-target-dir', # 4.2.1.19 '--optimization-info': '-opt-info', # 4.2.3.6 '--optimize': '-O', # 4.2.3.7 '--ftemplate-backtrace-limit': '-ftemplate-backtrace-limit', # 4.2.3.9 '--ftemplate-depth': '-ftemplate-depth', # 4.2.3.10 '--x': '-x', # 4.2.3.13 '--std': '-std', # 4.2.3.14 '--machine': '-m', # 4.2.3.19 '--compiler-options': '-Xcompiler', # 4.2.4.1 '--linker-options': '-Xlinker', # 4.2.4.2 '--archive-options': '-Xarchive', # 4.2.4.3 '--ptxas-options': '-Xptxas', # 4.2.4.4 '--nvlink-options': '-Xnvlink', # 4.2.4.5 '--threads': '-t', # 4.2.5.4 '--keep-dir': '-keep-dir', # 4.2.5.8 '--run-args': '-run-args', # 4.2.5.11 '--input-drive-prefix': '-idp', # 4.2.5.12 '--dependency-drive-prefix': '-ddp', # 4.2.5.13 '--drive-prefix': '-dp', # 4.2.5.14 '--dependency-target-name': '-MT', # 4.2.5.15 '--default-stream': '-default-stream', # 4.2.6.1 '--gpu-architecture': '-arch', # 4.2.7.1 '--gpu-code': '-code', # 4.2.7.2 '--generate-code': '-gencode', # 4.2.7.3 '--relocatable-device-code': '-rdc', # 4.2.7.4 '--entries': '-e', # 4.2.7.5 '--maxrregcount': '-maxrregcount', # 4.2.7.6 '--ftz': '-ftz', # 4.2.7.8 '--prec-div': '-prec-div', # 4.2.7.9 '--prec-sqrt': '-prec-sqrt', # 4.2.7.10 '--fmad': '-fmad', # 4.2.7.11 '--Werror': '-Werror', # 4.2.8.9 '--diag-error': '-diag-error', # 4.2.8.11 '--diag-suppress': '-diag-suppress', # 4.2.8.12 '--diag-warn': '-diag-warn', # 4.2.8.13 '--options-file': '-optf', # 4.2.8.17 '--time': '-time', # 4.2.8.18 '--qpp-config': '-qpp-config', # 4.2.8.19 } # Reverse map -short to --long options. _FLAG_SHORT2LONG_WITHARGS = {v: k for k, v in _FLAG_LONG2SHORT_WITHARGS.items()} id = 'nvcc' def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, exe_wrapper: T.Optional['ExternalProgram'], host_compiler: Compiler, info: 'MachineInfo', linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): super().__init__(ccache, exelist, version, for_machine, info, linker=linker, full_version=full_version, is_cross=is_cross) self.exe_wrapper = exe_wrapper self.host_compiler = host_compiler self.base_options = host_compiler.base_options self.warn_args = {level: self._to_host_flags(flags) for level, flags in host_compiler.warn_args.items()} @classmethod def _shield_nvcc_list_arg(cls, arg: str, listmode: bool = True) -> str: r""" Shield an argument against both splitting by NVCC's list-argument parse logic, and interpretation by any shell. NVCC seems to consider every comma , that is neither escaped by \ nor inside a double-quoted string a split-point. Single-quotes do not provide protection against splitting; In fact, after splitting they are \-escaped. Unfortunately, double-quotes don't protect against shell expansion. What follows is a complex dance to accommodate everybody. """ SQ = "'" DQ = '"' CM = "," BS = "\\" DQSQ = DQ+SQ+DQ quotable = set(string.whitespace+'"$`\\') if CM not in arg or not listmode: if SQ not in arg: # If any of the special characters "$`\ or whitespace are present, single-quote. # Otherwise return bare. if set(arg).intersection(quotable): return SQ+arg+SQ else: return arg # Easy case: no splits, no quoting. else: # There are single quotes. Double-quote them, and single-quote the # strings between them. l = [cls._shield_nvcc_list_arg(s) for s in arg.split(SQ)] l = sum([[s, DQSQ] for s in l][:-1], []) # Interleave l with DQSQs return ''.join(l) else: # A comma is present, and list mode was active. # We apply (what we guess is) the (primitive) NVCC splitting rule: l = [''] instring = False argit = iter(arg) for c in argit: if c == CM and not instring: l.append('') elif c == DQ: l[-1] += c instring = not instring elif c == BS: try: l[-1] += next(argit) except StopIteration: break else: l[-1] += c # Shield individual strings, without listmode, then return them with # escaped commas between them. l = [cls._shield_nvcc_list_arg(s, listmode=False) for s in l] return r'\,'.join(l) @classmethod def _merge_flags(cls, flags: T.List[str]) -> T.List[str]: r""" The flags to NVCC gets exceedingly verbose and unreadable when too many of them are shielded with -Xcompiler. Merge consecutive -Xcompiler-wrapped arguments into one. """ if len(flags) <= 1: return flags flagit = iter(flags) xflags = [] def is_xcompiler_flag_isolated(flag: str) -> bool: return flag == '-Xcompiler' def is_xcompiler_flag_glued(flag: str) -> bool: return flag.startswith('-Xcompiler=') def is_xcompiler_flag(flag: str) -> bool: return is_xcompiler_flag_isolated(flag) or is_xcompiler_flag_glued(flag) def get_xcompiler_val(flag: str, flagit: T.Iterator[str]) -> str: if is_xcompiler_flag_glued(flag): return flag[len('-Xcompiler='):] else: try: return next(flagit) except StopIteration: return "" ingroup = False for flag in flagit: if not is_xcompiler_flag(flag): ingroup = False xflags.append(flag) elif ingroup: xflags[-1] += ',' xflags[-1] += get_xcompiler_val(flag, flagit) elif is_xcompiler_flag_isolated(flag): ingroup = True xflags.append(flag) xflags.append(get_xcompiler_val(flag, flagit)) elif is_xcompiler_flag_glued(flag): ingroup = True xflags.append(flag) else: raise ValueError("-Xcompiler flag merging failed, unknown argument form!") return xflags def _to_host_flags(self, flags: T.List[str], phase: _Phase = _Phase.COMPILER) -> T.List[str]: """ Translate generic "GCC-speak" plus particular "NVCC-speak" flags to NVCC flags. NVCC's "short" flags have broad similarities to the GCC standard, but have gratuitous, irritating differences. """ xflags = [] flagit = iter(flags) for flag in flagit: # The CUDA Toolkit Documentation, in 4.1. Command Option Types and Notation, # specifies that NVCC does not parse the standard flags as GCC does. It has # its own strategy, to wit: # # nvcc recognizes three types of command options: boolean options, single # value options, and list options. # # Boolean options do not have an argument; they are either specified on a # command line or not. Single value options must be specified at most once, # and list options may be repeated. Examples of each of these option types # are, respectively: --verbose (switch to verbose mode), --output-file # (specify output file), and --include-path (specify include path). # # Single value options and list options must have arguments, which must # follow the name of the option itself by either one of more spaces or an # equals character. When a one-character short name such as -I, -l, and -L # is used, the value of the option may also immediately follow the option # itself without being separated by spaces or an equal character. The # individual values of list options may be separated by commas in a single # instance of the option, or the option may be repeated, or any # combination of these two cases. # # One strange consequence of this choice is that directory and filenames that # contain commas (',') cannot be passed to NVCC (at least, not as easily as # in GCC). Another strange consequence is that it is legal to supply flags # such as # # -lpthread,rt,dl,util # -l pthread,rt,dl,util # -l=pthread,rt,dl,util # # and each of the above alternatives is equivalent to GCC-speak # # -lpthread -lrt -ldl -lutil # -l pthread -l rt -l dl -l util # -l=pthread -l=rt -l=dl -l=util # # *With the exception of commas in the name*, GCC-speak for these list flags # is a strict subset of NVCC-speak, so we passthrough those flags. # # The -D macro-define flag is documented as somehow shielding commas from # splitting a definition. Balanced parentheses, braces and single-quotes # around the comma are not sufficient, but balanced double-quotes are. The # shielding appears to work with -l, -I, -L flags as well, for instance. # # Since our goal is to replicate GCC-speak as much as possible, we check for # commas in all list-arguments and shield them with double-quotes. We make # an exception for -D (where this would be value-changing) and -U (because # it isn't possible to define a macro with a comma in the name). if flag in self._FLAG_PASSTHRU_NOARGS: xflags.append(flag) continue # Handle breakup of flag-values into a flag-part and value-part. if flag[:1] not in '-/': # This is not a flag. It's probably a file input. Pass it through. xflags.append(flag) continue elif flag[:1] == '/': # This is ambiguously either an MVSC-style /switch or an absolute path # to a file. For some magical reason the following works acceptably in # both cases. wrap = '"' if ',' in flag else '' xflags.append(f'-X{phase.value}={wrap}{flag}{wrap}') continue elif len(flag) >= 2 and flag[0] == '-' and flag[1] in 'IDULlmOxmte': # This is a single-letter short option. These options (with the # exception of -o) are allowed to receive their argument with neither # space nor = sign before them. Detect and separate them in that event. if flag[2:3] == '': # -I something try: val = next(flagit) except StopIteration: pass elif flag[2:3] == '=': # -I=something val = flag[3:] else: # -Isomething val = flag[2:] flag = flag[:2] # -I elif flag in self._FLAG_LONG2SHORT_WITHARGS or \ flag in self._FLAG_SHORT2LONG_WITHARGS: # This is either -o or a multi-letter flag, and it is receiving its # value isolated. try: val = next(flagit) # -o something except StopIteration: pass elif flag.split('=', 1)[0] in self._FLAG_LONG2SHORT_WITHARGS or \ flag.split('=', 1)[0] in self._FLAG_SHORT2LONG_WITHARGS: # This is either -o or a multi-letter flag, and it is receiving its # value after an = sign. flag, val = flag.split('=', 1) # -o=something # Some dependencies (e.g., BoostDependency) add unspaced "-isystem/usr/include" arguments elif flag.startswith('-isystem'): val = flag[8:].strip() flag = flag[:8] else: # This is a flag, and it's foreign to NVCC. # # We do not know whether this GCC-speak flag takes an isolated # argument. Assuming it does not (the vast majority indeed don't), # wrap this argument in an -Xcompiler flag and send it down to NVCC. if flag == '-ffast-math': xflags.append('-use_fast_math') xflags.append('-Xcompiler='+flag) elif flag == '-fno-fast-math': xflags.append('-ftz=false') xflags.append('-prec-div=true') xflags.append('-prec-sqrt=true') xflags.append('-Xcompiler='+flag) elif flag == '-freciprocal-math': xflags.append('-prec-div=false') xflags.append('-Xcompiler='+flag) elif flag == '-fno-reciprocal-math': xflags.append('-prec-div=true') xflags.append('-Xcompiler='+flag) else: xflags.append('-Xcompiler='+self._shield_nvcc_list_arg(flag)) # The above should securely handle GCC's -Wl, -Wa, -Wp, arguments. continue assert val is not None # Should only trip if there is a missing argument. # Take care of the various NVCC-supported flags that need special handling. flag = self._FLAG_LONG2SHORT_WITHARGS.get(flag, flag) if flag in {'-include', '-isystem', '-I', '-L', '-l'}: # These flags are known to GCC, but list-valued in NVCC. They potentially # require double-quoting to prevent NVCC interpreting the flags as lists # when GCC would not have done so. # # We avoid doing this quoting for -D to avoid redefining macros and for # -U because it isn't possible to define a macro with a comma in the name. # -U with comma arguments is impossible in GCC-speak (and thus unambiguous #in NVCC-speak, albeit unportable). if len(flag) == 2: xflags.append(flag+self._shield_nvcc_list_arg(val)) elif flag == '-isystem' and val in self.host_compiler.get_default_include_dirs(): # like GnuLikeCompiler, we have to filter out include directories specified # with -isystem that overlap with the host compiler's search path pass else: xflags.append(flag) xflags.append(self._shield_nvcc_list_arg(val)) elif flag == '-O': # Handle optimization levels GCC knows about that NVCC does not. if val == 'fast': xflags.append('-O3') xflags.append('-use_fast_math') xflags.append('-Xcompiler') xflags.append(flag+val) elif val in {'s', 'g', 'z'}: xflags.append('-Xcompiler') xflags.append(flag+val) else: xflags.append(flag+val) elif flag in {'-D', '-U', '-m', '-t'}: xflags.append(flag+val) # For style, keep glued. elif flag in {'-std'}: xflags.append(flag+'='+val) # For style, keep glued. else: xflags.append(flag) xflags.append(val) return self._merge_flags(xflags) def needs_static_linker(self) -> bool: return False def thread_link_flags(self, environment: 'Environment') -> T.List[str]: return self._to_host_flags(self.host_compiler.thread_link_flags(environment), _Phase.LINKER) def sanity_check(self, work_dir: str, env: 'Environment') -> None: 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 T.Tuple[bool, bool]: if extra_args is None: extra_args = [] fargs = {'prefix': prefix, 'header': hname, 'symbol': symbol} # Check if it's a C-like 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; }}''' found, cached = self.compiles(t.format_map(fargs), env, extra_args=extra_args, dependencies=dependencies) if found: return True, cached # Check if it's a class or a template t = '''{prefix} #include <{header}> using {symbol}; int main(void) {{ return 0; }}''' return self.compiles(t.format_map(fargs), env, extra_args=extra_args, dependencies=dependencies) _CPP14_VERSION = '>=9.0' _CPP17_VERSION = '>=11.0' _CPP20_VERSION = '>=12.0' def get_options(self) -> 'MutableKeyedOptionDictType': opts = super().get_options() std_key = OptionKey('std', machine=self.for_machine, lang=self.language) ccbindir_key = OptionKey('ccbindir', machine=self.for_machine, lang=self.language) cpp_stds = ['none', 'c++03', 'c++11'] if version_compare(self.version, self._CPP14_VERSION): cpp_stds += ['c++14'] if version_compare(self.version, self._CPP17_VERSION): cpp_stds += ['c++17'] if version_compare(self.version, self._CPP20_VERSION): cpp_stds += ['c++20'] opts.update({ std_key: coredata.UserComboOption('C++ language standard to use with CUDA', cpp_stds, 'none'), ccbindir_key: coredata.UserStringOption('CUDA non-default toolchain directory to use (-ccbin)', ''), }) return opts def _to_host_compiler_options(self, options: 'KeyedOptionDictType') -> 'KeyedOptionDictType': """ Convert an NVCC Option set to a host compiler's option set. """ # We must strip the -std option from the host compiler option set, as NVCC has # its own -std flag that may not agree with the host compiler's. host_options = {key: options.get(key, opt) for key, opt in self.host_compiler.get_options().items()} std_key = OptionKey('std', machine=self.for_machine, lang=self.host_compiler.language) overrides = {std_key: 'none'} return coredata.OptionsView(host_options, overrides=overrides) def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = self.get_ccbin_args(options) # 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(): key = OptionKey('std', machine=self.for_machine, lang=self.language) std = options[key] 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))) def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = self.get_ccbin_args(options) return args + self._to_host_flags(self.host_compiler.get_option_link_args(self._to_host_compiler_options(options)), _Phase.LINKER) def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, suffix: str, soversion: str, darwin_versions: T.Tuple[str, str]) -> T.List[str]: return self._to_host_flags(self.host_compiler.get_soname_args( env, prefix, shlib_name, suffix, soversion, darwin_versions), _Phase.LINKER) def get_compile_only_args(self) -> T.List[str]: return ['-c'] def get_no_optimization_args(self) -> T.List[str]: return ['-O0'] def get_optimization_args(self, optimization_level: str) -> T.List[str]: # 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 sanitizer_compile_args(self, value: str) -> T.List[str]: return self._to_host_flags(self.host_compiler.sanitizer_compile_args(value)) def sanitizer_link_args(self, value: str) -> T.List[str]: return self._to_host_flags(self.host_compiler.sanitizer_link_args(value)) def get_debug_args(self, is_debug: bool) -> T.List[str]: return cuda_debug_args[is_debug] def get_werror_args(self) -> T.List[str]: return ['-Werror=cross-execution-space-call,deprecated-declarations,reorder'] def get_warn_args(self, level: str) -> T.List[str]: return self.warn_args[level] def get_buildtype_args(self, buildtype: str) -> T.List[str]: # 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: str, is_system: bool) -> T.List[str]: if path == '': path = '.' return ['-isystem=' + path] if is_system else ['-I' + path] def get_compile_debugfile_args(self, rel_obj: str, pch: bool = False) -> T.List[str]: return self._to_host_flags(self.host_compiler.get_compile_debugfile_args(rel_obj, pch)) def get_link_debugfile_args(self, targetfile: str) -> T.List[str]: return self._to_host_flags(self.host_compiler.get_link_debugfile_args(targetfile), _Phase.LINKER) def get_depfile_suffix(self) -> str: return 'd' def get_buildtype_linker_args(self, buildtype: str) -> T.List[str]: return self._to_host_flags(self.host_compiler.get_buildtype_linker_args(buildtype), _Phase.LINKER) def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, rpath_paths: T.Tuple[str, ...], build_rpath: str, install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: (rpath_args, rpath_dirs_to_remove) = self.host_compiler.build_rpath_args( env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath) return (self._to_host_flags(rpath_args, _Phase.LINKER), rpath_dirs_to_remove) def linker_to_compiler_args(self, args: T.List[str]) -> T.List[str]: return args def get_pic_args(self) -> T.List[str]: return self._to_host_flags(self.host_compiler.get_pic_args()) def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], build_dir: str) -> T.List[str]: 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._to_host_flags(self.host_compiler.get_std_exe_link_args(), _Phase.LINKER) def find_library(self, libname: str, env: 'Environment', extra_dirs: T.List[str], libtype: LibType = LibType.PREFER_SHARED, lib_prefix_warning: bool = True) -> T.Optional[T.List[str]]: return ['-l' + libname] # FIXME def get_crt_compile_args(self, crt_val: str, buildtype: str) -> T.List[str]: return self._to_host_flags(self.host_compiler.get_crt_compile_args(crt_val, buildtype)) def get_crt_link_args(self, crt_val: str, buildtype: str) -> T.List[str]: # 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._to_host_flags(host_link_arg_overrides + self.host_compiler.get_crt_link_args(crt_val, buildtype), _Phase.LINKER) def get_target_link_args(self, target: 'BuildTarget') -> T.List[str]: return self._to_host_flags(super().get_target_link_args(target), _Phase.LINKER) def get_dependency_compile_args(self, dep: 'Dependency') -> T.List[str]: return self._to_host_flags(super().get_dependency_compile_args(dep)) def get_dependency_link_args(self, dep: 'Dependency') -> T.List[str]: return self._to_host_flags(super().get_dependency_link_args(dep), _Phase.LINKER) def get_ccbin_args(self, options: 'KeyedOptionDictType') -> T.List[str]: key = OptionKey('ccbindir', machine=self.for_machine, lang=self.language) ccbindir = options[key].value if isinstance(ccbindir, str) and ccbindir != '': return [self._shield_nvcc_list_arg('-ccbin='+ccbindir, False)] else: return [] def get_profile_generate_args(self) -> T.List[str]: return ['-Xcompiler=' + x for x in self.host_compiler.get_profile_generate_args()] def get_profile_use_args(self) -> T.List[str]: return ['-Xcompiler=' + x for x in self.host_compiler.get_profile_use_args()] def get_assert_args(self, disable: bool) -> T.List[str]: return self.host_compiler.get_assert_args(disable) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/compilers/cython.py0000644000175000017500000000623214562742363021063 0ustar00jpakkanejpakkane# SPDX-License-Identifier: Apache-2.0 # Copyright Ā© 2021 Intel Corporation from __future__ import annotations """Abstraction for Cython language compilers.""" import typing as T from .. import coredata from ..mesonlib import EnvironmentException, OptionKey, version_compare from .compilers import Compiler if T.TYPE_CHECKING: from ..coredata import MutableKeyedOptionDictType, KeyedOptionDictType from ..environment import Environment class CythonCompiler(Compiler): """Cython Compiler.""" language = 'cython' id = 'cython' def needs_static_linker(self) -> bool: # We transpile into C, so we don't need any linker return False def get_always_args(self) -> T.List[str]: return ['--fast-fail'] def get_werror_args(self) -> T.List[str]: return ['-Werror'] def get_output_args(self, outputname: str) -> T.List[str]: return ['-o', outputname] def get_optimization_args(self, optimization_level: str) -> T.List[str]: # Cython doesn't have optimization levels itself, the underlying # compiler might though return [] def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: if version_compare(self.version, '>=0.29.33'): return ['-M'] return [] def get_depfile_suffix(self) -> str: return 'dep' def sanity_check(self, work_dir: str, environment: 'Environment') -> None: code = 'print("hello world")' with self.cached_compile(code, environment.coredata) as p: if p.returncode != 0: raise EnvironmentException(f'Cython compiler {self.id!r} cannot compile programs') def get_buildtype_args(self, buildtype: str) -> T.List[str]: # Cython doesn't implement this, but Meson requires an implementation return [] def get_pic_args(self) -> T.List[str]: # We can lie here, it's fine return [] def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], build_dir: str) -> T.List[str]: new: T.List[str] = [] for i in parameter_list: new.append(i) return new def get_options(self) -> 'MutableKeyedOptionDictType': opts = super().get_options() opts.update({ OptionKey('version', machine=self.for_machine, lang=self.language): coredata.UserComboOption( 'Python version to target', ['2', '3'], '3', ), OptionKey('language', machine=self.for_machine, lang=self.language): coredata.UserComboOption( 'Output C or C++ files', ['c', 'cpp'], 'c', ) }) return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = options[OptionKey('version', machine=self.for_machine, lang=self.language)] args.append(f'-{key.value}') lang = options[OptionKey('language', machine=self.for_machine, lang=self.language)] if lang.value == 'cpp': args.append('--cplus') return args ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/compilers/d.py0000644000175000017500000010752414562742363020010 0ustar00jpakkanejpakkane# Copyright 2012-2022 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 __future__ import annotations import os.path import re import subprocess import typing as T from .. import mesonlib from .. import mlog from ..arglist import CompilerArgs from ..linkers import RSPFileSyntax from ..mesonlib import ( EnvironmentException, version_compare, OptionKey, is_windows ) from . import compilers from .compilers import ( d_dmd_buildtype_args, d_gdc_buildtype_args, d_ldc_buildtype_args, clike_debug_args, Compiler, CompileCheckMode, ) from .mixins.gnu import GnuCompiler from .mixins.gnu import gnu_common_warning_args if T.TYPE_CHECKING: from ..build import DFeatures from ..dependencies import Dependency from ..programs import ExternalProgram from ..envconfig import MachineInfo from ..environment import Environment from ..linkers.linkers import DynamicLinker from ..mesonlib import MachineChoice CompilerMixinBase = Compiler else: CompilerMixinBase = object d_feature_args: T.Dict[str, T.Dict[str, str]] = { '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: T.Dict[str, T.List[str]] = { 'plain': [], '0': [], 'g': [], '1': ['-O1'], '2': ['-O2'], '3': ['-O3'], 's': ['-Oz'], } dmd_optimization_args: T.Dict[str, T.List[str]] = { 'plain': [], '0': [], 'g': [], '1': ['-O'], '2': ['-O'], '3': ['-O'], 's': ['-O'], } class DmdLikeCompilerMixin(CompilerMixinBase): """Mixin class for DMD and LDC. LDC has a number of DMD like arguments, and this class allows for code sharing between them as makes sense. """ def __init__(self, dmd_frontend_version: T.Optional[str]): if dmd_frontend_version is None: self._dmd_has_depfile = False else: # -makedeps switch introduced in 2.095 frontend self._dmd_has_depfile = version_compare(dmd_frontend_version, ">=2.095.0") if T.TYPE_CHECKING: mscrt_args: T.Dict[str, T.List[str]] = {} def _get_target_arch_args(self) -> T.List[str]: ... LINKER_PREFIX = '-L=' def get_output_args(self, outputname: str) -> T.List[str]: return ['-of=' + outputname] def get_linker_output_args(self, outputname: str) -> T.List[str]: return ['-of=' + outputname] def get_include_args(self, path: str, is_system: bool) -> T.List[str]: if path == "": path = "." 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[: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: str) -> T.List[str]: return ['-wi'] def get_werror_args(self) -> T.List[str]: return ['-w'] def get_coverage_args(self) -> T.List[str]: return ['-cov'] def get_coverage_link_args(self) -> T.List[str]: return [] def get_preprocess_only_args(self) -> T.List[str]: return ['-E'] def get_compile_only_args(self) -> T.List[str]: return ['-c'] def get_depfile_suffix(self) -> str: return 'deps' def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: if self._dmd_has_depfile: return [f'-makedeps={outfile}'] return [] def get_pic_args(self) -> T.List[str]: if self.info.is_windows(): return [] return ['-fPIC'] def get_buildtype_linker_args(self, buildtype: str) -> T.List[str]: if buildtype != 'plain': return self._get_target_arch_args() return [] def gen_import_library_args(self, implibname: str) -> T.List[str]: return self.linker.import_library_args(implibname) def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, rpath_paths: T.Tuple[str, ...], build_rpath: str, install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: if self.info.is_windows(): return ([], set()) # GNU ld, solaris ld, and lld acting like GNU ld if self.linker.id.startswith('ld'): # The way that dmd and ldc pass rpath to gcc is different than we would # do directly, each argument -rpath and the value to rpath, need to be # split into two separate arguments both prefaced with the -L=. args: T.List[str] = [] (rpath_args, rpath_dirs_to_remove) = super().build_rpath_args( env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath) for r in rpath_args: if ',' in r: a, b = r.split(',', maxsplit=1) args.append(a) args.append(self.LINKER_PREFIX + b) else: args.append(r) return (args, rpath_dirs_to_remove) return super().build_rpath_args( env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath) @classmethod def _translate_args_to_nongnu(cls, args: T.List[str], info: MachineInfo, link_id: str) -> T.List[str]: # 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. dcargs: T.List[str] = [] # whether we hit a linker argument that expect another arg # see the comment in the "-L" section link_expect_arg = False link_flags_with_arg = [ '-rpath', '-rpath-link', '-soname', '-compatibility_version', '-current_version', ] for arg in args: # Translate OS specific arguments first. osargs: T.List[str] = [] if info.is_windows(): osargs = cls.translate_arg_to_windows(arg) elif info.is_darwin(): osargs = cls._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') and not (arg == '-D' or arg.startswith(('-Dd', '-Df'))): # ignore all '-D*' flags (like '-D_THREAD_SAFE') # unless they are related to documentation 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'): # The D linker expect library search paths in the form of -L=-L/path (the '=' is optional). # # This function receives a mix of arguments already prepended # with -L for the D linker driver and other linker arguments. # The arguments starting with -L can be: # - library search path (with or without a second -L) # - it can come from pkg-config (a single -L) # - or from the user passing linker flags (-L-L would be expected) # - arguments like "-L=-rpath" that expect a second argument (also prepended with -L) # - arguments like "-L=@rpath/xxx" without a second argument (on Apple platform) # - arguments like "-L=/SUBSYSTEM:CONSOLE (for Windows linker) # # The logic that follows tries to detect all these cases (some may be missing) # in order to prepend a -L only for the library search paths with a single -L if arg.startswith('-L='): suffix = arg[3:] else: suffix = arg[2:] if link_expect_arg: # flags like rpath and soname expect a path or filename respectively, # we must not alter it (i.e. prefixing with -L for a lib search path) dcargs.append(arg) link_expect_arg = False continue if suffix in link_flags_with_arg: link_expect_arg = True if suffix.startswith('-') or suffix.startswith('@'): # this is not search path dcargs.append(arg) continue # linker flag such as -L=/DEBUG must pass through if info.is_windows() and link_id == 'link' and suffix.startswith('/'): dcargs.append(arg) continue # Make sure static library files are passed properly to the linker. if arg.endswith('.a') or arg.endswith('.lib'): if len(suffix) > 0 and not suffix.startswith('-'): dcargs.append('-L=' + suffix) 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: str) -> T.List[str]: args: T.List[str] = [] 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: str) -> T.List[str]: args: T.List[str] = [] if arg.startswith('-install_name'): args.append('-L=' + arg) return args @classmethod def _unix_args_to_native(cls, args: T.List[str], info: MachineInfo, link_id: str = '') -> T.List[str]: return cls._translate_args_to_nongnu(args, info, link_id) def get_debug_args(self, is_debug: bool) -> T.List[str]: 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: str, buildtype: str) -> T.List[str]: if not self.info.is_windows(): return [] return self.mscrt_args[self.get_crt_val(crt_val, buildtype)] def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, suffix: str, soversion: str, darwin_versions: T.Tuple[str, str]) -> T.List[str]: sargs = super().get_soname_args(env, prefix, shlib_name, suffix, soversion, darwin_versions) # LDC and DMD actually do use a linker, but they proxy all of that with # their own arguments soargs: T.List[str] = [] if self.linker.id.startswith('ld.'): for arg in sargs: a, b = arg.split(',', maxsplit=1) soargs.append(a) soargs.append(self.LINKER_PREFIX + b) return soargs elif self.linker.id.startswith('ld64'): for arg in sargs: if not arg.startswith(self.LINKER_PREFIX): soargs.append(self.LINKER_PREFIX + arg) else: soargs.append(arg) return soargs else: return sargs def get_allow_undefined_link_args(self) -> T.List[str]: args = self.linker.get_allow_undefined_args() if self.info.is_darwin(): # On macOS we're passing these options to the C compiler, but # they're linker options and need -Wl, so clang/gcc knows what to # do with them. I'm assuming, but don't know for certain, that # ldc/dmd do some kind of mapping internally for arguments they # understand, but pass arguments they don't understand directly. args = [a.replace('-L=', '-Xcc=-Wl,') for a in args] return args class DCompilerArgs(CompilerArgs): prepend_prefixes = ('-I', '-L') dedup2_prefixes = ('-I', ) 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: T.List[str], version: str, for_machine: MachineChoice, info: 'MachineInfo', arch: str, *, exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None, is_cross: bool = False): super().__init__([], exelist, version, for_machine, info, linker=linker, full_version=full_version, is_cross=is_cross) self.arch = arch self.exe_wrapper = exe_wrapper def sanity_check(self, work_dir: str, environment: 'Environment') -> None: source_name = os.path.join(work_dir, 'sanity.d') output_name = os.path.join(work_dir, 'dtest') with open(source_name, 'w', encoding='utf-8') 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 cannot 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) -> bool: return True def get_depfile_suffix(self) -> str: return 'deps' def get_pic_args(self) -> T.List[str]: if self.info.is_windows(): return [] return ['-fPIC'] def get_feature_args(self, kwargs: DFeatures, build_to_src: str) -> T.List[str]: res: T.List[str] = [] 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 kwargs['unittest']: res.append(unittest_arg) debug_level = -1 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 kwargs['debug']: 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(f'{debug_arg}={d}') if debug_level >= 0: res.append(f'{debug_arg}={debug_level}') version_level = -1 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 kwargs['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(f'{version_arg}={v}') if version_level >= 0: res.append(f'{version_arg}={version_level}') 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()) # TODO: ImportDirs.to_string_list(), but we need both the project source # root and project build root for that. for idir_obj in kwargs['import_dirs']: basedir = idir_obj.get_curdir() for idir in idir_obj.get_incdirs(): bldtreedir = os.path.join(basedir, idir) # Avoid superfluous '/.' at the end of paths when d is '.' if idir not in ('', '.'): expdir = bldtreedir else: expdir = basedir srctreedir = os.path.join(build_to_src, expdir) res.append(f'{import_dir_arg}{srctreedir}') res.append(f'{import_dir_arg}{bldtreedir}') return res def get_buildtype_linker_args(self, buildtype: str) -> T.List[str]: if buildtype != 'plain': return self._get_target_arch_args() return [] def compiler_args(self, args: T.Optional[T.Iterable[str]] = None) -> DCompilerArgs: return DCompilerArgs(self, args) def has_multi_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]: return self.compiles('int i;\n', env, extra_args=args) def _get_target_arch_args(self) -> T.List[str]: # 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: str, buildtype: str) -> T.List[str]: return [] def get_crt_link_args(self, crt_val: str, buildtype: str) -> T.List[str]: return [] def _get_compile_extra_args(self, extra_args: T.Union[T.List[str], T.Callable[[CompileCheckMode], T.List[str]], None] = None) -> T.List[str]: args = self._get_target_arch_args() if extra_args: if callable(extra_args): extra_args = extra_args(CompileCheckMode.COMPILE) if isinstance(extra_args, list): args.extend(extra_args) elif isinstance(extra_args, str): args.append(extra_args) return args def run(self, code: 'mesonlib.FileOrString', env: 'Environment', *, extra_args: T.Union[T.List[str], T.Callable[[CompileCheckMode], T.List[str]], None] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> compilers.RunResult: need_exe_wrapper = env.need_exe_wrapper(self.for_machine) if need_exe_wrapper and self.exe_wrapper is None: raise compilers.CrossNoRunException('Can not run test applications in this cross environment.') extra_args = self._get_compile_extra_args(extra_args) with self._build_wrapper(code, env, extra_args, dependencies, mode=CompileCheckMode.LINK, want_output=True) as p: if p.returncode != 0: mlog.debug(f'Could not compile test file {p.input_name}: {p.returncode}\n') return compilers.RunResult(False) if need_exe_wrapper: cmdlist = self.exe_wrapper.get_command() + [p.output_name] else: cmdlist = [p.output_name] try: pe, so, se = mesonlib.Popen_safe(cmdlist) except Exception as e: mlog.debug(f'Could not run: {cmdlist} (error: {e})\n') 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 sizeof(self, typename: str, prefix: str, env: 'Environment', *, extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[int, bool]: if extra_args is None: extra_args = [] t = f''' import std.stdio : writeln; {prefix} void main() {{ writeln(({typename}).sizeof); }} ''' res = self.cached_run(t, env, extra_args=extra_args, dependencies=dependencies) if not res.compiled: return -1, False if res.returncode != 0: raise mesonlib.EnvironmentException('Could not run sizeof test binary.') return int(res.stdout), res.cached def alignment(self, typename: str, prefix: str, env: 'Environment', *, extra_args: T.Optional[T.List[str]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[int, bool]: if extra_args is None: extra_args = [] t = f''' import std.stdio : writeln; {prefix} void main() {{ writeln(({typename}).alignof); }} ''' res = self.run(t, 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(f'Could not determine alignment of {typename}. Sorry. You might want to file a bug.') return align, res.cached def has_header(self, hname: str, prefix: str, env: 'Environment', *, extra_args: T.Union[None, T.List[str], T.Callable[['CompileCheckMode'], T.List[str]]] = None, dependencies: T.Optional[T.List['Dependency']] = None, disable_cache: bool = False) -> T.Tuple[bool, bool]: extra_args = self._get_compile_extra_args(extra_args) code = f'''{prefix} import {hname}; ''' return self.compiles(code, env, extra_args=extra_args, dependencies=dependencies, mode=CompileCheckMode.COMPILE, disable_cache=disable_cache) class GnuDCompiler(GnuCompiler, DCompiler): # we mostly want DCompiler, but that gives us the Compiler.LINKER_PREFIX instead LINKER_PREFIX = GnuCompiler.LINKER_PREFIX id = 'gcc' def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, info: 'MachineInfo', arch: str, *, exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None, is_cross: bool = False): DCompiler.__init__(self, exelist, version, for_machine, info, arch, exe_wrapper=exe_wrapper, linker=linker, full_version=full_version, is_cross=is_cross) GnuCompiler.__init__(self, {}) default_warn_args = ['-Wall', '-Wdeprecated'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic'], 'everything': (default_warn_args + ['-Wextra', '-Wpedantic'] + self.supported_warn_args(gnu_common_warning_args))} self.base_options = { OptionKey(o) for o in [ 'b_colorout', 'b_sanitize', 'b_staticpic', 'b_vscrt', 'b_coverage', 'b_pgo', 'b_ndebug']} 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: str) -> T.List[str]: if self._has_color_support: super().get_colorout_args(colortype) return [] def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: if self._has_deps_support: return super().get_dependency_gen_args(outtarget, outfile) return [] def get_warn_args(self, level: str) -> T.List[str]: return self.warn_args[level] def get_buildtype_args(self, buildtype: str) -> T.List[str]: return d_gdc_buildtype_args[buildtype] 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_allow_undefined_link_args(self) -> T.List[str]: return self.linker.get_allow_undefined_args() def get_linker_always_args(self) -> T.List[str]: args = super().get_linker_always_args() if self.info.is_windows(): return args return args + ['-shared-libphobos'] def get_assert_args(self, disable: bool) -> T.List[str]: if disable: return ['-frelease'] return [] # LDC uses the DMD frontend code to parse and analyse the code. # It then uses LLVM for the binary code generation and optimizations. # This function retrieves the dmd frontend version, which determines # the common features between LDC and DMD. # We need the complete version text because the match is not on first line # of version_output def find_ldc_dmd_frontend_version(version_output: T.Optional[str]) -> T.Optional[str]: if version_output is None: return None version_regex = re.search(r'DMD v(\d+\.\d+\.\d+)', version_output) if version_regex: return version_regex.group(1) return None class LLVMDCompiler(DmdLikeCompilerMixin, DCompiler): id = 'llvm' def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, info: 'MachineInfo', arch: str, *, exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None, is_cross: bool = False, version_output: T.Optional[str] = None): DCompiler.__init__(self, exelist, version, for_machine, info, arch, exe_wrapper=exe_wrapper, linker=linker, full_version=full_version, is_cross=is_cross) DmdLikeCompilerMixin.__init__(self, dmd_frontend_version=find_ldc_dmd_frontend_version(version_output)) self.base_options = {OptionKey(o) for o in ['b_coverage', 'b_colorout', 'b_vscrt', 'b_ndebug']} def get_colorout_args(self, colortype: str) -> T.List[str]: if colortype == 'always': return ['-enable-color'] return [] def get_warn_args(self, level: str) -> T.List[str]: if level in {'2', '3'}: return ['-wi', '-dw'] elif level == '1': return ['-wi'] return [] def get_buildtype_args(self, buildtype: str) -> T.List[str]: 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) -> T.List[str]: return ['-relocation-model=pic'] def get_crt_link_args(self, crt_val: str, buildtype: str) -> T.List[str]: return self._get_crt_args(crt_val, buildtype) def unix_args_to_native(self, args: T.List[str]) -> T.List[str]: return self._unix_args_to_native(args, self.info, self.linker.id) def get_optimization_args(self, optimization_level: str) -> T.List[str]: return ldc_optimization_args[optimization_level] @classmethod def use_linker_args(cls, linker: str, version: str) -> T.List[str]: return [f'-linker={linker}'] def get_linker_always_args(self) -> T.List[str]: args = super().get_linker_always_args() if self.info.is_windows(): return args return args + ['-link-defaultlib-shared'] def get_assert_args(self, disable: bool) -> T.List[str]: if disable: return ['--release'] return [] def rsp_file_syntax(self) -> RSPFileSyntax: # We use `mesonlib.is_windows` here because we want to know what the # build machine is, not the host machine. This really means we would # have the Environment not the MachineInfo in the compiler. return RSPFileSyntax.MSVC if is_windows() else RSPFileSyntax.GCC class DmdDCompiler(DmdLikeCompilerMixin, DCompiler): id = 'dmd' def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, info: 'MachineInfo', arch: str, *, exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None, is_cross: bool = False): DCompiler.__init__(self, exelist, version, for_machine, info, arch, exe_wrapper=exe_wrapper, linker=linker, full_version=full_version, is_cross=is_cross) DmdLikeCompilerMixin.__init__(self, version) self.base_options = {OptionKey(o) for o in ['b_coverage', 'b_colorout', 'b_vscrt', 'b_ndebug']} def get_colorout_args(self, colortype: str) -> T.List[str]: if colortype == 'always': return ['-color=on'] return [] def get_buildtype_args(self, buildtype: str) -> T.List[str]: 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) -> T.List[str]: 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) -> T.List[str]: 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) -> T.List[str]: # 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: str, buildtype: str) -> T.List[str]: return self._get_crt_args(crt_val, buildtype) def unix_args_to_native(self, args: T.List[str]) -> T.List[str]: return self._unix_args_to_native(args, self.info, self.linker.id) def get_optimization_args(self, optimization_level: str) -> T.List[str]: return dmd_optimization_args[optimization_level] def can_linker_accept_rsp(self) -> bool: return False def get_linker_always_args(self) -> T.List[str]: args = super().get_linker_always_args() if self.info.is_windows(): return args return args + ['-defaultlib=phobos2', '-debuglib=phobos2'] def get_assert_args(self, disable: bool) -> T.List[str]: if disable: return ['-release'] return [] def rsp_file_syntax(self) -> RSPFileSyntax: return RSPFileSyntax.MSVC ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0 meson-1.3.2/mesonbuild/compilers/detect.py0000644000175000017500000020177414562742373021040 0ustar00jpakkanejpakkane# Copyright 2012-2022 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 __future__ import annotations from ..mesonlib import ( MesonException, EnvironmentException, MachineChoice, join_args, search_version, is_windows, Popen_safe, Popen_safe_logged, windows_proof_rm, ) from ..envconfig import BinaryTable from .. import mlog from ..linkers import guess_win_linker, guess_nix_linker import subprocess import platform import re import shutil import tempfile import os import typing as T if T.TYPE_CHECKING: from .compilers import Compiler from .c import CCompiler from .cpp import CPPCompiler from .fortran import FortranCompiler from .rust import RustCompiler from ..linkers.linkers import StaticLinker, DynamicLinker from ..environment import Environment from ..programs import ExternalProgram # Default compilers and linkers # ============================= defaults: T.Dict[str, T.List[str]] = {} # List of potential compilers. if is_windows(): # Intel C and C++ compiler is icl on Windows, but icc and icpc elsewhere. # Search for icl before cl, since Intel "helpfully" provides a # cl.exe that returns *exactly the same thing* that microsofts # cl.exe does, and if icl is present, it's almost certainly what # you want. defaults['c'] = ['icl', 'cl', 'cc', 'gcc', 'clang', 'clang-cl', 'pgcc'] # There is currently no pgc++ for Windows, only for Mac and Linux. defaults['cpp'] = ['icl', 'cl', 'c++', 'g++', 'clang++', 'clang-cl'] defaults['fortran'] = ['ifort', 'gfortran', 'flang', 'pgfortran', 'g95'] # Clang and clang++ are valid, but currently unsupported. defaults['objc'] = ['cc', 'gcc'] defaults['objcpp'] = ['c++', 'g++'] defaults['cs'] = ['csc', 'mcs'] else: if platform.machine().lower() == 'e2k': defaults['c'] = ['cc', 'gcc', 'lcc', 'clang'] defaults['cpp'] = ['c++', 'g++', 'l++', 'clang++'] defaults['objc'] = ['clang'] defaults['objcpp'] = ['clang++'] else: defaults['c'] = ['cc', 'gcc', 'clang', 'nvc', 'pgcc', 'icc', 'icx'] defaults['cpp'] = ['c++', 'g++', 'clang++', 'nvc++', 'pgc++', 'icpc', 'icpx'] defaults['objc'] = ['cc', 'gcc', 'clang'] defaults['objcpp'] = ['c++', 'g++', 'clang++'] defaults['fortran'] = ['gfortran', 'flang', 'nvfortran', 'pgfortran', 'ifort', 'ifx', 'g95'] defaults['cs'] = ['mcs', 'csc'] defaults['d'] = ['ldc2', 'ldc', 'gdc', 'dmd'] defaults['java'] = ['javac'] defaults['cuda'] = ['nvcc'] defaults['rust'] = ['rustc'] defaults['swift'] = ['swiftc'] defaults['vala'] = ['valac'] defaults['cython'] = ['cython', 'cython3'] # Official name is cython, but Debian renamed it to cython3. defaults['static_linker'] = ['ar', 'gar'] defaults['strip'] = ['strip'] defaults['vs_static_linker'] = ['lib'] defaults['clang_cl_static_linker'] = ['llvm-lib'] defaults['cuda_static_linker'] = ['nvlink'] defaults['gcc_static_linker'] = ['gcc-ar'] defaults['clang_static_linker'] = ['llvm-ar'] defaults['nasm'] = ['nasm', 'yasm'] def compiler_from_language(env: 'Environment', lang: str, for_machine: MachineChoice) -> T.Optional[Compiler]: lang_map: T.Dict[str, T.Callable[['Environment', MachineChoice], Compiler]] = { 'c': detect_c_compiler, 'cpp': detect_cpp_compiler, 'objc': detect_objc_compiler, 'cuda': detect_cuda_compiler, 'objcpp': detect_objcpp_compiler, 'java': detect_java_compiler, 'cs': detect_cs_compiler, 'vala': detect_vala_compiler, 'd': detect_d_compiler, 'rust': detect_rust_compiler, 'fortran': detect_fortran_compiler, 'swift': detect_swift_compiler, 'cython': detect_cython_compiler, 'nasm': detect_nasm_compiler, 'masm': detect_masm_compiler, } return lang_map[lang](env, for_machine) if lang in lang_map else None def detect_compiler_for(env: 'Environment', lang: str, for_machine: MachineChoice, skip_sanity_check: bool) -> T.Optional[Compiler]: comp = compiler_from_language(env, lang, for_machine) if comp is None: return comp assert comp.for_machine == for_machine env.coredata.process_new_compiler(lang, comp, env) if not skip_sanity_check: comp.sanity_check(env.get_scratch_dir(), env) env.coredata.compilers[comp.for_machine][lang] = comp return comp # Helpers # ======= def _get_compilers(env: 'Environment', lang: str, for_machine: MachineChoice) -> T.Tuple[T.List[T.List[str]], T.List[str], T.Optional['ExternalProgram']]: ''' The list of compilers is detected in the exact same way for C, C++, ObjC, ObjC++, Fortran, CS so consolidate it here. ''' value = env.lookup_binary_entry(for_machine, lang) if value is not None: comp, ccache = BinaryTable.parse_entry(value) # Return value has to be a list of compiler 'choices' compilers = [comp] else: if not env.machines.matches_build_machine(for_machine): raise EnvironmentException(f'{lang!r} compiler binary not defined in cross or native file') compilers = [[x] for x in defaults[lang]] ccache = BinaryTable.detect_compiler_cache() if env.machines.matches_build_machine(for_machine): exe_wrap: T.Optional[ExternalProgram] = None else: exe_wrap = env.get_exe_wrapper() return compilers, ccache, exe_wrap def _handle_exceptions( exceptions: T.Mapping[str, T.Union[Exception, str]], binaries: T.List[T.List[str]], bintype: str = 'compiler') -> T.NoReturn: errmsg = f'Unknown {bintype}(s): {binaries}' if exceptions: errmsg += '\nThe following exception(s) were encountered:' for c, e in exceptions.items(): errmsg += f'\nRunning `{c}` gave "{e}"' raise EnvironmentException(errmsg) # Linker specific # =============== def detect_static_linker(env: 'Environment', compiler: Compiler) -> StaticLinker: from . import d from ..linkers import linkers linker = env.lookup_binary_entry(compiler.for_machine, 'ar') if linker is not None: trials = [linker] else: default_linkers = [[l] for l in defaults['static_linker']] if compiler.language == 'cuda': trials = [defaults['cuda_static_linker']] + default_linkers elif compiler.get_argument_syntax() == 'msvc': trials = [defaults['vs_static_linker'], defaults['clang_cl_static_linker']] elif compiler.id == 'gcc': # Use gcc-ar if available; needed for LTO trials = [defaults['gcc_static_linker']] + default_linkers elif compiler.id == 'clang': # Use llvm-ar if available; needed for LTO trials = [defaults['clang_static_linker']] + default_linkers elif compiler.language == 'd': # Prefer static linkers over linkers used by D compilers if is_windows(): trials = [defaults['vs_static_linker'], defaults['clang_cl_static_linker'], compiler.get_linker_exelist()] else: trials = default_linkers elif compiler.id == 'intel-cl' and compiler.language == 'c': # why not cpp? Is this a bug? # Intel has it's own linker that acts like microsoft's lib trials = [['xilib']] elif is_windows() and compiler.id == 'pgi': # this handles cpp / nvidia HPC, in addition to just c/fortran trials = [['ar']] # For PGI on Windows, "ar" is just a wrapper calling link/lib. elif is_windows() and compiler.id == 'nasm': # This may well be LINK.EXE if it's under a MSVC environment trials = [defaults['vs_static_linker'], defaults['clang_cl_static_linker']] + default_linkers else: trials = default_linkers popen_exceptions = {} for linker in trials: linker_name = os.path.basename(linker[0]) if any(os.path.basename(x) in {'lib', 'lib.exe', 'llvm-lib', 'llvm-lib.exe', 'xilib', 'xilib.exe'} for x in linker): arg = '/?' elif linker_name in {'ar2000', 'ar2000.exe', 'ar430', 'ar430.exe', 'armar', 'armar.exe'}: arg = '?' else: arg = '--version' try: p, out, err = Popen_safe_logged(linker + [arg], msg='Detecting archiver via') except OSError as e: popen_exceptions[join_args(linker + [arg])] = e continue if "xilib: executing 'lib'" in err: return linkers.IntelVisualStudioLinker(linker, getattr(compiler, 'machine', None)) if '/OUT:' in out.upper() or '/OUT:' in err.upper(): return linkers.VisualStudioLinker(linker, getattr(compiler, 'machine', None)) if 'ar-Error-Unknown switch: --version' in err: return linkers.PGIStaticLinker(linker) if p.returncode == 0 and 'armar' in linker_name: return linkers.ArmarLinker(linker) if 'DMD32 D Compiler' in out or 'DMD64 D Compiler' in out: assert isinstance(compiler, d.DCompiler) return linkers.DLinker(linker, compiler.arch) if 'LDC - the LLVM D compiler' in out: assert isinstance(compiler, d.DCompiler) return linkers.DLinker(linker, compiler.arch, rsp_syntax=compiler.rsp_file_syntax()) if 'GDC' in out and ' based on D ' in out: assert isinstance(compiler, d.DCompiler) return linkers.DLinker(linker, compiler.arch) if err.startswith('Renesas') and 'rlink' in linker_name: return linkers.CcrxLinker(linker) if out.startswith('GNU ar') and 'xc16-ar' in linker_name: return linkers.Xc16Linker(linker) if 'Texas Instruments Incorporated' in out: if 'ar2000' in linker_name: return linkers.C2000Linker(linker) else: return linkers.TILinker(linker) if out.startswith('The CompCert'): return linkers.CompCertLinker(linker) if out.strip().startswith('Metrowerks') or out.strip().startswith('Freescale'): if 'ARM' in out: return linkers.MetrowerksStaticLinkerARM(linker) else: return linkers.MetrowerksStaticLinkerEmbeddedPowerPC(linker) if p.returncode == 0: return linkers.ArLinker(compiler.for_machine, linker) if p.returncode == 1 and err.startswith('usage'): # OSX return linkers.AppleArLinker(compiler.for_machine, linker) if p.returncode == 1 and err.startswith('Usage'): # AIX return linkers.AIXArLinker(linker) if p.returncode == 1 and err.startswith('ar: bad option: --'): # Solaris return linkers.ArLinker(compiler.for_machine, linker) _handle_exceptions(popen_exceptions, trials, 'linker') raise EnvironmentException('Unreachable code (exception to make mypy happy)') # Compilers # ========= def _detect_c_or_cpp_compiler(env: 'Environment', lang: str, for_machine: MachineChoice, *, override_compiler: T.Optional[T.List[str]] = None) -> Compiler: """Shared implementation for finding the C or C++ compiler to use. the override_compiler option is provided to allow compilers which use the compiler (GCC or Clang usually) as their shared linker, to find the linker they need. """ from . import c, cpp from ..linkers import linkers popen_exceptions: T.Dict[str, T.Union[Exception, str]] = {} compilers, ccache, exe_wrap = _get_compilers(env, lang, for_machine) if override_compiler is not None: compilers = [override_compiler] is_cross = env.is_cross_build(for_machine) info = env.machines[for_machine] cls: T.Union[T.Type[CCompiler], T.Type[CPPCompiler]] lnk: T.Union[T.Type[StaticLinker], T.Type[DynamicLinker]] for compiler in compilers: if isinstance(compiler, str): compiler = [compiler] compiler_name = os.path.basename(compiler[0]) if any(os.path.basename(x) in {'cl', 'cl.exe', 'clang-cl', 'clang-cl.exe'} for x in 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: str) -> str: 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')), sanitize(os.path.join(os.environ['WATCOM'], 'BINNT64', 'cl')), sanitize(os.path.join(os.environ['WATCOM'], 'BINNT64', 'cl.exe'))] found_cl = sanitize(shutil.which('cl')) if found_cl in watcom_cls: mlog.debug('Skipping unsupported cl.exe clone at:', found_cl) continue arg = '/?' elif 'armcc' in compiler_name: arg = '--vsn' elif 'ccrx' in compiler_name: arg = '-v' elif 'xc16' in compiler_name: arg = '--version' elif 'ccomp' in compiler_name: arg = '-version' elif compiler_name in {'cl2000', 'cl2000.exe', 'cl430', 'cl430.exe', 'armcl', 'armcl.exe'}: # TI compiler arg = '-version' elif compiler_name in {'icl', 'icl.exe'}: # if you pass anything to icl you get stuck in a pager arg = '' else: arg = '--version' cmd = compiler + [arg] try: p, out, err = Popen_safe_logged(cmd, msg='Detecting compiler via') except OSError as e: popen_exceptions[join_args(cmd)] = e continue if 'ccrx' in compiler_name: out = err full_version = out.split('\n', 1)[0] version = search_version(out) guess_gcc_or_lcc: T.Optional[str] = None if 'Free Software Foundation' in out or out.startswith('xt-'): guess_gcc_or_lcc = 'gcc' if 'e2k' in out and 'lcc' in out: guess_gcc_or_lcc = 'lcc' if 'Microchip Technology' in out: # this output has "Free Software Foundation" in its version guess_gcc_or_lcc = None if guess_gcc_or_lcc: defines = _get_gnu_compiler_defines(compiler) if not defines: popen_exceptions[join_args(compiler)] = 'no pre-processor defines' continue if guess_gcc_or_lcc == 'lcc': version = _get_lcc_version_from_defines(defines) cls = c.ElbrusCCompiler if lang == 'c' else cpp.ElbrusCPPCompiler else: version = _get_gnu_version_from_defines(defines) cls = c.GnuCCompiler if lang == 'c' else cpp.GnuCPPCompiler linker = guess_nix_linker(env, compiler, cls, version, for_machine) return cls( ccache, compiler, version, for_machine, is_cross, info, exe_wrap, defines=defines, full_version=full_version, linker=linker) if 'Emscripten' in out: cls = c.EmscriptenCCompiler if lang == 'c' else cpp.EmscriptenCPPCompiler env.coredata.add_lang_args(cls.language, cls, for_machine, env) # emcc requires a file input in order to pass arguments to the # linker. It'll exit with an error code, but still print the # linker version. with tempfile.NamedTemporaryFile(suffix='.c') as f: cmd = compiler + [cls.LINKER_PREFIX + "--version", f.name] _, o, _ = Popen_safe(cmd) linker = linkers.WASMDynamicLinker( compiler, for_machine, cls.LINKER_PREFIX, [], version=search_version(o)) return cls( ccache, compiler, version, for_machine, is_cross, info, exe_wrap, linker=linker, full_version=full_version) if 'Arm C/C++/Fortran Compiler' in out: arm_ver_match = re.search(r'version (\d+)\.(\d+)\.?(\d+)? \(build number (\d+)\)', out) assert arm_ver_match is not None, 'for mypy' # because mypy *should* be complaining that this could be None version = '.'.join([x for x in arm_ver_match.groups() if x is not None]) if lang == 'c': cls = c.ArmLtdClangCCompiler elif lang == 'cpp': cls = cpp.ArmLtdClangCPPCompiler linker = guess_nix_linker(env, compiler, cls, version, for_machine) return cls( ccache, compiler, version, for_machine, is_cross, info, exe_wrap, linker=linker) 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_match = re.search('.*Component.*', out) if arm_ver_match is None: popen_exceptions[join_args(compiler)] = 'version string not found' continue arm_ver_str = arm_ver_match.group(0) # Override previous values version = search_version(arm_ver_str) full_version = arm_ver_str cls = c.ArmclangCCompiler if lang == 'c' else cpp.ArmclangCPPCompiler linker = linkers.ArmClangDynamicLinker(for_machine, version=version) env.coredata.add_lang_args(cls.language, cls, for_machine, env) 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_args(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 = c.ClangClCCompiler if lang == 'c' else cpp.ClangClCPPCompiler linker = guess_win_linker(env, ['lld-link'], cls, version, for_machine) return cls( compiler, version, for_machine, is_cross, info, target, exe_wrap, linker=linker) if 'clang' in out or 'Clang' in out: linker = None defines = _get_clang_compiler_defines(compiler) # Even if the for_machine is darwin, we could be using vanilla # clang. if 'Apple' in out: cls = c.AppleClangCCompiler if lang == 'c' else cpp.AppleClangCPPCompiler else: cls = c.ClangCCompiler if lang == 'c' else cpp.ClangCPPCompiler if 'windows' in out or env.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 = guess_win_linker(env, compiler, cls, version, for_machine, invoked_directly=False) except MesonException: pass if linker is None: linker = guess_nix_linker(env, compiler, cls, version, for_machine) return cls( ccache, compiler, version, for_machine, is_cross, info, exe_wrap, defines=defines, 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 = c.IntelClCCompiler if lang == 'c' else cpp.IntelClCPPCompiler env.coredata.add_lang_args(cls.language, cls, for_machine, env) linker = linkers.XilinkDynamicLinker(for_machine, [], version=version) return cls( compiler, version, for_machine, is_cross, info, target, exe_wrap, linker=linker) if 'Intel(R) oneAPI DPC++/C++ Compiler for applications' in err: version = search_version(err) target = 'x86' if 'IA-32' in err else 'x86_64' cls = c.IntelLLVMClCCompiler if lang == 'c' else cpp.IntelLLVMClCPPCompiler env.coredata.add_lang_args(cls.language, cls, for_machine, env) linker = linkers.XilinkDynamicLinker(for_machine, [], version=version) return cls( compiler, version, for_machine, is_cross, info, target, exe_wrap, 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: raise EnvironmentException(f'Failed to detect MSVC compiler version: stderr was\n{err!r}') cl_signature = lookat.split('\n', maxsplit=1)[0] match = re.search(r'.*(x86|x64|ARM|ARM64)([^_A-Za-z0-9]|$)', cl_signature) if match: target = match.group(1) else: m = f'Failed to detect MSVC compiler target architecture: \'cl /?\' output is\n{cl_signature}' raise EnvironmentException(m) cls = c.VisualStudioCCompiler if lang == 'c' else cpp.VisualStudioCPPCompiler linker = guess_win_linker(env, ['link'], cls, version, for_machine) # As of this writing, CCache does not support MSVC but sccache does. if 'sccache' not in ccache: ccache = [] return cls( ccache, compiler, version, for_machine, is_cross, info, target, exe_wrap, full_version=cl_signature, linker=linker) if 'PGI Compilers' in out: cls = c.PGICCompiler if lang == 'c' else cpp.PGICPPCompiler env.coredata.add_lang_args(cls.language, cls, for_machine, env) linker = linkers.PGIDynamicLinker(compiler, for_machine, cls.LINKER_PREFIX, [], version=version) return cls( ccache, compiler, version, for_machine, is_cross, info, exe_wrap, linker=linker) if 'NVIDIA Compilers and Tools' in out: cls = c.NvidiaHPC_CCompiler if lang == 'c' else cpp.NvidiaHPC_CPPCompiler env.coredata.add_lang_args(cls.language, cls, for_machine, env) linker = linkers.NvidiaHPC_DynamicLinker(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 = c.IntelCCompiler if lang == 'c' else cpp.IntelCPPCompiler l = guess_nix_linker(env, compiler, cls, version, for_machine) return cls( ccache, compiler, version, for_machine, is_cross, info, exe_wrap, full_version=full_version, linker=l) if 'Intel(R) oneAPI' in out: cls = c.IntelLLVMCCompiler if lang == 'c' else cpp.IntelLLVMCPPCompiler l = guess_nix_linker(env, compiler, cls, version, for_machine) return cls( ccache, compiler, version, for_machine, is_cross, info, exe_wrap, full_version=full_version, linker=l) if 'TMS320C2000 C/C++' in out or 'MSP430 C/C++' in out or 'TI ARM C/C++ Compiler' in out: if 'TMS320C2000 C/C++' in out: cls = c.C2000CCompiler if lang == 'c' else cpp.C2000CPPCompiler lnk = linkers.C2000DynamicLinker else: cls = c.TICCompiler if lang == 'c' else cpp.TICPPCompiler lnk = linkers.TIDynamicLinker env.coredata.add_lang_args(cls.language, cls, for_machine, env) linker = lnk(compiler, for_machine, version=version) return cls( ccache, compiler, version, for_machine, is_cross, info, exe_wrap, full_version=full_version, linker=linker) if 'ARM' in out and not ('Metrowerks' in out or 'Freescale' in out): cls = c.ArmCCompiler if lang == 'c' else cpp.ArmCPPCompiler env.coredata.add_lang_args(cls.language, cls, for_machine, env) linker = linkers.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 = c.CcrxCCompiler if lang == 'c' else cpp.CcrxCPPCompiler env.coredata.add_lang_args(cls.language, cls, for_machine, env) linker = linkers.CcrxDynamicLinker(for_machine, version=version) return cls( ccache, compiler, version, for_machine, is_cross, info, exe_wrap, full_version=full_version, linker=linker) if 'Microchip Technology' in out: cls = c.Xc16CCompiler env.coredata.add_lang_args(cls.language, cls, for_machine, env) linker = linkers.Xc16DynamicLinker(for_machine, version=version) return cls( ccache, compiler, version, for_machine, is_cross, info, exe_wrap, full_version=full_version, linker=linker) if 'CompCert' in out: cls = c.CompCertCCompiler env.coredata.add_lang_args(cls.language, cls, for_machine, env) linker = linkers.CompCertDynamicLinker(for_machine, version=version) return cls( ccache, compiler, version, for_machine, is_cross, info, exe_wrap, full_version=full_version, linker=linker) if 'Metrowerks C/C++' in out or 'Freescale C/C++' in out: if 'ARM' in out: cls = c.MetrowerksCCompilerARM if lang == 'c' else cpp.MetrowerksCPPCompilerARM lnk = linkers.MetrowerksLinkerARM else: cls = c.MetrowerksCCompilerEmbeddedPowerPC if lang == 'c' else cpp.MetrowerksCPPCompilerEmbeddedPowerPC lnk = linkers.MetrowerksLinkerEmbeddedPowerPC mwcc_ver_match = re.search(r'Version (\d+)\.(\d+)\.?(\d+)? build (\d+)', out) assert mwcc_ver_match is not None, 'for mypy' # because mypy *should* be complaning that this could be None compiler_version = '.'.join(x for x in mwcc_ver_match.groups() if x is not None) env.coredata.add_lang_args(cls.language, cls, for_machine, env) ld = env.lookup_binary_entry(for_machine, cls.language + '_ld') if ld is not None: _, o_ld, _ = Popen_safe(ld + ['--version']) mwld_ver_match = re.search(r'Version (\d+)\.(\d+)\.?(\d+)? build (\d+)', o_ld) assert mwld_ver_match is not None, 'for mypy' # because mypy *should* be complaning that this could be None linker_version = '.'.join(x for x in mwld_ver_match.groups() if x is not None) linker = lnk(ld, for_machine, version=linker_version) else: raise EnvironmentException(f'Failed to detect linker for {cls.id!r} compiler. Please update your cross file(s).') return cls( ccache, compiler, compiler_version, for_machine, is_cross, info, exe_wrap, full_version=full_version, linker=linker) _handle_exceptions(popen_exceptions, compilers) raise EnvironmentException(f'Unknown compiler {compilers}') def detect_c_compiler(env: 'Environment', for_machine: MachineChoice) -> Compiler: return _detect_c_or_cpp_compiler(env, 'c', for_machine) def detect_cpp_compiler(env: 'Environment', for_machine: MachineChoice) -> Compiler: return _detect_c_or_cpp_compiler(env, 'cpp', for_machine) def detect_cuda_compiler(env: 'Environment', for_machine: MachineChoice) -> Compiler: from .cuda import CudaCompiler from ..linkers.linkers import CudaLinker popen_exceptions = {} is_cross = env.is_cross_build(for_machine) compilers, ccache, exe_wrap = _get_compilers(env, 'cuda', for_machine) info = env.machines[for_machine] for compiler in compilers: arg = '--version' try: p, out, err = Popen_safe_logged(compiler + [arg], msg='Detecting compiler via') except OSError as e: popen_exceptions[join_args(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().rsplit('V', maxsplit=1)[-1] cpp_compiler = detect_cpp_compiler(env, for_machine) cls = CudaCompiler env.coredata.add_lang_args(cls.language, cls, for_machine, env) linker = CudaLinker(compiler, for_machine, 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(f'Could not find suitable CUDA compiler: "{"; ".join([" ".join(c) for c in compilers])}"') def detect_fortran_compiler(env: 'Environment', for_machine: MachineChoice) -> Compiler: from . import fortran from ..linkers import linkers popen_exceptions: T.Dict[str, T.Union[Exception, str]] = {} compilers, ccache, exe_wrap = _get_compilers(env, 'fortran', for_machine) is_cross = env.is_cross_build(for_machine) info = env.machines[for_machine] cls: T.Type[FortranCompiler] for compiler in compilers: for arg in ['--version', '-V']: try: p, out, err = Popen_safe_logged(compiler + [arg], msg='Detecting compiler via') except OSError as e: popen_exceptions[join_args(compiler + [arg])] = e continue version = search_version(out) full_version = out.split('\n', 1)[0] guess_gcc_or_lcc: T.Optional[str] = None 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 = _get_gnu_compiler_defines(compiler) if not defines: popen_exceptions[join_args(compiler)] = 'no pre-processor defines' continue if guess_gcc_or_lcc == 'lcc': version = _get_lcc_version_from_defines(defines) cls = fortran.ElbrusFortranCompiler linker = guess_nix_linker(env, compiler, cls, version, for_machine) return cls( compiler, version, for_machine, is_cross, info, exe_wrap, defines, full_version=full_version, linker=linker) else: version = _get_gnu_version_from_defines(defines) cls = fortran.GnuFortranCompiler linker = guess_nix_linker(env, compiler, cls, version, for_machine) return cls( compiler, version, for_machine, is_cross, info, exe_wrap, defines, full_version=full_version, linker=linker) if 'Arm C/C++/Fortran Compiler' in out: cls = fortran.ArmLtdFlangFortranCompiler arm_ver_match = re.search(r'version (\d+)\.(\d+)\.?(\d+)? \(build number (\d+)\)', out) assert arm_ver_match is not None, 'for mypy' # because mypy *should* be complaining that this could be None version = '.'.join([x for x in arm_ver_match.groups() if x is not None]) linker = guess_nix_linker(env, compiler, cls, version, for_machine) return cls( compiler, version, for_machine, is_cross, info, exe_wrap, linker=linker) if 'G95' in out: cls = fortran.G95FortranCompiler linker = guess_nix_linker(env, compiler, cls, version, for_machine) return cls( compiler, version, for_machine, is_cross, info, exe_wrap, full_version=full_version, linker=linker) if 'Sun Fortran' in err: version = search_version(err) cls = fortran.SunFortranCompiler linker = guess_nix_linker(env, compiler, cls, version, for_machine) return cls( compiler, version, for_machine, is_cross, info, exe_wrap, full_version=full_version, linker=linker) if 'Intel(R) Fortran Compiler for applications' in err: version = search_version(err) target = 'x86' if 'IA-32' in err else 'x86_64' cls = fortran.IntelLLVMClFortranCompiler env.coredata.add_lang_args(cls.language, cls, for_machine, env) linker = linkers.XilinkDynamicLinker(for_machine, [], version=version) return cls( compiler, version, for_machine, is_cross, info, target, exe_wrap, linker=linker) if 'Intel(R) Visual Fortran' in err or 'Intel(R) Fortran' in err: version = search_version(err) target = 'x86' if 'IA-32' in err else 'x86_64' cls = fortran.IntelClFortranCompiler env.coredata.add_lang_args(cls.language, cls, for_machine, env) linker = linkers.XilinkDynamicLinker(for_machine, [], version=version) return cls( compiler, version, for_machine, is_cross, info, target, exe_wrap, linker=linker) if 'ifort (IFORT)' in out: cls = fortran.IntelFortranCompiler linker = guess_nix_linker(env, compiler, cls, version, for_machine) return cls( compiler, version, for_machine, is_cross, info, exe_wrap, full_version=full_version, linker=linker) if 'ifx (IFORT)' in out or 'ifx (IFX)' in out: cls = fortran.IntelLLVMFortranCompiler linker = guess_nix_linker(env, compiler, cls, version, for_machine) return cls( compiler, version, for_machine, is_cross, info, exe_wrap, full_version=full_version, linker=linker) if 'PathScale EKOPath(tm)' in err: return fortran.PathScaleFortranCompiler( compiler, version, for_machine, is_cross, info, exe_wrap, full_version=full_version) if 'PGI Compilers' in out: cls = fortran.PGIFortranCompiler env.coredata.add_lang_args(cls.language, cls, for_machine, env) linker = linkers.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 'NVIDIA Compilers and Tools' in out: cls = fortran.NvidiaHPC_FortranCompiler env.coredata.add_lang_args(cls.language, cls, for_machine, env) linker = linkers.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: cls = fortran.FlangFortranCompiler linker = None if 'windows' in out or env.machines[for_machine].is_windows(): # If we're in a MINGW context this actually will use a gnu # style ld, but for flang on "real" windows we'll use # either link.exe or lld-link.exe try: linker = guess_win_linker( env, compiler, cls, version, for_machine, invoked_directly=False ) except MesonException: pass if linker is None: linker = guess_nix_linker(env, compiler, cls, version, for_machine) return cls( compiler, version, for_machine, is_cross, info, exe_wrap, full_version=full_version, linker=linker) if 'Open64 Compiler Suite' in err: cls = fortran.Open64FortranCompiler linker = guess_nix_linker(env, compiler, cls, version, for_machine) return cls( compiler, version, for_machine, is_cross, info, exe_wrap, full_version=full_version, linker=linker) if 'NAG Fortran' in err: full_version = err.split('\n', 1)[0] version = full_version.split()[-1] cls = fortran.NAGFortranCompiler env.coredata.add_lang_args(cls.language, cls, for_machine, env) linker = linkers.NAGDynamicLinker( 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) _handle_exceptions(popen_exceptions, compilers) raise EnvironmentException('Unreachable code (exception to make mypy happy)') def detect_objc_compiler(env: 'Environment', for_machine: MachineChoice) -> 'Compiler': return _detect_objc_or_objcpp_compiler(env, 'objc', for_machine) def detect_objcpp_compiler(env: 'Environment', for_machine: MachineChoice) -> 'Compiler': return _detect_objc_or_objcpp_compiler(env, 'objcpp', for_machine) def _detect_objc_or_objcpp_compiler(env: 'Environment', lang: str, for_machine: MachineChoice) -> 'Compiler': from . import objc, objcpp popen_exceptions: T.Dict[str, T.Union[Exception, str]] = {} compilers, ccache, exe_wrap = _get_compilers(env, lang, for_machine) is_cross = env.is_cross_build(for_machine) info = env.machines[for_machine] comp: T.Union[T.Type[objc.ObjCCompiler], T.Type[objcpp.ObjCPPCompiler]] for compiler in compilers: arg = ['--version'] try: p, out, err = Popen_safe_logged(compiler + arg, msg='Detecting compiler via') except OSError as e: popen_exceptions[join_args(compiler + arg)] = e continue version = search_version(out) if 'Free Software Foundation' in out: defines = _get_gnu_compiler_defines(compiler) if not defines: popen_exceptions[join_args(compiler)] = 'no pre-processor defines' continue version = _get_gnu_version_from_defines(defines) comp = objc.GnuObjCCompiler if lang == 'objc' else objcpp.GnuObjCPPCompiler linker = guess_nix_linker(env, compiler, comp, version, for_machine) return comp( ccache, compiler, version, for_machine, is_cross, info, exe_wrap, defines, linker=linker) if 'clang' in out: linker = None defines = _get_clang_compiler_defines(compiler) if not defines: popen_exceptions[join_args(compiler)] = 'no pre-processor defines' continue if 'Apple' in out: comp = objc.AppleClangObjCCompiler if lang == 'objc' else objcpp.AppleClangObjCPPCompiler else: comp = objc.ClangObjCCompiler if lang == 'objc' else objcpp.ClangObjCPPCompiler if 'windows' in out or env.machines[for_machine].is_windows(): # If we're in a MINGW context this actually will use a gnu style ld try: linker = guess_win_linker(env, compiler, comp, version, for_machine) except MesonException: pass if not linker: linker = guess_nix_linker(env, compiler, comp, version, for_machine) return comp( ccache, compiler, version, for_machine, is_cross, info, exe_wrap, linker=linker, defines=defines) _handle_exceptions(popen_exceptions, compilers) raise EnvironmentException('Unreachable code (exception to make mypy happy)') def detect_java_compiler(env: 'Environment', for_machine: MachineChoice) -> Compiler: from .java import JavaCompiler exelist = env.lookup_binary_entry(for_machine, 'java') info = env.machines[for_machine] if exelist is None: # TODO support fallback exelist = [defaults['java'][0]] try: p, out, err = Popen_safe_logged(exelist + ['-version'], msg='Detecting compiler via') except OSError: raise EnvironmentException('Could not execute Java compiler: {}'.format(join_args(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 env.coredata.add_lang_args(comp_class.language, comp_class, for_machine, env) return comp_class(exelist, version, for_machine, info) raise EnvironmentException('Unknown compiler: ' + join_args(exelist)) def detect_cs_compiler(env: 'Environment', for_machine: MachineChoice) -> Compiler: from . import cs compilers, ccache, exe_wrap = _get_compilers(env, 'cs', for_machine) popen_exceptions = {} info = env.machines[for_machine] for comp in compilers: try: p, out, err = Popen_safe_logged(comp + ['--version'], msg='Detecting compiler via') except OSError as e: popen_exceptions[join_args(comp + ['--version'])] = e continue version = search_version(out) cls: T.Type[cs.CsCompiler] if 'Mono' in out: cls = cs.MonoCompiler elif "Visual C#" in out: cls = cs.VisualStudioCsCompiler else: continue env.coredata.add_lang_args(cls.language, cls, for_machine, env) return cls(comp, version, for_machine, info) _handle_exceptions(popen_exceptions, compilers) raise EnvironmentException('Unreachable code (exception to make mypy happy)') def detect_cython_compiler(env: 'Environment', for_machine: MachineChoice) -> Compiler: """Search for a cython compiler.""" from .cython import CythonCompiler compilers, _, _ = _get_compilers(env, 'cython', MachineChoice.BUILD) is_cross = env.is_cross_build(for_machine) info = env.machines[for_machine] popen_exceptions: T.Dict[str, Exception] = {} for comp in compilers: try: _, out, err = Popen_safe_logged(comp + ['-V'], msg='Detecting compiler via') except OSError as e: popen_exceptions[join_args(comp + ['-V'])] = e continue version: T.Optional[str] = None # 3.0 if 'Cython' in out: version = search_version(out) # older elif 'Cython' in err: version = search_version(err) if version is not None: comp_class = CythonCompiler env.coredata.add_lang_args(comp_class.language, comp_class, for_machine, env) return comp_class([], comp, version, for_machine, info, is_cross=is_cross) _handle_exceptions(popen_exceptions, compilers) raise EnvironmentException('Unreachable code (exception to make mypy happy)') def detect_vala_compiler(env: 'Environment', for_machine: MachineChoice) -> Compiler: from .vala import ValaCompiler exelist = env.lookup_binary_entry(MachineChoice.BUILD, 'vala') is_cross = env.is_cross_build(for_machine) info = env.machines[for_machine] if exelist is None: # TODO support fallback exelist = [defaults['vala'][0]] try: p, out = Popen_safe_logged(exelist + ['--version'], msg='Detecting compiler via')[0:2] except OSError: raise EnvironmentException('Could not execute Vala compiler: {}'.format(join_args(exelist))) version = search_version(out) if 'Vala' in out: comp_class = ValaCompiler env.coredata.add_lang_args(comp_class.language, comp_class, for_machine, env) return comp_class(exelist, version, for_machine, is_cross, info) raise EnvironmentException('Unknown compiler: ' + join_args(exelist)) def detect_rust_compiler(env: 'Environment', for_machine: MachineChoice) -> RustCompiler: from . import rust from ..linkers import linkers popen_exceptions: T.Dict[str, Exception] = {} compilers, _, exe_wrap = _get_compilers(env, 'rust', for_machine) is_cross = env.is_cross_build(for_machine) info = env.machines[for_machine] cc = detect_c_compiler(env, for_machine) is_link_exe = isinstance(cc.linker, linkers.VisualStudioLikeLinkerMixin) override = env.lookup_binary_entry(for_machine, 'rust_ld') for compiler in compilers: arg = ['--version'] try: out = Popen_safe_logged(compiler + arg, msg='Detecting compiler via')[1] except OSError as e: popen_exceptions[join_args(compiler + arg)] = e continue version = search_version(out) cls: T.Type[RustCompiler] = rust.RustCompiler # Clippy is a wrapper around rustc, but it doesn't have rustc in it's # output. We can otherwise treat it as rustc. if 'clippy' in out: # clippy returns its own version and not the rustc version by # default so try harder here to get the correct version. # Also replace the whole output with the rustc output in # case this is later used for other purposes. arg = ['--rustc', '--version'] try: out = Popen_safe(compiler + arg)[1] except OSError as e: popen_exceptions[join_args(compiler + arg)] = e continue version = search_version(out) cls = rust.ClippyRustCompiler 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 any(a.startswith('linker=') for a in compiler): mlog.warning( 'Please do not put -C linker= in your compiler ' 'command, set rust_ld=command in your cross file ' 'or use the RUSTC_LD environment variable, otherwise meson ' 'will override your selection.') compiler = compiler.copy() # avoid mutating the original list if override is None: extra_args: T.Dict[str, T.Union[str, bool]] = {} always_args: T.List[str] = [] if is_link_exe: compiler.extend(cls.use_linker_args(cc.linker.exelist[0], '')) extra_args['direct'] = True extra_args['machine'] = cc.linker.machine else: exelist = cc.linker.exelist + cc.linker.get_always_args() if os.path.basename(exelist[0]) in {'ccache', 'sccache'}: del exelist[0] c = exelist.pop(0) compiler.extend(cls.use_linker_args(c, '')) # Also ensure that we pass any extra arguments to the linker for l in exelist: compiler.extend(['-C', f'link-arg={l}']) # This trickery with type() gets us the class of the linker # so we can initialize a new copy for the Rust Compiler # TODO rewrite this without type: ignore assert cc.linker is not None, 'for mypy' if is_link_exe: linker = type(cc.linker)(for_machine, always_args, exelist=cc.linker.exelist, # type: ignore version=cc.linker.version, **extra_args) # type: ignore 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 = guess_win_linker(env, override, cls, version, for_machine, use_linker_prefix=False) # rustc takes linker arguments without a prefix, and # inserts the correct prefix itself. assert isinstance(linker, linkers.VisualStudioLikeLinkerMixin) linker.direct = True compiler.extend(cls.use_linker_args(linker.exelist[0], '')) else: # On linux and macos rust will invoke the c compiler for # linking, on windows it will use lld-link or link.exe. # we will simply ask for the C compiler that corresponds to # it, and use that. cc = _detect_c_or_cpp_compiler(env, 'c', for_machine, override_compiler=override) linker = cc.linker # 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 = linker.exelist[1] if linker.exelist[0].endswith('ccache') else linker.exelist[0] compiler.extend(cls.use_linker_args(c, '')) env.coredata.add_lang_args(cls.language, cls, for_machine, env) return cls( compiler, version, for_machine, is_cross, info, exe_wrap, linker=linker) _handle_exceptions(popen_exceptions, compilers) raise EnvironmentException('Unreachable code (exception to make mypy happy)') def detect_d_compiler(env: 'Environment', for_machine: MachineChoice) -> Compiler: from . import c, d info = env.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': detect_c_compiler(env, for_machine)} is_msvc = isinstance(c_compiler['c'], c.VisualStudioCCompiler) if not is_msvc: c_compiler = {} # Import here to avoid circular imports from ..environment import detect_cpu_family arch = detect_cpu_family(c_compiler) if is_msvc and arch == 'x86': arch = 'x86_mscoff' popen_exceptions = {} is_cross = env.is_cross_build(for_machine) compilers, ccache, exe_wrap = _get_compilers(env, 'd', for_machine) cls: T.Type[d.DCompiler] for exelist in compilers: # 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 os.path.basename(exelist[-1]).startswith(('ldmd', 'gdmd')): raise EnvironmentException( f'Meson does not support {exelist[-1]} 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.') try: p, out = Popen_safe(exelist + ['--version'])[0:2] except OSError as e: popen_exceptions[join_args(exelist + ['--version'])] = e continue version = search_version(out) full_version = out.split('\n', 1)[0] if 'LLVM D compiler' in out: cls = d.LLVMDCompiler # LDC seems to require a file # We cannot use NamedTemporaryFile on windows, its documented # to not work for our uses. So, just use mkstemp and only have # one path for simplicity. o, f = tempfile.mkstemp('.d') os.close(o) try: if info.is_windows() or info.is_cygwin(): objfile = os.path.basename(f)[:-1] + 'obj' linker = guess_win_linker(env, exelist, cls, full_version, for_machine, use_linker_prefix=True, invoked_directly=False, extra_args=[f]) else: # LDC writes an object file to the current working directory. # Clean it up. objfile = os.path.basename(f)[:-1] + 'o' linker = guess_nix_linker(env, exelist, cls, full_version, for_machine, extra_args=[f]) finally: windows_proof_rm(f) windows_proof_rm(objfile) return cls( exelist, version, for_machine, info, arch, full_version=full_version, linker=linker, version_output=out) elif 'gdc' in out: cls = d.GnuDCompiler linker = guess_nix_linker(env, exelist, cls, version, for_machine) return cls( exelist, version, for_machine, info, arch, exe_wrapper=exe_wrap, is_cross=is_cross, full_version=full_version, linker=linker) elif 'The D Language Foundation' in out or 'Digital Mars' in out: cls = d.DmdDCompiler # DMD seems to require a file # We cannot use NamedTemporaryFile on windows, its documented # to not work for our uses. So, just use mkstemp and only have # one path for simplicity. o, f = tempfile.mkstemp('.d') os.close(o) # DMD as different detection logic for x86 and x86_64 arch_arg = '-m64' if arch == 'x86_64' else '-m32' try: if info.is_windows() or info.is_cygwin(): objfile = os.path.basename(f)[:-1] + 'obj' linker = guess_win_linker(env, exelist, cls, full_version, for_machine, invoked_directly=False, extra_args=[f, arch_arg]) else: objfile = os.path.basename(f)[:-1] + 'o' linker = guess_nix_linker(env, exelist, cls, full_version, for_machine, extra_args=[f, arch_arg]) finally: windows_proof_rm(f) windows_proof_rm(objfile) return cls( exelist, version, for_machine, info, arch, full_version=full_version, linker=linker) raise EnvironmentException('Unknown compiler: ' + join_args(exelist)) _handle_exceptions(popen_exceptions, compilers) raise EnvironmentException('Unreachable code (exception to make mypy happy)') def detect_swift_compiler(env: 'Environment', for_machine: MachineChoice) -> Compiler: from .swift import SwiftCompiler exelist = env.lookup_binary_entry(for_machine, 'swift') is_cross = env.is_cross_build(for_machine) info = env.machines[for_machine] if exelist is None: # TODO support fallback exelist = [defaults['swift'][0]] try: p, _, err = Popen_safe_logged(exelist + ['-v'], msg='Detecting compiler via') except OSError: raise EnvironmentException('Could not execute Swift compiler: {}'.format(join_args(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: cls = SwiftCompiler linker = guess_nix_linker(env, exelist, cls, version, for_machine, extra_args=[f.name]) return cls( exelist, version, for_machine, is_cross, info, linker=linker) raise EnvironmentException('Unknown compiler: ' + join_args(exelist)) def detect_nasm_compiler(env: 'Environment', for_machine: MachineChoice) -> Compiler: from .asm import NasmCompiler, YasmCompiler, MetrowerksAsmCompilerARM, MetrowerksAsmCompilerEmbeddedPowerPC compilers, _, _ = _get_compilers(env, 'nasm', for_machine) is_cross = env.is_cross_build(for_machine) # We need a C compiler to properly detect the machine info and linker cc = detect_c_compiler(env, for_machine) if not is_cross: from ..environment import detect_machine_info info = detect_machine_info({'c': cc}) else: info = env.machines[for_machine] popen_exceptions: T.Dict[str, Exception] = {} for comp in compilers: if comp == ['nasm'] and is_windows() and not shutil.which(comp[0]): # nasm is not in PATH on Windows by default default_path = os.path.join(os.environ['ProgramFiles'], 'NASM') comp[0] = shutil.which(comp[0], path=default_path) or comp[0] try: output = Popen_safe_logged(comp + ['--version'], msg='Detecting compiler via')[1] except OSError as e: popen_exceptions[' '.join(comp + ['--version'])] = e continue version = search_version(output) if 'NASM' in output: comp_class = NasmCompiler env.coredata.add_lang_args(comp_class.language, comp_class, for_machine, env) return comp_class([], comp, version, for_machine, info, cc.linker, is_cross=is_cross) elif 'yasm' in output: comp_class = YasmCompiler env.coredata.add_lang_args(comp_class.language, comp_class, for_machine, env) return comp_class([], comp, version, for_machine, info, cc.linker, is_cross=is_cross) elif 'Metrowerks' in output or 'Freescale' in output: if 'ARM' in output: comp_class_mwasmarm = MetrowerksAsmCompilerARM env.coredata.add_lang_args(comp_class_mwasmarm.language, comp_class_mwasmarm, for_machine, env) return comp_class_mwasmarm([], comp, version, for_machine, info, cc.linker, is_cross=is_cross) else: comp_class_mwasmeppc = MetrowerksAsmCompilerEmbeddedPowerPC env.coredata.add_lang_args(comp_class_mwasmeppc.language, comp_class_mwasmeppc, for_machine, env) return comp_class_mwasmeppc([], comp, version, for_machine, info, cc.linker, is_cross=is_cross) _handle_exceptions(popen_exceptions, compilers) raise EnvironmentException('Unreachable code (exception to make mypy happy)') def detect_masm_compiler(env: 'Environment', for_machine: MachineChoice) -> Compiler: # We need a C compiler to properly detect the machine info and linker is_cross = env.is_cross_build(for_machine) cc = detect_c_compiler(env, for_machine) if not is_cross: from ..environment import detect_machine_info info = detect_machine_info({'c': cc}) else: info = env.machines[for_machine] from .asm import MasmCompiler, MasmARMCompiler comp_class: T.Type[Compiler] if info.cpu_family == 'x86': comp = ['ml'] comp_class = MasmCompiler arg = '/?' elif info.cpu_family == 'x86_64': comp = ['ml64'] comp_class = MasmCompiler arg = '/?' elif info.cpu_family == 'arm': comp = ['armasm'] comp_class = MasmARMCompiler arg = '-h' elif info.cpu_family == 'aarch64': comp = ['armasm64'] comp_class = MasmARMCompiler arg = '-h' else: raise EnvironmentException(f'Platform {info.cpu_family} not supported by MASM') popen_exceptions: T.Dict[str, Exception] = {} try: output = Popen_safe(comp + [arg])[2] version = search_version(output) env.coredata.add_lang_args(comp_class.language, comp_class, for_machine, env) return comp_class([], comp, version, for_machine, info, cc.linker, is_cross=is_cross) except OSError as e: popen_exceptions[' '.join(comp + [arg])] = e _handle_exceptions(popen_exceptions, [comp]) raise EnvironmentException('Unreachable code (exception to make mypy happy)') # GNU/Clang defines and version # ============================= def _get_gnu_compiler_defines(compiler: T.List[str]) -> T.Dict[str, str]: """ 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', '-'] mlog.debug(f'Running command: {join_args(args)}') p, output, error = Popen_safe(args, write='', stdin=subprocess.PIPE) if p.returncode != 0: raise EnvironmentException('Unable to detect GNU compiler type:\n' f'Compiler stdout:\n{output}\n-----\n' f'Compiler stderr:\n{error}\n-----\n') # Parse several lines of the type: # `#define ___SOME_DEF some_value` # and extract `___SOME_DEF` defines: T.Dict[str, str] = {} 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[0]] = '' if len(rest) == 2: defines[rest[0]] = rest[1] return defines def _get_clang_compiler_defines(compiler: T.List[str]) -> T.Dict[str, str]: """ Get the list of Clang pre-processor defines """ args = compiler + ['-E', '-dM', '-'] mlog.debug(f'Running command: {join_args(args)}') p, output, error = Popen_safe(args, write='', stdin=subprocess.PIPE) if p.returncode != 0: raise EnvironmentException('Unable to get clang pre-processor defines:\n' f'Compiler stdout:\n{output}\n-----\n' f'Compiler stderr:\n{error}\n-----\n') defines: T.Dict[str, str] = {} 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[0]] = '' if len(rest) == 2: defines[rest[0]] = rest[1] return defines def _get_gnu_version_from_defines(defines: T.Dict[str, str]) -> str: dot = '.' major = defines.get('__GNUC__', '0') minor = defines.get('__GNUC_MINOR__', '0') patch = defines.get('__GNUC_PATCHLEVEL__', '0') return dot.join((major, minor, patch)) def _get_lcc_version_from_defines(defines: T.Dict[str, str]) -> str: 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)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/compilers/fortran.py0000644000175000017500000005641214562742363021237 0ustar00jpakkanejpakkane# 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 __future__ import annotations import typing as T import os from .. import coredata from .compilers import ( clike_debug_args, Compiler, CompileCheckMode, ) 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 mesonbuild.mesonlib import ( version_compare, MesonException, LibType, OptionKey, ) if T.TYPE_CHECKING: from ..coredata import MutableKeyedOptionDictType, KeyedOptionDictType from ..dependencies import Dependency from ..envconfig import MachineInfo from ..environment import Environment from ..linkers.linkers import DynamicLinker from ..mesonlib import MachineChoice from ..programs import ExternalProgram class FortranCompiler(CLikeCompiler, Compiler): language = 'fortran' def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): Compiler.__init__(self, [], exelist, version, for_machine, info, is_cross=is_cross, full_version=full_version, linker=linker) CLikeCompiler.__init__(self, exe_wrapper) 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) -> T.Tuple[bool, bool]: 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 _get_basic_compiler_args(self, env: 'Environment', mode: CompileCheckMode) -> T.Tuple[T.List[str], T.List[str]]: cargs = env.coredata.get_external_args(self.for_machine, self.language) largs = env.coredata.get_external_link_args(self.for_machine, self.language) return cargs, largs def sanity_check(self, work_dir: str, environment: 'Environment') -> None: source_name = 'sanitycheckf.f90' code = 'program main; print *, "Fortran compilation is working."; end program\n' return self._sanity_check_impl(work_dir, environment, source_name, code) def get_buildtype_args(self, buildtype: str) -> T.List[str]: return gnulike_buildtype_args[buildtype] def get_optimization_args(self, optimization_level: str) -> T.List[str]: return gnu_optimization_args[optimization_level] def get_debug_args(self, is_debug: bool) -> T.List[str]: return clike_debug_args[is_debug] def get_preprocess_only_args(self) -> T.List[str]: return ['-cpp'] + super().get_preprocess_only_args() def get_module_incdir_args(self) -> T.Tuple[str, ...]: return ('-I', ) def get_module_outdir_args(self, path: str) -> T.List[str]: return ['-module', 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] == '-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: str, env: 'Environment', extra_dirs: T.List[str], libtype: LibType = LibType.PREFER_SHARED, lib_prefix_warning: bool = True) -> T.Optional[T.List[str]]: code = 'stop; end program' return self._find_library_impl(libname, env, extra_dirs, code, libtype, lib_prefix_warning) def has_multi_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]: return self._has_multi_arguments(args, env, 'stop; end program') def has_multi_link_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]: return self._has_multi_link_arguments(args, env, 'stop; end program') def get_options(self) -> 'MutableKeyedOptionDictType': opts = super().get_options() key = OptionKey('std', machine=self.for_machine, lang=self.language) opts.update({ key: coredata.UserComboOption( 'Fortran language standard to use', ['none'], 'none', ), }) return opts class GnuFortranCompiler(GnuCompiler, FortranCompiler): def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, defines: T.Optional[T.Dict[str, str]] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) 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'], 'everything': default_warn_args + ['-Wextra', '-Wpedantic', '-fimplicit-none']} def get_options(self) -> 'MutableKeyedOptionDictType': 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'] key = OptionKey('std', machine=self.for_machine, lang=self.language) opts[key].choices = ['none'] + fortran_stds return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = OptionKey('std', machine=self.for_machine, lang=self.language) std = options[key] if std.value != 'none': args.append('-std=' + std.value) return args def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: # 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: str) -> T.List[str]: return ['-J' + path] def language_stdlib_only_link_flags(self, env: 'Environment') -> T.List[str]: # We need to apply the search prefix here, as these link arguments may # be passed to a different compiler with a different set of default # search paths, such as when using Clang for C/C++ and gfortran for # fortran, search_dirs: T.List[str] = [] for d in self.get_compiler_dirs(env, 'libraries'): search_dirs.append(f'-L{d}') return search_dirs + ['-lgfortran', '-lm'] def has_header(self, hname: str, prefix: str, env: 'Environment', *, extra_args: T.Union[None, T.List[str], T.Callable[['CompileCheckMode'], T.List[str]]] = None, dependencies: T.Optional[T.List['Dependency']] = None, disable_cache: bool = False) -> T.Tuple[bool, bool]: ''' Derived from mixins/clike.py:has_header, but without C-style usage of __has_include which breaks with GCC-Fortran 10: https://github.com/mesonbuild/meson/issues/7017 ''' code = f'{prefix}\n#include <{hname}>' return self.compiles(code, env, extra_args=extra_args, dependencies=dependencies, mode=CompileCheckMode.PREPROCESS, disable_cache=disable_cache) class ElbrusFortranCompiler(ElbrusCompiler, FortranCompiler): def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, defines: T.Optional[T.Dict[str, str]] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) ElbrusCompiler.__init__(self) def get_options(self) -> 'MutableKeyedOptionDictType': opts = FortranCompiler.get_options(self) fortran_stds = ['f95', 'f2003', 'f2008', 'gnu', 'legacy', 'f2008ts'] key = OptionKey('std', machine=self.for_machine, lang=self.language) opts[key].choices = ['none'] + fortran_stds return opts def get_module_outdir_args(self, path: str) -> T.List[str]: return ['-J' + path] class G95FortranCompiler(FortranCompiler): LINKER_PREFIX = '-Wl,' id = 'g95' def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) default_warn_args = ['-Wall'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-pedantic'], 'everything': default_warn_args + ['-Wextra', '-pedantic']} def get_module_outdir_args(self, path: str) -> T.List[str]: return ['-fmod=' + path] def get_no_warn_args(self) -> T.List[str]: # FIXME: Confirm that there's no compiler option to disable all warnings return [] class SunFortranCompiler(FortranCompiler): LINKER_PREFIX = '-Wl,' id = 'sun' def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: return ['-fpp'] def get_always_args(self) -> T.List[str]: return [] def get_warn_args(self, level: str) -> T.List[str]: return [] def get_module_incdir_args(self) -> T.Tuple[str, ...]: return ('-M', ) def get_module_outdir_args(self, path: str) -> T.List[str]: return ['-moddir=' + path] def openmp_flags(self) -> T.List[str]: return ['-xopenmp'] class IntelFortranCompiler(IntelGnuLikeCompiler, FortranCompiler): file_suffixes = ('f90', 'f', 'for', 'ftn', 'fpp', ) id = 'intel' def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) # FIXME: Add support for OS X and Windows in detect_fortran_compiler so # we are sent the type of compiler IntelGnuLikeCompiler.__init__(self) 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'], 'everything': ['-warn', 'all']} def get_options(self) -> 'MutableKeyedOptionDictType': opts = FortranCompiler.get_options(self) key = OptionKey('std', machine=self.for_machine, lang=self.language) opts[key].choices = ['none', 'legacy', 'f95', 'f2003', 'f2008', 'f2018'] return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = OptionKey('std', machine=self.for_machine, lang=self.language) std = options[key] 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) -> T.List[str]: return ['-cpp', '-EP'] def language_stdlib_only_link_flags(self, env: 'Environment') -> T.List[str]: # TODO: needs default search path added return ['-lifcore', '-limf'] def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: return ['-gen-dep=' + outtarget, '-gen-depformat=make'] class IntelLLVMFortranCompiler(IntelFortranCompiler): id = 'intel-llvm' class IntelClFortranCompiler(IntelVisualStudioLikeCompiler, FortranCompiler): file_suffixes = ('f90', 'f', 'for', 'ftn', 'fpp', ) always_args = ['/nologo'] def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', target: str, exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) 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'], 'everything': ['/warn:all']} def get_options(self) -> 'MutableKeyedOptionDictType': opts = FortranCompiler.get_options(self) key = OptionKey('std', machine=self.for_machine, lang=self.language) opts[key].choices = ['none', 'legacy', 'f95', 'f2003', 'f2008', 'f2018'] return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = OptionKey('std', machine=self.for_machine, lang=self.language) std = options[key] 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: str) -> T.List[str]: return ['/module:' + path] class IntelLLVMClFortranCompiler(IntelClFortranCompiler): id = 'intel-llvm-cl' class PathScaleFortranCompiler(FortranCompiler): id = 'pathscale' def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) default_warn_args = ['-fullwarn'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args, '3': default_warn_args, 'everything': default_warn_args} def openmp_flags(self) -> T.List[str]: return ['-mp'] class PGIFortranCompiler(PGICompiler, FortranCompiler): def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) 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'], 'everything': default_warn_args + ['-Mdclchk']} def language_stdlib_only_link_flags(self, env: 'Environment') -> T.List[str]: # TODO: needs default search path added return ['-lpgf90rtl', '-lpgf90', '-lpgf90_rpm1', '-lpgf902', '-lpgf90rtl', '-lpgftnrtl', '-lrt'] class NvidiaHPC_FortranCompiler(PGICompiler, FortranCompiler): id = 'nvidia_hpc' def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) 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'], 'everything': default_warn_args + ['-Mdclchk']} class FlangFortranCompiler(ClangCompiler, FortranCompiler): id = 'flang' def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) ClangCompiler.__init__(self, {}) default_warn_args = ['-Minform=inform'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args, '3': default_warn_args, 'everything': default_warn_args} def language_stdlib_only_link_flags(self, env: 'Environment') -> T.List[str]: # We need to apply the search prefix here, as these link arguments may # be passed to a different compiler with a different set of default # search paths, such as when using Clang for C/C++ and gfortran for # fortran, # XXX: Untested.... search_dirs: T.List[str] = [] for d in self.get_compiler_dirs(env, 'libraries'): search_dirs.append(f'-L{d}') return search_dirs + ['-lflang', '-lpgmath'] class ArmLtdFlangFortranCompiler(FlangFortranCompiler): id = 'armltdflang' class Open64FortranCompiler(FortranCompiler): id = 'open64' def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) default_warn_args = ['-fullwarn'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args, '3': default_warn_args, 'everything': default_warn_args} def openmp_flags(self) -> T.List[str]: return ['-mp'] class NAGFortranCompiler(FortranCompiler): id = 'nagfor' def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, linker: T.Optional['DynamicLinker'] = None, full_version: T.Optional[str] = None): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) # Warnings are on by default; -w disables (by category): self.warn_args = { '0': ['-w=all'], '1': [], '2': [], '3': [], 'everything': [], } def get_always_args(self) -> T.List[str]: return self.get_nagfor_quiet(self.version) def get_module_outdir_args(self, path: str) -> T.List[str]: return ['-mdir', path] @staticmethod def get_nagfor_quiet(version: str) -> T.List[str]: return ['-quiet'] if version_compare(version, '>=7100') else [] def get_pic_args(self) -> T.List[str]: return ['-PIC'] def get_preprocess_only_args(self) -> T.List[str]: return ['-fpp'] def get_std_exe_link_args(self) -> T.List[str]: return self.get_always_args() def openmp_flags(self) -> T.List[str]: return ['-openmp'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/compilers/java.py0000644000175000017500000001112214562742363020472 0ustar00jpakkanejpakkane# 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 __future__ import annotations import os import os.path import shutil import subprocess import textwrap import typing as T from ..mesonlib import EnvironmentException from .compilers import Compiler, java_buildtype_args from .mixins.islinker import BasicLinkerIsCompilerMixin if T.TYPE_CHECKING: from ..envconfig import MachineInfo from ..environment import Environment from ..mesonlib import MachineChoice class JavaCompiler(BasicLinkerIsCompilerMixin, Compiler): language = 'java' id = 'unknown' _WARNING_LEVELS: T.Dict[str, T.List[str]] = { '0': ['-nowarn'], '1': ['-Xlint:all'], '2': ['-Xlint:all', '-Xdoclint:all'], '3': ['-Xlint:all', '-Xdoclint:all'], } def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, info: 'MachineInfo', full_version: T.Optional[str] = None): super().__init__([], exelist, version, for_machine, info, full_version=full_version) self.javarunner = 'java' def get_warn_args(self, level: str) -> T.List[str]: return self._WARNING_LEVELS[level] def get_werror_args(self) -> T.List[str]: return ['-Werror'] def get_no_warn_args(self) -> T.List[str]: return ['-nowarn'] def get_output_args(self, outputname: str) -> T.List[str]: if outputname == '': outputname = './' return ['-d', outputname, '-s', outputname] def get_pic_args(self) -> T.List[str]: return [] def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: return [] def get_pch_name(self, name: str) -> str: return '' def get_buildtype_args(self, buildtype: str) -> T.List[str]: return java_buildtype_args[buildtype] 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 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: str, environment: 'Environment') -> None: src = 'SanityCheck.java' obj = 'SanityCheck' source_name = os.path.join(work_dir, src) with open(source_name, 'w', encoding='utf-8') as ofile: ofile.write(textwrap.dedent( '''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(f'Java compiler {self.name_string()} cannot compile programs.') runner = shutil.which(self.javarunner) if runner: cmdlist = [runner, '-cp', '.', obj] pe = subprocess.Popen(cmdlist, cwd=work_dir) pe.wait() if pe.returncode != 0: raise EnvironmentException(f'Executables created by Java compiler {self.name_string()} are not runnable.') 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) -> bool: return False def get_optimization_args(self, optimization_level: str) -> T.List[str]: return [] def get_debug_args(self, is_debug: bool) -> T.List[str]: if is_debug: return ['-g'] return ['-g:none'] ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.646638 meson-1.3.2/mesonbuild/compilers/mixins/0000755000175000017500000000000014562742414020506 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1650551419.0 meson-1.3.2/mesonbuild/compilers/mixins/__init__.py0000644000175000017500000000000014230265173022577 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/compilers/mixins/arm.py0000644000175000017500000001617414562742363021653 0ustar00jpakkanejpakkane# Copyright 2012-2020 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 __future__ import annotations """Representations specific to the arm family of compilers.""" import os import typing as T from ... import mesonlib from ...linkers.linkers import ArmClangDynamicLinker from ...mesonlib import OptionKey from ..compilers import clike_debug_args from .clang import clang_color_args if T.TYPE_CHECKING: from ...environment import Environment from ...compilers.compilers import Compiler else: # This is a bit clever, for mypy we pretend that these mixins descend from # Compiler, so we get all of the methods and attributes defined for us, but # for runtime we make them descend from object (which all classes normally # do). This gives up DRYer type checking, with no runtime impact Compiler = object arm_buildtype_args: T.Dict[str, T.List[str]] = { 'plain': [], 'debug': [], 'debugoptimized': [], 'release': [], 'minsize': [], 'custom': [], } arm_optimization_args: T.Dict[str, T.List[str]] = { 'plain': [], '0': ['-O0'], 'g': ['-g'], '1': ['-O1'], '2': [], # Compiler defaults to -O2 '3': ['-O3', '-Otime'], 's': ['-O3'], # Compiler defaults to -Ospace } armclang_buildtype_args: T.Dict[str, T.List[str]] = { 'plain': [], 'debug': [], 'debugoptimized': [], 'release': [], 'minsize': [], 'custom': [], } armclang_optimization_args: T.Dict[str, T.List[str]] = { 'plain': [], '0': [], # Compiler defaults to -O0 'g': ['-g'], '1': ['-O1'], '2': ['-O2'], '3': ['-O3'], 's': ['-Oz'] } class ArmCompiler(Compiler): """Functionality that is common to all ARM family compilers.""" id = 'arm' def __init__(self) -> None: if not self.is_cross: raise mesonlib.EnvironmentException('armcc supports only cross-compilation.') default_warn_args: T.List[str] = [] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + [], '3': default_warn_args + [], 'everything': default_warn_args + []} # Assembly self.can_compile_suffixes.add('s') self.can_compile_suffixes.add('sx') 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 [] def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: return ['--depend_target', outtarget, '--depend', outfile, '--depend_single_line'] 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(Compiler): ''' This is the Keil armclang. ''' id = 'armclang' def __init__(self) -> None: if not self.is_cross: raise mesonlib.EnvironmentException('armclang supports only cross-compilation.') # Check whether 'armlink' is available in path if not isinstance(self.linker, ArmClangDynamicLinker): raise mesonlib.EnvironmentException(f'Unsupported Linker {self.linker.exelist}, must be armlink') if not mesonlib.version_compare(self.version, '==' + self.linker.version): raise mesonlib.EnvironmentException('armlink version does not match with compiler version') self.base_options = { OptionKey(o) for o in ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage', 'b_ndebug', 'b_staticpic', 'b_colorout']} # Assembly self.can_compile_suffixes.add('s') self.can_compile_suffixes.add('sx') def get_pic_args(self) -> 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))] def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: return ['-MD', '-MT', outtarget, '-MF', outfile] 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/compilers/mixins/ccrx.py0000644000175000017500000001042614562742363022025 0ustar00jpakkanejpakkane# 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 __future__ import annotations """Representations specific to the Renesas CC-RX compiler family.""" import os import typing as T from ...mesonlib import EnvironmentException if T.TYPE_CHECKING: from ...envconfig import MachineInfo from ...environment import Environment from ...compilers.compilers import Compiler else: # This is a bit clever, for mypy we pretend that these mixins descend from # Compiler, so we get all of the methods and attributes defined for us, but # for runtime we make them descend from object (which all classes normally # do). This gives up DRYer type checking, with no runtime impact Compiler = object ccrx_buildtype_args: T.Dict[str, T.List[str]] = { 'plain': [], 'debug': [], 'debugoptimized': [], 'release': [], 'minsize': [], 'custom': [], } ccrx_optimization_args: T.Dict[str, T.List[str]] = { '0': ['-optimize=0'], 'g': ['-optimize=0'], '1': ['-optimize=1'], '2': ['-optimize=2'], '3': ['-optimize=max'], 's': ['-optimize=2', '-size'] } ccrx_debug_args: T.Dict[bool, T.List[str]] = { False: [], True: ['-debug'] } class CcrxCompiler(Compiler): if T.TYPE_CHECKING: is_cross = True can_compile_suffixes: T.Set[str] = set() id = 'ccrx' def __init__(self) -> None: if not self.is_cross: raise EnvironmentException('ccrx supports only cross-compilation.') # Assembly self.can_compile_suffixes.add('src') default_warn_args: T.List[str] = [] self.warn_args: T.Dict[str, T.List[str]] = { '0': [], '1': default_warn_args, '2': default_warn_args + [], '3': default_warn_args + [], 'everything': 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 [] 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], info: MachineInfo) -> T.List[str]: result: T.List[str] = [] 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/mesonbuild/compilers/mixins/clang.py0000644000175000017500000002001414562742363022144 0ustar00jpakkanejpakkane# Copyright 2019-2022 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 __future__ import annotations """Abstractions for the LLVM/Clang compiler family.""" import os import shutil import typing as T from ... import mesonlib from ...linkers.linkers import AppleDynamicLinker, ClangClDynamicLinker, LLVMDynamicLinker, GnuGoldDynamicLinker, \ MoldDynamicLinker from ...mesonlib import OptionKey from ..compilers import CompileCheckMode from .gnu import GnuLikeCompiler if T.TYPE_CHECKING: from ...environment import Environment from ...dependencies import Dependency # noqa: F401 clang_color_args: T.Dict[str, T.List[str]] = { 'auto': ['-fdiagnostics-color=auto'], 'always': ['-fdiagnostics-color=always'], 'never': ['-fdiagnostics-color=never'], } clang_optimization_args: T.Dict[str, T.List[str]] = { 'plain': [], '0': ['-O0'], 'g': ['-Og'], '1': ['-O1'], '2': ['-O2'], '3': ['-O3'], 's': ['-Oz'], } class ClangCompiler(GnuLikeCompiler): id = 'clang' def __init__(self, defines: T.Optional[T.Dict[str, str]]): super().__init__() self.defines = defines or {} self.base_options.update( {OptionKey('b_colorout'), OptionKey('b_lto_threads'), OptionKey('b_lto_mode'), OptionKey('b_thinlto_cache'), OptionKey('b_thinlto_cache_dir')}) # 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.add(OptionKey('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 has_builtin_define(self, define: str) -> bool: return define in self.defines def get_builtin_define(self, define: str) -> T.Optional[str]: return self.defines.get(define) def get_optimization_args(self, optimization_level: str) -> T.List[str]: return clang_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 get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: # Clang is different than GCC, it will return True when a symbol isn't # defined in a header. Specifically this seems to have something to do # with functions that may be in a header on some systems, but not all of # them. `strlcat` specifically with can trigger this. myargs: T.List[str] = ['-Werror=implicit-function-declaration'] if mode is CompileCheckMode.COMPILE: myargs.extend(['-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().get_compiler_check_args(mode) + myargs 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) -> T.Tuple[bool, 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 [] @classmethod def use_linker_args(cls, linker: str, version: str) -> T.List[str]: # Clang additionally can use a linker specified as a path, which GCC # (and other gcc-like compilers) cannot. This is because clang (being # llvm based) is retargetable, while GCC is not. # # qcld: Qualcomm Snapdragon linker, based on LLVM if linker == 'qcld': return ['-fuse-ld=qcld'] if linker == 'mold': return ['-fuse-ld=mold'] if shutil.which(linker): if not shutil.which(linker): raise mesonlib.MesonException( f'Cannot find linker {linker}.') return [f'-fuse-ld={linker}'] return super().use_linker_args(linker, version) def get_has_func_attribute_extra_args(self, name: str) -> T.List[str]: # Clang only warns about unknown or ignored attributes, so force an # error. return ['-Werror=attributes'] def get_coverage_link_args(self) -> T.List[str]: return ['--coverage'] def get_lto_compile_args(self, *, threads: int = 0, mode: str = 'default') -> T.List[str]: args: T.List[str] = [] if mode == 'thin': # ThinLTO requires the use of gold, lld, ld64, lld-link or mold 1.1+ if isinstance(self.linker, (MoldDynamicLinker)): # https://github.com/rui314/mold/commit/46995bcfc3e3113133620bf16445c5f13cd76a18 if not mesonlib.version_compare(self.linker.version, '>=1.1'): raise mesonlib.MesonException("LLVM's ThinLTO requires mold 1.1+") elif not isinstance(self.linker, (AppleDynamicLinker, ClangClDynamicLinker, LLVMDynamicLinker, GnuGoldDynamicLinker)): raise mesonlib.MesonException(f"LLVM's ThinLTO only works with gold, lld, lld-link, ld64 or mold, not {self.linker.id}") args.append(f'-flto={mode}') else: assert mode == 'default', 'someone forgot to wire something up' args.extend(super().get_lto_compile_args(threads=threads)) return args def get_lto_link_args(self, *, threads: int = 0, mode: str = 'default', thinlto_cache_dir: T.Optional[str] = None) -> T.List[str]: args = self.get_lto_compile_args(threads=threads, mode=mode) if mode == 'thin' and thinlto_cache_dir is not None: # We check for ThinLTO linker support above in get_lto_compile_args, and all of them support # get_thinlto_cache_args as well args.extend(self.linker.get_thinlto_cache_args(thinlto_cache_dir)) # In clang -flto-jobs=0 means auto, and is the default if unspecified, just like in meson if threads > 0: if not mesonlib.version_compare(self.version, '>=4.0.0'): raise mesonlib.MesonException('clang support for LTO threads requires clang >=4.0') args.append(f'-flto-jobs={threads}') return args ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0 meson-1.3.2/mesonbuild/compilers/mixins/clike.py0000644000175000017500000017413014562742373022161 0ustar00jpakkanejpakkane# Copyright 2012-2023 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 __future__ import annotations """Mixin classes to be shared between C and C++ compilers. Without this we'll end up with awful diamond inheritance 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 collections import functools import glob import itertools import os import re import subprocess import copy import typing as T from pathlib import Path from ... import arglist from ... import mesonlib from ... import mlog from ...linkers.linkers import GnuLikeDynamicLinkerMixin, SolarisDynamicLinker, CompCertDynamicLinker from ...mesonlib import LibType, OptionKey from .. import compilers from ..compilers import CompileCheckMode from .visualstudio import VisualStudioLikeCompiler if T.TYPE_CHECKING: from ...dependencies import Dependency from ..._typing import ImmutableListProtocol from ...environment import Environment from ...compilers.compilers import Compiler from ...programs import ExternalProgram else: # This is a bit clever, for mypy we pretend that these mixins descend from # Compiler, so we get all of the methods and attributes defined for us, but # for runtime we make them descend from object (which all classes normally # do). This gives up DRYer type checking, with no runtime impact Compiler = object GROUP_FLAGS = re.compile(r'''\.so (?:\.[0-9]+)? (?:\.[0-9]+)? (?:\.[0-9]+)?$ | ^(?:-Wl,)?-l | \.a$''', re.X) class CLikeCompilerArgs(arglist.CompilerArgs): prepend_prefixes = ('-I', '-L') dedup2_prefixes = ('-I', '-isystem', '-L', '-D', '-U') # 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') dedup1_args = ('-c', '-S', '-E', '-pipe', '-pthread') def to_native(self, copy: bool = False) -> T.List[str]: # This seems to be allowed, but could never work? assert isinstance(self.compiler, compilers.Compiler), 'How did you get here' # 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. self.flush_pre_post() 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.linker, (GnuLikeDynamicLinkerMixin, SolarisDynamicLinker, CompCertDynamicLinker)): group_start = -1 group_end = -1 for i, each in enumerate(new): if not GROUP_FLAGS.search(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 default_dirs = self.compiler.get_default_include_dirs() if default_dirs: real_default_dirs = [self._cached_realpath(i) for i in default_dirs] bad_idx_list: T.List[int] = [] for i, each in enumerate(new): if not each.startswith('-isystem'): continue # Remove the -isystem and the path if the path is a default path if (each == '-isystem' and i < (len(new) - 1) and self._cached_realpath(new[i + 1]) in real_default_dirs): bad_idx_list += [i, i + 1] elif each.startswith('-isystem=') and self._cached_realpath(each[9:]) in real_default_dirs: bad_idx_list += [i] elif self._cached_realpath(each[8:]) in real_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) @staticmethod @functools.lru_cache(maxsize=None) def _cached_realpath(arg: str) -> str: return os.path.realpath(arg) def __repr__(self) -> str: self.flush_pre_post() return f'CLikeCompilerArgs({self.compiler!r}, {self._container!r})' class CLikeCompiler(Compiler): """Shared bits for the C and CPP Compilers.""" if T.TYPE_CHECKING: warn_args: T.Dict[str, T.List[str]] = {} # TODO: Replace this manual cache with functools.lru_cache find_library_cache: T.Dict[T.Tuple[T.Tuple[str, ...], str, T.Tuple[str, ...], str, LibType], T.Optional[T.List[str]]] = {} find_framework_cache: T.Dict[T.Tuple[T.Tuple[str, ...], str, T.Tuple[str, ...], bool], T.Optional[T.List[str]]] = {} internal_libs = arglist.UNIXY_COMPILER_INTERNAL_LIBS def __init__(self, exe_wrapper: T.Optional['ExternalProgram'] = None): # If a child ObjC or CPP class has already set it, don't set it ourselves 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() or not exe_wrapper.get_command(): self.exe_wrapper = None else: self.exe_wrapper = exe_wrapper # Lazy initialized in get_preprocessor() self.preprocessor: T.Optional[Compiler] = None def compiler_args(self, args: T.Optional[T.Iterable[str]] = None) -> CLikeCompilerArgs: # This is correct, mypy just doesn't understand co-operative inheritance return CLikeCompilerArgs(self, args) def needs_static_linker(self) -> bool: return True # When compiling static libraries, so yes. def get_always_args(self) -> T.List[str]: ''' Args that are always-on for all C compilers other than MSVC ''' return self.get_largefile_args() def get_no_stdinc_args(self) -> T.List[str]: return ['-nostdinc'] def get_no_stdlib_link_args(self) -> T.List[str]: return ['-nostdlib'] def get_warn_args(self, level: str) -> T.List[str]: # TODO: this should be an enum return self.warn_args[level] def get_no_warn_args(self) -> T.List[str]: # Almost every compiler uses this for disabling warnings return ['-w'] def get_depfile_suffix(self) -> str: return 'd' def get_preprocess_only_args(self) -> T.List[str]: return ['-E', '-P'] def get_compile_only_args(self) -> T.List[str]: return ['-c'] def get_no_optimization_args(self) -> T.List[str]: return ['-O0'] def get_output_args(self, outputname: str) -> T.List[str]: return ['-o', outputname] def get_werror_args(self) -> T.List[str]: return ['-Werror'] def get_include_args(self, path: str, is_system: bool) -> T.List[str]: 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: 'Environment', elf_class: T.Optional[int] = None) -> 'ImmutableListProtocol[str]': # TODO: replace elf_class with enum 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: T.List[str] = [] 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 for f in files: file_to_check = os.path.join(d, f) try: 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 # stop scanning after the first successful read break except OSError: # Skip the file if we can't read it pass return retval def get_library_dirs(self, env: 'Environment', elf_class: T.Optional[int] = None) -> T.List[str]: """Wrap the lru_cache so that we return a new copy and don't allow mutation of the cached value. """ return self._get_library_dirs(env, elf_class).copy() @functools.lru_cache() def _get_program_dirs(self, env: 'Environment') -> 'ImmutableListProtocol[str]': ''' 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_program_dirs(self, env: 'Environment') -> T.List[str]: return self._get_program_dirs(env).copy() def get_pic_args(self) -> T.List[str]: return ['-fPIC'] 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, name: str) -> str: return os.path.basename(name) + '.' + self.get_pch_suffix() def get_default_include_dirs(self) -> T.List[str]: 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: str, environment: 'Environment', sname: str, code: str) -> None: mlog.debug('Sanity testing ' + self.get_display_language() + ' compiler:', mesonlib.join_args(self.exelist)) mlog.debug(f'Is cross compiler: {self.is_cross!s}.') source_name = os.path.join(work_dir, sname) binname = sname.rsplit('.', 1)[0] mode = CompileCheckMode.LINK if self.is_cross: binname += '_cross' if self.exe_wrapper is None: # Linking cross built C/C++ 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 = CompileCheckMode.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', encoding='utf-8') 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 + [sname] + self.get_output_args(binname) + extra_flags pc, stdo, stde = mesonlib.Popen_safe(cmdlist, cwd=work_dir) mlog.debug('Sanity check compiler command line:', mesonlib.join_args(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(f'Compiler {self.name_string()} cannot compile programs.') # 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.get_command() + [binary_name] else: cmdlist = [binary_name] mlog.debug('Running test binary command: ', mesonlib.join_args(cmdlist)) try: # fortran code writes to stdout pe = subprocess.run(cmdlist, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) except Exception as e: raise mesonlib.EnvironmentException(f'Could not invoke sanity test executable: {e!s}.') if pe.returncode != 0: raise mesonlib.EnvironmentException(f'Executables created by {self.language} compiler {self.name_string()} are not runnable.') def sanity_check(self, work_dir: str, environment: 'Environment') -> None: 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: str, prefix: str, env: 'Environment', *, extra_args: T.Union[None, T.List[str], T.Callable[['CompileCheckMode'], T.List[str]]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: code = f'''{prefix} #include <{hname}>''' return self.compiles(code, env, extra_args=extra_args, dependencies=dependencies) def has_header(self, hname: str, prefix: str, env: 'Environment', *, extra_args: T.Union[None, T.List[str], T.Callable[['CompileCheckMode'], T.List[str]]] = None, dependencies: T.Optional[T.List['Dependency']] = None, disable_cache: bool = False) -> T.Tuple[bool, bool]: code = f'''{prefix} #ifdef __has_include #if !__has_include("{hname}") #error "Header '{hname}' could not be found" #endif #else #include <{hname}> #endif''' return self.compiles(code, env, extra_args=extra_args, dependencies=dependencies, mode=CompileCheckMode.PREPROCESS, disable_cache=disable_cache) def has_header_symbol(self, hname: str, symbol: str, prefix: str, env: 'Environment', *, extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: t = f'''{prefix} #include <{hname}> 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, env, extra_args=extra_args, dependencies=dependencies) def _get_basic_compiler_args(self, env: 'Environment', mode: CompileCheckMode) -> T.Tuple[T.List[str], T.List[str]]: cargs: T.List[str] = [] largs: T.List[str] = [] if mode is CompileCheckMode.LINK: # Sometimes we need to manually select the CRT to use with MSVC. # One example is when trying to do a compiler check that involves # linking with static libraries since MSVC won't select a CRT for # us in that case and will error out asking us to pick one. try: crt_val = env.coredata.options[OptionKey('b_vscrt')].value buildtype = env.coredata.options[OptionKey('buildtype')].value cargs += self.get_crt_compile_args(crt_val, buildtype) except (KeyError, AttributeError): pass # Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS and CPPFLAGS from the env sys_args = env.coredata.get_external_args(self.for_machine, self.language) if isinstance(sys_args, str): sys_args = [sys_args] # 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 is CompileCheckMode.LINK: ld_value = env.lookup_binary_entry(self.for_machine, self.language + '_ld') if ld_value is not None: largs += self.use_linker_args(ld_value[0], self.version) # 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 build_wrapper_args(self, env: 'Environment', extra_args: T.Union[None, arglist.CompilerArgs, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]], dependencies: T.Optional[T.List['Dependency']], mode: CompileCheckMode = CompileCheckMode.COMPILE) -> arglist.CompilerArgs: # TODO: the caller should handle the listing of these arguments if extra_args is None: extra_args = [] else: # TODO: we want to do this in the caller extra_args = mesonlib.listify(extra_args) extra_args = mesonlib.listify([e(mode.value) if callable(e) else e for e in extra_args]) if dependencies is None: dependencies = [] elif not isinstance(dependencies, collections.abc.Iterable): # TODO: we want to ensure the front end does the listifing here dependencies = [dependencies] # Collect compiler arguments cargs: arglist.CompilerArgs = self.compiler_args() largs: T.List[str] = [] for d in dependencies: # Add compile flags needed by dependencies cargs += d.get_compile_args() system_incdir = d.get_include_type() == 'system' for i in d.get_include_dirs(): for idir in i.to_string_list(env.get_source_dir(), env.get_build_dir()): cargs.extend(self.get_include_args(idir, system_incdir)) if mode is CompileCheckMode.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(mode) # 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 '/link' not in extra_args: extra_args += ['/link'] args = cargs + extra_args + largs return args def run(self, code: 'mesonlib.FileOrString', env: 'Environment', *, extra_args: T.Union[T.List[str], T.Callable[[CompileCheckMode], T.List[str]], None] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> compilers.RunResult: need_exe_wrapper = env.need_exe_wrapper(self.for_machine) if need_exe_wrapper 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=CompileCheckMode.LINK, want_output=True) as p: if p.returncode != 0: mlog.debug(f'Could not compile test file {p.input_name}: {p.returncode}\n') return compilers.RunResult(False) if need_exe_wrapper: cmdlist = self.exe_wrapper.get_command() + [p.output_name] else: cmdlist = [p.output_name] try: pe, so, se = mesonlib.Popen_safe(cmdlist) except Exception as e: mlog.debug(f'Could not run: {cmdlist} (error: {e})\n') 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: str, prefix: str, env: 'Environment', extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]], dependencies: T.Optional[T.List['Dependency']]) -> bool: t = f'''{prefix} #include int main(void) {{ static int a[1-2*!({expression})]; a[0]=0; return 0; }}''' return self.compiles(t, env, extra_args=extra_args, dependencies=dependencies)[0] def cross_compute_int(self, expression: str, low: T.Optional[int], high: T.Optional[int], guess: T.Optional[int], prefix: str, env: 'Environment', extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> int: # Try user's guess first if isinstance(guess, int): if self._compile_int(f'{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(f'{expression} >= 0', prefix, env, extra_args, dependencies): low = cur = 0 while self._compile_int(f'{expression} > {cur}', prefix, env, extra_args, dependencies): low = cur + 1 if low > maxint: raise mesonlib.EnvironmentException('Cross-compile check overflowed') cur = min(cur * 2 + 1, maxint) high = cur else: high = cur = -1 while self._compile_int(f'{expression} < {cur}', prefix, env, extra_args, dependencies): high = cur - 1 if high < minint: raise mesonlib.EnvironmentException('Cross-compile check overflowed') cur = max(cur * 2, minint) low = cur else: # Sanity check limits given by user if high < low: raise mesonlib.EnvironmentException('high limit smaller than low limit') condition = f'{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(f'{expression} <= {cur}', prefix, env, extra_args, dependencies): high = cur else: low = cur + 1 return low def compute_int(self, expression: str, low: T.Optional[int], high: T.Optional[int], guess: T.Optional[int], prefix: str, env: 'Environment', *, extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]], dependencies: T.Optional[T.List['Dependency']] = None) -> int: 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) t = f'''{prefix} #include #include int main(void) {{ printf("%ld\\n", (long)({expression})); return 0; }}''' res = self.run(t, 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: str, prefix: str, env: 'Environment', *, extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> int: if extra_args is None: extra_args = [] t = f'''{prefix} #include int main(void) {{ {typename} something; return 0; }}''' if not self.compiles(t, env, extra_args=extra_args, dependencies=dependencies)[0]: return -1 return self.cross_compute_int(f'sizeof({typename})', None, None, None, prefix, env, extra_args, dependencies) def sizeof(self, typename: str, prefix: str, env: 'Environment', *, extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[int, bool]: if extra_args is None: extra_args = [] if self.is_cross: r = self.cross_sizeof(typename, prefix, env, extra_args=extra_args, dependencies=dependencies) return r, False t = f'''{prefix} #include #include int main(void) {{ printf("%ld\\n", (long)(sizeof({typename}))); return 0; }}''' res = self.cached_run(t, env, extra_args=extra_args, dependencies=dependencies) if not res.compiled: return -1, False if res.returncode != 0: raise mesonlib.EnvironmentException('Could not run sizeof test binary.') return int(res.stdout), res.cached def cross_alignment(self, typename: str, prefix: str, env: 'Environment', *, extra_args: T.Optional[T.List[str]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> int: if extra_args is None: extra_args = [] t = f'''{prefix} #include int main(void) {{ {typename} something; return 0; }}''' if not self.compiles(t, env, extra_args=extra_args, dependencies=dependencies)[0]: return -1 t = f'''{prefix} #include struct tmp {{ char c; {typename} target; }};''' return self.cross_compute_int('offsetof(struct tmp, target)', None, None, None, t, env, extra_args, dependencies) def alignment(self, typename: str, prefix: str, env: 'Environment', *, extra_args: T.Optional[T.List[str]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[int, bool]: if extra_args is None: extra_args = [] if self.is_cross: r = self.cross_alignment(typename, prefix, env, extra_args=extra_args, dependencies=dependencies) return r, False t = f'''{prefix} #include #include struct tmp {{ char c; {typename} target; }}; int main(void) {{ printf("%d", (int)offsetof(struct tmp, target)); return 0; }}''' res = self.cached_run(t, 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(f'Could not determine alignment of {typename}. Sorry. You might want to file a bug.') return align, res.cached def get_define(self, dname: str, prefix: str, env: 'Environment', extra_args: T.Union[T.List[str], T.Callable[[CompileCheckMode], T.List[str]]], dependencies: T.Optional[T.List['Dependency']], disable_cache: bool = False) -> T.Tuple[str, bool]: delim_start = '"MESON_GET_DEFINE_DELIMITER_START"\n' delim_end = '\n"MESON_GET_DEFINE_DELIMITER_END"' sentinel_undef = '"MESON_GET_DEFINE_UNDEFINED_SENTINEL"' code = f''' {prefix} #ifndef {dname} # define {dname} {sentinel_undef} #endif {delim_start}{dname}{delim_end}''' args = self.build_wrapper_args(env, extra_args, dependencies, mode=CompileCheckMode.PREPROCESS).to_native() func = functools.partial(self.cached_compile, code, env.coredata, extra_args=args, mode=CompileCheckMode.PREPROCESS) if disable_cache: func = functools.partial(self.compile, code, extra_args=args, mode=CompileCheckMode.PREPROCESS) with func() as p: cached = p.cached if p.returncode != 0: raise mesonlib.EnvironmentException(f'Could not get define {dname!r}') # Get the preprocessed value between the delimiters star_idx = p.stdout.find(delim_start) end_idx = p.stdout.rfind(delim_end) if (star_idx == -1) or (end_idx == -1) or (star_idx == end_idx): raise mesonlib.MesonBugException('Delimiters not found in preprocessor output.') define_value = p.stdout[star_idx + len(delim_start):end_idx] if define_value == sentinel_undef: define_value = None else: # Merge string literals define_value = self._concatenate_string_literals(define_value).strip() return define_value, cached def get_return_value(self, fname: str, rtype: str, prefix: str, env: 'Environment', extra_args: T.Optional[T.List[str]], dependencies: T.Optional[T.List['Dependency']]) -> T.Union[str, int]: # TODO: rtype should be an enum. # TODO: maybe we can use overload to tell mypy when this will return int vs str? if rtype == 'string': fmt = '%s' cast = '(char*)' elif rtype == 'int': fmt = '%lli' cast = '(long long int)' else: raise AssertionError(f'BUG: Unknown return type {rtype!r}') code = f'''{prefix} #include int main(void) {{ printf ("{fmt}", {cast} {fname}()); return 0; }}''' res = self.run(code, env, extra_args=extra_args, dependencies=dependencies) if not res.compiled: raise mesonlib.EnvironmentException(f'Could not get return value of {fname}()') if rtype == 'string': return res.stdout elif rtype == 'int': try: return int(res.stdout.strip()) except ValueError: raise mesonlib.EnvironmentException(f'Return value of {fname}() is not an int') assert False, 'Unreachable' @staticmethod def _no_prototype_templ() -> T.Tuple[str, str]: """ 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() -> T.Tuple[str, str]: """ 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 long b = (long long) a; return (int) b; }}''' return head, main 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) -> T.Tuple[bool, bool]: """Determine if a function exists. 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(f'Cross variable {varname} is not a boolean.') # TODO: we really need a protocol for this, # # class StrProto(typing.Protocol): # def __str__(self) -> str: ... fargs: T.Dict[str, T.Union[str, bool, int]] = {'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 is_builtin = funcname.startswith('__builtin_') fargs['is_builtin'] = is_builtin fargs['__builtin_'] = '' if is_builtin else '__builtin_' t = '''{prefix} int main(void) {{ /* With some toolchains (MSYS2/mingw for example) the compiler * provides various builtins which are not really implemented and * fall back to the stdlib where they aren't provided and fail at * build/link time. In case the user provides a header, including * the header didn't lead to the function being defined, and the * function we are checking isn't a builtin itself we assume the * builtin is not functional and we just error out. */ #if !{no_includes:d} && !defined({func}) && !{is_builtin:d} #error "No definition for {__builtin_}{func} found in the prefix" #endif #ifdef __has_builtin #if !__has_builtin({__builtin_}{func}) #error "{__builtin_}{func} not found" #endif #elif ! defined({func}) {__builtin_}{func}; #endif return 0; }}''' return self.links(t.format(**fargs), env, extra_args=extra_args, dependencies=dependencies) def has_members(self, typename: str, membernames: T.List[str], prefix: str, env: 'Environment', *, extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: if extra_args is None: extra_args = [] # Create code that accesses all members members = ''.join(f'foo.{member};\n' for member in membernames) t = f'''{prefix} void bar(void) {{ {typename} foo; {members} }}''' return self.compiles(t, env, extra_args=extra_args, dependencies=dependencies) def has_type(self, typename: str, prefix: str, env: 'Environment', extra_args: T.Union[T.List[str], T.Callable[[CompileCheckMode], T.List[str]]], *, dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: t = f'''{prefix} void bar(void) {{ sizeof({typename}); }}''' return self.compiles(t, env, extra_args=extra_args, dependencies=dependencies) def _symbols_have_underscore_prefix_searchbin(self, env: 'Environment') -> bool: ''' Check if symbols have underscore prefix by compiling a small test binary and then searching the binary for the string, ''' 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(CompileCheckMode.COMPILE) n = '_symbols_have_underscore_prefix_searchbin' with self._build_wrapper(code, env, extra_args=args, mode=CompileCheckMode.COMPILE, want_output=True) as p: if p.returncode != 0: raise RuntimeError(f'BUG: Unable to compile {n!r} check: {p.stderr}') if not os.path.isfile(p.output_name): raise RuntimeError(f'BUG: Can\'t find compiled test code for {n!r} check') 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("Underscore prefix check found prefixed function in binary") return True # Else, check if the non-underscored form is present elif symbol_name in line: mlog.debug("Underscore prefix check found non-prefixed function in binary") return False raise RuntimeError(f'BUG: {n!r} check did not find symbol string in binary') def _symbols_have_underscore_prefix_define(self, env: 'Environment') -> T.Optional[bool]: ''' Check if symbols have underscore prefix by querying the __USER_LABEL_PREFIX__ define that most compilers provide for this. Return if functions have underscore prefix or None if it was not possible to determine, like when the compiler does not set the define or the define has an unexpected value. ''' delim = '"MESON_HAVE_UNDERSCORE_DELIMITER" ' code = f''' #ifndef __USER_LABEL_PREFIX__ #define MESON_UNDERSCORE_PREFIX unsupported #else #define MESON_UNDERSCORE_PREFIX __USER_LABEL_PREFIX__ #endif {delim}MESON_UNDERSCORE_PREFIX ''' with self._build_wrapper(code, env, mode=CompileCheckMode.PREPROCESS, want_output=False) as p: if p.returncode != 0: raise RuntimeError(f'BUG: Unable to preprocess _symbols_have_underscore_prefix_define check: {p.stdout}') symbol_prefix = p.stdout.partition(delim)[-1].rstrip() mlog.debug(f'Queried compiler for function prefix: __USER_LABEL_PREFIX__ is "{symbol_prefix!s}"') if symbol_prefix == '_': return True elif symbol_prefix == '': return False else: return None def _symbols_have_underscore_prefix_list(self, env: 'Environment') -> T.Optional[bool]: ''' Check if symbols have underscore prefix by consulting a hardcoded list of cases where we know the results. Return if functions have underscore prefix or None if unknown. ''' m = env.machines[self.for_machine] # Darwin always uses the underscore prefix, not matter what if m.is_darwin(): return True # Windows uses the underscore prefix on x86 (32bit) only if m.is_windows() or m.is_cygwin(): return m.cpu_family == 'x86' return None def symbols_have_underscore_prefix(self, env: 'Environment') -> bool: ''' Check if the compiler prefixes an underscore to global C symbols ''' # First, try to query the compiler directly result = self._symbols_have_underscore_prefix_define(env) if result is not None: return result # Else, try to consult a hardcoded list of cases we know # absolutely have an underscore prefix result = self._symbols_have_underscore_prefix_list(env) if result is not None: return result # As a last resort, try search in a compiled binary, which is the # most unreliable way of checking this, see #5482 return self._symbols_have_underscore_prefix_searchbin(env) def _get_patterns(self, env: 'Environment', prefixes: T.List[str], suffixes: T.List[str], shared: bool = False) -> T.List[str]: patterns: T.List[str] = [] 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: 'Environment', libtype: LibType, strict: bool = False) -> T.Tuple[str, ...]: ''' 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: T.List[str]) -> T.List[str]: def tuple_key(x: str) -> T.Tuple[int, ...]: ver = x.rsplit('.so.', maxsplit=1)[1] return tuple(int(i) for i in ver.split('.')) filtered: T.List[str] = [] 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: tuple(int(i) for i in ret[1].split('.')) except ValueError: continue filtered.append(lib) return sorted(filtered, key=tuple_key, reverse=True) @classmethod def _get_trials_from_pattern(cls, pattern: str, directory: str, libname: str) -> T.List[Path]: 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: Environment, paths: T.List[Path]) -> T.Optional[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. ''' for p in paths: if p.is_file(): if env.machines.host.is_darwin() and env.machines.build.is_darwin(): # Run `lipo` and check if the library supports the arch we want archs = mesonlib.darwin_get_object_archs(str(p)) if not archs or env.machines.host.cpu_family not in archs: mlog.debug(f'Rejected {p}, supports {archs} but need {env.machines.host.cpu_family}') continue return p return None @functools.lru_cache() def output_is_64bit(self, env: 'Environment') -> bool: ''' returns true if the output produced is 64-bit, false if 32-bit ''' return self.sizeof('void *', '', env)[0] == 8 def _find_library_real(self, libname: str, env: 'Environment', extra_dirs: T.List[str], code: str, libtype: LibType, lib_prefix_warning: bool) -> T.Optional[T.List[str]]: # 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_linker_always_args() + 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: trials = self._get_trials_from_pattern(p, d, libname) if not trials: continue trial = self._get_file_from_list(env, trials) if not trial: continue if libname.startswith('lib') and trial.name.startswith(libname) and lib_prefix_warning: mlog.warning(f'find_library({libname!r}) starting in "lib" only works by accident and is not portable') return [trial.as_posix()] return None def _find_library_impl(self, libname: str, env: 'Environment', extra_dirs: T.List[str], code: str, libtype: LibType, lib_prefix_warning: bool) -> T.Optional[T.List[str]]: # 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, lib_prefix_warning) self.find_library_cache[key] = value else: value = self.find_library_cache[key] if value is None: return None return value.copy() def find_library(self, libname: str, env: 'Environment', extra_dirs: T.List[str], libtype: LibType = LibType.PREFER_SHARED, lib_prefix_warning: bool = True) -> T.Optional[T.List[str]]: code = 'int main(void) { return 0; }\n' return self._find_library_impl(libname, env, extra_dirs, code, libtype, lib_prefix_warning) def find_framework_paths(self, env: 'Environment') -> T.List[str]: ''' 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. ''' # TODO: this really needs to be *AppleClang*, not just any clang. if self.id != 'clang': raise mesonlib.MesonException('Cannot find framework path with non-clang compiler') # Construct the compiler command-line commands = self.get_exelist(ccache=False) + ['-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: T.List[str] = [] 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: str, env: 'Environment', extra_dirs: T.List[str], allow_system: bool) -> T.Optional[T.List[str]]: code = 'int main(void) { return 0; }' link_args: T.List[str] = [] 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 return None def _find_framework_impl(self, name: str, env: 'Environment', extra_dirs: T.List[str], allow_system: bool) -> T.Optional[T.List[str]]: 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.copy() def find_framework(self, name: str, env: 'Environment', extra_dirs: T.List[str], allow_system: bool = True) -> T.Optional[T.List[str]]: ''' Finds the framework with the specified name, and returns link args for the same or returns None when the framework is not found. ''' # TODO: should probably check for macOS? 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]: # TODO: does this belong here or in GnuLike or maybe PosixLike? return [] def get_crt_link_args(self, crt_val: str, buildtype: str) -> T.List[str]: # TODO: does this belong here or in GnuLike or maybe PosixLike? return [] def thread_flags(self, env: 'Environment') -> T.List[str]: # TODO: does this belong here or in GnuLike or maybe PosixLike? host_m = env.machines[self.for_machine] if host_m.is_haiku() or host_m.is_darwin(): return [] return ['-pthread'] def linker_to_compiler_args(self, args: T.List[str]) -> T.List[str]: return args.copy() def has_arguments(self, args: T.List[str], env: 'Environment', code: str, mode: CompileCheckMode) -> T.Tuple[bool, bool]: return self.compiles(code, env, extra_args=args, mode=mode) def _has_multi_arguments(self, args: T.List[str], env: 'Environment', code: str) -> T.Tuple[bool, bool]: new_args: T.List[str] = [] 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-'): new_args.append('-W' + arg[5:]) if arg.startswith('-Wl,'): mlog.warning(f'{arg} 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.') new_args.append(arg) return self.has_arguments(new_args, env, code, mode=CompileCheckMode.COMPILE) def has_multi_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]: return self._has_multi_arguments(args, env, 'extern int i;\nint i;\n') def _has_multi_link_arguments(self, args: T.List[str], env: 'Environment', code: str) -> T.Tuple[bool, bool]: # 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) return self.has_arguments(args, env, code, mode=CompileCheckMode.LINK) def has_multi_link_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]: return self._has_multi_link_arguments(args, env, 'int main(void) { return 0; }\n') @staticmethod def _concatenate_string_literals(s: str) -> str: 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 get_has_func_attribute_extra_args(self, name: str) -> T.List[str]:
        # Most compilers (such as GCC and Clang) only warn about unknown or
        # ignored attributes, so force an error. Overridden in GCC and Clang
        # mixins.
        return ['-Werror']

    def has_func_attribute(self, name: str, env: 'Environment') -> T.Tuple[bool, bool]:
        # 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

        return self.compiles(self.attribute_check_func(name), env,
                             extra_args=self.get_has_func_attribute_extra_args(name))

    def get_assert_args(self, disable: bool) -> T.List[str]:
        if disable:
            return ['-DNDEBUG']
        return []

    @functools.lru_cache(maxsize=None)
    def can_compile(self, src: 'mesonlib.FileOrString') -> bool:
        # Files we preprocess can be anything, e.g. .in
        if self.mode == 'PREPROCESSOR':
            return True
        return super().can_compile(src)

    def get_preprocessor(self) -> Compiler:
        if not self.preprocessor:
            self.preprocessor = copy.copy(self)
            self.preprocessor.exelist = self.exelist + self.get_preprocess_to_file_args()
            self.preprocessor.mode = 'PREPROCESSOR'
            self.modes.append(self.preprocessor)
        return self.preprocessor
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/compilers/mixins/compcert.py0000644000175000017500000001051214562742363022676 0ustar00jpakkanejpakkane# 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 __future__ import annotations

"""Representations specific to the CompCert C compiler family."""

import os
import re
import typing as T

if T.TYPE_CHECKING:
    from envconfig import MachineInfo
    from ...environment import Environment
    from ...compilers.compilers import Compiler
else:
    # This is a bit clever, for mypy we pretend that these mixins descend from
    # Compiler, so we get all of the methods and attributes defined for us, but
    # for runtime we make them descend from object (which all classes normally
    # do). This gives up DRYer type checking, with no runtime impact
    Compiler = object

ccomp_buildtype_args: T.Dict[str, T.List[str]] = {
    'plain': [''],
    'debug': ['-O0', '-g'],
    'debugoptimized': ['-O0', '-g'],
    'release': ['-O3'],
    'minsize': ['-Os'],
    'custom': ['-Obranchless'],
}

ccomp_optimization_args: T.Dict[str, T.List[str]] = {
    'plain': [],
    '0': ['-O0'],
    'g': ['-O0'],
    '1': ['-O1'],
    '2': ['-O2'],
    '3': ['-O3'],
    's': ['-Os']
}

ccomp_debug_args: T.Dict[bool, T.List[str]] = {
    False: [],
    True: ['-g']
}

# As of CompCert 20.04, these arguments should be passed to the underlying gcc linker (via -WUl,)
# There are probably (many) more, but these are those used by picolibc
ccomp_args_to_wul: T.List[str] = [
        r"^-ffreestanding$",
        r"^-r$"
]

class CompCertCompiler(Compiler):

    id = 'ccomp'

    def __init__(self) -> None:
        # Assembly
        self.can_compile_suffixes.add('s')
        self.can_compile_suffixes.add('sx')
        default_warn_args: T.List[str] = []
        self.warn_args: T.Dict[str, T.List[str]] = {
            '0': [],
            '1': default_warn_args,
            '2': default_warn_args + [],
            '3': default_warn_args + [],
            'everything': default_warn_args + []}

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

    def get_pic_args(self) -> T.List[str]:
        # As of now, CompCert does not support PIC
        return []

    def get_buildtype_args(self, buildtype: str) -> T.List[str]:
        return ccomp_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 []

    @classmethod
    def _unix_args_to_native(cls, args: T.List[str], info: MachineInfo) -> T.List[str]:
        "Always returns a copy that can be independently mutated"
        patched_args: T.List[str] = []
        for arg in args:
            added = 0
            for ptrn in ccomp_args_to_wul:
                if re.match(ptrn, arg):
                    patched_args.append('-WUl,' + arg)
                    added = 1
            if not added:
                patched_args.append(arg)
        return patched_args

    def thread_flags(self, env: 'Environment') -> T.List[str]:
        return []

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

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

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

    def get_no_stdinc_args(self) -> T.List[str]:
        return ['-nostdinc']

    def get_no_stdlib_link_args(self) -> T.List[str]:
        return ['-nostdlib']

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

    def get_debug_args(self, is_debug: bool) -> T.List[str]:
        return ccomp_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[:9] == '-I':
                parameter_list[idx] = i[:9] + os.path.normpath(os.path.join(build_dir, i[9:]))

        return parameter_list
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0
meson-1.3.2/mesonbuild/compilers/mixins/elbrus.py0000644000175000017500000001054114562742373022361 0ustar00jpakkanejpakkane# 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 __future__ import annotations

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

import functools
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, OptionKey

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


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.

    id = 'lcc'

    def __init__(self) -> None:
        super().__init__()
        self.base_options = {OptionKey(o) for o in ['b_pgo', 'b_coverage', 'b_ndebug', 'b_staticpic', 'b_lundef', 'b_asneeded']}
        default_warn_args = ['-Wall']
        self.warn_args = {'0': [],
                          '1': default_warn_args,
                          '2': default_warn_args + ['-Wextra'],
                          '3': default_warn_args + ['-Wextra', '-Wpedantic'],
                          'everything': default_warn_args + ['-Wextra', '-Wpedantic']}

    # 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.get_exelist(ccache=False) + ['--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.get_exelist(ccache=False) + ['--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 []

    @functools.lru_cache(maxsize=None)
    def get_default_include_dirs(self) -> T.List[str]:
        os_env = os.environ.copy()
        os_env['LC_ALL'] = 'C'
        p = subprocess.Popen(self.get_exelist(ccache=False) + ['-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: T.List[str] = []
        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_prelink_args(self, prelink_name: str, obj_list: T.List[str]) -> T.List[str]:
        return ['-r', '-nodefaultlibs', '-nostartfiles', '-o', prelink_name] + obj_list

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

    def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
        args: T.List[str] = []
        std = options[OptionKey('std', lang=self.language, machine=self.for_machine)]
        if std.value != 'none':
            args.append('-std=' + std.value)
        return args

    def openmp_flags(self) -> T.List[str]:
        return ['-fopenmp']
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/compilers/mixins/emscripten.py0000644000175000017500000001011214562742363023227 0ustar00jpakkanejpakkane# 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 __future__ import annotations

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

import os.path
import typing as T

from ... import coredata
from ... import mesonlib
from ...mesonlib import OptionKey
from ...mesonlib import LibType
from mesonbuild.compilers.compilers import CompileCheckMode

if T.TYPE_CHECKING:
    from ...environment import Environment
    from ...compilers.compilers import Compiler
    from ...dependencies import Dependency
else:
    # This is a bit clever, for mypy we pretend that these mixins descend from
    # Compiler, so we get all of the methods and attributes defined for us, but
    # for runtime we make them descend from object (which all classes normally
    # do). This gives up DRYer type checking, with no runtime impact
    Compiler = object


def wrap_js_includes(args: T.List[str]) -> T.List[str]:
    final_args: T.List[str] = []
    for i in args:
        if i.endswith('.js') and not i.startswith('-'):
            final_args += ['--js-library', i]
        else:
            final_args += [i]
    return final_args

class EmscriptenMixin(Compiler):

    def _get_compile_output(self, dirname: str, mode: CompileCheckMode) -> str:
        assert mode != CompileCheckMode.PREPROCESS, 'In pre-processor mode, the output is sent to stdout and discarded'
        # 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 == CompileCheckMode.LINK:
            suffix = 'js'
        else:
            suffix = 'o'
        return os.path.join(dirname, 'output.' + suffix)

    def thread_link_flags(self, env: 'Environment') -> T.List[str]:
        args = ['-pthread']
        count: int = env.coredata.options[OptionKey('thread_count', lang=self.language, machine=self.for_machine)].value
        if count:
            args.append(f'-sPTHREAD_POOL_SIZE={count}')
        return args

    def get_options(self) -> 'coredata.MutableKeyedOptionDictType':
        opts = super().get_options()
        key = OptionKey('thread_count', machine=self.for_machine, lang=self.language)
        opts.update({
            key: coredata.UserIntegerOption(
                'Number of threads to use in web assembly, set to 0 to disable',
                (0, None, 4),  # Default was picked at random
            ),
        })

        return opts

    @classmethod
    def native_args_to_unix(cls, args: T.List[str]) -> T.List[str]:
        return wrap_js_includes(super().native_args_to_unix(args))

    def get_dependency_link_args(self, dep: 'Dependency') -> T.List[str]:
        return wrap_js_includes(super().get_dependency_link_args(dep))

    def find_library(self, libname: str, env: 'Environment', extra_dirs: T.List[str],
                     libtype: LibType = LibType.PREFER_SHARED, lib_prefix_warning: bool = True) -> T.Optional[T.List[str]]:
        if not libname.endswith('.js'):
            return super().find_library(libname, env, extra_dirs, libtype, lib_prefix_warning)
        if os.path.isabs(libname):
            if os.path.exists(libname):
                return [libname]
        if len(extra_dirs) == 0:
            raise mesonlib.EnvironmentException('Looking up Emscripten JS libraries requires either an absolute path or specifying extra_dirs.')
        for d in extra_dirs:
            abs_path = os.path.join(d, libname)
            if os.path.exists(abs_path):
                return [abs_path]
        return None
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/compilers/mixins/gnu.py0000644000175000017500000005165614562742363021671 0ustar00jpakkanejpakkane# Copyright 2019-2022 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 __future__ import annotations

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

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

from ... import mesonlib
from ... import mlog
from ...mesonlib import OptionKey
from mesonbuild.compilers.compilers import CompileCheckMode

if T.TYPE_CHECKING:
    from ..._typing import ImmutableListProtocol
    from ...environment import Environment
    from ..compilers import Compiler
else:
    # This is a bit clever, for mypy we pretend that these mixins descend from
    # Compiler, so we get all of the methods and attributes defined for us, but
    # for runtime we make them descend from object (which all classes normally
    # do). This gives up DRYer type checking, with no runtime impact
    Compiler = object

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

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

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

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

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

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

# Warnings collected from the GCC source and documentation.  This is an
# objective set of all the warnings flags that apply to general projects: the
# only ones omitted are those that require a project-specific value, or are
# related to non-standard or legacy language support.  This behaves roughly
# like -Weverything in clang.  Warnings implied by -Wall, -Wextra, or
# higher-level warnings already enabled here are not included in these lists to
# keep them as short as possible.  History goes back to GCC 3.0.0, everything
# earlier is considered historical and listed under version 0.0.0.

# GCC warnings for all C-family languages
# Omitted non-general warnings:
#   -Wabi=
#   -Waggregate-return
#   -Walloc-size-larger-than=BYTES
#   -Walloca-larger-than=BYTES
#   -Wframe-larger-than=BYTES
#   -Wlarger-than=BYTES
#   -Wstack-usage=BYTES
#   -Wsystem-headers
#   -Wtrampolines
#   -Wvla-larger-than=BYTES
#
# Omitted warnings enabled elsewhere in meson:
#   -Winvalid-pch (GCC 3.4.0)
gnu_common_warning_args: T.Dict[str, T.List[str]] = {
    "0.0.0": [
        "-Wcast-qual",
        "-Wconversion",
        "-Wfloat-equal",
        "-Wformat=2",
        "-Winline",
        "-Wmissing-declarations",
        "-Wredundant-decls",
        "-Wshadow",
        "-Wundef",
        "-Wuninitialized",
        "-Wwrite-strings",
    ],
    "3.0.0": [
        "-Wdisabled-optimization",
        "-Wpacked",
        "-Wpadded",
    ],
    "3.3.0": [
        "-Wmultichar",
        "-Wswitch-default",
        "-Wswitch-enum",
        "-Wunused-macros",
    ],
    "4.0.0": [
        "-Wmissing-include-dirs",
    ],
    "4.1.0": [
        "-Wunsafe-loop-optimizations",
        "-Wstack-protector",
    ],
    "4.2.0": [
        "-Wstrict-overflow=5",
    ],
    "4.3.0": [
        "-Warray-bounds=2",
        "-Wlogical-op",
        "-Wstrict-aliasing=3",
        "-Wvla",
    ],
    "4.6.0": [
        "-Wdouble-promotion",
        "-Wsuggest-attribute=const",
        "-Wsuggest-attribute=noreturn",
        "-Wsuggest-attribute=pure",
        "-Wtrampolines",
    ],
    "4.7.0": [
        "-Wvector-operation-performance",
    ],
    "4.8.0": [
        "-Wsuggest-attribute=format",
    ],
    "4.9.0": [
        "-Wdate-time",
    ],
    "5.1.0": [
        "-Wformat-signedness",
        "-Wnormalized=nfc",
    ],
    "6.1.0": [
        "-Wduplicated-cond",
        "-Wnull-dereference",
        "-Wshift-negative-value",
        "-Wshift-overflow=2",
        "-Wunused-const-variable=2",
    ],
    "7.1.0": [
        "-Walloca",
        "-Walloc-zero",
        "-Wformat-overflow=2",
        "-Wformat-truncation=2",
        "-Wstringop-overflow=3",
    ],
    "7.2.0": [
        "-Wduplicated-branches",
    ],
    "8.1.0": [
        "-Wcast-align=strict",
        "-Wsuggest-attribute=cold",
        "-Wsuggest-attribute=malloc",
    ],
    "9.1.0": [
        "-Wattribute-alias=2",
    ],
    "10.1.0": [
        "-Wanalyzer-too-complex",
        "-Warith-conversion",
    ],
    "12.1.0": [
        "-Wbidi-chars=ucn",
        "-Wopenacc-parallelism",
        "-Wtrivial-auto-var-init",
    ],
}

# GCC warnings for C
# Omitted non-general or legacy warnings:
#   -Wc11-c2x-compat
#   -Wc90-c99-compat
#   -Wc99-c11-compat
#   -Wdeclaration-after-statement
#   -Wtraditional
#   -Wtraditional-conversion
gnu_c_warning_args: T.Dict[str, T.List[str]] = {
    "0.0.0": [
        "-Wbad-function-cast",
        "-Wmissing-prototypes",
        "-Wnested-externs",
        "-Wstrict-prototypes",
    ],
    "3.4.0": [
        "-Wold-style-definition",
        "-Winit-self",
    ],
    "4.1.0": [
        "-Wc++-compat",
    ],
    "4.5.0": [
        "-Wunsuffixed-float-constants",
    ],
}

# GCC warnings for C++
# Omitted non-general or legacy warnings:
#   -Wc++0x-compat
#   -Wc++1z-compat
#   -Wc++2a-compat
#   -Wctad-maybe-unsupported
#   -Wnamespaces
#   -Wtemplates
gnu_cpp_warning_args: T.Dict[str, T.List[str]] = {
    "0.0.0": [
        "-Wctor-dtor-privacy",
        "-Weffc++",
        "-Wnon-virtual-dtor",
        "-Wold-style-cast",
        "-Woverloaded-virtual",
        "-Wsign-promo",
    ],
    "4.0.1": [
        "-Wstrict-null-sentinel",
    ],
    "4.6.0": [
        "-Wnoexcept",
    ],
    "4.7.0": [
        "-Wzero-as-null-pointer-constant",
    ],
    "4.8.0": [
        "-Wabi-tag",
        "-Wuseless-cast",
    ],
    "4.9.0": [
        "-Wconditionally-supported",
    ],
    "5.1.0": [
        "-Wsuggest-final-methods",
        "-Wsuggest-final-types",
        "-Wsuggest-override",
    ],
    "6.1.0": [
        "-Wmultiple-inheritance",
        "-Wplacement-new=2",
        "-Wvirtual-inheritance",
    ],
    "7.1.0": [
        "-Waligned-new=all",
        "-Wnoexcept-type",
        "-Wregister",
    ],
    "8.1.0": [
        "-Wcatch-value=3",
        "-Wextra-semi",
    ],
    "9.1.0": [
        "-Wdeprecated-copy-dtor",
        "-Wredundant-move",
    ],
    "10.1.0": [
        "-Wcomma-subscript",
        "-Wmismatched-tags",
        "-Wredundant-tags",
        "-Wvolatile",
    ],
    "11.1.0": [
        "-Wdeprecated-enum-enum-conversion",
        "-Wdeprecated-enum-float-conversion",
        "-Winvalid-imported-macros",
    ],
}

# GCC warnings for Objective C and Objective C++
# Omitted non-general or legacy warnings:
#   -Wtraditional
#   -Wtraditional-conversion
gnu_objc_warning_args: T.Dict[str, T.List[str]] = {
    "0.0.0": [
        "-Wselector",
    ],
    "3.3": [
        "-Wundeclared-selector",
    ],
    "4.1.0": [
        "-Wassign-intercept",
        "-Wstrict-selector-match",
    ],
}

_LANG_MAP = {
    'c': 'c',
    'cpp': 'c++',
    'objc': 'objective-c',
    'objcpp': 'objective-c++'
}

@functools.lru_cache(maxsize=None)
def gnulike_default_include_dirs(compiler: T.Tuple[str, ...], lang: str) -> 'ImmutableListProtocol[str]':
    if lang not in _LANG_MAP:
        return []
    lang = _LANG_MAP[lang]
    env = os.environ.copy()
    env["LC_ALL"] = 'C'
    cmd = list(compiler) + [f'-x{lang}', '-E', '-v', '-']
    _, stdout, _ = mesonlib.Popen_safe(cmd, stderr=subprocess.STDOUT, env=env)
    parse_state = 0
    paths: T.List[str] = []
    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(Compiler, 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) -> None:
        self.base_options = {
            OptionKey(o) for o in ['b_pch', 'b_lto', 'b_pgo', '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.add(OptionKey('b_lundef'))
        if not self.info.is_windows() or self.info.is_cygwin():
            self.base_options.add(OptionKey('b_asneeded'))
        if not self.info.is_hurd():
            self.base_options.add(OptionKey('b_sanitize'))
        # All GCC-like backends can do assembly
        self.can_compile_suffixes.add('s')
        self.can_compile_suffixes.add('sx')

    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]:
        pass

    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:
        pass

    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.get_exelist(ccache=False)), self.language).copy()

    @abc.abstractmethod
    def openmp_flags(self) -> T.List[str]:
        pass

    def gnu_symbol_visibility_args(self, vistype: str) -> T.List[str]:
        if vistype == 'inlineshidden' and self.language not in {'cpp', 'objcpp'}:
            vistype = 'hidden'
        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']

    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']
        with self._build_wrapper('', env, extra_args=extra_args,
                                 dependencies=None, mode=CompileCheckMode.COMPILE,
                                 want_output=True) as p:
            return p.stdout

    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: T.List[str] = []
        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, *, threads: int = 0, mode: str = 'default') -> T.List[str]:
        # This provides a base for many compilers, GCC and Clang override this
        # for their specific arguments
        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, outputname: str) -> T.List[str]:
        return ['-o', outputname]

    def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]:
        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, version: str) -> T.List[str]:
        if linker not in {'gold', 'bfd', 'lld'}:
            raise mesonlib.MesonException(
                f'Unsupported linker, only bfd, gold, and lld are supported, not {linker}.')
        return [f'-fuse-ld={linker}']

    def get_coverage_args(self) -> T.List[str]:
        return ['--coverage']

    def get_preprocess_to_file_args(self) -> T.List[str]:
        # We want to allow preprocessing files with any extension, such as
        # foo.c.in. In that case we need to tell GCC/CLANG to treat them as
        # assembly file.
        lang = _LANG_MAP.get(self.language, 'assembler-with-cpp')
        return self.get_preprocess_only_args() + [f'-x{lang}']


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

    def __init__(self, defines: T.Optional[T.Dict[str, str]]):
        super().__init__()
        self.defines = defines or {}
        self.base_options.update({OptionKey('b_colorout'), OptionKey('b_lto_threads')})

    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]:
        # Mypy doesn't understand cooperative inheritance
        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 supported_warn_args(self, warn_args_by_version: T.Dict[str, T.List[str]]) -> T.List[str]:
        result: T.List[str] = []
        for version, warn_args in warn_args_by_version.items():
            if mesonlib.version_compare(self.version, '>=' + version):
                result += warn_args
        return result

    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: T.List[str], env: 'Environment', code: str,
                      mode: CompileCheckMode) -> T.Tuple[bool, bool]:
        # 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) as p:
            result = p.returncode == 0
            if self.language in {'cpp', 'objcpp'} and 'is valid for C/ObjC' in p.stderr:
                result = False
            if self.language in {'c', 'objc'} and 'is valid for C++/ObjC++' in p.stderr:
                result = False
        return result, p.cached

    def get_has_func_attribute_extra_args(self, name: str) -> T.List[str]:
        # GCC only warns about unknown or ignored attributes, so force an
        # error.
        return ['-Werror=attributes']

    def get_prelink_args(self, prelink_name: str, obj_list: T.List[str]) -> T.List[str]:
        return ['-r', '-o', prelink_name] + obj_list

    def get_lto_compile_args(self, *, threads: int = 0, mode: str = 'default') -> T.List[str]:
        if threads == 0:
            if mesonlib.version_compare(self.version, '>= 10.0'):
                return ['-flto=auto']
            # This matches clang's behavior of using the number of cpus
            return [f'-flto={multiprocessing.cpu_count()}']
        elif threads > 0:
            return [f'-flto={threads}']
        return super().get_lto_compile_args(threads=threads)

    @classmethod
    def use_linker_args(cls, linker: str, version: str) -> T.List[str]:
        if linker == 'mold' and mesonlib.version_compare(version, '>=12.0.1'):
            return ['-fuse-ld=mold']
        return super().use_linker_args(linker, version)

    def get_profile_use_args(self) -> T.List[str]:
        return super().get_profile_use_args() + ['-fprofile-correction']
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/compilers/mixins/intel.py0000644000175000017500000001555114562742363022205 0ustar00jpakkanejpakkane# 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 __future__ import annotations

"""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 ..compilers import CompileCheckMode
from .gnu import GnuLikeCompiler
from .visualstudio import VisualStudioLikeCompiler

# 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: T.Dict[str, T.List[str]] = {
        'plain': [],
        'debug': ["-g", "-traceback"],
        'debugoptimized': ["-g", "-traceback"],
        'release': [],
        'minsize': [],
        'custom': [],
    }

    OPTIM_ARGS: T.Dict[str, T.List[str]] = {
        'plain': [],
        '0': ['-O0'],
        'g': ['-O0'],
        '1': ['-O1'],
        '2': ['-O2'],
        '3': ['-O3'],
        's': ['-Os'],
    }
    id = 'intel'

    def __init__(self) -> None:
        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 = {mesonlib.OptionKey(o) for o in [
            'b_pch', 'b_lundef', 'b_asneeded', 'b_pgo', 'b_coverage',
            'b_ndebug', 'b_staticpic', 'b_pie']}
        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, name: str) -> str:
        return os.path.basename(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 get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]:
        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
        ]
        return super().get_compiler_check_args(mode) + extra_args

    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]

    def get_has_func_attribute_extra_args(self, name: str) -> T.List[str]:
        return ['-diag-error', '1292']


class IntelVisualStudioLikeCompiler(VisualStudioLikeCompiler):

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

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

    OPTIM_ARGS: T.Dict[str, T.List[str]] = {
        'plain': [],
        '0': ['/Od'],
        'g': ['/Od'],
        '1': ['/O1'],
        '2': ['/O2'],
        '3': ['/O3'],
        's': ['/Os'],
    }

    id = 'intel-cl'

    def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]:
        args = super().get_compiler_check_args(mode)
        if mode is not CompileCheckMode.LINK:
            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 args

    def get_toolset_version(self) -> T.Optional[str]:
        # 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, *_ = mesonlib.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]

    def get_pch_base_name(self, header: str) -> str:
        return os.path.basename(header)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/compilers/mixins/islinker.py0000644000175000017500000001123214562742363022702 0ustar00jpakkanejpakkane# 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 __future__ import annotations

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

from ...mesonlib import EnvironmentException, MesonException, is_windows

if T.TYPE_CHECKING:
    from ...coredata import KeyedOptionDictType
    from ...environment import Environment
    from ...compilers.compilers import Compiler
else:
    # This is a bit clever, for mypy we pretend that these mixins descend from
    # Compiler, so we get all of the methods and attributes defined for us, but
    # for runtime we make them descend from object (which all classes normally
    # do). This gives up DRYer type checking, with no runtime impact
    Compiler = object


class BasicLinkerIsCompilerMixin(Compiler):

    """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, *, threads: int = 0, mode: str = 'default',
                          thinlto_cache_dir: T.Optional[str] = None) -> T.List[str]:
        return []

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

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

    def get_linker_output_args(self, outputname: 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: 'KeyedOptionDictType') -> 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: 'KeyedOptionDictType') -> 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 EnvironmentException(f'Linker {self.id} does not support link_whole')

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

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

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

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

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

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

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

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

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

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

    def get_link_debugfile_name(self, targetfile: str) -> T.Optional[str]:
        return None

    def thread_flags(self, env: 'Environment') -> T.List[str]:
        return []

    def thread_link_flags(self, env: 'Environment') -> T.List[str]:
        return []
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/compilers/mixins/metrowerks.py0000644000175000017500000002265514562742363023277 0ustar00jpakkanejpakkane# 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 __future__ import annotations

"""Representations specific to the Metrowerks/Freescale Embedded C/C++ compiler family."""

import os
import typing as T

from ...mesonlib import EnvironmentException, OptionKey

if T.TYPE_CHECKING:
    from ...envconfig import MachineInfo
    from ...compilers.compilers import Compiler, CompileCheckMode
else:
    # This is a bit clever, for mypy we pretend that these mixins descend from
    # Compiler, so we get all of the methods and attributes defined for us, but
    # for runtime we make them descend from object (which all classes normally
    # do). This gives up DRYer type checking, with no runtime impact
    Compiler = object

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

mwccarm_instruction_set_args: T.Dict[str, T.List[str]] = {
    'generic': ['-proc', 'generic'],
    'v4': ['-proc', 'v4'],
    'v4t': ['-proc', 'v4t'],
    'v5t': ['-proc', 'v5t'],
    'v5te': ['-proc', 'v5te'],
    'v6': ['-proc', 'v6'],
    'arm7tdmi': ['-proc', 'arm7tdmi'],
    'arm710t': ['-proc', 'arm710t'],
    'arm720t': ['-proc', 'arm720t'],
    'arm740t': ['-proc', 'arm740t'],
    'arm7ej': ['-proc', 'arm7ej'],
    'arm9tdmi': ['-proc', 'arm9tdmi'],
    'arm920t': ['-proc', 'arm920t'],
    'arm922t': ['-proc', 'arm922t'],
    'arm940t': ['-proc', 'arm940t'],
    'arm9ej': ['-proc', 'arm9ej'],
    'arm926ej': ['-proc', 'arm926ej'],
    'arm946e': ['-proc', 'arm946e'],
    'arm966e': ['-proc', 'arm966e'],
    'arm1020e': ['-proc', 'arm1020e'],
    'arm1022e': ['-proc', 'arm1022e'],
    'arm1026ej': ['-proc', 'arm1026ej'],
    'dbmx1': ['-proc', 'dbmx1'],
    'dbmxl': ['-proc', 'dbmxl'],
    'XScale': ['-proc', 'XScale'],
    'pxa255': ['-proc', 'pxa255'],
    'pxa261': ['-proc', 'pxa261'],
    'pxa262': ['-proc', 'pxa262'],
    'pxa263': ['-proc', 'pxa263']
}

mwcceppc_instruction_set_args: T.Dict[str, T.List[str]] = {
    'generic': ['-proc', 'generic'],
    '401': ['-proc', '401'],
    '403': ['-proc', '403'],
    '505': ['-proc', '505'],
    '509': ['-proc', '509'],
    '555': ['-proc', '555'],
    '601': ['-proc', '601'],
    '602': ['-proc', '602'],
    '603': ['-proc', '603'],
    '603e': ['-proc', '603e'],
    '604': ['-proc', '604'],
    '604e': ['-proc', '604e'],
    '740': ['-proc', '740'],
    '750': ['-proc', '750'],
    '801': ['-proc', '801'],
    '821': ['-proc', '821'],
    '823': ['-proc', '823'],
    '850': ['-proc', '850'],
    '860': ['-proc', '860'],
    '7400': ['-proc', '7400'],
    '7450': ['-proc', '7450'],
    '8240': ['-proc', '8240'],
    '8260': ['-proc', '8260'],
    'e500': ['-proc', 'e500'],
    'gekko': ['-proc', 'gekko'],
}

mwasmarm_instruction_set_args: T.Dict[str, T.List[str]] = {
    'arm4': ['-proc', 'arm4'],
    'arm4t': ['-proc', 'arm4t'],
    'arm4xm': ['-proc', 'arm4xm'],
    'arm4txm': ['-proc', 'arm4txm'],
    'arm5': ['-proc', 'arm5'],
    'arm5T': ['-proc', 'arm5T'],
    'arm5xM': ['-proc', 'arm5xM'],
    'arm5TxM': ['-proc', 'arm5TxM'],
    'arm5TE': ['-proc', 'arm5TE'],
    'arm5TExP': ['-proc', 'arm5TExP'],
    'arm6': ['-proc', 'arm6'],
    'xscale': ['-proc', 'xscale']
}

mwasmeppc_instruction_set_args: T.Dict[str, T.List[str]] = {
    '401': ['-proc', '401'],
    '403': ['-proc', '403'],
    '505': ['-proc', '505'],
    '509': ['-proc', '509'],
    '555': ['-proc', '555'],
    '56X': ['-proc', '56X'],
    '601': ['-proc', '601'],
    '602': ['-proc', '602'],
    '603': ['-proc', '603'],
    '603e': ['-proc', '603e'],
    '604': ['-proc', '604'],
    '604e': ['-proc', '604e'],
    '740': ['-proc', '740'],
    '74X': ['-proc', '74X'],
    '750': ['-proc', '750'],
    '75X': ['-proc', '75X'],
    '801': ['-proc', '801'],
    '821': ['-proc', '821'],
    '823': ['-proc', '823'],
    '850': ['-proc', '850'],
    '85X': ['-proc', '85X'],
    '860': ['-proc', '860'],
    '86X': ['-proc', '86X'],
    '87X': ['-proc', '87X'],
    '88X': ['-proc', '88X'],
    '5100': ['-proc', '5100'],
    '5200': ['-proc', '5200'],
    '7400': ['-proc', '7400'],
    '744X': ['-proc', '744X'],
    '7450': ['-proc', '7450'],
    '745X': ['-proc', '745X'],
    '82XX': ['-proc', '82XX'],
    '8240': ['-proc', '8240'],
    '824X': ['-proc', '824X'],
    '8260': ['-proc', '8260'],
    '827X': ['-proc', '827X'],
    '8280': ['-proc', '8280'],
    'e300': ['-proc', 'e300'],
    'e300c2': ['-proc', 'e300c2'],
    'e300c3': ['-proc', 'e300c3'],
    'e300c4': ['-proc', 'e300c4'],
    'e600': ['-proc', 'e600'],
    '85xx': ['-proc', '85xx'],
    'e500': ['-proc', 'e500'],
    'e500v2': ['-proc', 'e500v2'],
    'Zen': ['-proc', 'Zen'],
    '5565': ['-proc', '5565'],
    '5674': ['-proc', '5674'],
    'gekko': ['-proc', 'gekko'],
    'generic': ['-proc', 'generic'],
}

mwcc_optimization_args: T.Dict[str, T.List[str]] = {
    'plain': [],
    '0': ['-O0'],
    'g': ['-Op'],
    '1': ['-O1'],
    '2': ['-O2'],
    '3': ['-O4,p'],
    's': ['-Os']
}

mwcc_debug_args: T.Dict[bool, T.List[str]] = {
    False: [],
    True: ['-g']
}


class MetrowerksCompiler(Compiler):
    id = 'mwcc'

    # These compilers can actually invoke the linker, but they choke on
    # linker-specific flags. So it's best to invoke the linker directly
    INVOKES_LINKER = False

    def __init__(self) -> None:
        if not self.is_cross:
            raise EnvironmentException(f'{id} supports only cross-compilation.')

        self.base_options = {
            OptionKey(o) for o in ['b_pch', 'b_ndebug']}

        default_warn_args: T.List[str] = []
        self.warn_args: T.Dict[str, T.List[str]] = {
            '0': ['-w', 'off'],
            '1': default_warn_args,
            '2': default_warn_args + ['-w', 'most'],
            '3': default_warn_args + ['-w', 'all'],
            'everything': default_warn_args + ['-w', 'full']}

    def depfile_for_object(self, objfile: str) -> T.Optional[str]:
        # Earlier versions of these compilers do not support specifying
        # a custom name for a depfile, and can only generate '.d'
        return os.path.splitext(objfile)[0] + '.' + self.get_depfile_suffix()

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

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

    def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]:
        return []

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

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

    def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]:
        # Check comment in depfile_for_object()
        return ['-gccdep', '-MD']

    def get_depfile_suffix(self) -> str:
        return 'd'

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

    def get_no_optimization_args(self) -> T.List[str]:
        return ['-opt', 'off']

    def get_no_stdinc_args(self) -> T.List[str]:
        return ['-nostdinc']

    def get_no_stdlib_link_args(self) -> T.List[str]:
        return ['-nostdlib']

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

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

    def get_pic_args(self) -> T.List[str]:
        return ['-pic']

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

    def get_preprocess_to_file_args(self) -> T.List[str]:
        return ['-P']

    def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]:
        return ['-prefix', self.get_pch_name(header)]

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

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

    def get_warn_args(self, level: str) -> T.List[str]:
        return self.warn_args[level]

    def get_werror_args(self) -> T.List[str]:
        return ['-w', 'error']

    @classmethod
    def _unix_args_to_native(cls, args: T.List[str], info: MachineInfo) -> T.List[str]:
        result: T.List[str] = []
        for i in args:
            if i.startswith('-D'):
                i = '-D' + i[2:]
            if i.startswith('-I'):
                i = '-I' + i[2:]
            if i.startswith('-Wl,-rpath='):
                continue
            elif i == '--print-search-dirs':
                continue
            elif i.startswith('-L'):
                continue
            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[:2] == '-I':
                parameter_list[idx] = i[:9] + os.path.normpath(os.path.join(build_dir, i[9:]))

        return parameter_list
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/compilers/mixins/pgi.py0000644000175000017500000000723014562742363021644 0ustar00jpakkanejpakkane# 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 __future__ import annotations

"""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
from ...mesonlib import OptionKey

if T.TYPE_CHECKING:
    from ...environment import Environment
    from ...compilers.compilers import Compiler
else:
    # This is a bit clever, for mypy we pretend that these mixins descend from
    # Compiler, so we get all of the methods and attributes defined for us, but
    # for runtime we make them descend from object (which all classes normally
    # do). This gives up DRYer type checking, with no runtime impact
    Compiler = object

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


class PGICompiler(Compiler):

    id = 'pgi'

    def __init__(self) -> None:
        self.base_options = {OptionKey('b_pch')}

        default_warn_args = ['-Minform=inform']
        self.warn_args: T.Dict[str, T.List[str]] = {
            '0': [],
            '1': default_warn_args,
            '2': default_warn_args,
            '3': default_warn_args,
            'everything': 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_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),
                    f'-I{hdr.parent}']
        else:
            return []

    def thread_flags(self, env: 'Environment') -> T.List[str]:
        # PGI cannot accept -pthread, it's already threaded
        return []
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/compilers/mixins/ti.py0000644000175000017500000001152414562742363021502 0ustar00jpakkanejpakkane# 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 __future__ import annotations

"""Representations specific to the Texas Instruments compiler family."""

import os
import typing as T

from ...mesonlib import EnvironmentException

if T.TYPE_CHECKING:
    from ...envconfig import MachineInfo
    from ...environment import Environment
    from ...compilers.compilers import Compiler
else:
    # This is a bit clever, for mypy we pretend that these mixins descend from
    # Compiler, so we get all of the methods and attributes defined for us, but
    # for runtime we make them descend from object (which all classes normally
    # do). This gives up DRYer type checking, with no runtime impact
    Compiler = object

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

ti_optimization_args: T.Dict[str, T.List[str]] = {
    'plain': [],
    '0': ['-O0'],
    'g': ['-Ooff'],
    '1': ['-O1'],
    '2': ['-O2'],
    '3': ['-O3'],
    's': ['-O4']
}

ti_debug_args: T.Dict[bool, T.List[str]] = {
    False: [],
    True: ['-g']
}


class TICompiler(Compiler):

    id = 'ti'

    def __init__(self) -> None:
        if not self.is_cross:
            raise EnvironmentException('TI compilers only support cross-compilation.')

        self.can_compile_suffixes.add('asm')    # Assembly
        self.can_compile_suffixes.add('cla')    # Control Law Accelerator (CLA) used in C2000

        default_warn_args: T.List[str] = []
        self.warn_args: T.Dict[str, T.List[str]] = {
            '0': [],
            '1': default_warn_args,
            '2': default_warn_args + [],
            '3': default_warn_args + [],
            'everything': default_warn_args + []}

    def get_pic_args(self) -> T.List[str]:
        # PIC support is not enabled by default for TI compilers,
        # 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 ti_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 []

    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 ti_optimization_args[optimization_level]

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

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

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

    def get_output_args(self, outputname: str) -> T.List[str]:
        return [f'--output_file={outputname}']

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

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

    @classmethod
    def _unix_args_to_native(cls, args: T.List[str], info: MachineInfo) -> T.List[str]:
        result: T.List[str] = []
        for i in args:
            if i.startswith('-D'):
                i = '--define=' + i[2:]
            if i.startswith('-Wl,-rpath='):
                continue
            elif i == '--print-search-dirs':
                continue
            elif i.startswith('-L'):
                continue
            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[:15] == '--include_path=':
                parameter_list[idx] = i[:15] + os.path.normpath(os.path.join(build_dir, i[15:]))
            if i[:2] == '-I':
                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 ['--preproc_with_compile', f'--preproc_dependency={outfile}']
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/compilers/mixins/visualstudio.py0000644000175000017500000004400214562742363023616 0ustar00jpakkanejpakkane# 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 __future__ import annotations

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

import abc
import os
import typing as T

from ... import arglist
from ... import mesonlib
from ... import mlog
from mesonbuild.compilers.compilers import CompileCheckMode

if T.TYPE_CHECKING:
    from ...environment import Environment
    from ...dependencies import Dependency
    from .clike import CLikeCompiler as Compiler
else:
    # This is a bit clever, for mypy we pretend that these mixins descend from
    # Compiler, so we get all of the methods and attributes defined for us, but
    # for runtime we make them descend from object (which all classes normally
    # do). This gives up DRYer type checking, with no runtime impact
    Compiler = object

vs32_instruction_set_args: T.Dict[str, T.Optional[T.List[str]]] = {
    '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,
}

# The 64 bit compiler defaults to /arch:avx.
vs64_instruction_set_args: T.Dict[str, T.Optional[T.List[str]]] = {
    '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,
}

msvc_optimization_args: T.Dict[str, T.List[str]] = {
    'plain': [],
    '0': ['/Od'],
    'g': [], # No specific flag to optimize debugging, /Zi or /ZI will create debug information
    '1': ['/O1'],
    '2': ['/O2'],
    '3': ['/O2', '/Gw'],
    's': ['/O1', '/Gw'],
}

msvc_debug_args: T.Dict[bool, T.List[str]] = {
    False: [],
    True: ['/Zi']
}


class VisualStudioLikeCompiler(Compiler, 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']
    ignore_libs = arglist.UNIXY_COMPILER_INTERNAL_LIBS + ['execinfo']
    internal_libs: T.List[str] = []

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

    # /showIncludes is needed for build dependency tracking in Ninja
    # See: https://ninja-build.org/manual.html#_deps
    # Assume UTF-8 sources by default, but self.unix_args_to_native() removes it
    # if `/source-charset` is set too.
    # It is also dropped if Visual Studio 2013 or earlier is used, since it would
    # not be supported in that case.
    always_args = ['/nologo', '/showIncludes', '/utf-8']
    warn_args: T.Dict[str, T.List[str]] = {
        '0': [],
        '1': ['/W2'],
        '2': ['/W3'],
        '3': ['/W4'],
        'everything': ['/Wall'],
    }

    INVOKES_LINKER = False

    def __init__(self, target: str):
        self.base_options = {mesonlib.OptionKey(o) for o in ['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'
        elif 'aarch64' in target:
            self.machine = 'arm64'
        elif 'arm' in target:
            self.machine = 'arm'
        else:
            self.machine = target
        if mesonlib.version_compare(self.version, '>=19.28.29910'): # VS 16.9.0 includes cl 19.28.29910
            self.base_options.add(mesonlib.OptionKey('b_sanitize'))
        assert self.linker is not None
        self.linker.machine = self.machine

    # Override CCompiler.get_always_args
    def get_always_args(self) -> T.List[str]:
        # TODO: use ImmutableListProtocol[str] here instead
        return self.always_args.copy()

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

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

    def get_pch_base_name(self, header: str) -> str:
        # This needs to be implemented by inheriting classes
        raise NotImplementedError

    def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]:
        base = self.get_pch_base_name(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_preprocess_to_file_args(self) -> T.List[str]:
        return ['/EP', '/P']

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

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

    def sanitizer_compile_args(self, value: str) -> T.List[str]:
        if value == 'none':
            return []
        if value != 'address':
            raise mesonlib.MesonException('VS only supports address sanitizer at the moment.')
        return ['/fsanitize=address']

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

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

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

    def get_optimization_args(self, optimization_level: str) -> T.List[str]:
        args = msvc_optimization_args[optimization_level]
        if mesonlib.version_compare(self.version, '<18.0'):
            args = [arg for arg in args if arg != '/Gw']
        return args

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

    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(source)[0] + '.obj'
        return objname, ['/Yc' + header, '/Fp' + pchname, '/Fo' + objname]

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

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

    # 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: T.List[str] = []
        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
            # cl.exe does not allow specifying both, so remove /utf-8 that we
            # added automatically in the case the user overrides it manually.
            elif (i.startswith('/source-charset:')
                    or i.startswith('/execution-charset:')
                    or i == '/validate-charset-'):
                try:
                    result.remove('/utf-8')
                except ValueError:
                    pass
            result.append(i)
        return result

    @classmethod
    def native_args_to_unix(cls, args: T.List[str]) -> T.List[str]:
        result: T.List[str] = []
        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: str, mode: CompileCheckMode) -> T.Tuple[bool, bool]:
        warning_text = '4044' if mode == CompileCheckMode.LINK else '9002'
        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.stderr or warning_text in p.stdout), 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)]
        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)
        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)
        elif version < 1940:
            return '14.3' # (Visual Studio 2022)
        mlog.warning(f'Could not find toolset for version {self.version!r}')
        return None

    def get_toolset_version(self) -> T.Optional[str]:
        # 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]:
        crt_val = self.get_crt_val(crt_val, buildtype)
        return self.crt_args[crt_val]

    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'

    def symbols_have_underscore_prefix(self, env: 'Environment') -> bool:
        '''
        Check if the compiler prefixes an underscore to global C symbols.

        This overrides the Clike method, as for MSVC checking the
        underscore prefix based on the compiler define never works,
        so do not even try.
        '''
        # Try to consult a hardcoded list of cases we know
        # absolutely have an underscore prefix
        result = self._symbols_have_underscore_prefix_list(env)
        if result is not None:
            return result

        # As a last resort, try search in a compiled binary
        return self._symbols_have_underscore_prefix_searchbin(env)


class MSVCCompiler(VisualStudioLikeCompiler):

    """Specific to the Microsoft Compilers."""

    id = 'msvc'

    def __init__(self, target: str):
        super().__init__(target)

        # Visual Studio 2013 and earlier don't support the /utf-8 argument.
        # We want to remove it. We also want to make an explicit copy so we
        # don't mutate class constant state
        if mesonlib.version_compare(self.version, '<19.00') and '/utf-8' in self.always_args:
            self.always_args = [r for r in self.always_args if r != '/utf-8']

    def get_compile_debugfile_args(self, rel_obj: str, pch: bool = False) -> T.List[str]:
        args = super().get_compile_debugfile_args(rel_obj, pch)
        # 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 mesonlib.version_compare(self.version, '>=18.0'):
            args = ['/FS'] + args
        return args

    # Override CCompiler.get_always_args
    # We want to drop '/utf-8' for Visual Studio 2013 and earlier
    def get_always_args(self) -> T.List[str]:
        return self.always_args

    def get_instruction_set_args(self, instruction_set: str) -> T.Optional[T.List[str]]:
        if 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 they cannot be called.
            return None
        return super().get_instruction_set_args(instruction_set)

    def get_pch_base_name(self, header: str) -> str:
        return os.path.basename(header)


class ClangClCompiler(VisualStudioLikeCompiler):

    """Specific to Clang-CL."""

    id = 'clang-cl'

    def __init__(self, target: str):
        super().__init__(target)

        # Assembly
        self.can_compile_suffixes.add('s')
        self.can_compile_suffixes.add('sx')

    def has_arguments(self, args: T.List[str], env: 'Environment', code: str, mode: CompileCheckMode) -> T.Tuple[bool, bool]:
        if mode != CompileCheckMode.LINK:
            args = args + ['-Werror=unknown-argument', '-Werror=unknown-warning-option']
        return super().has_arguments(args, env, code, mode)

    def get_toolset_version(self) -> T.Optional[str]:
        # XXX: what is the right thing to do here?
        return '14.1'

    def get_pch_base_name(self, header: str) -> str:
        return header

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

    def get_dependency_compile_args(self, dep: 'Dependency') -> T.List[str]:
        if dep.get_include_type() == 'system':
            converted: T.List[str] = []
            for i in dep.get_compile_args():
                if i.startswith('-isystem'):
                    converted += ['/clang:' + i]
                else:
                    converted += [i]
            return converted
        else:
            return dep.get_compile_args()
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/compilers/mixins/xc16.py0000644000175000017500000001021414562742363021642 0ustar00jpakkanejpakkane# 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 __future__ import annotations

"""Representations specific to the Microchip XC16 C compiler family."""

import os
import typing as T

from ...mesonlib import EnvironmentException

if T.TYPE_CHECKING:
    from ...envconfig import MachineInfo
    from ...environment import Environment
    from ...compilers.compilers import Compiler
else:
    # This is a bit clever, for mypy we pretend that these mixins descend from
    # Compiler, so we get all of the methods and attributes defined for us, but
    # for runtime we make them descend from object (which all classes normally
    # do). This gives up DRYer type checking, with no runtime impact
    Compiler = object

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

xc16_optimization_args: T.Dict[str, T.List[str]] = {
    'plain': [],
    '0': ['-O0'],
    'g': ['-O0'],
    '1': ['-O1'],
    '2': ['-O2'],
    '3': ['-O3'],
    's': ['-Os']
}

xc16_debug_args: T.Dict[bool, T.List[str]] = {
    False: [],
    True: []
}


class Xc16Compiler(Compiler):

    id = 'xc16'

    def __init__(self) -> None:
        if not self.is_cross:
            raise EnvironmentException('xc16 supports only cross-compilation.')
        # Assembly
        self.can_compile_suffixes.add('s')
        self.can_compile_suffixes.add('sx')
        default_warn_args: T.List[str] = []
        self.warn_args = {'0': [],
                          '1': default_warn_args,
                          '2': default_warn_args + [],
                          '3': default_warn_args + [],
                          'everything': default_warn_args + []}

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

    def get_pic_args(self) -> T.List[str]:
        # PIC support is not enabled by default for xc16,
        # 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 xc16_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 []

    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 ['-nostdinc']

    def get_no_stdlib_link_args(self) -> T.List[str]:
        return ['--nostdlib']

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

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

    @classmethod
    def _unix_args_to_native(cls, args: T.List[str], info: MachineInfo) -> T.List[str]:
        result = []
        for i in args:
            if i.startswith('-D'):
                i = '-D' + i[2:]
            if i.startswith('-I'):
                i = '-I' + i[2:]
            if i.startswith('-Wl,-rpath='):
                continue
            elif i == '--print-search-dirs':
                continue
            elif i.startswith('-L'):
                continue
            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] == '-I':
                parameter_list[idx] = i[:9] + os.path.normpath(os.path.join(build_dir, i[9:]))

        return parameter_list
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/compilers/objc.py0000644000175000017500000001212714562742363020474 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import typing as T

from .. import coredata
from ..mesonlib import OptionKey

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

if T.TYPE_CHECKING:
    from ..programs import ExternalProgram
    from ..envconfig import MachineInfo
    from ..environment import Environment
    from ..linkers.linkers import DynamicLinker
    from ..mesonlib import MachineChoice


class ObjCCompiler(CLikeCompiler, Compiler):

    language = 'objc'

    def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice,
                 is_cross: bool, info: 'MachineInfo',
                 exe_wrap: T.Optional['ExternalProgram'],
                 linker: T.Optional['DynamicLinker'] = None,
                 full_version: T.Optional[str] = None):
        Compiler.__init__(self, ccache, exelist, version, for_machine, info,
                          is_cross=is_cross, full_version=full_version,
                          linker=linker)
        CLikeCompiler.__init__(self, exe_wrap)

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

    def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
        code = '#import\nint main(void) { return 0; }\n'
        return self._sanity_check_impl(work_dir, environment, 'sanitycheckobjc.m', code)


class GnuObjCCompiler(GnuCompiler, ObjCCompiler):
    def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice,
                 is_cross: bool, info: 'MachineInfo',
                 exe_wrapper: T.Optional['ExternalProgram'] = None,
                 defines: T.Optional[T.Dict[str, str]] = None,
                 linker: T.Optional['DynamicLinker'] = None,
                 full_version: T.Optional[str] = None):
        ObjCCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross,
                              info, exe_wrapper, linker=linker, full_version=full_version)
        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'],
                          'everything': (default_warn_args + ['-Wextra', '-Wpedantic'] +
                                         self.supported_warn_args(gnu_common_warning_args) +
                                         self.supported_warn_args(gnu_objc_warning_args))}


class ClangObjCCompiler(ClangCompiler, ObjCCompiler):
    def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice,
                 is_cross: bool, info: 'MachineInfo',
                 exe_wrapper: T.Optional['ExternalProgram'] = None,
                 defines: T.Optional[T.Dict[str, str]] = None,
                 linker: T.Optional['DynamicLinker'] = None,
                 full_version: T.Optional[str] = None):
        ObjCCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross,
                              info, exe_wrapper, linker=linker, full_version=full_version)
        ClangCompiler.__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'],
                          'everything': ['-Weverything']}

    def get_options(self) -> 'coredata.MutableKeyedOptionDictType':
        opts = super().get_options()
        opts.update({
            OptionKey('std', machine=self.for_machine, lang='c'): coredata.UserComboOption(
                'C language standard to use',
                ['none', 'c89', 'c99', 'c11', 'c17', 'gnu89', 'gnu99', 'gnu11', 'gnu17'],
                'none',
            )
        })
        return opts

    def get_option_compile_args(self, options: 'coredata.KeyedOptionDictType') -> T.List[str]:
        args = []
        std = options[OptionKey('std', machine=self.for_machine, lang='c')]
        if std.value != 'none':
            args.append('-std=' + std.value)
        return args

class AppleClangObjCCompiler(ClangObjCCompiler):

    """Handle the differences between Apple's clang and vanilla clang."""
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/compilers/objcpp.py0000644000175000017500000001234214562742363021033 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import typing as T

from .. import coredata
from ..mesonlib import OptionKey

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

if T.TYPE_CHECKING:
    from ..programs import ExternalProgram
    from ..envconfig import MachineInfo
    from ..environment import Environment
    from ..linkers.linkers import DynamicLinker
    from ..mesonlib import MachineChoice

class ObjCPPCompiler(CLikeCompiler, Compiler):

    language = 'objcpp'

    def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice,
                 is_cross: bool, info: 'MachineInfo',
                 exe_wrap: T.Optional['ExternalProgram'],
                 linker: T.Optional['DynamicLinker'] = None,
                 full_version: T.Optional[str] = None):
        Compiler.__init__(self, ccache, exelist, version, for_machine, info,
                          is_cross=is_cross, full_version=full_version,
                          linker=linker)
        CLikeCompiler.__init__(self, exe_wrap)

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

    def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
        code = '#import\nclass MyClass;int main(void) { return 0; }\n'
        return self._sanity_check_impl(work_dir, environment, 'sanitycheckobjcpp.mm', code)


class GnuObjCPPCompiler(GnuCompiler, ObjCPPCompiler):
    def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice,
                 is_cross: bool, info: 'MachineInfo',
                 exe_wrapper: T.Optional['ExternalProgram'] = None,
                 defines: T.Optional[T.Dict[str, str]] = None,
                 linker: T.Optional['DynamicLinker'] = None,
                 full_version: T.Optional[str] = None):
        ObjCPPCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross,
                                info, exe_wrapper, linker=linker, full_version=full_version)
        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'],
                          'everything': (default_warn_args + ['-Wextra', '-Wpedantic'] +
                                         self.supported_warn_args(gnu_common_warning_args) +
                                         self.supported_warn_args(gnu_objc_warning_args))}


class ClangObjCPPCompiler(ClangCompiler, ObjCPPCompiler):

    def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice,
                 is_cross: bool, info: 'MachineInfo',
                 exe_wrapper: T.Optional['ExternalProgram'] = None,
                 defines: T.Optional[T.Dict[str, str]] = None,
                 linker: T.Optional['DynamicLinker'] = None,
                 full_version: T.Optional[str] = None):
        ObjCPPCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross,
                                info, exe_wrapper, linker=linker, full_version=full_version)
        ClangCompiler.__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'],
                          'everything': ['-Weverything']}

    def get_options(self) -> 'coredata.MutableKeyedOptionDictType':
        opts = super().get_options()
        opts.update({
            OptionKey('std', machine=self.for_machine, lang='cpp'): coredata.UserComboOption(
                'C++ language standard to use',
                ['none', 'c++98', 'c++11', 'c++14', 'c++17', 'c++20', 'c++2b',
                 'gnu++98', 'gnu++11', 'gnu++14', 'gnu++17', 'gnu++20',
                 'gnu++2b'],
                'none',
            )
        })
        return opts

    def get_option_compile_args(self, options: 'coredata.KeyedOptionDictType') -> T.List[str]:
        args = []
        std = options[OptionKey('std', machine=self.for_machine, lang='cpp')]
        if std.value != 'none':
            args.append('-std=' + std.value)
        return args


class AppleClangObjCPPCompiler(ClangObjCPPCompiler):

    """Handle the differences between Apple's clang and vanilla clang."""
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0
meson-1.3.2/mesonbuild/compilers/rust.py0000644000175000017500000002335314562742373020560 0ustar00jpakkanejpakkane# Copyright 2012-2022 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 __future__ import annotations

import functools
import subprocess, os.path
import textwrap
import re
import typing as T

from .. import coredata
from ..mesonlib import EnvironmentException, MesonException, Popen_safe_logged, OptionKey
from .compilers import Compiler, rust_buildtype_args, clike_debug_args

if T.TYPE_CHECKING:
    from ..coredata import MutableKeyedOptionDictType, KeyedOptionDictType
    from ..envconfig import MachineInfo
    from ..environment import Environment  # noqa: F401
    from ..linkers.linkers import DynamicLinker
    from ..mesonlib import MachineChoice
    from ..programs import ExternalProgram
    from ..dependencies import Dependency


rust_optimization_args: T.Dict[str, T.List[str]] = {
    'plain': [],
    '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'
    id = 'rustc'

    _WARNING_LEVELS: T.Dict[str, T.List[str]] = {
        '0': ['-A', 'warnings'],
        '1': [],
        '2': [],
        '3': ['-W', 'warnings'],
    }

    # Those are static libraries, but we use dylib= here as workaround to avoid
    # rust --tests to use /WHOLEARCHIVE.
    # https://github.com/rust-lang/rust/issues/116910
    MSVCRT_ARGS: T.Mapping[str, T.List[str]] = {
        'none': [],
        'md': [], # this is the default, no need to inject anything
        'mdd': ['-l', 'dylib=msvcrtd'],
        'mt': ['-l', 'dylib=libcmt'],
        'mtd': ['-l', 'dylib=libcmtd'],
    }

    def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice,
                 is_cross: bool, info: 'MachineInfo',
                 exe_wrapper: T.Optional['ExternalProgram'] = None,
                 full_version: T.Optional[str] = None,
                 linker: T.Optional['DynamicLinker'] = None):
        super().__init__([], exelist, version, for_machine, info,
                         is_cross=is_cross, full_version=full_version,
                         linker=linker)
        self.exe_wrapper = exe_wrapper
        self.base_options.update({OptionKey(o) for o in ['b_colorout', 'b_ndebug']})
        if 'link' in self.linker.id:
            self.base_options.add(OptionKey('b_vscrt'))
        self.native_static_libs: T.List[str] = []

    def needs_static_linker(self) -> bool:
        return False

    def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
        source_name = os.path.join(work_dir, 'sanity.rs')
        output_name = os.path.join(work_dir, 'rusttest')
        with open(source_name, 'w', encoding='utf-8') as ofile:
            ofile.write(textwrap.dedent(
                '''fn main() {
                }
                '''))

        cmdlist = self.exelist + ['-o', output_name, source_name]
        pc, stdo, stde = Popen_safe_logged(cmdlist, cwd=work_dir)
        if pc.returncode != 0:
            raise EnvironmentException(f'Rust compiler {self.name_string()} cannot compile programs.')
        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]
        pe = subprocess.Popen(cmdlist, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        pe.wait()
        if pe.returncode != 0:
            raise EnvironmentException(f'Executables created by Rust compiler {self.name_string()} are not runnable.')
        # Get libraries needed to link with a Rust staticlib
        cmdlist = self.exelist + ['--crate-type', 'staticlib', '--print', 'native-static-libs', source_name]
        p, stdo, stde = Popen_safe_logged(cmdlist, cwd=work_dir)
        if p.returncode == 0:
            match = re.search('native-static-libs: (.*)$', stde, re.MULTILINE)
            if match:
                # Exclude some well known libraries that we don't need because they
                # are always part of C/C++ linkers. Rustc probably should not print
                # them, pkg-config for example never specify them.
                # FIXME: https://github.com/rust-lang/rust/issues/55120
                exclude = {'-lc', '-lgcc_s', '-lkernel32', '-ladvapi32'}
                self.native_static_libs = [i for i in match.group(1).split() if i not in exclude]

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

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

    def get_sysroot(self) -> str:
        cmd = self.get_exelist(ccache=False) + ['--print', 'sysroot']
        p, stdo, stde = Popen_safe_logged(cmd)
        return stdo.split('\n', maxsplit=1)[0]

    @functools.lru_cache(maxsize=None)
    def get_crt_static(self) -> bool:
        cmd = self.get_exelist(ccache=False) + ['--print', 'cfg']
        p, stdo, stde = Popen_safe_logged(cmd)
        return bool(re.search('^target_feature="crt-static"$', stdo, re.MULTILINE))

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

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

    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] == '-L':
                for j in ['dependency', 'crate', 'native', 'framework', 'all']:
                    combined_len = len(j) + 3
                    if i[:combined_len] == f'-L{j}=':
                        parameter_list[idx] = i[:combined_len] + os.path.normpath(os.path.join(build_dir, i[combined_len:]))
                        break

        return parameter_list

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

    @classmethod
    def use_linker_args(cls, linker: str, version: str) -> T.List[str]:
        return ['-C', f'linker={linker}']

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

    def get_options(self) -> 'MutableKeyedOptionDictType':
        key = OptionKey('std', machine=self.for_machine, lang=self.language)
        return {
            key: coredata.UserComboOption(
                'Rust edition to use',
                ['none', '2015', '2018', '2021'],
                'none',
            ),
        }

    def get_dependency_compile_args(self, dep: 'Dependency') -> T.List[str]:
        # Rust doesn't have dependency compile arguments so simply return
        # nothing here. Dependencies are linked and all required metadata is
        # provided by the linker flags.
        return []

    def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
        args = []
        key = OptionKey('std', machine=self.for_machine, lang=self.language)
        std = options[key]
        if std.value != 'none':
            args.append('--edition=' + std.value)
        return args

    def get_crt_compile_args(self, crt_val: str, buildtype: str) -> T.List[str]:
        # Rust handles this for us, we don't need to do anything
        return []

    def get_crt_link_args(self, crt_val: str, buildtype: str) -> T.List[str]:
        if self.linker.id not in {'link', 'lld-link'}:
            return []
        return self.MSVCRT_ARGS[self.get_crt_val(crt_val, buildtype)]

    def get_colorout_args(self, colortype: str) -> T.List[str]:
        if colortype in {'always', 'never', 'auto'}:
            return [f'--color={colortype}']
        raise MesonException(f'Invalid color type for rust {colortype}')

    def get_linker_always_args(self) -> T.List[str]:
        args: T.List[str] = []
        for a in super().get_linker_always_args():
            args.extend(['-C', f'link-arg={a}'])
        return args

    def get_werror_args(self) -> T.List[str]:
        # Use -D warnings, which makes every warning not explicitly allowed an
        # error
        return ['-D', 'warnings']

    def get_warn_args(self, level: str) -> T.List[str]:
        # TODO: I'm not really sure what to put here, Rustc doesn't have warning
        return self._WARNING_LEVELS[level]

    def get_no_warn_args(self) -> T.List[str]:
        return self._WARNING_LEVELS["0"]

    def get_pic_args(self) -> T.List[str]:
        # relocation-model=pic is rustc's default already.
        return []

    def get_pie_args(self) -> T.List[str]:
        # Rustc currently has no way to toggle this, it's controlled by whether
        # pic is on by rustc
        return []

    def get_assert_args(self, disable: bool) -> T.List[str]:
        action = "no" if disable else "yes"
        return ['-C', f'debug-assertions={action}', '-C', 'overflow-checks=no']


class ClippyRustCompiler(RustCompiler):

    """Clippy is a linter that wraps Rustc.

    This just provides us a different id
    """

    id = 'clippy-driver rustc'
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/compilers/swift.py0000644000175000017500000001145614562742363020717 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import subprocess, os.path
import typing as T

from ..mesonlib import EnvironmentException

from .compilers import Compiler, swift_buildtype_args, clike_debug_args

if T.TYPE_CHECKING:
    from ..envconfig import MachineInfo
    from ..environment import Environment
    from ..linkers.linkers import DynamicLinker
    from ..mesonlib import MachineChoice

swift_optimization_args: T.Dict[str, T.List[str]] = {
    'plain': [],
    '0': [],
    'g': [],
    '1': ['-O'],
    '2': ['-O'],
    '3': ['-O'],
    's': ['-O'],
}

class SwiftCompiler(Compiler):

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

    def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice,
                 is_cross: bool, info: 'MachineInfo', full_version: T.Optional[str] = None,
                 linker: T.Optional['DynamicLinker'] = None):
        super().__init__([], exelist, version, for_machine, info,
                         is_cross=is_cross, full_version=full_version,
                         linker=linker)
        self.version = version

    def needs_static_linker(self) -> bool:
        return True

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

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

    def depfile_for_object(self, objfile: str) -> T.Optional[str]:
        return os.path.splitext(objfile)[0] + '.' + self.get_depfile_suffix()

    def get_depfile_suffix(self) -> str:
        return 'd'

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

    def get_header_import_args(self, headername: str) -> T.List[str]:
        return ['-import-objc-header', headername]

    def get_warn_args(self, level: str) -> T.List[str]:
        return []

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

    def get_std_exe_link_args(self) -> T.List[str]:
        return ['-emit-executable']

    def get_module_args(self, modname: str) -> T.List[str]:
        return ['-module-name', modname]

    def get_mod_gen_args(self) -> T.List[str]:
        return ['-emit-module']

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

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

    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 sanity_check(self, work_dir: str, environment: 'Environment') -> None:
        src = 'swifttest.swift'
        source_name = os.path.join(work_dir, src)
        output_name = os.path.join(work_dir, 'swifttest')
        extra_flags: T.List[str] = []
        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', encoding='utf-8') 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 cannot 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: bool) -> T.List[str]:
        return clike_debug_args[is_debug]

    def get_optimization_args(self, optimization_level: str) -> T.List[str]:
        return swift_optimization_args[optimization_level]
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/compilers/vala.py0000644000175000017500000001275114562742363020505 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import os.path
import typing as T

from .. import mlog
from ..mesonlib import EnvironmentException, version_compare, LibType, OptionKey
from .compilers import CompileCheckMode, Compiler

if T.TYPE_CHECKING:
    from ..envconfig import MachineInfo
    from ..environment import Environment
    from ..mesonlib import MachineChoice

class ValaCompiler(Compiler):

    language = 'vala'
    id = 'valac'

    def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice,
                 is_cross: bool, info: 'MachineInfo'):
        super().__init__([], exelist, version, for_machine, info, is_cross=is_cross)
        self.version = version
        self.base_options = {OptionKey('b_colorout')}

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

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

    def get_debug_args(self, is_debug: bool) -> T.List[str]:
        return ['--debug'] if is_debug else []

    def get_output_args(self, outputname: str) -> T.List[str]:
        return [] # Because compiles into C.

    def get_compile_only_args(self) -> T.List[str]:
        return [] # Because compiles into C.

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

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

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

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

    def get_warn_args(self, level: str) -> T.List[str]:
        return []

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

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

    def get_colorout_args(self, colortype: str) -> T.List[str]:
        if version_compare(self.version, '>=0.37.1'):
            return ['--color=' + colortype]
        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[: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: str, environment: 'Environment') -> None:
        code = 'class MesonSanityCheck : Object { }'
        extra_flags: T.List[str] = []
        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=CompileCheckMode.COMPILE) as p:
            if p.returncode != 0:
                msg = f'Vala compiler {self.name_string()!r} cannot compile programs'
                raise EnvironmentException(msg)

    def get_buildtype_args(self, buildtype: str) -> T.List[str]:
        if buildtype in {'debug', 'debugoptimized', 'minsize'}:
            return ['--debug']
        return []

    def find_library(self, libname: str, env: 'Environment', extra_dirs: T.List[str],
                     libtype: LibType = LibType.PREFER_SHARED, lib_prefix_warning: bool = True) -> T.Optional[T.List[str]]:
        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: T.List[str] = []
            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=CompileCheckMode.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(f'Searched {extra_dirs!r} and {libname!r} wasn\'t found')
        return None

    def thread_flags(self, env: 'Environment') -> T.List[str]:
        return []

    def thread_link_flags(self, env: 'Environment') -> T.List[str]:
        return []
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0
meson-1.3.2/mesonbuild/coredata.py0000644000175000017500000017575014562742373017361 0ustar00jpakkanejpakkane# Copyright 2013-2023 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 __future__ import annotations

import copy

from . import mlog, mparser
import pickle, os, uuid
import sys
from itertools import chain
from pathlib import PurePath
from collections import OrderedDict, abc
from dataclasses import dataclass

from .mesonlib import (
    HoldableObject,
    MesonException, EnvironmentException, MachineChoice, PerMachine,
    PerMachineDefaultable, default_libdir, default_libexecdir,
    default_prefix, default_datadir, default_includedir, default_infodir,
    default_localedir, default_mandir, default_sbindir, default_sysconfdir,
    split_args, OptionKey, OptionType, stringlistify,
    pickle_load
)
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.compilers import Compiler, CompileResult, RunResult, CompileCheckMode
    from .dependencies.detect import TV_DepID
    from .environment import Environment
    from .mesonlib import FileOrString
    from .cmake.traceparser import CMakeCacheEntry

    OptionDictType = T.Union[T.Dict[str, 'UserOption[T.Any]'], 'OptionsView']
    MutableKeyedOptionDictType = T.Dict['OptionKey', 'UserOption[T.Any]']
    KeyedOptionDictType = T.Union[MutableKeyedOptionDictType, 'OptionsView']
    CompilerCheckCacheKey = T.Tuple[T.Tuple[str, ...], str, FileOrString, T.Tuple[str, ...], CompileCheckMode]
    # code, args
    RunCheckCacheKey = T.Tuple[str, T.Tuple[str, ...]]

    # typeshed
    StrOrBytesPath = T.Union[str, bytes, os.PathLike[str], os.PathLike[bytes]]

# Check major_versions_differ() if changing versioning scheme.
#
# Pip requires that RCs are named like this: '0.1.0.rc1'
# But the corresponding Git tag needs to be '0.1.0rc1'
version = '1.3.2'

# The next stable version when we are in dev. This is used to allow projects to
# require meson version >=1.2.0 when using 1.1.99. FeatureNew won't warn when
# using a feature introduced in 1.2.0 when using Meson 1.1.99.
stable_version = version
if stable_version.endswith('.99'):
    stable_version_array = stable_version.split('.')
    stable_version_array[-1] = '0'
    stable_version_array[-2] = str(int(stable_version_array[-2]) + 1)
    stable_version = '.'.join(stable_version_array)

backendlist = ['ninja', 'vs', 'vs2010', 'vs2012', 'vs2013', 'vs2015', 'vs2017', 'vs2019', 'vs2022', 'xcode', 'none']
genvslitelist = ['vs2022']
buildtypelist = ['plain', 'debug', 'debugoptimized', 'release', 'minsize', 'custom']

DEFAULT_YIELDING = False

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


def get_genvs_default_buildtype_list() -> list[str]:
    # just debug, debugoptimized, and release for now
    # but this should probably be configurable through some extra option, alongside --genvslite.
    return buildtypelist[1:-2]


class MesonVersionMismatchException(MesonException):
    '''Build directory generated with Meson version is incompatible with current version'''
    def __init__(self, old_version: str, current_version: str, extra_msg: str = '') -> None:
        super().__init__(f'Build directory has been generated with Meson version {old_version}, '
                         f'which is incompatible with the current version {current_version}.'
                         + extra_msg)
        self.old_version = old_version
        self.current_version = current_version


class UserOption(T.Generic[_T], HoldableObject):
    def __init__(self, description: str, choices: T.Optional[T.Union[str, T.List[_T]]],
                 yielding: bool,
                 deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False):
        super().__init__()
        self.choices = choices
        self.description = description
        if not isinstance(yielding, bool):
            raise MesonException('Value of "yielding" must be a boolean.')
        self.yielding = yielding
        self.deprecated = deprecated
        self.readonly = False

    def listify(self, value: T.Any) -> T.List[T.Any]:
        return [value]

    def printable_value(self) -> T.Union[str, int, bool, T.List[T.Union[str, int, bool]]]:
        assert isinstance(self.value, (str, int, bool, list))
        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: T.Any) -> bool:
        oldvalue = getattr(self, 'value', None)
        self.value = self.validate_value(newvalue)
        return self.value != oldvalue

class UserStringOption(UserOption[str]):
    def __init__(self, description: str, value: T.Any, yielding: bool = DEFAULT_YIELDING,
                 deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False):
        super().__init__(description, None, yielding, deprecated)
        self.set_value(value)

    def validate_value(self, value: T.Any) -> str:
        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: str, value: bool, yielding: bool = DEFAULT_YIELDING,
                 deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False):
        super().__init__(description, [True, False], yielding, deprecated)
        self.set_value(value)

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

    def validate_value(self, value: T.Any) -> bool:
        if isinstance(value, bool):
            return value
        if not isinstance(value, str):
            raise MesonException(f'Value {value} cannot be converted to a boolean')
        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: str, value: T.Any, yielding: bool = DEFAULT_YIELDING,
                 deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False):
        min_value, max_value, default_value = value
        self.min_value = min_value
        self.max_value = max_value
        c: T.List[str] = []
        if min_value is not None:
            c.append('>=' + str(min_value))
        if max_value is not None:
            c.append('<=' + str(max_value))
        choices = ', '.join(c)
        super().__init__(description, choices, yielding, deprecated)
        self.set_value(default_value)

    def validate_value(self, value: T.Any) -> 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: str) -> int:
        try:
            return int(valuestring)
        except ValueError:
            raise MesonException('Value string "%s" is not convertible to an integer.' % valuestring)

class OctalInt(int):
    # NinjaBackend.get_user_option_args uses str() to converts it to a command line option
    # UserUmaskOption.toint() uses int(str, 8) to convert it to an integer
    # So we need to use oct instead of dec here if we do not want values to be misinterpreted.
    def __str__(self):
        return oct(int(self))

class UserUmaskOption(UserIntegerOption, UserOption[T.Union[str, OctalInt]]):
    def __init__(self, description: str, value: T.Any, yielding: bool = DEFAULT_YIELDING,
                 deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False):
        super().__init__(description, (0, 0o777, value), yielding, deprecated)
        self.choices = ['preserve', '0000-0777']

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

    def validate_value(self, value: T.Any) -> T.Union[str, OctalInt]:
        if value == 'preserve':
            return 'preserve'
        return OctalInt(super().validate_value(value))

    def toint(self, valuestring: T.Union[str, OctalInt]) -> int:
        try:
            return int(valuestring, 8)
        except ValueError as e:
            raise MesonException(f'Invalid mode: {e}')

class UserComboOption(UserOption[str]):
    def __init__(self, description: str, choices: T.List[str], value: T.Any,
                 yielding: bool = DEFAULT_YIELDING,
                 deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False):
        super().__init__(description, choices, yielding, deprecated)
        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: T.Any) -> str:
        if value not in self.choices:
            if isinstance(value, bool):
                _type = 'boolean'
            elif isinstance(value, (int, float)):
                _type = 'number'
            else:
                _type = 'string'
            optionsstring = ', '.join([f'"{item}"' for item in self.choices])
            raise MesonException('Value "{}" (of type "{}") for combo option "{}" is not one of the choices.'
                                 ' Possible choices are (as string): {}.'.format(
                                     value, _type, self.description, optionsstring))
        return value

class UserArrayOption(UserOption[T.List[str]]):
    def __init__(self, description: str, value: T.Union[str, T.List[str]],
                 split_args: bool = False,
                 allow_dups: bool = False, yielding: bool = DEFAULT_YIELDING,
                 choices: T.Optional[T.List[str]] = None,
                 deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False):
        super().__init__(description, choices if choices is not None else [], yielding, deprecated)
        self.split_args = split_args
        self.allow_dups = allow_dups
        self.set_value(value)

    @staticmethod
    def listify_value(value: T.Union[str, T.List[str]], shlex_split_args: bool = False) -> T.List[str]:
        if isinstance(value, str):
            if value.startswith('['):
                try:
                    newvalue = ast.literal_eval(value)
                except ValueError:
                    raise MesonException(f'malformed option {value}')
            elif value == '':
                newvalue = []
            else:
                if shlex_split_args:
                    newvalue = split_args(value)
                else:
                    newvalue = [v.strip() for v in value.split(',')]
        elif isinstance(value, list):
            newvalue = value
        else:
            raise MesonException(f'"{value}" should be a string array, but it is not')
        return newvalue

    def listify(self, value: T.Any) -> T.List[T.Any]:
        return self.listify_value(value, self.split_args)

    def validate_value(self, value: T.Union[str, T.List[str]]) -> T.List[str]:
        newvalue = self.listify(value)

        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(f'String array element "{newvalue!s}" is not a string.')
        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

    def extend_value(self, value: T.Union[str, T.List[str]]) -> None:
        """Extend the value with an additional value."""
        new = self.validate_value(value)
        self.set_value(self.value + new)


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

    def __init__(self, description: str, value: T.Any, yielding: bool = DEFAULT_YIELDING,
                 deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False):
        super().__init__(description, self.static_choices, value, yielding, deprecated)
        self.name: T.Optional[str] = None  # TODO: Refactor options to all store their name

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

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

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

class UserStdOption(UserComboOption):
    '''
    UserOption specific to c_std and cpp_std options. User can set a list of
    STDs in preference order and it selects the first one supported by current
    compiler.

    For historical reasons, some compilers (msvc) allowed setting a GNU std and
    silently fell back to C std. This is now deprecated. Projects that support
    both GNU and MSVC compilers should set e.g. c_std=gnu11,c11.

    This is not using self.deprecated mechanism we already have for project
    options because we want to print a warning if ALL values are deprecated, not
    if SOME values are deprecated.
    '''
    def __init__(self, lang: str, all_stds: T.List[str]) -> None:
        self.lang = lang.lower()
        self.all_stds = ['none'] + all_stds
        # Map a deprecated std to its replacement. e.g. gnu11 -> c11.
        self.deprecated_stds: T.Dict[str, str] = {}
        super().__init__(f'{lang} language standard to use', ['none'], 'none')

    def set_versions(self, versions: T.List[str], gnu: bool = False, gnu_deprecated: bool = False) -> None:
        assert all(std in self.all_stds for std in versions)
        self.choices += versions
        if gnu:
            gnu_stds_map = {f'gnu{std[1:]}': std for std in versions}
            if gnu_deprecated:
                self.deprecated_stds.update(gnu_stds_map)
            else:
                self.choices += gnu_stds_map.keys()

    def validate_value(self, value: T.Union[str, T.List[str]]) -> str:
        candidates = UserArrayOption.listify_value(value)
        unknown = [std for std in candidates if std not in self.all_stds]
        if unknown:
            raise MesonException(f'Unknown {self.lang.upper()} std {unknown}. Possible values are {self.all_stds}.')
        # Check first if any of the candidates are not deprecated
        for std in candidates:
            if std in self.choices:
                return std
        # Fallback to a deprecated std if any
        for std in candidates:
            newstd = self.deprecated_stds.get(std)
            if newstd is not None:
                mlog.deprecation(
                    f'None of the values {candidates} are supported by the {self.lang} compiler.\n' +
                    f'However, the deprecated {std} std currently falls back to {newstd}.\n' +
                    'This will be an error in the future.\n' +
                    'If the project supports both GNU and MSVC compilers, a value such as\n' +
                    '"c_std=gnu11,c11" specifies that GNU is prefered but it can safely fallback to plain c11.')
                return newstd
        raise MesonException(f'None of values {candidates} are supported by the {self.lang.upper()} compiler. ' +
                             f'Possible values are {self.choices}')

@dataclass
class OptionsView(abc.Mapping):
    '''A view on an options dictionary for a given subproject and with overrides.
    '''

    # TODO: the typing here could be made more explicit using a TypeDict from
    # python 3.8 or typing_extensions
    options: KeyedOptionDictType
    subproject: T.Optional[str] = None
    overrides: T.Optional[T.Mapping[OptionKey, T.Union[str, int, bool, T.List[str]]]] = None

    def __getitem__(self, key: OptionKey) -> UserOption:
        # FIXME: This is fundamentally the same algorithm than interpreter.get_option_internal().
        # We should try to share the code somehow.
        key = key.evolve(subproject=self.subproject)
        if not key.is_project():
            opt = self.options.get(key)
            if opt is None or opt.yielding:
                opt = self.options[key.as_root()]
        else:
            opt = self.options[key]
            if opt.yielding:
                opt = self.options.get(key.as_root(), opt)
        if self.overrides:
            override_value = self.overrides.get(key.as_root())
            if override_value is not None:
                opt = copy.copy(opt)
                opt.set_value(override_value)
        return opt

    def __iter__(self) -> T.Iterator[OptionKey]:
        return iter(self.options)

    def __len__(self) -> int:
        return len(self.options)

class DependencyCacheType(enum.Enum):

    OTHER = 0
    PKG_CONFIG = 1
    CMAKE = 2

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


class DependencySubCache:

    def __init__(self, type_: DependencyCacheType):
        self.types = [type_]
        self.__cache: T.Dict[T.Tuple[str, ...], 'dependencies.Dependency'] = {}

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

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

    def __contains__(self, key: T.Tuple[str, ...]) -> 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: 'KeyedOptionDictType', for_machine: MachineChoice):
        self.__cache: T.MutableMapping[TV_DepID, DependencySubCache] = OrderedDict()
        self.__builtins = builtins
        self.__pkg_conf_key = OptionKey('pkg_config_path', machine=for_machine)
        self.__cmake_key = OptionKey('cmake_prefix_path', machine=for_machine)

    def __calculate_subkey(self, type_: DependencyCacheType) -> T.Tuple[str, ...]:
        data: T.Dict[DependencyCacheType, T.List[str]] = {
            DependencyCacheType.PKG_CONFIG: stringlistify(self.__builtins[self.__pkg_conf_key].value),
            DependencyCacheType.CMAKE: stringlistify(self.__builtins[self.__cmake_key].value),
            DependencyCacheType.OTHER: [],
        }
        assert type_ in data, 'Someone forgot to update subkey calculations for a new type'
        return tuple(data[type_])

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

    def put(self, key: 'TV_DepID', 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: 'TV_DepID') -> 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['TV_DepID']:
        return iter(self.__cache.keys())

    def items(self) -> T.Iterator[T.Tuple['TV_DepID', T.List['dependencies.Dependency']]]:
        for k, v in self.__cache.items():
            vs: T.List[dependencies.Dependency] = []
            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()


class CMakeStateCache:
    """Class that stores internal CMake compiler states.

    This cache is used to reduce the startup overhead of CMake by caching
    all internal CMake compiler variables.
    """

    def __init__(self) -> None:
        self.__cache: T.Dict[str, T.Dict[str, T.List[str]]] = {}
        self.cmake_cache: T.Dict[str, 'CMakeCacheEntry'] = {}

    def __iter__(self) -> T.Iterator[T.Tuple[str, T.Dict[str, T.List[str]]]]:
        return iter(self.__cache.items())

    def items(self) -> T.Iterator[T.Tuple[str, T.Dict[str, T.List[str]]]]:
        return iter(self.__cache.items())

    def update(self, language: str, variables: T.Dict[str, T.List[str]]):
        if language not in self.__cache:
            self.__cache[language] = {}
        self.__cache[language].update(variables)

    @property
    def languages(self) -> T.Set[str]:
        return set(self.__cache.keys())


# 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, meson_command: T.List[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.meson_command = meson_command
        self.target_guids = {}
        self.version = version
        self.options: 'MutableKeyedOptionDictType' = {}
        self.cross_files = self.__load_config_files(options, scratch_dir, 'cross')
        self.compilers: PerMachine[T.Dict[str, Compiler]] = PerMachine(OrderedDict(), OrderedDict())

        # Set of subprojects that have already been initialized once, this is
        # required to be stored and reloaded with the coredata, as we don't
        # want to overwrite options for such subprojects.
        self.initialized_subprojects: T.Set[str] = set()

        # For host == build configurations these caches should be the same.
        self.deps: PerMachine[DependencyCache] = PerMachineDefaultable.default(
            self.is_cross_build(),
            DependencyCache(self.options, MachineChoice.BUILD),
            DependencyCache(self.options, MachineChoice.HOST))

        self.compiler_check_cache: T.Dict['CompilerCheckCacheKey', 'CompileResult'] = OrderedDict()
        self.run_check_cache: T.Dict['RunCheckCacheKey', 'RunResult'] = OrderedDict()

        # CMake cache
        self.cmake_cache: PerMachine[CMakeStateCache] = PerMachine(CMakeStateCache(), CMakeStateCache())

        # Only to print a warning if it changes between Meson invocations.
        self.config_files = self.__load_config_files(options, scratch_dir, 'native')
        self.builtin_options_libdir_cross_fixup()
        self.init_builtins('')

    @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: T.List[str] = []
        missing: T.List[str] = []
        real: 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, f'{uuid.uuid4()}.{ftype}.ini')
                    with open(f, encoding='utf-8') as rf:
                        with open(copy, 'w', encoding='utf-8') 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(f'Cannot find specified {ftype} file: {f}')
        return real

    def builtin_options_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:
            BUILTIN_OPTIONS[OptionKey('libdir')].default = 'lib'

    def sanitize_prefix(self, prefix: str) -> str:
        prefix = os.path.expanduser(prefix)
        if not os.path.isabs(prefix):
            raise MesonException(f'prefix value {prefix!r} must be an absolute path')
        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: str, option: OptionKey, value: T.Any) -> T.Any:
        '''
        If the option is an installation directory option, the value is an
        absolute path and resides within prefix, return the value
        as a path relative to the prefix. Otherwise, return it as is.

        This way everyone can do f.ex, get_option('libdir') and usually get
        the library directory relative to prefix, even though it really
        should not be relied upon.
        '''
        try:
            value = PurePath(value)
        except TypeError:
            return value
        if option.name.endswith('dir') and value.is_absolute() and \
           option not in BUILTIN_DIR_NOPREFIX_OPTIONS:
            try:
                # Try to relativize the path.
                value = value.relative_to(prefix)
            except ValueError:
                # Path is not relative, let’s keep it as is.
                pass
            if '..' in value.parts:
                raise MesonException(
                    f'The value of the \'{option}\' option is \'{value}\' but '
                    'directory options are not allowed to contain \'..\'.\n'
                    f'If you need a path outside of the {prefix!r} prefix, '
                    'please use an absolute path.'
                )
        # .as_posix() keeps the posix-like file separators Meson uses.
        return value.as_posix()

    def init_builtins(self, subproject: str) -> None:
        # Create builtin options with default values
        for key, opt in BUILTIN_OPTIONS.items():
            self.add_builtin_option(self.options, key.evolve(subproject=subproject), opt)
        for for_machine in iter(MachineChoice):
            for key, opt in BUILTIN_OPTIONS_PER_MACHINE.items():
                self.add_builtin_option(self.options, key.evolve(subproject=subproject, machine=for_machine), opt)

    @staticmethod
    def add_builtin_option(opts_map: 'MutableKeyedOptionDictType', key: OptionKey,
                           opt: 'BuiltinOption') -> None:
        if key.subproject:
            if opt.yielding:
                # This option is global and not per-subproject
                return
            value = opts_map[key.as_root()].value
        else:
            value = None
        opts_map[key] = opt.init_option(key, value, default_prefix())

    def init_backend_options(self, backend_name: str) -> None:
        if backend_name == 'ninja':
            self.options[OptionKey('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.options[OptionKey('backend_startup_project')] = UserStringOption(
                'Default project to execute in Visual Studio',
                '')

    def get_option(self, key: OptionKey) -> T.Union[T.List[str], str, int, bool, WrapMode]:
        try:
            v = self.options[key].value
            if key.name == 'wrap_mode':
                return WrapMode[v]
            return v
        except KeyError:
            pass

        try:
            v = self.options[key.as_root()]
            if v.yielding:
                if key.name == 'wrap_mode':
                    return WrapMode[v.value]
                return v.value
        except KeyError:
            pass

        raise MesonException(f'Tried to get unknown builtin option {str(key)}')

    def set_option(self, key: OptionKey, value, first_invocation: bool = False) -> bool:
        dirty = False
        if key.is_builtin():
            if key.name == 'prefix':
                value = self.sanitize_prefix(value)
            else:
                prefix = self.options[OptionKey('prefix')].value
                value = self.sanitize_dir_option_value(prefix, key, value)

        try:
            opt = self.options[key]
        except KeyError:
            raise MesonException(f'Tried to set unknown builtin option {str(key)}')

        if opt.deprecated is True:
            mlog.deprecation(f'Option {key.name!r} is deprecated')
        elif isinstance(opt.deprecated, list):
            for v in opt.listify(value):
                if v in opt.deprecated:
                    mlog.deprecation(f'Option {key.name!r} value {v!r} is deprecated')
        elif isinstance(opt.deprecated, dict):
            def replace(v):
                newvalue = opt.deprecated.get(v)
                if newvalue is not None:
                    mlog.deprecation(f'Option {key.name!r} value {v!r} is replaced by {newvalue!r}')
                    return newvalue
                return v
            newvalue = [replace(v) for v in opt.listify(value)]
            value = ','.join(newvalue)
        elif isinstance(opt.deprecated, str):
            # Option is deprecated and replaced by another. Note that a project
            # option could be replaced by a built-in or module option, which is
            # why we use OptionKey.from_string(newname) instead of
            # key.evolve(newname). We set the value on both the old and new names,
            # assuming they accept the same value. That could for example be
            # achieved by adding the values from old option as deprecated on the
            # new option, for example in the case of boolean option is replaced
            # by a feature option with a different name.
            newname = opt.deprecated
            newkey = OptionKey.from_string(newname).evolve(subproject=key.subproject)
            mlog.deprecation(f'Option {key.name!r} is replaced by {newname!r}')
            dirty |= self.set_option(newkey, value, first_invocation)

        changed = opt.set_value(value)
        if changed and opt.readonly and not first_invocation:
            raise MesonException(f'Tried modify read only option {str(key)!r}')
        dirty |= changed

        if key.name == 'buildtype':
            dirty |= self._set_others_from_buildtype(value)

        return dirty

    def clear_cache(self) -> None:
        self.deps.host.clear()
        self.deps.build.clear()
        self.compiler_check_cache.clear()
        self.run_check_cache.clear()

    def get_nondefault_buildtype_args(self) -> T.List[T.Union[T.Tuple[str, str, str], T.Tuple[str, bool, bool]]]:
        result: T.List[T.Union[T.Tuple[str, str, str], T.Tuple[str, bool, bool]]] = []
        value = self.options[OptionKey('buildtype')].value
        if value == 'plain':
            opt = 'plain'
            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 []
        actual_opt = self.options[OptionKey('optimization')].value
        actual_debug = self.options[OptionKey('debug')].value
        if actual_opt != opt:
            result.append(('optimization', actual_opt, opt))
        if actual_debug != debug:
            result.append(('debug', actual_debug, debug))
        return result

    def _set_others_from_buildtype(self, value: str) -> bool:
        dirty = False

        if value == 'plain':
            opt = 'plain'
            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 False

        dirty |= self.options[OptionKey('optimization')].set_value(opt)
        dirty |= self.options[OptionKey('debug')].set_value(debug)

        return dirty

    @staticmethod
    def is_per_machine_option(optname: OptionKey) -> bool:
        if optname.name in BUILTIN_OPTIONS_PER_MACHINE:
            return True
        return optname.lang is not None

    def get_external_args(self, for_machine: MachineChoice, lang: str) -> T.List[str]:
        return self.options[OptionKey('args', machine=for_machine, lang=lang)].value

    def get_external_link_args(self, for_machine: MachineChoice, lang: str) -> T.List[str]:
        return self.options[OptionKey('link_args', machine=for_machine, lang=lang)].value

    def update_project_options(self, options: 'MutableKeyedOptionDictType') -> None:
        for key, value in options.items():
            if not key.is_project():
                continue
            if key not in self.options:
                self.options[key] = value
                continue

            oldval = self.options[key]
            if type(oldval) is not type(value):
                self.options[key] = value
            elif oldval.choices != value.choices:
                # If the choices have changed, use the new value, but attempt
                # to keep the old options. If they are not valid keep the new
                # defaults but warn.
                self.options[key] = value
                try:
                    value.set_value(oldval.value)
                except MesonException:
                    mlog.warning(f'Old value(s) of {key} are no longer valid, resetting to default ({value.value}).',
                                 fatal=False)

    def is_cross_build(self, when_building_for: MachineChoice = MachineChoice.HOST) -> bool:
        if when_building_for == MachineChoice.BUILD:
            return False
        return len(self.cross_files) > 0

    def copy_build_options_from_regular_ones(self) -> bool:
        dirty = False
        assert not self.is_cross_build()
        for k in BUILTIN_OPTIONS_PER_MACHINE:
            o = self.options[k]
            dirty |= self.options[k.as_build()].set_value(o.value)
        for bk, bv in self.options.items():
            if bk.machine is MachineChoice.BUILD:
                hk = bk.as_host()
                try:
                    hv = self.options[hk]
                    dirty |= bv.set_value(hv.value)
                except KeyError:
                    continue

        return dirty

    def set_options(self, options: T.Dict[OptionKey, T.Any], subproject: str = '', first_invocation: bool = False) -> bool:
        dirty = False
        if not self.is_cross_build():
            options = {k: v for k, v in options.items() if k.machine is not MachineChoice.BUILD}
        # Set prefix first because it's needed to sanitize other options
        pfk = OptionKey('prefix')
        if pfk in options:
            prefix = self.sanitize_prefix(options[pfk])
            dirty |= self.options[OptionKey('prefix')].set_value(prefix)
            for key in BUILTIN_DIR_NOPREFIX_OPTIONS:
                if key not in options:
                    dirty |= self.options[key].set_value(BUILTIN_OPTIONS[key].prefixed_default(key, prefix))

        unknown_options: T.List[OptionKey] = []
        for k, v in options.items():
            if k == pfk:
                continue
            elif k in self.options:
                dirty |= self.set_option(k, v, first_invocation)
            elif k.machine != MachineChoice.BUILD and k.type != OptionType.COMPILER:
                unknown_options.append(k)
        if unknown_options:
            unknown_options_str = ', '.join(sorted(str(s) for s in unknown_options))
            sub = f'In subproject {subproject}: ' if subproject else ''
            raise MesonException(f'{sub}Unknown options: "{unknown_options_str}"')

        if not self.is_cross_build():
            dirty |= self.copy_build_options_from_regular_ones()

        return dirty

    def set_default_options(self, default_options: T.MutableMapping[OptionKey, str], subproject: str, env: 'Environment') -> None:
        # Main project can set default options on subprojects, but subprojects
        # can only set default options on themselves.
        # Preserve order: if env.options has 'buildtype' it must come after
        # 'optimization' if it is in default_options.
        options: T.MutableMapping[OptionKey, T.Any] = OrderedDict()
        for k, v in default_options.items():
            if not subproject or k.subproject == subproject:
                options[k] = v
        options.update(env.options)
        env.options = options

        # Create a subset of options, keeping only project and builtin
        # options for this subproject.
        # 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 = OrderedDict()

        for k, v in env.options.items():
            # If this is a subproject, don't use other subproject options
            if k.subproject and k.subproject != subproject:
                continue
            # If the option is a builtin and is yielding then it's not allowed per subproject.
            #
            # Always test this using the HOST machine, as many builtin options
            # are not valid for the BUILD machine, but the yielding value does
            # not differ between them even when they are valid for both.
            if subproject and k.is_builtin() and self.options[k.evolve(subproject='', machine=MachineChoice.HOST)].yielding:
                continue
            # Skip base, compiler, and backend options, they are handled when
            # adding languages and setting backend.
            if k.type in {OptionType.COMPILER, OptionType.BACKEND, OptionType.BASE}:
                continue
            options[k] = v

        self.set_options(options, subproject=subproject, first_invocation=env.first_invocation)

    def add_compiler_options(self, options: 'MutableKeyedOptionDictType', lang: str, for_machine: MachineChoice,
                             env: 'Environment') -> None:
        for k, o in options.items():
            value = env.options.get(k)
            if value is not None:
                o.set_value(value)
            self.options.setdefault(k, o)

    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
        # These options are all new at this point, because the compiler is
        # responsible for adding its own options, thus calling
        # `self.options.update()`` is perfectly safe.
        self.options.update(compilers.get_global_options(lang, comp, for_machine, env))

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

        self.add_compiler_options(comp.get_options(), lang, comp.for_machine, env)

        enabled_opts: T.List[OptionKey] = []
        for key in comp.base_options:
            if key in self.options:
                continue
            oobj = copy.deepcopy(compilers.base_options[key])
            if key in env.options:
                oobj.set_value(env.options[key])
                enabled_opts.append(key)
            self.options[key] = oobj
        self.emit_base_options_warnings(enabled_opts)

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

class CmdLineFileParser(configparser.ConfigParser):
    def __init__(self) -> None:
        # 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 read(self, filenames: T.Union['StrOrBytesPath', T.Iterable['StrOrBytesPath']], encoding: T.Optional[str] = 'utf-8') -> T.List[str]:
        return super().read(filenames, encoding)

    def optionxform(self, optionstr: str) -> str:
        # Don't call str.lower() on keys
        return optionstr

class MachineFileParser():
    def __init__(self, filenames: T.List[str], sourcedir: str) -> None:
        self.parser = CmdLineFileParser()
        self.constants: T.Dict[str, T.Union[str, bool, int, T.List[str]]] = {'True': True, 'False': False}
        self.sections: T.Dict[str, T.Dict[str, T.Union[str, bool, int, T.List[str]]]] = {}

        for fname in filenames:
            with open(fname, encoding='utf-8') as f:
                content = f.read()
                content = content.replace('@GLOBAL_SOURCE_ROOT@', sourcedir)
                content = content.replace('@DIRNAME@', os.path.dirname(fname))
                try:
                    self.parser.read_string(content, fname)
                except configparser.Error as e:
                    raise EnvironmentException(f'Malformed machine file: {e}')

        # Parse [constants] first so they can be used in other sections
        if self.parser.has_section('constants'):
            self.constants.update(self._parse_section('constants'))

        for s in self.parser.sections():
            if s == 'constants':
                continue
            self.sections[s] = self._parse_section(s)

    def _parse_section(self, s: str) -> T.Dict[str, T.Union[str, bool, int, T.List[str]]]:
        self.scope = self.constants.copy()
        section: T.Dict[str, T.Union[str, bool, int, T.List[str]]] = {}
        for entry, value in self.parser.items(s):
            if ' ' in entry or '\t' in entry or "'" in entry or '"' in entry:
                raise EnvironmentException(f'Malformed variable name {entry!r} in machine file.')
            # Windows paths...
            value = value.replace('\\', '\\\\')
            try:
                ast = mparser.Parser(value, 'machinefile').parse()
                if not ast.lines:
                    raise EnvironmentException('value cannot be empty')
                res = self._evaluate_statement(ast.lines[0])
            except MesonException as e:
                raise EnvironmentException(f'Malformed value in machine file variable {entry!r}: {str(e)}.')
            except KeyError as e:
                raise EnvironmentException(f'Undefined constant {e.args[0]!r} in machine file variable {entry!r}.')
            section[entry] = res
            self.scope[entry] = res
        return section

    def _evaluate_statement(self, node: mparser.BaseNode) -> T.Union[str, bool, int, T.List[str]]:
        if isinstance(node, (mparser.BaseStringNode)):
            return node.value
        elif isinstance(node, mparser.BooleanNode):
            return node.value
        elif isinstance(node, mparser.NumberNode):
            return node.value
        elif isinstance(node, mparser.ParenthesizedNode):
            return self._evaluate_statement(node.inner)
        elif isinstance(node, mparser.ArrayNode):
            # TODO: This is where recursive types would come in handy
            return [self._evaluate_statement(arg) for arg in node.args.arguments]
        elif isinstance(node, mparser.IdNode):
            return self.scope[node.value]
        elif isinstance(node, mparser.ArithmeticNode):
            l = self._evaluate_statement(node.left)
            r = self._evaluate_statement(node.right)
            if node.operation == 'add':
                if (isinstance(l, str) and isinstance(r, str)) or \
                   (isinstance(l, list) and isinstance(r, list)):
                    return l + r
            elif node.operation == 'div':
                if isinstance(l, str) and isinstance(r, str):
                    return os.path.join(l, r)
        raise EnvironmentException('Unsupported node type')

def parse_machine_files(filenames: T.List[str], sourcedir: str):
    parser = MachineFileParser(filenames, sourcedir)
    return parser.sections

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

def read_cmd_line_file(build_dir: str, options: argparse.Namespace) -> None:
    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 = {OptionKey.from_string(k): v for k, v in config['options'].items()}
    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 write_cmd_line_file(build_dir: str, options: argparse.Namespace) -> None:
    filename = get_cmd_line_file(build_dir)
    config = CmdLineFileParser()

    properties: OrderedDict[str, str] = OrderedDict()
    if options.cross_file:
        properties['cross_file'] = options.cross_file
    if options.native_file:
        properties['native_file'] = options.native_file

    config['options'] = {str(k): str(v) for k, v in options.cmd_line_options.items()}
    config['properties'] = properties
    with open(filename, 'w', encoding='utf-8') as f:
        config.write(f)

def update_cmd_line_file(build_dir: str, options: argparse.Namespace):
    filename = get_cmd_line_file(build_dir)
    config = CmdLineFileParser()
    config.read(filename)
    config['options'].update({str(k): str(v) for k, v in options.cmd_line_options.items()})
    with open(filename, 'w', encoding='utf-8') as f:
        config.write(f)

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

def major_versions_differ(v1: str, v2: str) -> bool:
    v1_major, v1_minor = v1.rsplit('.', 1)
    v2_major, v2_minor = v2.rsplit('.', 1)
    # Major version differ, or one is development version but not the other.
    return v1_major != v2_major or ('99' in {v1_minor, v2_minor} and v1_minor != v2_minor)

def load(build_dir: str, suggest_reconfigure: bool = True) -> CoreData:
    filename = os.path.join(build_dir, 'meson-private', 'coredata.dat')
    return pickle_load(filename, 'Coredata', CoreData, suggest_reconfigure)


def save(obj: CoreData, build_dir: str) -> str:
    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: argparse.ArgumentParser) -> None:
    for n, b in BUILTIN_OPTIONS.items():
        b.add_to_argparse(str(n), parser, '')
    for n, b in BUILTIN_OPTIONS_PER_MACHINE.items():
        b.add_to_argparse(str(n), parser, ' (just for host machine)')
        b.add_to_argparse(str(n.as_build()), parser, ' (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: T.List[str], subproject: str = '') -> T.Dict[OptionKey, str]:
    result: T.OrderedDict[OptionKey, str] = OrderedDict()
    for o in options:
        try:
            (key, value) = o.split('=', 1)
        except ValueError:
            raise MesonException(f'Option {o!r} must have a value separated by equals sign.')
        k = OptionKey.from_string(key)
        if subproject:
            k = k.evolve(subproject=subproject)
        result[k] = value
    return result

def parse_cmd_line_options(args: argparse.Namespace) -> None:
    args.cmd_line_options = create_options_dict(args.projectoptions)

    # Merge builtin options set with --option into the dict.
    for key in chain(
            BUILTIN_OPTIONS.keys(),
            (k.as_build() for k in BUILTIN_OPTIONS_PER_MACHINE.keys()),
            BUILTIN_OPTIONS_PER_MACHINE.keys(),
    ):
        name = str(key)
        value = getattr(args, name, None)
        if value is not None:
            if key in args.cmd_line_options:
                cmdline_name = BuiltinOption.argparse_name_to_arg(name)
                raise MesonException(
                    f'Got argument {name} as both -D{name} and {cmdline_name}. Pick one.')
            args.cmd_line_options[key] = value
            delattr(args, name)


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

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

    """Class for a builtin option type.

    There are some cases that are not fully supported yet.
    """

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

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

    def _argparse_action(self) -> T.Optional[str]:
        # If the type is a boolean, the presence of the argument in --foo form
        # is to enable it. Disabling happens by using -Dfoo=false, which is
        # parsed under `args.projectoptions` and does not hit this codepath.
        if isinstance(self.default, bool):
            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: 'OptionKey', 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, help_suffix: str) -> None:
        kwargs = OrderedDict()

        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'] = name

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


# Update `docs/markdown/Builtin-options.md` after changing the options below
# Also update mesonlib._BUILTIN_NAMES. See the comment there for why this is required.
# Please also update completion scripts in $MESONSRC/data/shell-completions/
BUILTIN_DIR_OPTIONS: 'MutableKeyedOptionDictType' = OrderedDict([
    (OptionKey('prefix'),          BuiltinOption(UserStringOption, 'Installation prefix', default_prefix())),
    (OptionKey('bindir'),          BuiltinOption(UserStringOption, 'Executable directory', 'bin')),
    (OptionKey('datadir'),         BuiltinOption(UserStringOption, 'Data file directory', default_datadir())),
    (OptionKey('includedir'),      BuiltinOption(UserStringOption, 'Header file directory', default_includedir())),
    (OptionKey('infodir'),         BuiltinOption(UserStringOption, 'Info page directory', default_infodir())),
    (OptionKey('libdir'),          BuiltinOption(UserStringOption, 'Library directory', default_libdir())),
    (OptionKey('licensedir'),      BuiltinOption(UserStringOption, 'Licenses directory', '')),
    (OptionKey('libexecdir'),      BuiltinOption(UserStringOption, 'Library executable directory', default_libexecdir())),
    (OptionKey('localedir'),       BuiltinOption(UserStringOption, 'Locale data directory', default_localedir())),
    (OptionKey('localstatedir'),   BuiltinOption(UserStringOption, 'Localstate data directory', 'var')),
    (OptionKey('mandir'),          BuiltinOption(UserStringOption, 'Manual page directory', default_mandir())),
    (OptionKey('sbindir'),         BuiltinOption(UserStringOption, 'System executable directory', default_sbindir())),
    (OptionKey('sharedstatedir'),  BuiltinOption(UserStringOption, 'Architecture-independent data directory', 'com')),
    (OptionKey('sysconfdir'),      BuiltinOption(UserStringOption, 'Sysconf data directory', default_sysconfdir())),
])

BUILTIN_CORE_OPTIONS: 'MutableKeyedOptionDictType' = OrderedDict([
    (OptionKey('auto_features'),   BuiltinOption(UserFeatureOption, "Override value of all 'auto' features", 'auto')),
    (OptionKey('backend'),         BuiltinOption(UserComboOption, 'Backend to use', 'ninja', choices=backendlist,
                                                 readonly=True)),
    (OptionKey('genvslite'),
     BuiltinOption(
         UserComboOption,
         'Setup multiple buildtype-suffixed ninja-backend build directories, '
         'and a [builddir]_vs containing a Visual Studio meta-backend with multiple configurations that calls into them',
         'vs2022',
         choices=genvslitelist)
     ),
    (OptionKey('buildtype'),       BuiltinOption(UserComboOption, 'Build type to use', 'debug',
                                                 choices=buildtypelist)),
    (OptionKey('debug'),           BuiltinOption(UserBooleanOption, 'Enable debug symbols and other information', True)),
    (OptionKey('default_library'), BuiltinOption(UserComboOption, 'Default library type', 'shared', choices=['shared', 'static', 'both'],
                                                 yielding=False)),
    (OptionKey('errorlogs'),       BuiltinOption(UserBooleanOption, "Whether to print the logs from failing tests", True)),
    (OptionKey('install_umask'),   BuiltinOption(UserUmaskOption, 'Default umask to apply on permissions of installed files', '022')),
    (OptionKey('layout'),          BuiltinOption(UserComboOption, 'Build directory layout', 'mirror', choices=['mirror', 'flat'])),
    (OptionKey('optimization'),    BuiltinOption(UserComboOption, 'Optimization level', '0', choices=['plain', '0', 'g', '1', '2', '3', 's'])),
    (OptionKey('prefer_static'),   BuiltinOption(UserBooleanOption, 'Whether to try static linking before shared linking', False)),
    (OptionKey('stdsplit'),        BuiltinOption(UserBooleanOption, 'Split stdout and stderr in test logs', True)),
    (OptionKey('strip'),           BuiltinOption(UserBooleanOption, 'Strip targets on install', False)),
    (OptionKey('unity'),           BuiltinOption(UserComboOption, 'Unity build', 'off', choices=['on', 'off', 'subprojects'])),
    (OptionKey('unity_size'),      BuiltinOption(UserIntegerOption, 'Unity block size', (2, None, 4))),
    (OptionKey('warning_level'),   BuiltinOption(UserComboOption, 'Compiler warning level to use', '1', choices=['0', '1', '2', '3', 'everything'], yielding=False)),
    (OptionKey('werror'),          BuiltinOption(UserBooleanOption, 'Treat warnings as errors', False, yielding=False)),
    (OptionKey('wrap_mode'),       BuiltinOption(UserComboOption, 'Wrap mode', 'default', choices=['default', 'nofallback', 'nodownload', 'forcefallback', 'nopromote'])),
    (OptionKey('force_fallback_for'), BuiltinOption(UserArrayOption, 'Force fallback for those subprojects', [])),
    (OptionKey('vsenv'),           BuiltinOption(UserBooleanOption, 'Activate Visual Studio environment', False, readonly=True)),

    # Pkgconfig module
    (OptionKey('relocatable', module='pkgconfig'),
     BuiltinOption(UserBooleanOption, 'Generate pkgconfig files as relocatable', False)),

    # Python module
    (OptionKey('bytecompile', module='python'),
     BuiltinOption(UserIntegerOption, 'Whether to compile bytecode', (-1, 2, 0))),
    (OptionKey('install_env', module='python'),
     BuiltinOption(UserComboOption, 'Which python environment to install to', 'prefix', choices=['auto', 'prefix', 'system', 'venv'])),
    (OptionKey('platlibdir', module='python'),
     BuiltinOption(UserStringOption, 'Directory for site-specific, platform-specific files.', '')),
    (OptionKey('purelibdir', module='python'),
     BuiltinOption(UserStringOption, 'Directory for site-specific, non-platform-specific files.', '')),
    (OptionKey('allow_limited_api', module='python'),
     BuiltinOption(UserBooleanOption, 'Whether to allow use of the Python Limited API', True)),
])

BUILTIN_OPTIONS = OrderedDict(chain(BUILTIN_DIR_OPTIONS.items(), BUILTIN_CORE_OPTIONS.items()))

BUILTIN_OPTIONS_PER_MACHINE: 'MutableKeyedOptionDictType' = OrderedDict([
    (OptionKey('pkg_config_path'), BuiltinOption(UserArrayOption, 'List of additional paths for pkg-config to search', [])),
    (OptionKey('cmake_prefix_path'), BuiltinOption(UserArrayOption, '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: T.Dict[OptionKey, T.Dict[str, str]] = {
    OptionKey('sysconfdir'):     {'/usr': '/etc'},
    OptionKey('localstatedir'):  {'/usr': '/var',     '/usr/local': '/var/local'},
    OptionKey('sharedstatedir'): {'/usr': '/var/lib', '/usr/local': '/var/local/lib'},
    OptionKey('platlibdir', module='python'): {},
    OptionKey('purelibdir', module='python'): {},
}

FORBIDDEN_TARGET_NAMES = frozenset({
    'clean',
    'clean-ctlist',
    'clean-gcno',
    'clean-gcda',
    'coverage',
    'coverage-text',
    'coverage-xml',
    'coverage-html',
    'phony',
    'PHONY',
    'all',
    'test',
    'benchmark',
    'install',
    'uninstall',
    'build.ninja',
    'scan-build',
    'reconfigure',
    'dist',
    'distcheck',
})
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.6666384
meson-1.3.2/mesonbuild/dependencies/0000755000175000017500000000000014562742414017630 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/dependencies/__init__.py0000644000175000017500000002101414562742363021742 0ustar00jpakkanejpakkane# 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 .base import Dependency, InternalDependency, ExternalDependency, NotFoundDependency, MissingCompiler
from .base import (
        ExternalLibrary, DependencyException, DependencyMethods,
        BuiltinDependency, SystemDependency, get_leaf_external_dependencies)
from .detect import find_external_dependency, get_dep_identifier, packages, _packages_accept_language

__all__ = [
    'Dependency',
    'InternalDependency',
    'ExternalDependency',
    'SystemDependency',
    'BuiltinDependency',
    'NotFoundDependency',
    'ExternalLibrary',
    'DependencyException',
    'DependencyMethods',
    'MissingCompiler',

    'find_external_dependency',
    'get_dep_identifier',
    'get_leaf_external_dependencies',
]

"""Dependency representations and discovery logic.

Meson attempts to largely abstract away dependency discovery information, and
to encapsulate that logic itself so that the DSL doesn't have too much direct
information. There are some cases where this is impossible/undesirable, such
as the `get_variable()` method.

Meson has four primary dependency types:
  1. pkg-config
  2. apple frameworks
  3. CMake
  4. system

Plus a few more niche ones.

When a user calls `dependency('foo')` Meson creates a list of candidates, and
tries those candidates in order to find one that matches the criteria
provided by the user (such as version requirements, or optional components
that are required.)

Except to work around bugs or handle odd corner cases, pkg-config and CMake
generally just workā„¢, though there are exceptions. Most of this package is
concerned with dependencies that don't (always) provide CMake and/or
pkg-config files.

For these cases one needs to write a `system` dependency. These dependencies
descend directly from `ExternalDependency`, in their constructor they
manually set up the necessary link and compile args (and additional
dependencies as necessary).

For example, imagine a dependency called Foo, it uses an environment variable
called `$FOO_ROOT` to point to its install root, which looks like this:
```txt
$FOOROOT
→ include/
→ lib/
```
To use Foo, you need its include directory, and you need to link to
`lib/libfoo.ext`.

You could write code that looks like:

```python
class FooSystemDependency(ExternalDependency):

    def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__(name, environment, kwargs)
        root = os.environ.get('FOO_ROOT')
        if root is None:
            mlog.debug('$FOO_ROOT is unset.')
            self.is_found = False
            return

        lib = self.clib_compiler.find_library('foo', environment, [os.path.join(root, 'lib')])
        if lib is None:
            mlog.debug('Could not find lib.')
            self.is_found = False
            return

        self.compile_args.append(f'-I{os.path.join(root, "include")}')
        self.link_args.append(lib)
        self.is_found = True
```

This code will look for `FOO_ROOT` in the environment, handle `FOO_ROOT` being
undefined gracefully, then set its `compile_args` and `link_args` gracefully.
It will also gracefully handle not finding the required lib (hopefully that
doesn't happen, but it could if, for example, the lib is only static and
shared linking is requested).

There are a couple of things about this that still aren't ideal. For one, we
don't want to be reading random environment variables at this point. Those
should actually be added to `envconfig.Properties` and read in
`environment.Environment._set_default_properties_from_env` (see how
`BOOST_ROOT` is handled). We can also handle the `static` keyword and the
`prefer_static` built-in option. So now that becomes:

```python
class FooSystemDependency(ExternalDependency):

    def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__(name, environment, kwargs)
        root = environment.properties[self.for_machine].foo_root
        if root is None:
            mlog.debug('foo_root is unset.')
            self.is_found = False
            return

        get_option = environment.coredata.get_option
        static_opt = kwargs.get('static', get_option(Mesonlib.OptionKey('prefer_static'))
        static = Mesonlib.LibType.STATIC if static_opt else Mesonlib.LibType.SHARED
        lib = self.clib_compiler.find_library(
            'foo', environment, [os.path.join(root, 'lib')], libtype=static)
        if lib is None:
            mlog.debug('Could not find lib.')
            self.is_found = False
            return

        self.compile_args.append(f'-I{os.path.join(root, "include")}')
        self.link_args.append(lib)
        self.is_found = True
```

This is nicer in a couple of ways. First we can properly cross compile as we
are allowed to set `FOO_ROOT` for both the build and host machines, it also
means that users can override this in their machine files, and if that
environment variables changes during a Meson reconfigure Meson won't re-read
it, this is important for reproducibility. Finally, Meson will figure out
whether it should be finding `libfoo.so` or `libfoo.a` (or the platform
specific names). Things are looking pretty good now, so it can be added to
the `packages` dict below:

```python
packages.update({
    'foo': FooSystemDependency,
})
```

Now, what if foo also provides pkg-config, but it's only shipped on Unices,
or only included in very recent versions of the dependency? We can use the
`DependencyFactory` class:

```python
foo_factory = DependencyFactory(
    'foo',
    [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM],
    system_class=FooSystemDependency,
)
```

This is a helper function that will generate a default pkg-config based
dependency, and use the `FooSystemDependency` as well. It can also handle
custom finders for pkg-config and cmake based dependencies that need some
extra help. You would then add the `foo_factory` to packages instead of
`FooSystemDependency`:

```python
packages.update({
    'foo': foo_factory,
})
```

If you have a dependency that is very complicated, (such as having multiple
implementations) you may need to write your own factory function. There are a
number of examples in this package.

_Note_ before we moved to factory functions it was common to use an
`ExternalDependency` class that would instantiate different types of
dependencies and hold the one it found. There are a number of drawbacks to
this approach, and no new dependencies should do this.
"""

# This is a dict where the keys should be strings, and the values must be one
# of:
# - An ExternalDependency subclass
# - A DependencyFactory object
# - A callable with a signature of (Environment, MachineChoice, Dict[str, Any]) -> List[Callable[[], ExternalDependency]]
#
# The internal "defaults" attribute contains a separate dictionary mapping
# for lazy imports. The values must be:
# - a string naming the submodule that should be imported from `mesonbuild.dependencies` to populate the dependency
packages.defaults.update({
    # From dev:
    'gtest': 'dev',
    'gmock': 'dev',
    'llvm': 'dev',
    'valgrind': 'dev',
    'zlib': 'dev',
    'jni': 'dev',
    'jdk': 'dev',

    'boost': 'boost',
    'cuda': 'cuda',

    # per-file
    'coarray': 'coarrays',
    'hdf5': 'hdf5',
    'mpi': 'mpi',
    'scalapack': 'scalapack',

    # From misc:
    'blocks': 'misc',
    'curses': 'misc',
    'netcdf': 'misc',
    'openmp': 'misc',
    'threads': 'misc',
    'pcap': 'misc',
    'cups': 'misc',
    'libwmf': 'misc',
    'libgcrypt': 'misc',
    'gpgme': 'misc',
    'shaderc': 'misc',
    'iconv': 'misc',
    'intl': 'misc',
    'dl': 'misc',
    'openssl': 'misc',
    'libcrypto': 'misc',
    'libssl': 'misc',

    # From platform:
    'appleframeworks': 'platform',

    # from python:
    'python3': 'python',
    'pybind11': 'python',

    # From ui:
    'gl': 'ui',
    'gnustep': 'ui',
    'sdl2': 'ui',
    'wxwidgets': 'ui',
    'vulkan': 'ui',

    # from qt
    'qt4': 'qt',
    'qt5': 'qt',
    'qt6': 'qt',
})
_packages_accept_language.update({
    'hdf5',
    'mpi',
    'netcdf',
    'openmp',
})
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/dependencies/base.py0000644000175000017500000006703514562742363021132 0ustar00jpakkanejpakkane# 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.

from __future__ import annotations
import copy
import os
import collections
import itertools
import typing as T
from enum import Enum

from .. import mlog, mesonlib
from ..compilers import clib_langs
from ..mesonlib import LibType, MachineChoice, MesonException, HoldableObject, OptionKey
from ..mesonlib import version_compare_many
#from ..interpreterbase import FeatureDeprecated, FeatureNew

if T.TYPE_CHECKING:
    from ..compilers.compilers import Compiler
    from ..environment import Environment
    from ..interpreterbase import FeatureCheckBase
    from ..build import (
        CustomTarget, IncludeDirs, CustomTargetIndex, LibTypes,
        StaticLibrary, StructuredSources, ExtractedObjects, GeneratedTypes
    )
    from ..interpreter.type_checking import PkgConfigDefineType

    _MissingCompilerBase = Compiler
else:
    _MissingCompilerBase = object


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


class MissingCompiler(_MissingCompilerBase):
    """Represent a None Compiler - when no tool chain is found.
    replacing AttributeError with DependencyException"""

    # These are needed in type checking mode to avoid errors, but we don't want
    # the extra overhead at runtime
    if T.TYPE_CHECKING:
        def __init__(self) -> None:
            pass

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

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

        def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
            return None

    def __getattr__(self, item: str) -> T.Any:
        if item.startswith('__'):
            raise AttributeError()
        raise DependencyException('no toolchain found')

    def __bool__(self) -> bool:
        return False


class DependencyMethods(Enum):
    # Auto means to use whatever dependency checking mechanisms in whatever order meson thinks is best.
    AUTO = 'auto'
    PKGCONFIG = 'pkg-config'
    CMAKE = 'cmake'
    # The dependency is provided by the standard library and does not need to be linked
    BUILTIN = 'builtin'
    # 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'
    QMAKE = 'qmake'
    # Misc
    DUB = 'dub'


DependencyTypeName = T.NewType('DependencyTypeName', str)


class Dependency(HoldableObject):

    @classmethod
    def _process_include_type_kw(cls, kwargs: T.Dict[str, T.Any]) -> 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: DependencyTypeName, kwargs: T.Dict[str, T.Any]) -> None:
        self.name = f'dep{id(self)}'
        self.version:  T.Optional[str] = None
        self.language: T.Optional[str] = None # None means C-like
        self.is_found = False
        self.type_name = type_name
        self.compile_args: T.List[str] = []
        self.link_args:    T.List[str] = []
        # Raw -L and -l arguments without manual library searching
        # If None, self.link_args will be used
        self.raw_link_args: T.Optional[T.List[str]] = None
        self.sources: T.List[T.Union[mesonlib.File, GeneratedTypes, 'StructuredSources']] = []
        self.extra_files: T.List[mesonlib.File] = []
        self.include_type = self._process_include_type_kw(kwargs)
        self.ext_deps: T.List[Dependency] = []
        self.d_features: T.DefaultDict[str, T.List[T.Any]] = collections.defaultdict(list)
        self.featurechecks: T.List['FeatureCheckBase'] = []
        self.feature_since: T.Optional[T.Tuple[str, str]] = None

    def __repr__(self) -> str:
        return f'<{self.__class__.__name__} {self.name}: {self.is_found}>'

    def is_built(self) -> bool:
        return False

    def summary_value(self) -> T.Union[str, mlog.AnsiDecorator, mlog.AnsiText]:
        if not self.found():
            return mlog.red('NO')
        if not self.version:
            return mlog.green('YES')
        return mlog.AnsiText(mlog.green('YES'), ' ', mlog.cyan(self.version))

    def get_compile_args(self) -> T.List[str]:
        if self.include_type == 'system':
            converted = []
            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_all_compile_args(self) -> T.List[str]:
        """Get the compile arguments from this dependency and it's sub dependencies."""
        return list(itertools.chain(self.get_compile_args(),
                                    *(d.get_all_compile_args() for d in self.ext_deps)))

    def get_link_args(self, language: T.Optional[str] = None, 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 get_all_link_args(self) -> T.List[str]:
        """Get the link arguments from this dependency and it's sub dependencies."""
        return list(itertools.chain(self.get_link_args(),
                                    *(d.get_all_link_args() for d in self.ext_deps)))

    def found(self) -> bool:
        return self.is_found

    def get_sources(self) -> T.List[T.Union[mesonlib.File, GeneratedTypes, 'StructuredSources']]:
        """Source files that need to be added to the target.
        As an example, gtest-all.cc when using GTest."""
        return self.sources

    def get_extra_files(self) -> T.List[mesonlib.File]:
        """Mostly for introspection and IDEs"""
        return self.extra_files

    def get_name(self) -> str:
        return self.name

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

    def get_include_dirs(self) -> T.List['IncludeDirs']:
        return []

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

    def get_exe_args(self, compiler: 'Compiler') -> T.List[str]:
        return []

    def get_partial_dependency(self, *, compile_args: bool = False,
                               link_args: bool = False, links: bool = False,
                               includes: bool = False, sources: bool = False) -> 'Dependency':
        """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, deplist: T.Iterable[T.Callable[[], 'Dependency']]) -> bool:
        """Add an internal dependency from a list of possible dependencies.

        This method is intended to make it easier to add additional
        dependencies to another dependency internally.

        Returns true if the dependency was successfully added, false
        otherwise.
        """
        for d in deplist:
            dep = d()
            if dep.is_found:
                self.ext_deps.append(dep)
                return True
        return False

    def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None,
                     configtool: T.Optional[str] = None, internal: T.Optional[str] = None,
                     default_value: T.Optional[str] = None,
                     pkgconfig_define: PkgConfigDefineType = None) -> str:
        if default_value is not None:
            return default_value
        raise DependencyException(f'No default provided for dependency {self!r}, which is not pkg-config, cmake, or config-tool based.')

    def generate_system_dependency(self, include_type: str) -> '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: str, incdirs: T.List['IncludeDirs'], compile_args: T.List[str],
                 link_args: T.List[str],
                 libraries: T.List[LibTypes],
                 whole_libraries: T.List[T.Union[StaticLibrary, CustomTarget, CustomTargetIndex]],
                 sources: T.Sequence[T.Union[mesonlib.File, GeneratedTypes, StructuredSources]],
                 extra_files: T.Sequence[mesonlib.File],
                 ext_deps: T.List[Dependency], variables: T.Dict[str, str],
                 d_module_versions: T.List[T.Union[str, int]], d_import_dirs: T.List['IncludeDirs'],
                 objects: T.List['ExtractedObjects']):
        super().__init__(DependencyTypeName('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 = list(sources)
        self.extra_files = list(extra_files)
        self.ext_deps = ext_deps
        self.variables = variables
        self.objects = objects
        if d_module_versions:
            self.d_features['versions'] = d_module_versions
        if d_import_dirs:
            self.d_features['import_dirs'] = d_import_dirs

    def __deepcopy__(self, memo: T.Dict[int, 'InternalDependency']) -> 'InternalDependency':
        result = self.__class__.__new__(self.__class__)
        assert isinstance(result, InternalDependency)
        memo[id(self)] = result
        for k, v in self.__dict__.items():
            if k in {'libraries', 'whole_libraries'}:
                setattr(result, k, copy.copy(v))
            else:
                setattr(result, k, copy.deepcopy(v, memo))
        return result

    def summary_value(self) -> mlog.AnsiDecorator:
        # Omit the version.  Most of the time it will be just the project
        # version, which is uninteresting in the summary.
        return mlog.green('YES')

    def is_built(self) -> bool:
        if self.sources or self.libraries or self.whole_libraries:
            return True
        return any(d.is_built() for d in self.ext_deps)

    def get_partial_dependency(self, *, compile_args: bool = False,
                               link_args: bool = False, links: bool = False,
                               includes: bool = False, sources: bool = False,
                               extra_files: bool = False) -> InternalDependency:
        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_extra_files = self.extra_files.copy() if extra_files 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_extra_files, final_deps, self.variables, [], [], [])

    def get_include_dirs(self) -> T.List['IncludeDirs']:
        return self.include_directories

    def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None,
                     configtool: T.Optional[str] = None, internal: T.Optional[str] = None,
                     default_value: T.Optional[str] = None,
                     pkgconfig_define: PkgConfigDefineType = None) -> str:
        val = self.variables.get(internal, default_value)
        if val is not None:
            return val
        raise DependencyException(f'Could not get an internal variable and no default provided for {self!r}')

    def generate_link_whole_dependency(self) -> Dependency:
        from ..build import SharedLibrary, CustomTarget, CustomTargetIndex
        new_dep = copy.deepcopy(self)
        for x in new_dep.libraries:
            if isinstance(x, SharedLibrary):
                raise MesonException('Cannot convert a dependency to link_whole when it contains a '
                                     'SharedLibrary')
            elif isinstance(x, (CustomTarget, CustomTargetIndex)) and x.links_dynamically():
                raise MesonException('Cannot convert a dependency to link_whole when it contains a '
                                     'CustomTarget or CustomTargetIndex which is a shared library')

        # Mypy doesn't understand that the above is a TypeGuard
        new_dep.whole_libraries += T.cast('T.List[T.Union[StaticLibrary, CustomTarget, CustomTargetIndex]]',
                                          new_dep.libraries)
        new_dep.libraries = []
        return new_dep

class HasNativeKwarg:
    def __init__(self, kwargs: T.Dict[str, T.Any]):
        self.for_machine = self.get_for_machine_from_kwargs(kwargs)

    def get_for_machine_from_kwargs(self, kwargs: T.Dict[str, T.Any]) -> MachineChoice:
        return MachineChoice.BUILD if kwargs.get('native', False) else MachineChoice.HOST

class ExternalDependency(Dependency, HasNativeKwarg):
    def __init__(self, type_name: DependencyTypeName, environment: 'Environment', kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None):
        Dependency.__init__(self, type_name, kwargs)
        self.env = environment
        self.name = type_name # default
        self.is_found = False
        self.language = language
        version_reqs = kwargs.get('version', None)
        if isinstance(version_reqs, str):
            version_reqs = [version_reqs]
        self.version_reqs: T.Optional[T.List[str]] = version_reqs
        self.required = kwargs.get('required', True)
        self.silent = kwargs.get('silent', False)
        self.static = kwargs.get('static', self.env.coredata.get_option(OptionKey('prefer_static')))
        self.libtype = LibType.STATIC if self.static else LibType.PREFER_SHARED
        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 = detect_compiler(self.name, environment, self.for_machine, self.language)

    def get_compiler(self) -> T.Union['MissingCompiler', 'Compiler']:
        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) -> Dependency:
        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:
            pass # TODO maybe filter compile_args?
        if not sources:
            new.sources = []

        return new

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

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

    @staticmethod
    def log_tried() -> str:
        return ''

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

        if self.version_reqs:
            # an unknown version can never satisfy any requirement
            if not self.version:
                self.is_found = False
                found_msg: mlog.TV_LoggableList = []
                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 = f'Unknown version, but need {self.version_reqs!r}.'
                    raise DependencyException(m)

            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([f"'{e}'" for e in not_found]))]
                    if found:
                        found_msg += ['; matched:',
                                      ', '.join([f"'{e}'" for e in found])]
                    mlog.log(*found_msg)

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


class NotFoundDependency(Dependency):
    def __init__(self, name: str, environment: 'Environment') -> None:
        super().__init__(DependencyTypeName('not-found'), {})
        self.env = environment
        self.name = name
        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) -> 'NotFoundDependency':
        return copy.copy(self)


class ExternalLibrary(ExternalDependency):
    def __init__(self, name: str, link_args: T.List[str], environment: 'Environment',
                 language: str, silent: bool = False) -> None:
        super().__init__(DependencyTypeName('library'), environment, {}, language=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: T.Optional[str] = None, raw: bool = False) -> T.List[str]:
        '''
        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(language=language, raw=raw)

    def get_partial_dependency(self, *, compile_args: bool = False,
                               link_args: bool = False, links: bool = False,
                               includes: bool = False, sources: bool = False) -> 'ExternalLibrary':
        # 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


def get_leaf_external_dependencies(deps: T.List[Dependency]) -> T.List[Dependency]:
    if not deps:
        # Ensure that we always return a new instance
        return deps.copy()
    final_deps = []
    while deps:
        next_deps = []
        for d in mesonlib.listify(deps):
            if not isinstance(d, Dependency) or d.is_built():
                raise DependencyException('Dependencies must be external dependencies')
            final_deps.append(d)
            next_deps.extend(d.ext_deps)
        deps = next_deps
    return final_deps


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: str) -> T.Tuple[int, int]:
        common_lengths: T.List[int] = []
        for refpath in refpaths:
            try:
                common_path: str = 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: 'Environment', for_machine: MachineChoice, link_args: T.List[str]) -> T.List[str]:
    """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 = {f'-L{p}' for p in environment.get_compiler_system_lib_dirs(for_machine)}
    return [l for l in link_args if l not in exclude]

def strip_system_includedirs(environment: 'Environment', for_machine: MachineChoice, include_args: T.List[str]) -> T.List[str]:
    """Remove -I arguments.

    leaving these in will break builds where user want dependencies with system
    include-type used in rust.bindgen targets as if will cause system headers
    to not be found.
    """

    exclude = {f'-I{p}' for p in environment.get_compiler_system_include_dirs(for_machine)}
    return [i for i in include_args if i not in exclude]

def process_method_kw(possible: T.Iterable[DependencyMethods], kwargs: T.Dict[str, T.Any]) -> T.List[DependencyMethods]:
    method: T.Union[DependencyMethods, str] = kwargs.get('method', 'auto')
    if isinstance(method, DependencyMethods):
        return [method]
    # TODO: try/except?
    if method not in [e.value for e in DependencyMethods]:
        raise DependencyException(f'method {method!r} is invalid')
    method = DependencyMethods(method)

    # Raise FeatureNew where appropriate
    if method is DependencyMethods.CONFIG_TOOL:
        # FIXME: needs to get a handle on the subproject
        # FeatureNew.single_use('Configuration method "config-tool"', '0.44.0')
        pass
    # 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]:
        # FIXME: needs to get a handle on the subproject
        #FeatureDeprecated.single_use(f'Configuration method {method.value}', '0.44', 'Use "config-tool" instead.')
        method = DependencyMethods.CONFIG_TOOL
    if method is DependencyMethods.QMAKE:
        # FIXME: needs to get a handle on the subproject
        # FeatureDeprecated.single_use('Configuration method "qmake"', '0.58', 'Use "config-tool" instead.')
        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 = list(possible)
    elif method in possible:
        methods = [method]
    else:
        raise DependencyException(
            'Unsupported detection method: {}, allowed methods are {}'.format(
                method.value,
                mlog.format_list([x.value for x in [DependencyMethods.AUTO] + list(possible)])))

    return methods

def detect_compiler(name: str, env: 'Environment', for_machine: MachineChoice,
                    language: T.Optional[str]) -> T.Union['MissingCompiler', 'Compiler']:
    """Given a language and environment find the compiler used."""
    compilers = env.coredata.compilers[for_machine]

    # Set the compiler for this dependency if a language is specified,
    # else try to pick something that looks usable.
    if language:
        if language not in compilers:
            m = name.capitalize() + ' requires a {0} compiler, but ' \
                '{0} is not in the list of project languages'
            raise DependencyException(m.format(language.capitalize()))
        return compilers[language]
    else:
        for lang in clib_langs:
            try:
                return compilers[lang]
            except KeyError:
                continue
    return MissingCompiler()


class SystemDependency(ExternalDependency):

    """Dependency base for System type dependencies."""

    def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any],
                 language: T.Optional[str] = None) -> None:
        super().__init__(DependencyTypeName('system'), env, kwargs, language=language)
        self.name = name

    @staticmethod
    def log_tried() -> str:
        return 'system'


class BuiltinDependency(ExternalDependency):

    """Dependency base for Builtin type dependencies."""

    def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any],
                 language: T.Optional[str] = None) -> None:
        super().__init__(DependencyTypeName('builtin'), env, kwargs, language=language)
        self.name = name

    @staticmethod
    def log_tried() -> str:
        return 'builtin'
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/dependencies/boost.py0000644000175000017500000011512114562742363021334 0ustar00jpakkanejpakkane# Copyright 2013-2020 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 __future__ import annotations

import re
import dataclasses
import functools
import typing as T
from pathlib import Path

from .. import mlog
from .. import mesonlib

from .base import DependencyException, SystemDependency
from .detect import packages
from .pkgconfig import PkgConfigDependency
from .misc import threads_factory

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

# 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
#
# 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.
#
# We follow the following strategy for finding modules:
# A) Detect potential boost root directories (uses also BOOST_ROOT env var)
# B) Foreach candidate
#   1. Look for the boost headers (boost/version.pp)
#   2. Find all boost libraries
#     2.1 Add all libraries in lib*
#     2.2 Filter out non boost libraries
#     2.3 Filter the remaining libraries based on the meson requirements (static/shared, etc.)
#     2.4 Ensure that all libraries have the same boost tag (and are thus compatible)
#   3. Select the libraries matching the requested modules

@dataclasses.dataclass(eq=False, order=False)
class UnknownFileException(Exception):
    path: Path

@functools.total_ordering
class BoostIncludeDir():
    def __init__(self, path: Path, version_int: int):
        self.path = path
        self.version_int = version_int
        major = int(self.version_int / 100000)
        minor = int((self.version_int / 100) % 1000)
        patch = int(self.version_int % 100)
        self.version = f'{major}.{minor}.{patch}'
        self.version_lib = f'{major}_{minor}'

    def __repr__(self) -> str:
        return f''

    def __lt__(self, other: object) -> bool:
        if isinstance(other, BoostIncludeDir):
            return (self.version_int, self.path) < (other.version_int, other.path)
        return NotImplemented

@functools.total_ordering
class BoostLibraryFile():
    # Python libraries are special because of the included
    # minor version in the module name.
    boost_python_libs = ['boost_python', 'boost_numpy']
    reg_python_mod_split = re.compile(r'(boost_[a-zA-Z]+)([0-9]*)')

    reg_abi_tag = re.compile(r'^s?g?y?d?p?n?$')
    reg_ver_tag = re.compile(r'^[0-9_]+$')

    def __init__(self, path: Path):
        self.path = path
        self.name = self.path.name

        # Initialize default properties
        self.static = False
        self.toolset = ''
        self.arch = ''
        self.version_lib = ''
        self.mt = True

        self.runtime_static = False
        self.runtime_debug = False
        self.python_debug = False
        self.debug = False
        self.stlport = False
        self.deprecated_iostreams = False

        # Post process the library name
        name_parts = self.name.split('.')
        self.basename = name_parts[0]
        self.suffixes = name_parts[1:]
        self.vers_raw = [x for x in self.suffixes if x.isdigit()]
        self.suffixes = [x for x in self.suffixes if not x.isdigit()]
        self.nvsuffix = '.'.join(self.suffixes)  # Used for detecting the library type
        self.nametags = self.basename.split('-')
        self.mod_name = self.nametags[0]
        if self.mod_name.startswith('lib'):
            self.mod_name = self.mod_name[3:]

        # Set library version if possible
        if len(self.vers_raw) >= 2:
            self.version_lib = '{}_{}'.format(self.vers_raw[0], self.vers_raw[1])

        # Detecting library type
        if self.nvsuffix in {'so', 'dll', 'dll.a', 'dll.lib', 'dylib'}:
            self.static = False
        elif self.nvsuffix in {'a', 'lib'}:
            self.static = True
        else:
            raise UnknownFileException(self.path)

        # boost_.lib is the dll import library
        if self.basename.startswith('boost_') and self.nvsuffix == 'lib':
            self.static = False

        # Process tags
        tags = self.nametags[1:]
        # Filter out the python version tag and fix modname
        if self.is_python_lib():
            tags = self.fix_python_name(tags)
        if not tags:
            return

        # Without any tags mt is assumed, however, an absence of mt in the name
        # with tags present indicates that the lib was built without mt support
        self.mt = False
        for i in tags:
            if i == 'mt':
                self.mt = True
            elif len(i) == 3 and i[1:] in {'32', '64'}:
                self.arch = i
            elif BoostLibraryFile.reg_abi_tag.match(i):
                self.runtime_static = 's' in i
                self.runtime_debug = 'g' in i
                self.python_debug = 'y' in i
                self.debug = 'd' in i
                self.stlport = 'p' in i
                self.deprecated_iostreams = 'n' in i
            elif BoostLibraryFile.reg_ver_tag.match(i):
                self.version_lib = i
            else:
                self.toolset = i

    def __repr__(self) -> str:
        return f''

    def __lt__(self, other: object) -> bool:
        if isinstance(other, BoostLibraryFile):
            return (
                self.mod_name, self.static, self.version_lib, self.arch,
                not self.mt, not self.runtime_static,
                not self.debug, self.runtime_debug, self.python_debug,
                self.stlport, self.deprecated_iostreams,
                self.name,
            ) < (
                other.mod_name, other.static, other.version_lib, other.arch,
                not other.mt, not other.runtime_static,
                not other.debug, other.runtime_debug, other.python_debug,
                other.stlport, other.deprecated_iostreams,
                other.name,
            )
        return NotImplemented

    def __eq__(self, other: object) -> bool:
        if isinstance(other, BoostLibraryFile):
            return self.name == other.name
        return NotImplemented

    def __hash__(self) -> int:
        return hash(self.name)

    @property
    def abitag(self) -> str:
        abitag = ''
        abitag += 'S' if self.static else '-'
        abitag += 'M' if self.mt else '-'
        abitag += ' '
        abitag += 's' if self.runtime_static else '-'
        abitag += 'g' if self.runtime_debug else '-'
        abitag += 'y' if self.python_debug else '-'
        abitag += 'd' if self.debug else '-'
        abitag += 'p' if self.stlport else '-'
        abitag += 'n' if self.deprecated_iostreams else '-'
        abitag += ' ' + (self.arch or '???')
        abitag += ' ' + (self.toolset or '?')
        abitag += ' ' + (self.version_lib or 'x_xx')
        return abitag

    def is_boost(self) -> bool:
        return any(self.name.startswith(x) for x in ['libboost_', 'boost_'])

    def is_python_lib(self) -> bool:
        return any(self.mod_name.startswith(x) for x in BoostLibraryFile.boost_python_libs)

    def fix_python_name(self, tags: T.List[str]) -> T.List[str]:
        # Handle the boost_python naming madness.
        # See https://github.com/mesonbuild/meson/issues/4788 for some distro
        # specific naming variations.
        other_tags: T.List[str] = []

        # Split the current modname into the base name and the version
        m_cur = BoostLibraryFile.reg_python_mod_split.match(self.mod_name)
        cur_name = m_cur.group(1)
        cur_vers = m_cur.group(2)

        # Update the current version string if the new version string is longer
        def update_vers(new_vers: str) -> None:
            nonlocal cur_vers
            new_vers = new_vers.replace('_', '')
            new_vers = new_vers.replace('.', '')
            if not new_vers.isdigit():
                return
            if len(new_vers) > len(cur_vers):
                cur_vers = new_vers

        for i in tags:
            if i.startswith('py'):
                update_vers(i[2:])
            elif i.isdigit():
                update_vers(i)
            elif len(i) >= 3 and i[0].isdigit and i[2].isdigit() and i[1] == '.':
                update_vers(i)
            else:
                other_tags += [i]

        self.mod_name = cur_name + cur_vers
        return other_tags

    def mod_name_matches(self, mod_name: str) -> bool:
        if self.mod_name == mod_name:
            return True
        if not self.is_python_lib():
            return False

        m_cur = BoostLibraryFile.reg_python_mod_split.match(self.mod_name)
        m_arg = BoostLibraryFile.reg_python_mod_split.match(mod_name)

        if not m_cur or not m_arg:
            return False

        if m_cur.group(1) != m_arg.group(1):
            return False

        cur_vers = m_cur.group(2)
        arg_vers = m_arg.group(2)

        # Always assume python 2 if nothing is specified
        if not arg_vers:
            arg_vers = '2'

        return cur_vers.startswith(arg_vers)

    def version_matches(self, version_lib: str) -> bool:
        # If no version tag is present, assume that it fits
        if not self.version_lib or not version_lib:
            return True
        return self.version_lib == version_lib

    def arch_matches(self, arch: str) -> bool:
        # If no version tag is present, assume that it fits
        if not self.arch or not arch:
            return True
        return self.arch == arch

    def vscrt_matches(self, vscrt: str) -> bool:
        # If no vscrt tag present, assume that it fits  ['/MD', '/MDd', '/MT', '/MTd']
        if not vscrt:
            return True
        if vscrt in {'/MD', '-MD'}:
            return not self.runtime_static and not self.runtime_debug
        elif vscrt in {'/MDd', '-MDd'}:
            return not self.runtime_static and self.runtime_debug
        elif vscrt in {'/MT', '-MT'}:
            return (self.runtime_static or not self.static) and not self.runtime_debug
        elif vscrt in {'/MTd', '-MTd'}:
            return (self.runtime_static or not self.static) and self.runtime_debug

        mlog.warning(f'Boost: unknown vscrt tag {vscrt}. This may cause the compilation to fail. Please consider reporting this as a bug.', once=True)
        return True

    def get_compiler_args(self) -> T.List[str]:
        args: T.List[str] = []
        if self.mod_name in boost_libraries:
            libdef = boost_libraries[self.mod_name]
            if self.static:
                args += libdef.static
            else:
                args += libdef.shared
            if self.mt:
                args += libdef.multi
            else:
                args += libdef.single
        return args

    def get_link_args(self) -> T.List[str]:
        return [self.path.as_posix()]

class BoostDependency(SystemDependency):
    def __init__(self, environment: Environment, kwargs: T.Dict[str, T.Any]) -> None:
        super().__init__('boost', environment, kwargs, language='cpp')
        buildtype = environment.coredata.get_option(mesonlib.OptionKey('buildtype'))
        assert isinstance(buildtype, str)
        self.debug = buildtype.startswith('debug')
        self.multithreading = kwargs.get('threading', 'multi') == 'multi'

        self.boost_root: T.Optional[Path] = None
        self.explicit_static = 'static' in kwargs

        # Extract and validate modules
        self.modules: T.List[str] = mesonlib.extract_as_list(kwargs, 'modules')
        for i in self.modules:
            if not isinstance(i, str):
                raise DependencyException('Boost module argument is not a string.')
            if i.startswith('boost_'):
                raise DependencyException('Boost modules must be passed without the boost_ prefix')

        self.modules_found: T.List[str] = []
        self.modules_missing: T.List[str] = []

        # Do we need threads?
        if 'thread' in self.modules:
            if not self._add_sub_dependency(threads_factory(environment, self.for_machine, {})):
                self.is_found = False
                return

        # Try figuring out the architecture tag
        self.arch = environment.machines[self.for_machine].cpu_family
        self.arch = boost_arch_map.get(self.arch, None)

        # First, look for paths specified in a machine file
        props = self.env.properties[self.for_machine]
        if any(x in self.env.properties[self.for_machine] for x in
               ['boost_includedir', 'boost_librarydir', 'boost_root']):
            self.detect_boost_machine_file(props)
            return

        # Finally, look for paths from .pc files and from searching the filesystem
        self.detect_roots()

    def check_and_set_roots(self, roots: T.List[Path], use_system: bool) -> None:
        roots = list(mesonlib.OrderedSet(roots))
        for j in roots:
            #   1. Look for the boost headers (boost/version.hpp)
            mlog.debug(f'Checking potential boost root {j.as_posix()}')
            inc_dirs = self.detect_inc_dirs(j)
            inc_dirs = sorted(inc_dirs, reverse=True)  # Prefer the newer versions

            # Early abort when boost is not found
            if not inc_dirs:
                continue

            lib_dirs = self.detect_lib_dirs(j, use_system)
            self.is_found = self.run_check(inc_dirs, lib_dirs)
            if self.is_found:
                self.boost_root = j
                break

    def detect_boost_machine_file(self, props: 'Properties') -> None:
        """Detect boost with values in the machine file or environment.

        The machine file values are defaulted to the environment values.
        """
        # XXX: if we had a TypedDict we wouldn't need this
        incdir = props.get('boost_includedir')
        assert incdir is None or isinstance(incdir, str)
        libdir = props.get('boost_librarydir')
        assert libdir is None or isinstance(libdir, str)

        if incdir and libdir:
            inc_dir = Path(incdir)
            lib_dir = Path(libdir)

            if not inc_dir.is_absolute() or not lib_dir.is_absolute():
                raise DependencyException('Paths given for boost_includedir and boost_librarydir in machine file must be absolute')

            mlog.debug('Trying to find boost with:')
            mlog.debug(f'  - boost_includedir = {inc_dir}')
            mlog.debug(f'  - boost_librarydir = {lib_dir}')

            return self.detect_split_root(inc_dir, lib_dir)

        elif incdir or libdir:
            raise DependencyException('Both boost_includedir *and* boost_librarydir have to be set in your machine file (one is not enough)')

        rootdir = props.get('boost_root')
        # It shouldn't be possible to get here without something in boost_root
        assert rootdir

        raw_paths = mesonlib.stringlistify(rootdir)
        paths = [Path(x) for x in raw_paths]
        if paths and any(not x.is_absolute() for x in paths):
            raise DependencyException('boost_root path given in machine file must be absolute')

        self.check_and_set_roots(paths, use_system=False)

    def run_check(self, inc_dirs: T.List[BoostIncludeDir], lib_dirs: T.List[Path]) -> bool:
        mlog.debug('  - potential library dirs: {}'.format([x.as_posix() for x in lib_dirs]))
        mlog.debug('  - potential include dirs: {}'.format([x.path.as_posix() for x in inc_dirs]))

        #   2. Find all boost libraries
        libs: T.List[BoostLibraryFile] = []
        for i in lib_dirs:
            libs = self.detect_libraries(i)
            if libs:
                mlog.debug(f'  - found boost library dir: {i}')
                # mlog.debug('  - raw library list:')
                # for j in libs:
                #     mlog.debug('    - {}'.format(j))
                break
        libs = sorted(set(libs))

        modules = ['boost_' + x for x in self.modules]
        for inc in inc_dirs:
            mlog.debug(f'  - found boost {inc.version} include dir: {inc.path}')
            f_libs = self.filter_libraries(libs, inc.version_lib)

            mlog.debug('  - filtered library list:')
            for j in f_libs:
                mlog.debug(f'    - {j}')

            #   3. Select the libraries matching the requested modules
            not_found: T.List[str] = []
            selected_modules: T.List[BoostLibraryFile] = []
            for mod in modules:
                found = False
                for l in f_libs:
                    if l.mod_name_matches(mod):
                        selected_modules += [l]
                        found = True
                        break
                if not found:
                    not_found += [mod]

            # log the result
            mlog.debug('  - found:')
            comp_args: T.List[str] = []
            link_args: T.List[str] = []
            for j in selected_modules:
                c_args = j.get_compiler_args()
                l_args = j.get_link_args()
                mlog.debug('    - {:<24} link={} comp={}'.format(j.mod_name, str(l_args), str(c_args)))
                comp_args += c_args
                link_args += l_args

            comp_args = list(mesonlib.OrderedSet(comp_args))
            link_args = list(mesonlib.OrderedSet(link_args))

            self.modules_found = [x.mod_name for x in selected_modules]
            self.modules_found = [x[6:] for x in self.modules_found]
            self.modules_found = sorted(set(self.modules_found))
            self.modules_missing = not_found
            self.modules_missing = [x[6:] for x in self.modules_missing]
            self.modules_missing = sorted(set(self.modules_missing))

            # if we found all modules we are done
            if not not_found:
                self.version = inc.version
                self.compile_args = ['-I' + inc.path.as_posix()]
                self.compile_args += comp_args
                self.compile_args += self._extra_compile_args()
                self.compile_args = list(mesonlib.OrderedSet(self.compile_args))
                self.link_args = link_args
                mlog.debug(f'  - final compile args: {self.compile_args}')
                mlog.debug(f'  - final link args:    {self.link_args}')
                return True

            # in case we missed something log it and try again
            mlog.debug('  - NOT found:')
            for mod in not_found:
                mlog.debug(f'    - {mod}')

        return False

    def detect_inc_dirs(self, root: Path) -> T.List[BoostIncludeDir]:
        candidates: T.List[Path] = []
        inc_root = root / 'include'

        candidates += [root / 'boost']
        candidates += [inc_root / 'boost']
        if inc_root.is_dir():
            for i in inc_root.iterdir():
                if not i.is_dir() or not i.name.startswith('boost-'):
                    continue
                candidates += [i / 'boost']
        candidates = [x for x in candidates if x.is_dir()]
        candidates = [x / 'version.hpp' for x in candidates]
        candidates = [x for x in candidates if x.exists()]
        return [self._include_dir_from_version_header(x) for x in candidates]

    def detect_lib_dirs(self, root: Path, use_system: bool) -> T.List[Path]:
        # First check the system include paths. Only consider those within the
        # given root path

        if use_system:
            system_dirs_t = self.clib_compiler.get_library_dirs(self.env)
            system_dirs = [Path(x) for x in system_dirs_t]
            system_dirs = [x.resolve() for x in system_dirs if x.exists()]
            system_dirs = [x for x in system_dirs if mesonlib.path_is_in_root(x, root)]
            system_dirs = list(mesonlib.OrderedSet(system_dirs))

            if system_dirs:
                return system_dirs

        # No system include paths were found --> fall back to manually looking
        # for library dirs in root
        dirs: T.List[Path] = []
        subdirs: T.List[Path] = []
        for i in root.iterdir():
            if i.is_dir() and i.name.startswith('lib'):
                dirs += [i]

        # Some distros put libraries not directly inside /usr/lib but in /usr/lib/x86_64-linux-gnu
        for i in dirs:
            for j in i.iterdir():
                if j.is_dir() and j.name.endswith('-linux-gnu'):
                    subdirs += [j]

        # Filter out paths that don't match the target arch to avoid finding
        # the wrong libraries. See https://github.com/mesonbuild/meson/issues/7110
        if not self.arch:
            return dirs + subdirs

        arch_list_32 = ['32', 'i386']
        arch_list_64 = ['64']

        raw_list = dirs + subdirs
        no_arch = [x for x in raw_list if not any(y in x.name for y in arch_list_32 + arch_list_64)]

        matching_arch: T.List[Path] = []
        if '32' in self.arch:
            matching_arch = [x for x in raw_list if any(y in x.name for y in arch_list_32)]
        elif '64' in self.arch:
            matching_arch = [x for x in raw_list if any(y in x.name for y in arch_list_64)]

        return sorted(matching_arch) + sorted(no_arch)

    def filter_libraries(self, libs: T.List[BoostLibraryFile], lib_vers: str) -> T.List[BoostLibraryFile]:
        # MSVC is very picky with the library tags
        vscrt = ''
        try:
            crt_val = self.env.coredata.options[mesonlib.OptionKey('b_vscrt')].value
            buildtype = self.env.coredata.options[mesonlib.OptionKey('buildtype')].value
            vscrt = self.clib_compiler.get_crt_compile_args(crt_val, buildtype)[0]
        except (KeyError, IndexError, AttributeError):
            pass

        # mlog.debug('    - static: {}'.format(self.static))
        # mlog.debug('    - not explicit static: {}'.format(not self.explicit_static))
        # mlog.debug('    - mt: {}'.format(self.multithreading))
        # mlog.debug('    - version: {}'.format(lib_vers))
        # mlog.debug('    - arch: {}'.format(self.arch))
        # mlog.debug('    - vscrt: {}'.format(vscrt))
        libs = [x for x in libs if x.static == self.static or not self.explicit_static]
        libs = [x for x in libs if x.mt == self.multithreading]
        libs = [x for x in libs if x.version_matches(lib_vers)]
        libs = [x for x in libs if x.arch_matches(self.arch)]
        libs = [x for x in libs if x.vscrt_matches(vscrt)]
        libs = [x for x in libs if x.nvsuffix != 'dll']  # Only link to import libraries

        # Only filter by debug when we are building in release mode. Debug
        # libraries are automatically preferred through sorting otherwise.
        if not self.debug:
            libs = [x for x in libs if not x.debug]

        # Take the abitag from the first library and filter by it. This
        # ensures that we have a set of libraries that are always compatible.
        if not libs:
            return []
        abitag = libs[0].abitag
        libs = [x for x in libs if x.abitag == abitag]

        return libs

    def detect_libraries(self, libdir: Path) -> T.List[BoostLibraryFile]:
        libs: T.Set[BoostLibraryFile] = set()
        for i in libdir.iterdir():
            if not i.is_file():
                continue
            if not any(i.name.startswith(x) for x in ['libboost_', 'boost_']):
                continue
            # Windows binaries from SourceForge ship with PDB files alongside
            # DLLs (#8325).  Ignore them.
            if i.name.endswith('.pdb'):
                continue

            try:
                libs.add(BoostLibraryFile(i.resolve()))
            except UnknownFileException as e:
                mlog.warning('Boost: ignoring unknown file {} under lib directory'.format(e.path.name))

        return [x for x in libs if x.is_boost()]  # Filter out no boost libraries

    def detect_split_root(self, inc_dir: Path, lib_dir: Path) -> None:
        boost_inc_dir = None
        for j in [inc_dir / 'version.hpp', inc_dir / 'boost' / 'version.hpp']:
            if j.is_file():
                boost_inc_dir = self._include_dir_from_version_header(j)
                break
        if not boost_inc_dir:
            self.is_found = False
            return

        self.is_found = self.run_check([boost_inc_dir], [lib_dir])

    def detect_roots(self) -> None:
        roots: T.List[Path] = []

        # Try getting the BOOST_ROOT from a boost.pc if it exists. This primarily
        # allows BoostDependency to find boost from Conan. See #5438
        try:
            boost_pc = PkgConfigDependency('boost', self.env, {'required': False})
            if boost_pc.found():
                boost_root = boost_pc.get_variable(pkgconfig='prefix')
                if boost_root:
                    roots += [Path(boost_root)]
        except DependencyException:
            pass

        # Add roots from system paths
        inc_paths = [Path(x) for x in self.clib_compiler.get_default_include_dirs()]
        inc_paths = [x.parent for x in inc_paths if x.exists()]
        inc_paths = [x.resolve() for x in inc_paths]
        roots += inc_paths

        # Add system paths
        if self.env.machines[self.for_machine].is_windows():
            # Where boost built from source actually installs it
            c_root = Path('C:/Boost')
            if c_root.is_dir():
                roots += [c_root]

            # Where boost documentation says it should be
            prog_files = Path('C:/Program Files/boost')
            # Where boost prebuilt binaries are
            local_boost = Path('C:/local')

            candidates: T.List[Path] = []
            if prog_files.is_dir():
                candidates += [*prog_files.iterdir()]
            if local_boost.is_dir():
                candidates += [*local_boost.iterdir()]

            roots += [x for x in candidates if x.name.lower().startswith('boost') and x.is_dir()]
        else:
            tmp: T.List[Path] = []

            # Add some default system paths
            tmp += [Path('/opt/local')]
            tmp += [Path('/usr/local/opt/boost')]
            tmp += [Path('/usr/local')]
            tmp += [Path('/usr')]

            # Cleanup paths
            tmp = [x for x in tmp if x.is_dir()]
            tmp = [x.resolve() for x in tmp]
            roots += tmp

        self.check_and_set_roots(roots, use_system=True)

    def log_details(self) -> str:
        res = ''
        if self.modules_found:
            res += 'found: ' + ', '.join(self.modules_found)
        if self.modules_missing:
            if res:
                res += ' | '
            res += 'missing: ' + ', '.join(self.modules_missing)
        return res

    def log_info(self) -> str:
        if self.boost_root:
            return self.boost_root.as_posix()
        return ''

    def _include_dir_from_version_header(self, hfile: Path) -> BoostIncludeDir:
        # Extract the version with a regex. Using clib_compiler.get_define would
        # also work, however, this is slower (since it the compiler has to be
        # invoked) and overkill since the layout of the header is always the same.
        assert hfile.exists()
        raw = hfile.read_text(encoding='utf-8')
        m = re.search(r'#define\s+BOOST_VERSION\s+([0-9]+)', raw)
        if not m:
            mlog.debug(f'Failed to extract version information from {hfile}')
            return BoostIncludeDir(hfile.parents[1], 0)
        return BoostIncludeDir(hfile.parents[1], int(m.group(1)))

    def _extra_compile_args(self) -> T.List[str]:
        # BOOST_ALL_DYN_LINK should not be required with the known defines below
        return ['-DBOOST_ALL_NO_LIB']  # Disable automatic linking

packages['boost'] = BoostDependency

# See https://www.boost.org/doc/libs/1_72_0/more/getting_started/unix-variants.html#library-naming
# See https://mesonbuild.com/Reference-tables.html#cpu-families
boost_arch_map = {
    'aarch64': 'a64',
    'arc': 'a32',
    'arm': 'a32',
    'ia64': 'i64',
    'mips': 'm32',
    'mips64': 'm64',
    'ppc': 'p32',
    'ppc64': 'p64',
    'sparc': 's32',
    'sparc64': 's64',
    'x86': 'x32',
    'x86_64': 'x64',
}


####      ---- BEGIN GENERATED ----      ####
#                                           #
# Generated with tools/boost_names.py:
#  - boost version:   1.73.0
#  - modules found:   159
#  - libraries found: 43
#

class BoostLibrary():
    def __init__(self, name: str, shared: T.List[str], static: T.List[str], single: T.List[str], multi: T.List[str]):
        self.name = name
        self.shared = shared
        self.static = static
        self.single = single
        self.multi = multi

class BoostModule():
    def __init__(self, name: str, key: str, desc: str, libs: T.List[str]):
        self.name = name
        self.key = key
        self.desc = desc
        self.libs = libs


# dict of all know libraries with additional compile options
boost_libraries = {
    'boost_atomic': BoostLibrary(
        name='boost_atomic',
        shared=['-DBOOST_ATOMIC_DYN_LINK=1'],
        static=['-DBOOST_ATOMIC_STATIC_LINK=1'],
        single=[],
        multi=[],
    ),
    'boost_chrono': BoostLibrary(
        name='boost_chrono',
        shared=['-DBOOST_CHRONO_DYN_LINK=1'],
        static=['-DBOOST_CHRONO_STATIC_LINK=1'],
        single=['-DBOOST_CHRONO_THREAD_DISABLED'],
        multi=[],
    ),
    'boost_container': BoostLibrary(
        name='boost_container',
        shared=['-DBOOST_CONTAINER_DYN_LINK=1'],
        static=['-DBOOST_CONTAINER_STATIC_LINK=1'],
        single=[],
        multi=[],
    ),
    'boost_context': BoostLibrary(
        name='boost_context',
        shared=['-DBOOST_CONTEXT_DYN_LINK=1'],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_contract': BoostLibrary(
        name='boost_contract',
        shared=['-DBOOST_CONTRACT_DYN_LINK'],
        static=['-DBOOST_CONTRACT_STATIC_LINK'],
        single=['-DBOOST_CONTRACT_DISABLE_THREADS'],
        multi=[],
    ),
    'boost_coroutine': BoostLibrary(
        name='boost_coroutine',
        shared=['-DBOOST_COROUTINES_DYN_LINK=1'],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_date_time': BoostLibrary(
        name='boost_date_time',
        shared=['-DBOOST_DATE_TIME_DYN_LINK=1'],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_exception': BoostLibrary(
        name='boost_exception',
        shared=[],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_fiber': BoostLibrary(
        name='boost_fiber',
        shared=['-DBOOST_FIBERS_DYN_LINK=1'],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_fiber_numa': BoostLibrary(
        name='boost_fiber_numa',
        shared=['-DBOOST_FIBERS_DYN_LINK=1'],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_filesystem': BoostLibrary(
        name='boost_filesystem',
        shared=['-DBOOST_FILESYSTEM_DYN_LINK=1'],
        static=['-DBOOST_FILESYSTEM_STATIC_LINK=1'],
        single=[],
        multi=[],
    ),
    'boost_graph': BoostLibrary(
        name='boost_graph',
        shared=[],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_iostreams': BoostLibrary(
        name='boost_iostreams',
        shared=['-DBOOST_IOSTREAMS_DYN_LINK=1'],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_locale': BoostLibrary(
        name='boost_locale',
        shared=[],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_log': BoostLibrary(
        name='boost_log',
        shared=['-DBOOST_LOG_DYN_LINK=1'],
        static=[],
        single=['-DBOOST_LOG_NO_THREADS'],
        multi=[],
    ),
    'boost_log_setup': BoostLibrary(
        name='boost_log_setup',
        shared=['-DBOOST_LOG_SETUP_DYN_LINK=1'],
        static=[],
        single=['-DBOOST_LOG_NO_THREADS'],
        multi=[],
    ),
    'boost_math_c99': BoostLibrary(
        name='boost_math_c99',
        shared=[],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_math_c99f': BoostLibrary(
        name='boost_math_c99f',
        shared=[],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_math_c99l': BoostLibrary(
        name='boost_math_c99l',
        shared=[],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_math_tr1': BoostLibrary(
        name='boost_math_tr1',
        shared=[],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_math_tr1f': BoostLibrary(
        name='boost_math_tr1f',
        shared=[],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_math_tr1l': BoostLibrary(
        name='boost_math_tr1l',
        shared=[],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_mpi': BoostLibrary(
        name='boost_mpi',
        shared=[],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_nowide': BoostLibrary(
        name='boost_nowide',
        shared=['-DBOOST_NOWIDE_DYN_LINK=1'],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_prg_exec_monitor': BoostLibrary(
        name='boost_prg_exec_monitor',
        shared=['-DBOOST_TEST_DYN_LINK=1'],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_program_options': BoostLibrary(
        name='boost_program_options',
        shared=[],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_random': BoostLibrary(
        name='boost_random',
        shared=['-DBOOST_RANDOM_DYN_LINK'],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_regex': BoostLibrary(
        name='boost_regex',
        shared=[],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_serialization': BoostLibrary(
        name='boost_serialization',
        shared=[],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_stacktrace_addr2line': BoostLibrary(
        name='boost_stacktrace_addr2line',
        shared=[],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_stacktrace_backtrace': BoostLibrary(
        name='boost_stacktrace_backtrace',
        shared=[],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_stacktrace_basic': BoostLibrary(
        name='boost_stacktrace_basic',
        shared=[],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_stacktrace_noop': BoostLibrary(
        name='boost_stacktrace_noop',
        shared=[],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_stacktrace_windbg': BoostLibrary(
        name='boost_stacktrace_windbg',
        shared=[],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_stacktrace_windbg_cached': BoostLibrary(
        name='boost_stacktrace_windbg_cached',
        shared=[],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_system': BoostLibrary(
        name='boost_system',
        shared=['-DBOOST_SYSTEM_DYN_LINK=1'],
        static=['-DBOOST_SYSTEM_STATIC_LINK=1'],
        single=[],
        multi=[],
    ),
    'boost_test_exec_monitor': BoostLibrary(
        name='boost_test_exec_monitor',
        shared=['-DBOOST_TEST_DYN_LINK=1'],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_thread': BoostLibrary(
        name='boost_thread',
        shared=['-DBOOST_THREAD_BUILD_DLL=1', '-DBOOST_THREAD_USE_DLL=1'],
        static=['-DBOOST_THREAD_BUILD_LIB=1', '-DBOOST_THREAD_USE_LIB=1'],
        single=[],
        multi=[],
    ),
    'boost_timer': BoostLibrary(
        name='boost_timer',
        shared=['-DBOOST_TIMER_DYN_LINK=1'],
        static=['-DBOOST_TIMER_STATIC_LINK=1'],
        single=[],
        multi=[],
    ),
    'boost_type_erasure': BoostLibrary(
        name='boost_type_erasure',
        shared=['-DBOOST_TYPE_ERASURE_DYN_LINK'],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_unit_test_framework': BoostLibrary(
        name='boost_unit_test_framework',
        shared=['-DBOOST_TEST_DYN_LINK=1'],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_wave': BoostLibrary(
        name='boost_wave',
        shared=[],
        static=[],
        single=[],
        multi=[],
    ),
    'boost_wserialization': BoostLibrary(
        name='boost_wserialization',
        shared=[],
        static=[],
        single=[],
        multi=[],
    ),
}

#                                           #
####       ---- END GENERATED ----       ####
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0
meson-1.3.2/mesonbuild/dependencies/cmake.py0000644000175000017500000007273114562742373021300 0ustar00jpakkanejpakkane# Copyright 2013-2021 The Meson development team

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

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

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

from .base import ExternalDependency, DependencyException, DependencyTypeName
from ..mesonlib import is_windows, MesonException, PerMachine, stringlistify, extract_as_list
from ..cmake import CMakeExecutor, CMakeTraceParser, CMakeException, CMakeToolchain, CMakeExecScope, check_cmake_args, resolve_cmake_trace_targets, cmake_is_debug
from .. import mlog
import importlib.resources
from pathlib import Path
import functools
import re
import os
import shutil
import textwrap
import typing as T

if T.TYPE_CHECKING:
    from ..cmake import CMakeTarget
    from ..environment import Environment
    from ..envconfig import MachineInfo
    from ..interpreter.type_checking import PkgConfigDefineType

class CMakeInfo(T.NamedTuple):
    module_paths: T.List[str]
    cmake_root: str
    archs: T.List[str]
    common_paths: T.List[str]

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[T.Optional[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: T.Optional[str] = None

    def _gen_exception(self, msg: str) -> DependencyException:
        return DependencyException(f'Dependency {self.name} not found: {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]], components: 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.
        #
        # Both the modules and components inputs contain the original lists.
        return modules

    def _map_component_list(self, modules: T.List[T.Tuple[str, bool]], components: T.List[T.Tuple[str, bool]]) -> T.List[T.Tuple[str, bool]]:
        # Map the input components list to something else. This
        # function will be executed BEFORE the initial CMake interpreter
        # pass. Thus variables from the CMakeLists.txt can NOT be accessed.
        #
        # Both the modules and components inputs contain the original lists.
        return components

    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: T.Dict[str, T.Any], language: T.Optional[str] = None, force_use_global_compilers: bool = False) -> None:
        # Gather a list of all languages to support
        self.language_list: T.List[str] = []
        if language is None or force_use_global_compilers:
            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__(DependencyTypeName('cmake'), environment, kwargs, language=language)
        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:  T.Optional[CMakeExecutor] = None
        self.cmakeinfo: T.Optional[CMakeInfo] = None

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

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

        # Initialize with None before the first return to avoid
        # AttributeError exceptions in derived classes
        self.traceparser: T.Optional[CMakeTraceParser] = None

        # TODO further evaluate always using MachineChoice.BUILD
        self.cmakebin = CMakeExecutor(environment, CMakeDependency.class_cmake_version, self.for_machine, silent=self.silent)
        if not self.cmakebin.found():
            self.cmakebin = None
            msg = f'CMake binary for machine {self.for_machine} not found. Giving up.'
            if self.required:
                raise DependencyException(msg)
            mlog.debug(msg)
            return

        # Setup the trace parser
        self.traceparser = CMakeTraceParser(self.cmakebin.version(), self._get_build_dir(), self.env)

        cm_args = stringlistify(extract_as_list(kwargs, 'cmake_args'))
        cm_args = check_cmake_args(cm_args)
        if CMakeDependency.class_cmakeinfo[self.for_machine] is None:
            CMakeDependency.class_cmakeinfo[self.for_machine] = self._get_cmake_info(cm_args)
        self.cmakeinfo = CMakeDependency.class_cmakeinfo[self.for_machine]
        if self.cmakeinfo is None:
            raise self._gen_exception('Unable to obtain CMake system information')

        package_version = kwargs.get('cmake_package_version', '')
        if not isinstance(package_version, str):
            raise DependencyException('Keyword "cmake_package_version" must be a string.')
        components = [(x, True) for x in stringlistify(extract_as_list(kwargs, 'components'))]
        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]
        if cm_path:
            cm_args.append('-DCMAKE_MODULE_PATH=' + ';'.join(cm_path))
        if not self._preliminary_find_check(name, cm_path, self.cmakebin.get_cmake_prefix_paths(), environment.machines[self.for_machine]):
            mlog.debug('Preliminary CMake check failed. Aborting.')
            return
        self._detect_dep(name, package_version, modules, components, cm_args)

    def __repr__(self) -> str:
        return f'<{self.__class__.__name__} {self.name}: {self.is_found} {self.version_reqs}>'

    def _get_cmake_info(self, cm_args: T.List[str]) -> T.Optional[CMakeInfo]:
        mlog.debug("Extracting basic cmake information")

        # 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

        temp_parser = CMakeTraceParser(self.cmakebin.version(), self._get_build_dir(), self.env)
        toolchain = CMakeToolchain(self.cmakebin, self.env, self.for_machine, CMakeExecScope.DEPENDENCY, self._get_build_dir())
        toolchain.write()

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

            # Prepare options
            cmake_opts = temp_parser.trace_args() + toolchain.get_cmake_args() + ['.']
            cmake_opts += cm_args
            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(f'CMake failed to gather system information for generator {i} with error code {ret1}')
            mlog.debug(f'OUT:\n{out1}\n\n\nERR:\n{err1}\n\n')

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

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

        def process_paths(l: T.List[str]) -> T.Set[str]:
            if is_windows():
                # Cannot split on ':' on Windows because its in the drive letter
                tmp = [x.split(os.pathsep) for x in l]
            else:
                # https://github.com/mesonbuild/meson/issues/7294
                tmp = [re.split(r':|;', x) for x in l]
            flattened = [x for sublist in tmp for x in sublist]
            return set(flattened)

        # Extract the variables and sanity check them
        root_paths_set = process_paths(temp_parser.get_cmake_var('MESON_FIND_ROOT_PATH'))
        root_paths_set.update(process_paths(temp_parser.get_cmake_var('MESON_CMAKE_SYSROOT')))
        root_paths = sorted(root_paths_set)
        root_paths = [x for x in root_paths if os.path.isdir(x)]
        module_paths_set = process_paths(temp_parser.get_cmake_var('MESON_PATHS_LIST'))
        rooted_paths: T.List[str] = []
        for j in [Path(x) for x in root_paths]:
            for p in [Path(x) for x in module_paths_set]:
                rooted_paths.append(str(j / p.relative_to(p.anchor)))
        module_paths = sorted(module_paths_set.union(rooted_paths))
        module_paths = [x for x in module_paths if os.path.isdir(x)]
        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 = CMakeInfo(
            module_paths=module_paths,
            cmake_root=temp_parser.get_cmake_var('MESON_CMAKE_ROOT')[0],
            archs=archs,
            common_paths=common_paths,
        )

        mlog.debug(f'  -- Module search paths:    {res.module_paths}')
        mlog.debug(f'  -- CMake root:             {res.cmake_root}')
        mlog.debug(f'  -- CMake architectures:    {res.archs}')
        mlog.debug(f'  -- CMake lib search paths: {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 tuple()

    @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 insensitive
                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 = tuple(x for x in content if x[1].startswith(lname))
                    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 = tuple(x for x in content if x[1].startswith(lname))
                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 PATH
        system_env: T.List[str] = []
        for i in os.environ.get('PATH', '').split(os.pathsep):
            if i.endswith('/bin') or i.endswith('\\bin'):
                i = i[:-4]
            if i.endswith('/sbin') or i.endswith('\\sbin'):
                i = i[:-5]
            system_env += [i]

        # Check the system paths
        for i in self.cmakeinfo.module_paths + system_env:
            if find_module(i):
                return True

            if search_lib_dirs(i):
                return True

            content = self._cached_listdir(i)
            content = tuple(x for x in content if x[1].startswith(lname))
            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 [f'{lname}.framework', f'{lname}.app']:
                    for k in content:
                        if k[1] != j:
                            continue
                        if find_module(os.path.join(i, k[0], 'Resources')) or find_module(os.path.join(i, k[0], 'Version')):
                            return True

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

        # Check the Linux CMake registry
        linux_reg = Path.home() / '.cmake' / 'packages'
        for p in [linux_reg / name, linux_reg / lname]:
            if p.exists():
                return True

        return False

    def _detect_dep(self, name: str, package_version: str, modules: T.List[T.Tuple[str, bool]], components: T.List[T.Tuple[str, bool]], args: T.List[str]) -> None:
        # 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

        # Map the components
        comp_mapped = self._map_component_list(modules, components)
        toolchain = CMakeToolchain(self.cmakebin, self.env, self.for_machine, CMakeExecScope.DEPENDENCY, self._get_build_dir())
        toolchain.write()

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

            # Prepare options
            cmake_opts = []
            cmake_opts += [f'-DNAME={name}']
            cmake_opts += ['-DARCHS={}'.format(';'.join(self.cmakeinfo.archs))]
            cmake_opts += [f'-DVERSION={package_version}']
            cmake_opts += ['-DCOMPS={}'.format(';'.join([x[0] for x in comp_mapped]))]
            cmake_opts += ['-DSTATIC={}'.format('ON' if self.static else 'OFF')]
            cmake_opts += args
            cmake_opts += self.traceparser.trace_args()
            cmake_opts += toolchain.get_cmake_args()
            cmake_opts += self._extra_cmake_opts()
            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(f'CMake failed for generator {i} and package {name} with error code {ret1}')
            mlog.debug(f'OUT:\n{out1}\n\n\nERR:\n{err1}\n\n')

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

        try:
            self.traceparser.parse(err1)
        except CMakeException as e:
            e2 = self._gen_exception(str(e))
            if self.required:
                raise
            else:
                self.compile_args = []
                self.link_args = []
                self.is_found = False
                self.reason = e2
                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, components)
        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 f'{lname}::{lname}' == tg or lname == tg.replace('::', ''):
                    mlog.debug(f'Guessed CMake target \'{i}\'')
                    modules = [(i, True)]
                    autodetected_module_list = True
                    break

        # Failed to guess a target --> try the old-style method
        if len(modules) == 0:
            # Warn when there might be matching imported targets but no automatic match was used
            partial_modules: T.List[CMakeTarget] = []
            for k, v in self.traceparser.targets.items():
                tg = k.lower()
                lname = name.lower()
                if tg.startswith(f'{lname}::'):
                    partial_modules += [v]
            if partial_modules:
                mlog.warning(textwrap.dedent(f'''\
                    Could not find and exact match for the CMake dependency {name}.

                    However, Meson found the following partial matches:

                        {[x.name for x in partial_modules]}

                    Using imported is recommended, since this approach is less error prone
                    and better supported by Meson. Consider explicitly specifying one of
                    these in the dependency call with:

                        dependency('{name}', modules: ['{name}::', ...])

                    Meson will now continue to use the old-style {name}_LIBRARIES CMake
                    variables to extract the dependency information since no explicit
                    target is currently specified.

                '''))
                mlog.debug('More info for the partial match targets:')
                for tgt in partial_modules:
                    mlog.debug(tgt)

            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_raw = [x for x in self.traceparser.get_cmake_var('PACKAGE_LIBRARIES') if x]

            # CMake has a "fun" API, where certain keywords describing
            # configurations can be in the *_LIBRARIES variables. See:
            # - https://github.com/mesonbuild/meson/issues/9197
            # - https://gitlab.freedesktop.org/libnice/libnice/-/issues/140
            # - https://cmake.org/cmake/help/latest/command/target_link_libraries.html#overview  (the last point in the section)
            libs: T.List[str] = []
            cfg_matches = True
            is_debug = cmake_is_debug(self.env)
            cm_tag_map = {'debug': is_debug, 'optimized': not is_debug, 'general': True}
            for i in libs_raw:
                if i.lower() in cm_tag_map:
                    cfg_matches = cm_tag_map[i.lower()]
                    continue
                if cfg_matches:
                    libs += [i]
                # According to the CMake docs, a keyword only works for the
                # directly the following item and all items without a keyword
                # are implicitly `general`
                cfg_matches = True

            # Try to use old style variables if no module is specified
            if len(libs) > 0:
                self.compile_args = [f'-I{x}' for x in incDirs] + defs
                self.link_args = []
                for j in libs:
                    rtgt = resolve_cmake_trace_targets(j, self.traceparser, self.env, clib_compiler=self.clib_compiler)
                    self.link_args += rtgt.libraries
                    self.compile_args += [f'-I{x}' for x in rtgt.include_directories]
                    self.compile_args += rtgt.public_compile_opts
                mlog.debug(f'using old-style CMake variables for dependency {name}')
                mlog.debug(f'Include Dirs:         {incDirs}')
                mlog.debug(f'Compiler Definitions: {defs}')
                mlog.debug(f'Libraries:            {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
        # recognise arguments we should pass directly to the linker
        incDirs = []
        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())))

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

            rtgt = resolve_cmake_trace_targets(i, self.traceparser, self.env,
                                               clib_compiler=self.clib_compiler,
                                               not_found_warning=lambda x:
                                                   mlog.warning('CMake: Dependency', mlog.bold(x), 'for', mlog.bold(name), 'was not found')
                                               )
            incDirs += rtgt.include_directories
            compileOptions += rtgt.public_compile_opts
            libraries += rtgt.libraries + rtgt.link_flags

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

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

        self.compile_args = compileOptions + [f'-I{x}' for x in incDirs]
        self.link_args = libraries

    def _get_build_dir(self) -> Path:
        build_dir = Path(self.cmake_root_dir) / f'cmake_{self.name}'
        build_dir.mkdir(parents=True, exist_ok=True)
        return build_dir

    def _setup_cmake_dir(self, cmake_file: str) -> Path:
        # Setup the CMake build environment and return the "build" directory
        build_dir = self._get_build_dir()

        # Remove old CMake cache so we can try out multiple generators
        cmake_cache = build_dir / 'CMakeCache.txt'
        cmake_files = build_dir / 'CMakeFiles'
        if cmake_cache.exists():
            cmake_cache.unlink()
        shutil.rmtree(cmake_files.as_posix(), ignore_errors=True)

        # Insert language parameters into the CMakeLists.txt and write new CMakeLists.txt
        cmake_txt = importlib.resources.read_text('mesonbuild.dependencies.data', cmake_file, encoding = 'utf-8')

        # 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 = textwrap.dedent("""
            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, encoding='utf-8')
        mlog.cmd_ci_include(cm_file.absolute().as_posix())

        return build_dir

    def _call_cmake(self,
                    args: T.List[str],
                    cmake_file: str,
                    env: T.Optional[T.Dict[str, str]] = None) -> T.Tuple[int, T.Optional[str], T.Optional[str]]:
        build_dir = self._setup_cmake_dir(cmake_file)
        return self.cmakebin.call(args, build_dir, env=env)

    @staticmethod
    def log_tried() -> str:
        return 'cmake'

    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, internal: T.Optional[str] = None,
                     default_value: T.Optional[str] = None,
                     pkgconfig_define: PkgConfigDefineType = None) -> str:
        if cmake and self.traceparser is not None:
            try:
                v = self.traceparser.vars[cmake]
            except KeyError:
                pass
            else:
                # CMake does NOT have a list datatype. We have no idea whether
                # anything is a string or a string-separated-by-; Internally,
                # we treat them as the latter and represent everything as a
                # list, because it is convenient when we are mostly handling
                # imported targets, which have various properties that are
                # actually lists.
                #
                # As a result we need to convert them back to strings when grabbing
                # raw variables the user requested.
                return ';'.join(v)
        if default_value is not None:
            return default_value
        raise DependencyException(f'Could not get cmake variable and no default provided for {self!r}')


class CMakeDependencyFactory:

    def __init__(self, name: T.Optional[str] = None, modules: T.Optional[T.List[str]] = None):
        self.name = name
        self.modules = modules

    def __call__(self, name: str, env: Environment, kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None, force_use_global_compilers: bool = False) -> CMakeDependency:
        if self.modules:
            kwargs['modules'] = self.modules
        return CMakeDependency(self.name or name, env, kwargs, language, force_use_global_compilers)

    @staticmethod
    def log_tried() -> str:
        return CMakeDependency.log_tried()
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/dependencies/coarrays.py0000644000175000017500000000715214562742363022035 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import functools
import typing as T

from .base import DependencyMethods, detect_compiler, SystemDependency
from .cmake import CMakeDependency
from .detect import packages
from .pkgconfig import PkgConfigDependency
from .factory import factory_methods

if T.TYPE_CHECKING:
    from . factory import DependencyGenerator
    from ..environment import Environment
    from ..mesonlib import MachineChoice


@factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE, DependencyMethods.SYSTEM})
def coarray_factory(env: 'Environment',
                    for_machine: 'MachineChoice',
                    kwargs: T.Dict[str, T.Any],
                    methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']:
    fcid = detect_compiler('coarray', env, for_machine, 'fortran').get_id()
    candidates: T.List['DependencyGenerator'] = []

    if fcid == 'gcc':
        # OpenCoarrays is the most commonly used method for Fortran Coarray with GCC
        if DependencyMethods.PKGCONFIG in methods:
            for pkg in ['caf-openmpi', 'caf']:
                candidates.append(functools.partial(
                    PkgConfigDependency, pkg, env, kwargs, language='fortran'))

        if DependencyMethods.CMAKE in methods:
            if 'modules' not in kwargs:
                kwargs['modules'] = 'OpenCoarrays::caf_mpi'
            candidates.append(functools.partial(
                CMakeDependency, 'OpenCoarrays', env, kwargs, language='fortran'))

    if DependencyMethods.SYSTEM in methods:
        candidates.append(functools.partial(CoarrayDependency, env, kwargs))

    return candidates
packages['coarray'] = coarray_factory


class CoarrayDependency(SystemDependency):
    """
    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: 'Environment', kwargs: T.Dict[str, T.Any]) -> None:
        super().__init__('coarray', environment, kwargs, language='fortran')
        kwargs['required'] = False
        kwargs['silent'] = True

        cid = self.get_compiler().get_id()
        if cid == 'gcc':
            # Fallback to single image
            self.compile_args = ['-fcoarray=single']
            self.version = 'single image (fallback)'
            self.is_found = True
        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
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/dependencies/configtool.py0000644000175000017500000001663114562742363022357 0ustar00jpakkanejpakkane# Copyright 2013-2021 The Meson development team

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

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

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

from .base import ExternalDependency, DependencyException, DependencyTypeName
from ..mesonlib import listify, Popen_safe, Popen_safe_logged, split_args, version_compare, version_compare_many
from ..programs import find_external_program
from .. import mlog
import re
import typing as T

from mesonbuild import mesonlib

if T.TYPE_CHECKING:
    from ..environment import Environment
    from ..interpreter.type_checking import PkgConfigDefineType

class ConfigToolDependency(ExternalDependency):

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

    Takes the following extra keys in kwargs that it uses internally:
    :tools List[str]: A list of tool names to use
    :version_arg str: The argument to pass to the tool to get it's version
    :skip_version str: The argument to pass to the tool to ignore its version
        (if ``version_arg`` fails, but it may start accepting it in the future)
        Because some tools are stupid and don't accept --version
    :returncode_value int: The value of the correct returncode
        Because some tools are stupid and don't return 0
    """

    tools: T.Optional[T.List[str]] = None
    tool_name: T.Optional[str] = None
    version_arg = '--version'
    skip_version: T.Optional[str] = None
    allow_default_for_cross = False
    __strip_version = re.compile(r'^[0-9][0-9.]+')

    def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None):
        super().__init__(DependencyTypeName('config-tool'), environment, kwargs, language=language)
        self.name = name
        # You may want to overwrite the class version in some cases
        self.tools = listify(kwargs.get('tools', self.tools))
        if not self.tool_name:
            self.tool_name = self.tools[0]
        if 'version_arg' in kwargs:
            self.version_arg = kwargs['version_arg']

        req_version_raw = kwargs.get('version', None)
        if req_version_raw is not None:
            req_version = mesonlib.stringlistify(req_version_raw)
        else:
            req_version = []
        tool, version = self.find_config(req_version, kwargs.get('returncode_value', 0))
        self.config = tool
        self.is_found = self.report_config(version, req_version)
        if not self.is_found:
            self.config = None
            return
        self.version = version

    def _sanitize_version(self, version: str) -> str:
        """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

    def find_config(self, versions: T.List[str], returncode: int = 0) \
            -> T.Tuple[T.Optional[T.List[str]], T.Optional[str]]:
        """Helper method that searches for config tool binaries in PATH and
        returns the one that best matches the given version requirements.
        """
        best_match: T.Tuple[T.Optional[T.List[str]], T.Optional[str]] = (None, None)
        for potential_bin in find_external_program(
                self.env, self.for_machine, self.tool_name,
                self.tool_name, self.tools, allow_default_for_cross=self.allow_default_for_cross):
            if not potential_bin.found():
                continue
            tool = potential_bin.get_command()
            try:
                p, out = Popen_safe(tool + [self.version_arg])[:2]
            except (FileNotFoundError, PermissionError):
                continue
            if p.returncode != returncode:
                if self.skip_version:
                    # maybe the executable is valid even if it doesn't support --version
                    p = Popen_safe(tool + [self.skip_version])[0]
                    if p.returncode != returncode:
                        continue
                else:
                    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: T.Optional[str], req_version: T.List[str]) -> bool:
        """Helper method to print messages about the tool."""

        found_msg: T.List[T.Union[str, mlog.AnsiDecorator]] = [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:
                found_msg.append(f'found {version!r} but need {req_version!r}')
            elif req_version:
                found_msg.append(f'need {req_version!r}')
        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: T.List[str], stage: str) -> T.List[str]:
        p, out, err = Popen_safe_logged(self.config + args)
        if p.returncode != 0:
            if self.required:
                raise DependencyException(f'Could not generate {stage} for {self.name}.\n{err}')
            return []
        return split_args(out)

    def get_variable_args(self, variable_name: str) -> T.List[str]:
        return [f'--{variable_name}']

    @staticmethod
    def log_tried() -> str:
        return 'config-tool'

    def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None,
                     configtool: T.Optional[str] = None, internal: T.Optional[str] = None,
                     default_value: T.Optional[str] = None,
                     pkgconfig_define: PkgConfigDefineType = None) -> str:
        if configtool:
            p, out, _ = Popen_safe(self.config + self.get_variable_args(configtool))
            if p.returncode == 0:
                variable = out.strip()
                mlog.debug(f'Got config-tool variable {configtool} : {variable}')
                return variable
        if default_value is not None:
            return default_value
        raise DependencyException(f'Could not get config-tool variable and no default provided for {self!r}')
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/dependencies/cuda.py0000644000175000017500000003333414562742363021127 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import glob
import re
import os
import typing as T
from pathlib import Path

from .. import mesonlib
from .. import mlog
from ..environment import detect_cpu_family
from .base import DependencyException, SystemDependency
from .detect import packages


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

    TV_ResultTuple = T.Tuple[T.Optional[str], T.Optional[str], bool]

class CudaDependency(SystemDependency):

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

    def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None:
        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(f'Language \'{language}\' is not supported by the CUDA Toolkit. Supported languages are {self.supported_languages}.')

        super().__init__('cuda', environment, kwargs, language=language)
        self.lib_modules: T.Dict[str, T.List[str]] = {}
        self.requested_modules = self.get_requested(kwargs)
        if not any(runtime in self.requested_modules for runtime in ['cudart', 'cudart_static']):
            # By default, we prefer to link the static CUDA runtime, since this is what nvcc also does by default:
            # https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html#cudart-none-shared-static-cudart
            req_modules = ['cudart']
            if kwargs.get('static', True):
                req_modules = ['cudart_static']
                machine = self.env.machines[self.for_machine]
                if machine.is_linux():
                    # extracted by running
                    #   nvcc -v foo.o
                    req_modules += ['rt', 'pthread', 'dl']
            self.requested_modules = req_modules + 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(f'CUDA Toolkit path must be absolute, got \'{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 += [f'-I{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: T.Dict[str, 'Compiler']) -> str:
        for lang in cls.supported_languages:
            if lang in compilers:
                return lang
        return list(compilers.keys())[0]

    def _detect_cuda_path_and_version(self) -> TV_ResultTuple:
        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 = f'The current nvcc version {nvcc_version} does not satisfy the specified CUDA Toolkit version requirements {version_reqs}.'
                    return self._report_dependency_error(msg, (None, None, False))

            # use nvcc version to find a matching CUDA Toolkit
            version_reqs = [f'={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 = f'Please specify the desired CUDA Toolkit version (e.g. dependency(\'cuda\', version : \'>=10.1\')) or {platform_msg} to point to the location of your desired version.'
        return self._report_dependency_error(msg, (None, None, False))

    def _find_matching_toolkit(self, paths: T.List[TV_ResultTuple], version_reqs: T.List[str], nvcc_version: T.Optional[str]) -> TV_ResultTuple:
        # keep the default paths order intact, sort the rest in the descending order
        # according to the toolkit version
        part_func: T.Callable[[TV_ResultTuple], bool] = lambda t: not t[2]
        defaults_it, rest_it = mesonlib.partition(part_func, paths)
        defaults = list(defaults_it)
        paths = defaults + sorted(rest_it, key=lambda t: mesonlib.Version(t[1]), reverse=True)
        mlog.debug(f'Search paths: {paths}')

        if nvcc_version and defaults:
            default_src = f"the {self.env_var} environment variable" 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) -> T.Optional[str]:
        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 = {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) -> T.List[T.Tuple[str, bool]]:
        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) -> T.List[T.Tuple[str, bool]]:
        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) -> T.List[T.Tuple[str, bool]]:
        # 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-(.*)$')
    cudart_version_regex = re.compile(r'#define\s+CUDART_VERSION\s+([0-9]+)')

    def _cuda_toolkit_version(self, path: str) -> str:
        version = self._read_toolkit_version_txt(path)
        if version:
            return version
        version = self._read_cuda_runtime_api_version(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
        try:
            m = path_version_regex.match(os.path.basename(path))
            if m:
                return m.group(1)
            else:
                mlog.warning(f'Could not detect CUDA Toolkit version for {path}')
        except Exception as e:
            mlog.warning(f'Could not detect CUDA Toolkit version for {path}: {e!s}')

        return '0.0'

    def _read_cuda_runtime_api_version(self, path_str: str) -> T.Optional[str]:
        path = Path(path_str)
        for i in path.rglob('cuda_runtime_api.h'):
            raw = i.read_text(encoding='utf-8')
            m = self.cudart_version_regex.search(raw)
            if not m:
                continue
            try:
                vers_int = int(m.group(1))
            except ValueError:
                continue
            # use // for floor instead of / which produces a float
            major = vers_int // 1000
            minor = (vers_int - major * 1000) // 10
            return f'{major}.{minor}'
        return None

    def _read_toolkit_version_txt(self, path: str) -> T.Optional[str]:
        # Read 'version.txt' at the root of the CUDA Toolkit directory to determine the toolkit version
        version_file_path = os.path.join(path, 'version.txt')
        try:
            with open(version_file_path, encoding='utf-8') 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.group(1))
        except Exception as e:
            mlog.debug(f'Could not read CUDA Toolkit\'s version file {version_file_path}: {e!s}')

        return None

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

    def _detect_arch_libdir(self) -> str:
        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', 'aarch64': 'lib64', 'loongarch64': 'lib64'}
            if arch not in libdirs:
                raise DependencyException(msg.format(arch, 'Linux'))
            return libdirs[arch]
        elif machine.is_darwin():
            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) -> bool:
        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(f'Couldn\'t find requested CUDA module \'{module}\'')
                all_found = False
            else:
                mlog.debug(f'Link args for CUDA module \'{module}\' are {args}')
                self.lib_modules[module] = args

        return all_found

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

    @T.overload
    def _report_dependency_error(self, msg: str) -> None: ...

    @T.overload
    def _report_dependency_error(self, msg: str, ret_val: TV_ResultTuple) -> TV_ResultTuple: ... # noqa: F811

    def _report_dependency_error(self, msg: str, ret_val: T.Optional[TV_ResultTuple] = None) -> T.Optional[TV_ResultTuple]: # noqa: F811
        if self.required:
            raise DependencyException(msg)

        mlog.debug(msg)
        return ret_val

    def log_details(self) -> str:
        module_str = ', '.join(self.requested_modules)
        return 'modules: ' + module_str

    def log_info(self) -> str:
        return self.cuda_path if self.cuda_path else ''

    def get_requested(self, kwargs: T.Dict[str, T.Any]) -> T.List[str]:
        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, language: T.Optional[str] = None, raw: bool = False) -> T.List[str]:
        args: T.List[str] = []
        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

packages['cuda'] = CudaDependency
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.6786385
meson-1.3.2/mesonbuild/dependencies/data/0000755000175000017500000000000014562742414020541 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1685461376.0
meson-1.3.2/mesonbuild/dependencies/data/CMakeLists.txt0000644000175000017500000000573114435414600023277 0ustar00jpakkanejpakkane# 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)

if("${STATIC}" STREQUAL "True")
  set("${NAME}_USE_STATIC_LIBS" "ON")
endif()

while(TRUE)
  if ("${VERSION}" STREQUAL "")
    find_package("${NAME}" QUIET COMPONENTS ${COMPS})
  else()
    find_package("${NAME}" "${VERSION}" QUIET COMPONENTS ${COMPS})
  endif()

  # 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()
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0
meson-1.3.2/mesonbuild/dependencies/data/CMakeListsLLVM.txt0000644000175000017500000001403714562742373024005 0ustar00jpakkanejpakkane# 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)

list(REMOVE_DUPLICATES LLVM_MESON_VERSIONS)

while(TRUE)
  #Activate CMake version selection
  foreach(i IN LISTS LLVM_MESON_VERSIONS)
    find_package(LLVM ${i}
      CONFIG
      NAMES ${LLVM_MESON_PACKAGE_NAMES}
      QUIET)
    if(LLVM_FOUND)
      break()
    endif()
  endforeach()

  # 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()

function(meson_llvm_cmake_dynamic_available mod out)
  # Check if we can only compare LLVM_DYLIB_COMPONENTS, because
  # we do not need complex component translation logic, if all
  # is covered by one variable
  if(mod IN_LIST LLVM_DYLIB_COMPONENTS)
    set(${out} TRUE PARENT_SCOPE)
    return()
  elseif((NOT (mod IN_LIST LLVM_DYLIB_COMPONENTS))
      AND (NOT("${LLVM_DYLIB_COMPONENTS}" STREQUAL "all")))
    set(${out} FALSE PARENT_SCOPE)
    return()
  endif()

  # Complex heuristic to filter all pseudo-components and skip invalid names
  # LLVM_DYLIB_COMPONENTS will be 'all', because in other case we returned
  # in previous check. 'all' is also handled there.
  set(llvm_pseudo_components "native" "backend" "engine" "all-targets")
  is_llvm_target_specifier(${mod} mod_spec INCLUDED_TARGETS)
  string(TOUPPER "${LLVM_AVAILABLE_LIBS}" capitalized_libs)
  string(TOUPPER "${LLVM_TARGETS_TO_BUILD}" capitalized_tgts)
  if(mod_spec)
    set(${out} TRUE PARENT_SCOPE)
  elseif(mod IN_LIST capitalized_tgts)
    set(${out} TRUE PARENT_SCOPE)
  elseif(mod IN_LIST llvm_pseudo_components)
    set(${out} TRUE PARENT_SCOPE)
  elseif(LLVM${mod} IN_LIST capitalized_libs)
    set(${out} TRUE PARENT_SCOPE)
  else()
    set(${out} FALSE PARENT_SCOPE)
  endif()
endfunction()

function(is_static target ret)
  if(TARGET ${target})
    get_target_property(target_type ${target} TYPE)
    if(target_type STREQUAL "STATIC_LIBRARY")
      set(${ret} TRUE PARENT_SCOPE)
      return()
    endif()
  endif()
  set(${ret} FALSE PARENT_SCOPE)
endfunction()

# Concatenate LLVM_MESON_REQUIRED_MODULES and LLVM_MESON_OPTIONAL_MODULES
set(LLVM_MESON_MODULES ${LLVM_MESON_REQUIRED_MODULES} ${LLVM_MESON_OPTIONAL_MODULES})


# Check if LLVM exists in dynamic world
# Initialization before modules checking
if(LLVM_FOUND)
  if(LLVM_MESON_DYLIB AND TARGET LLVM)
    set(PACKAGE_FOUND TRUE)
  elseif(NOT LLVM_MESON_DYLIB)
    # Use LLVMSupport to check if static targets exist
    set(static_tg FALSE)
    is_static(LLVMCore static_tg)
    if(static_tg)
      set(PACKAGE_FOUND TRUE)
    endif(static_tg)
  endif()
endif()

if(PACKAGE_FOUND)
  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)

    # Special case - "all-targets" pseudo target
    # Just append all targets, if pseudo-target exists
    if("${mod}" STREQUAL "all-targets")
      set(mod_L  ${LLVM_TARGETS_TO_BUILD})
      string(TOUPPER "${LLVM_TARGETS_TO_BUILD}" mod_U)
    endif()

    # Check if required module is linked is inside libLLVM.so.
    # If not, skip this module
    if(LLVM_MESON_DYLIB
       AND DEFINED LLVM_DYLIB_COMPONENTS)
        meson_llvm_cmake_dynamic_available(${mod} MOD_F)
        meson_llvm_cmake_dynamic_available(${mod_L} MOD_L_F)
        meson_llvm_cmake_dynamic_available(${mod_U} MOD_U_F)
        if(MOD_F OR MOD_L_F OR MOD_U_F)
          set(MESON_LLVM_TARGETS_${mod} LLVM)
        endif()
    elseif(LLVM_MESON_DYLIB AND (mod IN_LIST LLVM_MESON_REQUIRED_MODULES))
      # Dynamic was requested, but no required variables set, we cannot continue
      set(PACKAGE_FOUND FALSE)
      break()
    elseif(LLVM_MESON_DYLIB)
      # Dynamic was requested, and we request optional modules only. Continue
      continue()
    else()
      # CMake only do this for static components, and we
      # replicate its behaviour
      # 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)
        set(static_tg FALSE)
        is_static(${i} static_tg)
        if(static_tg)
          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()
    endif()
  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)
  #Hardcode LLVM, because we links with libLLVM.so when dynamic
  if(LLVM_MESON_DYLIB)
    get_target_property(libs LLVM IMPORTED_LOCATION)
  elseif(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()
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0
meson-1.3.2/mesonbuild/dependencies/data/CMakePathInfo.txt0000644000175000017500000000222213716006331023700 0ustar00jpakkanejpakkanecmake_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})
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665806.0
meson-1.3.2/mesonbuild/dependencies/data/__init__.py0000644000175000017500000000000014253672216022637 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/dependencies/detect.py0000644000175000017500000002305214562742363021457 0ustar00jpakkanejpakkane# Copyright 2013-2021 The Meson development team

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

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

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

import collections, functools, importlib
import typing as T

from .base import ExternalDependency, DependencyException, DependencyMethods, NotFoundDependency

from ..mesonlib import listify, MachineChoice, PerMachine
from .. import mlog

if T.TYPE_CHECKING:
    from ..environment import Environment
    from .factory import DependencyFactory, WrappedFactoryFunc, DependencyGenerator

    TV_DepIDEntry = T.Union[str, bool, int, T.Tuple[str, ...]]
    TV_DepID = T.Tuple[T.Tuple[str, TV_DepIDEntry], ...]
    PackageTypes = T.Union[T.Type[ExternalDependency], DependencyFactory, WrappedFactoryFunc]

class DependencyPackages(collections.UserDict):
    data: T.Dict[str, PackageTypes]
    defaults: T.Dict[str, str] = {}

    def __missing__(self, key: str) -> PackageTypes:
        if key in self.defaults:
            modn = self.defaults[key]
            importlib.import_module(f'mesonbuild.dependencies.{modn}')

            return self.data[key]
        raise KeyError(key)

    def __contains__(self, key: object) -> bool:
        return key in self.defaults or key in self.data

# These must be defined in this file to avoid cyclical references.
packages = DependencyPackages()
_packages_accept_language: T.Set[str] = set()

def get_dep_identifier(name: str, kwargs: T.Dict[str, T.Any]) -> 'TV_DepID':
    identifier: 'TV_DepID' = (('name', name), )
    from ..interpreter import permitted_dependency_kwargs
    assert len(permitted_dependency_kwargs) == 19, \
           'Extra kwargs have been added to dependency(), please review if it makes sense to handle it here'
    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' and 'allow_fallback' is not part of the cache because,
        #     once a dependency has been found through a fallback, it should
        #     be used for the rest of the Meson run.
        # 'default_options' is only used in fallback case
        # 'not_found_message' has no impact on the dependency lookup
        # 'include_type' is handled after the dependency lookup
        if key in {'version', 'native', 'required', 'fallback', 'allow_fallback', 'default_options',
                   'not_found_message', 'include_type'}:
            continue
        # All keyword arguments are strings, ints, or lists (or lists of lists)
        if isinstance(value, list):
            for i in value:
                assert isinstance(i, str)
            value = tuple(frozenset(listify(value)))
        else:
            assert isinstance(value, (str, bool, int))
        identifier = (*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: str, env: 'Environment', kwargs: T.Dict[str, object], candidates: T.Optional[T.List['DependencyGenerator']] = None) -> T.Union['ExternalDependency', NotFoundDependency]:
    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(f'{name} dependency does not accept "language" keyword argument')
    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
    if candidates is None:
        candidates = _build_external_dependency_list(name, env, for_machine, kwargs)

    pkg_exc: T.List[DependencyException] = []
    pkgdep:  T.List[ExternalDependency] = []
    details = ''

    for c in candidates:
        # try this dependency method
        try:
            d = c()
            d._check_version()
            pkgdep.append(d)
        except DependencyException as e:
            assert isinstance(c, functools.partial), 'for mypy'
            bettermsg = f'Dependency lookup for {name} with method {c.func.log_tried()!r} failed: {e}'
            mlog.debug(bettermsg)
            e.args = (bettermsg,)
            pkg_exc.append(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: mlog.TV_LoggableList = []
                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 = mlog.format_list(tried_methods)
    else:
        tried = ''

    mlog.log(type_text, mlog.bold(display_name), details + 'found:', mlog.red('NO'),
             f'(tried {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(f'Dependency "{name}" not found' +
                                  (f', tried {tried}' if tried else ''))

    return NotFoundDependency(name, env)


def _build_external_dependency_list(name: str, env: 'Environment', for_machine: MachineChoice,
                                    kwargs: T.Dict[str, T.Any]) -> T.List['DependencyGenerator']:
    # 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 isinstance(packages[lname], type):
            entry1 = T.cast('T.Type[ExternalDependency]', packages[lname])  # mypy doesn't understand isinstance(..., type)
            if issubclass(entry1, ExternalDependency):
                func: T.Callable[[], 'ExternalDependency'] = functools.partial(entry1, env, kwargs)
                dep = [func]
        else:
            entry2 = T.cast('T.Union[DependencyFactory, WrappedFactoryFunc]', packages[lname])
            dep = entry2(env, for_machine, kwargs)
        return dep

    candidates: T.List['DependencyGenerator'] = []

    if kwargs.get('method', 'auto') == 'auto':
        # Just use the standard detection methods.
        methods = ['pkg-config', 'extraframework', 'cmake']
    else:
        # If it's explicitly requested, use that detection method (only).
        methods = [kwargs['method']]

    # Exclusive to when it is explicitly requested
    if 'dub' in methods:
        from .dub import DubDependency
        candidates.append(functools.partial(DubDependency, name, env, kwargs))

    # Preferred first candidate for auto.
    if 'pkg-config' in methods:
        from .pkgconfig import PkgConfigDependency
        candidates.append(functools.partial(PkgConfigDependency, name, env, kwargs))

    # On OSX only, try framework dependency detector.
    if 'extraframework' in methods:
        if env.machines[for_machine].is_darwin():
            from .framework import ExtraFrameworkDependency
            candidates.append(functools.partial(ExtraFrameworkDependency, name, env, kwargs))

    # Only use CMake:
    # - if it's explicitly requested
    # - as a last resort, since it might not work 100% (see #6113)
    if 'cmake' in methods:
        from .cmake import CMakeDependency
        candidates.append(functools.partial(CMakeDependency, name, env, kwargs))

    return candidates
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0
meson-1.3.2/mesonbuild/dependencies/dev.py0000644000175000017500000007307014562742373020773 0ustar00jpakkanejpakkane# 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..

from __future__ import annotations

import glob
import os
import re
import pathlib
import shutil
import subprocess
import typing as T
import functools

from mesonbuild.interpreterbase.decorators import FeatureDeprecated

from .. import mesonlib, mlog
from ..environment import get_llvm_tool_names
from ..mesonlib import version_compare, version_compare_many, search_version, stringlistify, extract_as_list
from .base import DependencyException, DependencyMethods, detect_compiler, strip_system_includedirs, strip_system_libdirs, SystemDependency, ExternalDependency, DependencyTypeName
from .cmake import CMakeDependency
from .configtool import ConfigToolDependency
from .detect import packages
from .factory import DependencyFactory
from .misc import threads_factory
from .pkgconfig import PkgConfigDependency

if T.TYPE_CHECKING:
    from ..envconfig import MachineInfo
    from ..environment import Environment
    from ..mesonlib import MachineChoice
    from typing_extensions import TypedDict

    class JNISystemDependencyKW(TypedDict):
        modules: T.List[str]
        # FIXME: When dependency() moves to typed Kwargs, this should inherit
        # from its TypedDict type.
        version: T.Optional[str]


def get_shared_library_suffix(environment: 'Environment', for_machine: MachineChoice) -> str:
    """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 GTestDependencySystem(SystemDependency):
    def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None:
        super().__init__(name, environment, kwargs, language='cpp')
        self.main = kwargs.get('main', False)
        self.src_dirs = ['/usr/src/gtest/src', '/usr/src/googletest/googletest/src']
        if not self._add_sub_dependency(threads_factory(environment, self.for_machine, {})):
            self.is_found = False
            return
        self.detect()

    def detect(self) -> None:
        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) -> bool:
        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) -> str:
        if self.prebuilt:
            return 'prebuilt'
        else:
            return 'building self'


class GTestDependencyPC(PkgConfigDependency):

    def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]):
        assert name == 'gtest'
        if kwargs.get('main'):
            name = 'gtest_main'
        super().__init__(name, environment, kwargs)


class GMockDependencySystem(SystemDependency):
    def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None:
        super().__init__(name, environment, kwargs, language='cpp')
        self.main = kwargs.get('main', False)
        if not self._add_sub_dependency(threads_factory(environment, self.for_machine, {})):
            self.is_found = False
            return

        # 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
        found = self._add_sub_dependency(gtest_factory(environment, self.for_machine, gtest_kwargs))
        if not found:
            self.is_found = False
            return

        # 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) -> str:
        if self.prebuilt:
            return 'prebuilt'
        else:
            return 'building self'


class GMockDependencyPC(PkgConfigDependency):

    def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]):
        assert name == 'gmock'
        if kwargs.get('main'):
            name = 'gmock_main'
        super().__init__(name, environment, kwargs)


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, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]):
        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__(name, environment, kwargs, language='cpp')
        self.provided_modules: T.List[str] = []
        self.required_modules: mesonlib.OrderedSet[str] = mesonlib.OrderedSet()
        self.module_details:   T.List[str] = []
        if not self.is_found:
            return

        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 = mesonlib.OrderedSet(self.get_config_value(['--cppflags'], 'compile_args'))
        self.compile_args = list(cargs.difference(self.__cpp_blacklist))
        self.compile_args = strip_system_includedirs(environment, self.for_machine, self.compile_args)

        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)
        if not self._add_sub_dependency(threads_factory(environment, self.for_machine, {})):
            self.is_found = False
            return

    def __fix_bogus_link_args(self, args: T.List[str]) -> T.List[str]:
        """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 ..."
        """

        new_args = []
        for arg in args:
            if arg.startswith('-l') and arg.endswith('.so'):
                new_args.append(arg.lstrip('-l'))
            elif arg.startswith('-LIBPATH:'):
                cpp = self.env.coredata.compilers[self.for_machine]['cpp']
                new_args.extend(cpp.get_linker_search_args(arg.lstrip('-LIBPATH:')))
            else:
                new_args.append(arg)
        return new_args

    def __check_libfiles(self, shared: bool) -> None:
        """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: 'Environment') -> None:
        """How to set linker args for LLVM versions >= 3.9"""
        try:
            mode = self.get_config_value(['--shared-mode'], 'link_args')[0]
        except IndexError:
            mlog.debug('llvm-config --shared-mode returned an error')
            self.is_found = False
            return

        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, f'libLLVM*{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(f'-l{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) -> None:
        """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-linking, 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 = f'libLLVM-{self.version}'
            re_name = re.compile(fr'{expected_name}.(so|dll|dylib)$')

            for file_ in os.listdir(libdir):
                if re_name.match(file_):
                    self.link_args = [f'-L{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: T.List[str], required: bool = True) -> None:
        """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(
                            f'Could not find required LLVM Component: {mod}')
                    status = '(missing)'
                else:
                    status = '(missing but optional)'
            else:
                self.required_modules.add(mod)

            self.module_details.append(mod + status)

    def log_details(self) -> str:
        if self.module_details:
            return 'modules: ' + ', '.join(self.module_details)
        return ''

class LLVMDependencyCMake(CMakeDependency):
    def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]) -> None:
        self.llvm_modules = stringlistify(extract_as_list(kwargs, 'modules'))
        self.llvm_opt_modules = stringlistify(extract_as_list(kwargs, 'optional_modules'))

        compilers = None
        if kwargs.get('native', False):
            compilers = env.coredata.compilers.build
        else:
            compilers = env.coredata.compilers.host
        if not compilers or not all(x in compilers for x in ('c', 'cpp')):
            # Initialize basic variables
            ExternalDependency.__init__(self, DependencyTypeName('cmake'), env, kwargs)

            # Initialize CMake specific variables
            self.found_modules: T.List[str] = []
            self.name = name

            # Warn and return
            mlog.warning('The LLVM dependency was not found via CMake since both a C and C++ compiler are required.')
            return

        super().__init__(name, env, kwargs, language='cpp', force_use_global_compilers=True)

        if self.traceparser is None:
            return

        if not self.is_found:
            return

        # CMake will return not found due to not defined LLVM_DYLIB_COMPONENTS
        if not self.static and version_compare(self.version, '< 7.0') and self.llvm_modules:
            mlog.warning('Before version 7.0 cmake does not export modules for dynamic linking, cannot check required modules')
            return

        # Extract extra include directories and definitions
        inc_dirs = self.traceparser.get_cmake_var('PACKAGE_INCLUDE_DIRS')
        defs = self.traceparser.get_cmake_var('PACKAGE_DEFINITIONS')
        # LLVM explicitly uses space-separated variables rather than semicolon lists
        if len(defs) == 1:
            defs = defs[0].split(' ')
        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.compile_args = strip_system_includedirs(env, self.for_machine, self.compile_args)
        if not self._add_sub_dependency(threads_factory(env, self.for_machine, {})):
            self.is_found = False
            return

    def _main_cmake_file(self) -> str:
        # Use a custom CMakeLists.txt for LLVM
        return 'CMakeListsLLVM.txt'

    # Check version in CMake to return exact version as config tool (latest allowed)
    # It is safe to add .0 to latest argument, it will discarded if we use search_version
    def llvm_cmake_versions(self) -> T.List[str]:

        def ver_from_suf(req: str) -> str:
            return search_version(req.strip('-')+'.0')

        def version_sorter(a: str, b: str) -> int:
            if version_compare(a, "="+b):
                return 0
            if version_compare(a, "<"+b):
                return 1
            return -1

        llvm_requested_versions = [ver_from_suf(x) for x in get_llvm_tool_names('') if version_compare(ver_from_suf(x), '>=0')]
        if self.version_reqs:
            llvm_requested_versions = [ver_from_suf(x) for x in get_llvm_tool_names('') if version_compare_many(ver_from_suf(x), self.version_reqs)]
        # CMake sorting before 3.18 is incorrect, sort it here instead
        return sorted(llvm_requested_versions, key=functools.cmp_to_key(version_sorter))

    # Split required and optional modules to distinguish it in CMake
    def _extra_cmake_opts(self) -> T.List[str]:
        return ['-DLLVM_MESON_REQUIRED_MODULES={}'.format(';'.join(self.llvm_modules)),
                '-DLLVM_MESON_OPTIONAL_MODULES={}'.format(';'.join(self.llvm_opt_modules)),
                '-DLLVM_MESON_PACKAGE_NAMES={}'.format(';'.join(get_llvm_tool_names(self.name))),
                '-DLLVM_MESON_VERSIONS={}'.format(';'.join(self.llvm_cmake_versions())),
                '-DLLVM_MESON_DYLIB={}'.format('OFF' if self.static else 'ON')]

    def _map_module_list(self, modules: T.List[T.Tuple[str, bool]], components: 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(f'MESON_LLVM_TARGETS_{mod}')
            if not cm_targets:
                if required:
                    raise self._gen_exception(f'LLVM module {mod} was not found')
                else:
                    mlog.warning('Optional LLVM module', mlog.bold(mod), 'was not found', fatal=False)
                    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(f'MESON_TARGET_TO_LLVM_{module}')
        if orig_name:
            return orig_name[0]
        return module


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: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__('valgrind', env, kwargs)

    def get_link_args(self, language: T.Optional[str] = None, raw: bool = False) -> T.List[str]:
        return []

packages['valgrind'] = ValgrindDependency


class ZlibSystemDependency(SystemDependency):

    def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__(name, environment, kwargs)
        from ..compilers.c import AppleClangCCompiler
        from ..compilers.cpp import AppleClangCPPCompiler

        m = self.env.machines[self.for_machine]

        # I'm not sure this is entirely correct. What if we're cross compiling
        # from something to macOS?
        if ((m.is_darwin() and isinstance(self.clib_compiler, (AppleClangCCompiler, AppleClangCPPCompiler))) or
                m.is_freebsd() or m.is_dragonflybsd() or m.is_android()):
            # No need to set includes,
            # on macos xcode/clang will do that for us.
            # on freebsd zlib.h is in /usr/include

            self.is_found = True
            self.link_args = ['-lz']
        else:
            if self.clib_compiler.get_argument_syntax() == 'msvc':
                libs = ['zlib1', 'zlib']
            else:
                libs = ['z']
            for lib in libs:
                l = self.clib_compiler.find_library(lib, environment, [], self.libtype)
                h = self.clib_compiler.has_header('zlib.h', '', environment, dependencies=[self])
                if l and h[0]:
                    self.is_found = True
                    self.link_args = l
                    break
            else:
                return

        v, _ = self.clib_compiler.get_define('ZLIB_VERSION', '#include ', self.env, [], [self])
        self.version = v.strip('"')


class JNISystemDependency(SystemDependency):
    def __init__(self, environment: 'Environment', kwargs: JNISystemDependencyKW):
        super().__init__('jni', environment, T.cast('T.Dict[str, T.Any]', kwargs))

        self.feature_since = ('0.62.0', '')

        m = self.env.machines[self.for_machine]

        if 'java' not in environment.coredata.compilers[self.for_machine]:
            detect_compiler(self.name, environment, self.for_machine, 'java')
        self.javac = environment.coredata.compilers[self.for_machine]['java']
        self.version = self.javac.version

        modules: T.List[str] = mesonlib.listify(kwargs.get('modules', []))
        for module in modules:
            if module not in {'jvm', 'awt'}:
                msg = f'Unknown JNI module ({module})'
                if self.required:
                    mlog.error(msg)
                else:
                    mlog.debug(msg)
                self.is_found = False
                return

        if 'version' in kwargs and not version_compare(self.version, kwargs['version']):
            mlog.error(f'Incorrect JDK version found ({self.version}), wanted {kwargs["version"]}')
            self.is_found = False
            return

        self.java_home = environment.properties[self.for_machine].get_java_home()
        if not self.java_home:
            self.java_home = pathlib.Path(shutil.which(self.javac.exelist[0])).resolve().parents[1]
            if m.is_darwin():
                problem_java_prefix = pathlib.Path('/System/Library/Frameworks/JavaVM.framework/Versions')
                if problem_java_prefix in self.java_home.parents:
                    res = subprocess.run(['/usr/libexec/java_home', '--failfast', '--arch', m.cpu_family],
                                         stdout=subprocess.PIPE)
                    if res.returncode != 0:
                        msg = 'JAVA_HOME could not be discovered on the system. Please set it explicitly.'
                        if self.required:
                            mlog.error(msg)
                        else:
                            mlog.debug(msg)
                        self.is_found = False
                        return
                    self.java_home = pathlib.Path(res.stdout.decode().strip())

        platform_include_dir = self.__machine_info_to_platform_include_dir(m)
        if platform_include_dir is None:
            mlog.error("Could not find a JDK platform include directory for your OS, please open an issue or provide a pull request.")
            self.is_found = False
            return

        java_home_include = self.java_home / 'include'
        self.compile_args.append(f'-I{java_home_include}')
        self.compile_args.append(f'-I{java_home_include / platform_include_dir}')

        if modules:
            if m.is_windows():
                java_home_lib = self.java_home / 'lib'
                java_home_lib_server = java_home_lib
            else:
                if version_compare(self.version, '<= 1.8.0'):
                    java_home_lib = self.java_home / 'jre' / 'lib' / self.__cpu_translate(m.cpu_family)
                else:
                    java_home_lib = self.java_home / 'lib'

                java_home_lib_server = java_home_lib / 'server'

            if 'jvm' in modules:
                jvm = self.clib_compiler.find_library('jvm', environment, extra_dirs=[str(java_home_lib_server)])
                if jvm is None:
                    mlog.debug('jvm library not found.')
                    self.is_found = False
                else:
                    self.link_args.extend(jvm)
            if 'awt' in modules:
                jawt = self.clib_compiler.find_library('jawt', environment, extra_dirs=[str(java_home_lib)])
                if jawt is None:
                    mlog.debug('jawt library not found.')
                    self.is_found = False
                else:
                    self.link_args.extend(jawt)

        self.is_found = True

    @staticmethod
    def __cpu_translate(cpu: str) -> str:
        '''
        The JDK and Meson have a disagreement here, so translate it over. In the event more
        translation needs to be done, add to following dict.
        '''
        java_cpus = {
            'x86_64': 'amd64',
        }

        return java_cpus.get(cpu, cpu)

    @staticmethod
    def __machine_info_to_platform_include_dir(m: 'MachineInfo') -> T.Optional[str]:
        '''Translates the machine information to the platform-dependent include directory

        When inspecting a JDK release tarball or $JAVA_HOME, inside the `include/` directory is a
        platform-dependent directory that must be on the target's include path in addition to the
        parent `include/` directory.
        '''
        if m.is_linux():
            return 'linux'
        elif m.is_windows():
            return 'win32'
        elif m.is_darwin():
            return 'darwin'
        elif m.is_sunos():
            return 'solaris'
        elif m.is_freebsd():
            return 'freebsd'
        elif m.is_netbsd():
            return 'netbsd'
        elif m.is_openbsd():
            return 'openbsd'
        elif m.is_dragonflybsd():
            return 'dragonfly'

        return None

packages['jni'] = JNISystemDependency


class JDKSystemDependency(JNISystemDependency):
    def __init__(self, environment: 'Environment', kwargs: JNISystemDependencyKW):
        super().__init__(environment, kwargs)

        self.feature_since = ('0.59.0', '')
        self.featurechecks.append(FeatureDeprecated(
            'jdk system dependency',
            '0.62.0',
            'Use the jni system dependency instead'
        ))

packages['jdk'] = JDKSystemDependency


packages['llvm'] = llvm_factory = DependencyFactory(
    'LLVM',
    [DependencyMethods.CMAKE, DependencyMethods.CONFIG_TOOL],
    cmake_class=LLVMDependencyCMake,
    configtool_class=LLVMDependencyConfigTool,
)

packages['gtest'] = gtest_factory = DependencyFactory(
    'gtest',
    [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM],
    pkgconfig_class=GTestDependencyPC,
    system_class=GTestDependencySystem,
)

packages['gmock'] = gmock_factory = DependencyFactory(
    'gmock',
    [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM],
    pkgconfig_class=GMockDependencyPC,
    system_class=GMockDependencySystem,
)

packages['zlib'] = zlib_factory = DependencyFactory(
    'zlib',
    [DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE, DependencyMethods.SYSTEM],
    cmake_name='ZLIB',
    system_class=ZlibSystemDependency,
)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/dependencies/dub.py0000644000175000017500000004317714562742363020773 0ustar00jpakkanejpakkane# Copyright 2013-2021 The Meson development team

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

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

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

from .base import ExternalDependency, DependencyException, DependencyTypeName
from .pkgconfig import PkgConfigDependency
from ..mesonlib import (Popen_safe, OptionKey, join_args, version_compare)
from ..programs import ExternalProgram
from .. import mlog
import re
import os
import json
import typing as T

if T.TYPE_CHECKING:
    from ..environment import Environment


class DubDependency(ExternalDependency):
    # dub program and version
    class_dubbin: T.Optional[T.Tuple[ExternalProgram, str]] = None
    class_dubbin_searched = False

    def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__(DependencyTypeName('dub'), environment, kwargs, language='d')
        self.name = name
        from ..compilers.d import DCompiler, d_feature_args

        _temp_comp = super().get_compiler()
        assert isinstance(_temp_comp, DCompiler)
        self.compiler = _temp_comp

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

        if DubDependency.class_dubbin is None and not DubDependency.class_dubbin_searched:
            DubDependency.class_dubbin = self._check_dub()
            DubDependency.class_dubbin_searched = True
        if DubDependency.class_dubbin is None:
            if self.required:
                raise DependencyException('DUB not found.')
            self.is_found = False
            return

        (self.dubbin, dubver) = DubDependency.class_dubbin  # pylint: disable=unpacking-non-sequence

        assert isinstance(self.dubbin, ExternalProgram)

        # Check if Dub version is compatible with Meson
        if version_compare(dubver, '>1.31.1'):
            if self.required:
                raise DependencyException(
                    f"DUB version {dubver} is not compatible with Meson (can't locate artifacts in Dub cache)")
            self.is_found = False
            return

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

        # if an explicit version spec was stated, use this when querying Dub
        main_pack_spec = name
        if 'version' in kwargs:
            version_spec = kwargs['version']
            if isinstance(version_spec, list):
                version_spec = " ".join(version_spec)
            main_pack_spec = f'{name}@{version_spec}'

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

        # we need to know the build type as well
        dub_buildtype = str(environment.coredata.get_option(OptionKey('buildtype')))
        # MESON types: choices=['plain', 'debug', 'debugoptimized', 'release', 'minsize', 'custom'])),
        # DUB types: debug (default), plain, release, release-debug, release-nobounds, unittest, profile, profile-gc,
        # docs, ddox, cov, unittest-cov, syntax and custom
        if dub_buildtype == 'debugoptimized':
            dub_buildtype = 'release-debug'
        elif dub_buildtype == 'minsize':
            dub_buildtype = 'release'

        # Ask dub for the package
        describe_cmd = [
            'describe', main_pack_spec, '--arch=' + dub_arch,
            '--build=' + dub_buildtype, '--compiler=' + self.compiler.get_exelist()[-1]
        ]
        ret, res, err = self._call_dubbin(describe_cmd)

        if ret != 0:
            mlog.debug('DUB describe failed: ' + err)
            if 'locally' in err:
                fetch_cmd = ['dub', 'fetch', main_pack_spec]
                mlog.error(mlog.bold(main_pack_spec), 'is not present locally. You may try the following command:')
                mlog.log(mlog.bold(join_args(fetch_cmd)))
            self.is_found = False
            return

        # A command that might be useful in case of missing DUB package
        def dub_build_deep_command() -> str:
            cmd = [
                'dub', 'run', 'dub-build-deep', '--yes', '--', main_pack_spec,
                '--arch=' + dub_arch, '--compiler=' + self.compiler.get_exelist()[-1],
                '--build=' + dub_buildtype
            ]
            return join_args(cmd)

        dub_comp_id = self.compiler.get_id().replace('llvm', 'ldc').replace('gcc', 'gdc')
        description = json.loads(res)

        self.compile_args = []
        self.link_args = self.raw_link_args = []

        show_buildtype_warning = False

        def find_package_target(pkg: T.Dict[str, str]) -> bool:
            nonlocal show_buildtype_warning
            # try to find a static library in a DUB folder corresponding to
            # version, configuration, compiler, arch and build-type
            # if can find, add to link_args.
            # link_args order is meaningful, so this function MUST be called in the right order
            pack_id = f'{pkg["name"]}@{pkg["version"]}'
            (tgt_file, compatibilities) = self._find_compatible_package_target(description, pkg, dub_comp_id)
            if tgt_file is None:
                if not compatibilities:
                    mlog.error(mlog.bold(pack_id), 'not found')
                elif 'compiler' not in compatibilities:
                    mlog.error(mlog.bold(pack_id), 'found but not compiled with ', mlog.bold(dub_comp_id))
                elif dub_comp_id != 'gdc' and 'compiler_version' not in compatibilities:
                    mlog.error(mlog.bold(pack_id), 'found but not compiled with',
                               mlog.bold(f'{dub_comp_id}-{self.compiler.version}'))
                elif 'arch' not in compatibilities:
                    mlog.error(mlog.bold(pack_id), 'found but not compiled for', mlog.bold(dub_arch))
                elif 'platform' not in compatibilities:
                    mlog.error(mlog.bold(pack_id), 'found but not compiled for',
                               mlog.bold(description['platform'].join('.')))
                elif 'configuration' not in compatibilities:
                    mlog.error(mlog.bold(pack_id), 'found but not compiled for the',
                               mlog.bold(pkg['configuration']), 'configuration')
                else:
                    mlog.error(mlog.bold(pack_id), 'not found')

                mlog.log('You may try the following command to install the necessary DUB libraries:')
                mlog.log(mlog.bold(dub_build_deep_command()))

                return False

            if 'build_type' not in compatibilities:
                mlog.warning(mlog.bold(pack_id), 'found but not compiled as', mlog.bold(dub_buildtype))
                show_buildtype_warning = True

            self.link_args.append(tgt_file)
            return True

        # Main algorithm:
        # 1. Ensure that the target is a compatible library type (not dynamic)
        # 2. Find a compatible built library for the main dependency
        # 3. Do the same for each sub-dependency.
        #    link_args MUST be in the same order than the "linkDependencies" of the main target
        # 4. Add other build settings (imports, versions etc.)

        # 1
        self.is_found = False
        packages = {}
        for pkg in description['packages']:
            packages[pkg['name']] = pkg

            if not pkg['active']:
                continue

            if pkg['targetType'] == 'dynamicLibrary':
                mlog.error('DUB dynamic library dependencies are not supported.')
                self.is_found = False
                return

            # check that the main dependency is indeed a library
            if pkg['name'] == name:
                self.is_found = True

                if pkg['targetType'] not in ['library', 'sourceLibrary', 'staticLibrary']:
                    mlog.error(mlog.bold(name), "found but it isn't a library")
                    self.is_found = False
                    return

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

        # collect all targets
        targets = {}
        for tgt in description['targets']:
            targets[tgt['rootPackage']] = tgt

        if name not in targets:
            self.is_found = False
            if self.pkg['targetType'] == 'sourceLibrary':
                # source libraries have no associated targets,
                # but some build settings like import folders must be found from the package object.
                # Current algo only get these from "buildSettings" in the target object.
                # Let's save this for a future PR.
                # (See openssl DUB package for example of sourceLibrary)
                mlog.error('DUB targets of type', mlog.bold('sourceLibrary'), 'are not supported.')
            else:
                mlog.error('Could not find target description for', mlog.bold(main_pack_spec))

        if not self.is_found:
            mlog.error(f'Could not find {name} in DUB description')
            return

        # Current impl only supports static libraries
        self.static = True

        # 2
        if not find_package_target(self.pkg):
            self.is_found = False
            return

        # 3
        for link_dep in targets[name]['linkDependencies']:
            pkg = packages[link_dep]
            if not find_package_target(pkg):
                self.is_found = False
                return

        if show_buildtype_warning:
            mlog.log('If it is not suitable, try the following command and reconfigure Meson with', mlog.bold('--clearcache'))
            mlog.log(mlog.bold(dub_build_deep_command()))

        # 4
        bs = targets[name]['buildSettings']

        for flag in bs['dflags']:
            self.compile_args.append(flag)

        for path in bs['importPaths']:
            self.compile_args.append('-I' + path)

        for path in bs['stringImportPaths']:
            if 'import_dir' not in d_feature_args[self.compiler.id]:
                break
            flag = d_feature_args[self.compiler.id]['import_dir']
            self.compile_args.append(f'{flag}={path}')

        for ver in bs['versions']:
            if 'version' not in d_feature_args[self.compiler.id]:
                break
            flag = d_feature_args[self.compiler.id]['version']
            self.compile_args.append(f'{flag}={ver}')

        if bs['mainSourceFile']:
            self.compile_args.append(bs['mainSourceFile'])

        # pass static libraries
        # linkerFiles are added during step 3
        # for file in bs['linkerFiles']:
        #     self.link_args.append(file)

        for file in bs['sourceFiles']:
            # sourceFiles may contain static libraries
            if file.endswith('.lib') or file.endswith('.a'):
                self.link_args.append(file)

        for flag in bs['lflags']:
            self.link_args.append(flag)

        is_windows = self.env.machines.host.is_windows()
        if is_windows:
            winlibs = ['kernel32', 'user32', 'gdi32', 'winspool', 'shell32', 'ole32',
                       'oleaut32', 'uuid', 'comdlg32', 'advapi32', 'ws2_32']

        for lib in bs['libs']:
            if os.name != 'nt':
                # trying to add system libraries by pkg-config
                pkgdep = PkgConfigDependency(lib, environment, {'required': 'true', 'silent': 'true'})
                if pkgdep.is_found:
                    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)
                    continue

            if is_windows and lib in winlibs:
                self.link_args.append(lib + '.lib')
                continue

            # fallback
            self.link_args.append('-l'+lib)

    # This function finds the target of the provided JSON package, built for the right
    # compiler, architecture, configuration...
    # It returns (target|None, {compatibilities})
    # If None is returned for target, compatibilities will list what other targets were found without full compatibility
    def _find_compatible_package_target(self, jdesc: T.Dict[str, str], jpack: T.Dict[str, str], dub_comp_id: str) -> T.Tuple[str, T.Set[str]]:
        dub_build_path = os.path.join(jpack['path'], '.dub', 'build')

        if not os.path.exists(dub_build_path):
            return (None, None)

        # try to find a dir like library-debug-linux.posix-x86_64-ldc_2081-EF934983A3319F8F8FF2F0E107A363BA

        # fields are:
        #  - configuration
        #  - build type
        #  - platform
        #  - architecture
        #  - compiler id (dmd, ldc, gdc)
        #  - compiler version or frontend id or frontend version?

        conf = jpack['configuration']
        build_type = jdesc['buildType']
        platforms = jdesc['platform']
        archs = jdesc['architecture']

        # Get D frontend version implemented in the compiler, or the compiler version itself
        # gdc doesn't support this
        comp_versions = []

        if dub_comp_id != 'gdc':
            comp_versions.append(self.compiler.version)

            ret, res = self._call_compbin(['--version'])[0:2]
            if ret != 0:
                mlog.error('Failed to run {!r}', mlog.bold(dub_comp_id))
                return (None, None)
            d_ver_reg = re.search('v[0-9].[0-9][0-9][0-9].[0-9]', res)  # Ex.: v2.081.2

            if d_ver_reg is not None:
                frontend_version = d_ver_reg.group()
                frontend_id = frontend_version.rsplit('.', 1)[0].replace(
                    'v', '').replace('.', '')  # Fix structure. Ex.: 2081
                comp_versions.extend([frontend_version, frontend_id])

        compatibilities: T.Set[str] = set()

        # build_type is not in check_list because different build types might be compatible.
        # We do show a WARNING that the build type is not the same.
        # It might be critical in release builds, and acceptable otherwise
        check_list = ('configuration', 'platform', 'arch', 'compiler', 'compiler_version')

        for entry in os.listdir(dub_build_path):

            target = os.path.join(dub_build_path, entry, jpack['targetFileName'])
            if not os.path.exists(target):
                # unless Dub and Meson are racing, the target file should be present
                # when the directory is present
                mlog.debug("WARNING: Could not find a Dub target: " + target)
                continue

            # we build a new set for each entry, because if this target is returned
            # we want to return only the compatibilities associated to this target
            # otherwise we could miss the WARNING about build_type
            comps = set()

            if conf in entry:
                comps.add('configuration')

            if build_type in entry:
                comps.add('build_type')

            if all(platform in entry for platform in platforms):
                comps.add('platform')

            if all(arch in entry for arch in archs):
                comps.add('arch')

            if dub_comp_id in entry:
                comps.add('compiler')

            if dub_comp_id == 'gdc' or any(cv in entry for cv in comp_versions):
                comps.add('compiler_version')

            if all(key in comps for key in check_list):
                return (target, comps)
            else:
                compatibilities = set.union(compatibilities, comps)

        return (None, compatibilities)

    def _call_dubbin(self, args: T.List[str], env: T.Optional[T.Dict[str, str]] = None) -> T.Tuple[int, str, str]:
        assert isinstance(self.dubbin, ExternalProgram)
        p, out, err = Popen_safe(self.dubbin.get_command() + args, env=env)
        return p.returncode, out.strip(), err.strip()

    def _call_compbin(self, args: T.List[str], env: T.Optional[T.Dict[str, str]] = None) -> T.Tuple[int, str, str]:
        p, out, err = Popen_safe(self.compiler.get_exelist() + args, env=env)
        return p.returncode, out.strip(), err.strip()

    def _check_dub(self) -> T.Optional[T.Tuple[ExternalProgram, str]]:

        def find() -> T.Optional[T.Tuple[ExternalProgram, str]]:
            dubbin = ExternalProgram('dub', silent=True)

            if not dubbin.found():
                return None

            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())))
                    return None

            except (FileNotFoundError, PermissionError):
                return None

            vermatch = re.search(r'DUB version (\d+\.\d+\.\d+.*), ', out.strip())
            if vermatch:
                dubver = vermatch.group(1)
            else:
                mlog.warning(f"Found dub {' '.join(dubbin.get_command())} but couldn't parse version in {out.strip()}")
                return None

            return (dubbin, dubver)

        found = find()

        if found is None:
            mlog.log('Found DUB:', mlog.red('NO'))
        else:
            (dubbin, dubver) = found
            mlog.log('Found DUB:', mlog.bold(dubbin.get_path()),
                     '(version %s)' % dubver)

        return found
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/dependencies/factory.py0000644000175000017500000001554014562742363021661 0ustar00jpakkanejpakkane# Copyright 2013-2021 The Meson development team
# Copyright Ā© 2021 Intel Corporation

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

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

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

import functools
import typing as T

from .base import DependencyException, DependencyMethods
from .base import process_method_kw
from .base import BuiltinDependency, SystemDependency
from .cmake import CMakeDependency
from .framework import ExtraFrameworkDependency
from .pkgconfig import PkgConfigDependency

if T.TYPE_CHECKING:
    from .base import ExternalDependency
    from .configtool import ConfigToolDependency
    from ..environment import Environment
    from ..mesonlib import MachineChoice

    DependencyGenerator = T.Callable[[], ExternalDependency]
    FactoryFunc = T.Callable[
        [
            'Environment',
            MachineChoice,
            T.Dict[str, T.Any],
            T.List[DependencyMethods]
        ],
        T.List[DependencyGenerator]
    ]

    WrappedFactoryFunc = T.Callable[
        [
            'Environment',
            MachineChoice,
            T.Dict[str, T.Any]
        ],
        T.List[DependencyGenerator]
    ]

    # This should be str, Environment, T.Dict[str, T.Any], T.Optional[str]
    # But if you try that, you get error: Cannot infer type of lambda
    CmakeDependencyFunc = T.Callable[..., CMakeDependency]

class DependencyFactory:

    """Factory to get dependencies from multiple sources.

    This class provides an initializer that takes a set of names and classes
    for various kinds of dependencies. When the initialized object is called
    it returns a list of callables return Dependency objects to try in order.

    :name: The name of the dependency. This will be passed as the name
        parameter of the each dependency unless it is overridden on a per
        type basis.
    :methods: An ordered list of DependencyMethods. This is the order
        dependencies will be returned in unless they are removed by the
        _process_method function
    :*_name: This will overwrite the name passed to the corresponding class.
        For example, if the name is 'zlib', but cmake calls the dependency
        'Z', then using `cmake_name='Z'` will pass the name as 'Z' to cmake.
    :*_class: A *type* or callable that creates a class, and has the
        signature of an ExternalDependency
    :system_class: If you pass DependencyMethods.SYSTEM in methods, you must
        set this argument.
    """

    def __init__(self, name: str, methods: T.List[DependencyMethods], *,
                 extra_kwargs: T.Optional[T.Dict[str, T.Any]] = None,
                 pkgconfig_name: T.Optional[str] = None,
                 pkgconfig_class: 'T.Type[PkgConfigDependency]' = PkgConfigDependency,
                 cmake_name: T.Optional[str] = None,
                 cmake_class: 'T.Union[T.Type[CMakeDependency], CmakeDependencyFunc]' = CMakeDependency,
                 configtool_class: 'T.Optional[T.Type[ConfigToolDependency]]' = None,
                 framework_name: T.Optional[str] = None,
                 framework_class: 'T.Type[ExtraFrameworkDependency]' = ExtraFrameworkDependency,
                 builtin_class: 'T.Type[BuiltinDependency]' = BuiltinDependency,
                 system_class: 'T.Type[SystemDependency]' = SystemDependency):

        if DependencyMethods.CONFIG_TOOL in methods and not configtool_class:
            raise DependencyException('A configtool must have a custom class')

        self.extra_kwargs = extra_kwargs or {}
        self.methods = methods
        self.classes: T.Dict[
            DependencyMethods,
            T.Callable[['Environment', T.Dict[str, T.Any]], ExternalDependency]
        ] = {
            # Just attach the correct name right now, either the generic name
            # or the method specific name.
            DependencyMethods.EXTRAFRAMEWORK: functools.partial(framework_class, framework_name or name),
            DependencyMethods.PKGCONFIG: functools.partial(pkgconfig_class, pkgconfig_name or name),
            DependencyMethods.CMAKE: functools.partial(cmake_class, cmake_name or name),
            DependencyMethods.SYSTEM: functools.partial(system_class, name),
            DependencyMethods.BUILTIN: functools.partial(builtin_class, name),
            DependencyMethods.CONFIG_TOOL: None,
        }
        if configtool_class is not None:
            self.classes[DependencyMethods.CONFIG_TOOL] = functools.partial(configtool_class, name)

    @staticmethod
    def _process_method(method: DependencyMethods, env: 'Environment', for_machine: MachineChoice) -> bool:
        """Report whether a method is valid or not.

        If the method is valid, return true, otherwise return false. This is
        used in a list comprehension to filter methods that are not possible.

        By default this only remove EXTRAFRAMEWORK dependencies for non-mac platforms.
        """
        # Extra frameworks are only valid for macOS and other apple products
        if (method is DependencyMethods.EXTRAFRAMEWORK and
                not env.machines[for_machine].is_darwin()):
            return False
        return True

    def __call__(self, env: 'Environment', for_machine: MachineChoice,
                 kwargs: T.Dict[str, T.Any]) -> T.List['DependencyGenerator']:
        """Return a list of Dependencies with the arguments already attached."""
        methods = process_method_kw(self.methods, kwargs)
        nwargs = self.extra_kwargs.copy()
        nwargs.update(kwargs)

        return [functools.partial(self.classes[m], env, nwargs) for m in methods
                if self._process_method(m, env, for_machine)]


def factory_methods(methods: T.Set[DependencyMethods]) -> T.Callable[['FactoryFunc'], 'WrappedFactoryFunc']:
    """Decorator for handling methods for dependency factory functions.

    This helps to make factory functions self documenting
    >>> @factory_methods([DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE])
    >>> def factory(env: Environment, for_machine: MachineChoice, kwargs: T.Dict[str, T.Any], methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']:
    >>>     pass
    """

    def inner(func: 'FactoryFunc') -> 'WrappedFactoryFunc':

        @functools.wraps(func)
        def wrapped(env: 'Environment', for_machine: MachineChoice, kwargs: T.Dict[str, T.Any]) -> T.List['DependencyGenerator']:
            return func(env, for_machine, kwargs, process_method_kw(methods, kwargs))

        return wrapped

    return inner
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/dependencies/framework.py0000644000175000017500000001270014562742363022202 0ustar00jpakkanejpakkane# Copyright 2013-2021 The Meson development team

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

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

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

from .base import DependencyTypeName, ExternalDependency, DependencyException
from ..mesonlib import MesonException, Version, stringlistify
from .. import mlog
from pathlib import Path
import typing as T

if T.TYPE_CHECKING:
    from ..environment import Environment

class ExtraFrameworkDependency(ExternalDependency):
    system_framework_paths: T.Optional[T.List[str]] = None

    def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None) -> None:
        paths = stringlistify(kwargs.get('paths', []))
        super().__init__(DependencyTypeName('extraframeworks'), env, kwargs, language=language)
        self.name = name
        # Full path to framework directory
        self.framework_path: T.Optional[str] = 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: str, paths: T.List[str]) -> None:
        if not paths:
            paths = self.system_framework_paths
        for p in paths:
            mlog.debug(f'Looking for framework {name} in {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 += ['-idirafter' + incdir]
            self.is_found = True
            return

    def _get_framework_path(self, path: str, name: str) -> T.Optional[Path]:
        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: Path) -> str:
        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: Path) -> T.Optional[str]:
        # 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

    def log_info(self) -> str:
        return self.framework_path or ''

    @staticmethod
    def log_tried() -> str:
        return 'framework'
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0
meson-1.3.2/mesonbuild/dependencies/hdf5.py0000644000175000017500000001611014562742373021033 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import functools
import os
import re
from pathlib import Path

from ..mesonlib import OrderedSet, join_args
from .base import DependencyException, DependencyMethods
from .configtool import ConfigToolDependency
from .detect import packages
from .pkgconfig import PkgConfigDependency, PkgConfigInterface
from .factory import factory_methods
import typing as T

if T.TYPE_CHECKING:
    from .factory import DependencyGenerator
    from ..environment import Environment
    from ..mesonlib import MachineChoice


class HDF5PkgConfigDependency(PkgConfigDependency):

    """Handle brokenness in the HDF5 pkg-config files."""

    def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None) -> None:
        language = language or 'c'
        if language not in {'c', 'cpp', 'fortran'}:
            raise DependencyException(f'Language {language} is not supported with HDF5.')

        super().__init__(name, environment, kwargs, language)
        if not self.is_found:
            return

        # some broken pkgconfig don't actually list the full path to the needed includes
        newinc: T.List[str] = []
        for arg in self.compile_args:
            if arg.startswith('-I'):
                stem = 'static' if self.static else 'shared'
                if (Path(arg[2:]) / stem).is_dir():
                    newinc.append('-I' + str(Path(arg[2:]) / stem))
        self.compile_args += newinc

        link_args: T.List[str] = []
        for larg in self.get_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


class HDF5ConfigToolDependency(ConfigToolDependency):

    """Wrapper around hdf5 binary config tools."""

    version_arg = '-showconfig'

    def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None) -> None:
        language = language or 'c'
        if language not in {'c', 'cpp', 'fortran'}:
            raise DependencyException(f'Language {language} is not supported with HDF5.')

        if language == 'c':
            cenv = 'CC'
            lenv = 'C'
            tools = ['h5cc', 'h5pcc']
        elif language == 'cpp':
            cenv = 'CXX'
            lenv = 'CXX'
            tools = ['h5c++', 'h5pc++']
        elif language == 'fortran':
            cenv = 'FC'
            lenv = 'F'
            tools = ['h5fc', 'h5pfc']
        else:
            raise DependencyException('How did you get here?')

        # We need this before we call super()
        for_machine = self.get_for_machine_from_kwargs(kwargs)

        nkwargs = kwargs.copy()
        nkwargs['tools'] = tools

        # Override the compiler that the config tools are going to use by
        # setting the environment variables that they use for the compiler and
        # linkers.
        compiler = environment.coredata.compilers[for_machine][language]
        try:
            os.environ[f'HDF5_{cenv}'] = join_args(compiler.get_exelist())
            os.environ[f'HDF5_{lenv}LINKER'] = join_args(compiler.get_linker_exelist())
            super().__init__(name, environment, nkwargs, language)
        finally:
            del os.environ[f'HDF5_{cenv}']
            del os.environ[f'HDF5_{lenv}LINKER']
        if not self.is_found:
            return

        # We first need to call the tool with -c to get the compile arguments
        # and then without -c to get the link arguments.
        args = self.get_config_value(['-show', '-c'], 'args')[1:]
        args += self.get_config_value(['-show', '-noshlib' if self.static else '-shlib'], 'args')[1:]
        found = False
        for arg in args:
            if arg.startswith(('-I', '-f', '-D')) or arg == '-pthread':
                self.compile_args.append(arg)
            elif arg.startswith(('-L', '-l', '-Wl')):
                self.link_args.append(arg)
                found = True
            elif Path(arg).is_file():
                self.link_args.append(arg)
                found = True

        # cmake h5cc is broken
        if not found:
            raise DependencyException('HDF5 was built with cmake instead of autotools, and h5cc is broken.')

    def _sanitize_version(self, ver: str) -> str:
        v = re.search(r'\s*HDF5 Version: (\d+\.\d+\.\d+)', ver)
        return v.group(1)


@factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL})
def hdf5_factory(env: 'Environment', for_machine: 'MachineChoice',
                 kwargs: T.Dict[str, T.Any], methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']:
    language = kwargs.get('language')
    candidates: T.List['DependencyGenerator'] = []

    if DependencyMethods.PKGCONFIG in methods:
        # Use an ordered set so that these remain the first tried pkg-config files
        pkgconfig_files = OrderedSet(['hdf5', 'hdf5-serial'])
        pkg = PkgConfigInterface.instance(env, for_machine, silent=False)
        if pkg:
            # some distros put hdf5-1.2.3.pc with version number in .pc filename.
            for mod in pkg.list_all():
                if mod.startswith('hdf5'):
                    pkgconfig_files.add(mod)
        for mod in pkgconfig_files:
            candidates.append(functools.partial(HDF5PkgConfigDependency, mod, env, kwargs, language))

    if DependencyMethods.CONFIG_TOOL in methods:
        candidates.append(functools.partial(HDF5ConfigToolDependency, 'hdf5', env, kwargs, language))

    return candidates

packages['hdf5'] = hdf5_factory
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0
meson-1.3.2/mesonbuild/dependencies/misc.py0000644000175000017500000006272214562742373021152 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import functools
import re
import typing as T

from .. import mesonlib
from .. import mlog
from .base import DependencyException, DependencyMethods
from .base import BuiltinDependency, SystemDependency
from .cmake import CMakeDependency, CMakeDependencyFactory
from .configtool import ConfigToolDependency
from .detect import packages
from .factory import DependencyFactory, factory_methods
from .pkgconfig import PkgConfigDependency

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


@factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE})
def netcdf_factory(env: 'Environment',
                   for_machine: 'mesonlib.MachineChoice',
                   kwargs: T.Dict[str, T.Any],
                   methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']:
    language = kwargs.get('language', 'c')
    if language not in ('c', 'cpp', 'fortran'):
        raise DependencyException(f'Language {language} is not supported with NetCDF.')

    candidates: T.List['DependencyGenerator'] = []

    if DependencyMethods.PKGCONFIG in methods:
        if language == 'fortran':
            pkg = 'netcdf-fortran'
        else:
            pkg = 'netcdf'

        candidates.append(functools.partial(PkgConfigDependency, pkg, env, kwargs, language=language))

    if DependencyMethods.CMAKE in methods:
        candidates.append(functools.partial(CMakeDependency, 'NetCDF', env, kwargs, language=language))

    return candidates

packages['netcdf'] = netcdf_factory


class DlBuiltinDependency(BuiltinDependency):
    def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__(name, env, kwargs)
        self.feature_since = ('0.62.0', "consider checking for `dlopen` with and without `find_library('dl')`")

        if self.clib_compiler.has_function('dlopen', '#include ', env)[0]:
            self.is_found = True


class DlSystemDependency(SystemDependency):
    def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__(name, env, kwargs)
        self.feature_since = ('0.62.0', "consider checking for `dlopen` with and without `find_library('dl')`")

        h = self.clib_compiler.has_header('dlfcn.h', '', env)
        self.link_args = self.clib_compiler.find_library('dl', env, [], self.libtype)

        if h[0] and self.link_args:
            self.is_found = True


class OpenMPDependency(SystemDependency):
    # Map date of specification release (which is the macro value) to a version.
    VERSIONS = {
        '202111': '5.2',
        '202011': '5.1',
        '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: 'Environment', kwargs: T.Dict[str, T.Any]) -> None:
        language = kwargs.get('language')
        super().__init__('openmp', environment, kwargs, language=language)
        self.is_found = False
        if self.clib_compiler.get_id() == 'nagfor':
            # 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
        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:
            try:
                self.version = self.VERSIONS[openmp_date]
            except KeyError:
                mlog.debug(f'Could not find an OpenMP version matching {openmp_date}')
                if openmp_date == '_OPENMP':
                    mlog.debug('This can be caused by flags such as gcc\'s `-fdirectives-only`, which affect preprocessor behavior.')
                return

            if self.clib_compiler.get_id() == 'clang-cl':
                # this is necessary for clang-cl, see https://github.com/mesonbuild/meson/issues/5298
                clangcl_openmp_link_args = self.clib_compiler.find_library("libomp", self.env, [])
                if not clangcl_openmp_link_args:
                    mlog.log(mlog.yellow('WARNING:'), 'OpenMP found but libomp for clang-cl missing.')
                    return
                self.link_args.extend(clangcl_openmp_link_args)

            # 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.extend(self.clib_compiler.openmp_flags())
                    self.link_args.extend(self.clib_compiler.openmp_link_flags())
                    break
            if not self.is_found:
                mlog.log(mlog.yellow('WARNING:'), 'OpenMP found but omp.h missing.')

packages['openmp'] = OpenMPDependency


class ThreadDependency(SystemDependency):
    def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None:
        super().__init__(name, environment, kwargs)
        self.is_found = True
        # Happens if you are using a language with threads
        # concept without C, such as plain Cuda.
        if not self.clib_compiler:
            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)


class BlocksDependency(SystemDependency):
    def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None:
        super().__init__('blocks', environment, 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

packages['blocks'] = BlocksDependency


class PcapDependencyConfigTool(ConfigToolDependency):

    tools = ['pcap-config']
    tool_name = 'pcap-config'

    # version 1.10.2 added error checking for invalid arguments
    # version 1.10.3 will hopefully add actual support for --version
    skip_version = '--help'

    def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__(name, environment, kwargs)
        if not self.is_found:
            return
        self.compile_args = self.get_config_value(['--cflags'], 'compile_args')
        self.link_args = self.get_config_value(['--libs'], 'link_args')
        if self.version is None:
            # older pcap-config versions don't support this
            self.version = self.get_pcap_lib_version()

    def get_pcap_lib_version(self) -> T.Optional[str]:
        # Since we seem to need to run a program to discover the pcap version,
        # we can't do that when cross-compiling
        # FIXME: this should be handled if we have an exe_wrapper
        if not self.env.machines.matches_build_machine(self.for_machine):
            return None

        v = self.clib_compiler.get_return_value('pcap_lib_version', 'string',
                                                '#include ', self.env, [], [self])
        v = re.sub(r'libpcap version ', '', str(v))
        v = re.sub(r' -- Apple version.*$', '', v)
        return v


class CupsDependencyConfigTool(ConfigToolDependency):

    tools = ['cups-config']
    tool_name = 'cups-config'

    def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__(name, environment, kwargs)
        if not self.is_found:
            return
        self.compile_args = self.get_config_value(['--cflags'], 'compile_args')
        self.link_args = self.get_config_value(['--ldflags', '--libs'], 'link_args')


class LibWmfDependencyConfigTool(ConfigToolDependency):

    tools = ['libwmf-config']
    tool_name = 'libwmf-config'

    def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__(name, environment, kwargs)
        if not self.is_found:
            return
        self.compile_args = self.get_config_value(['--cflags'], 'compile_args')
        self.link_args = self.get_config_value(['--libs'], 'link_args')


class LibGCryptDependencyConfigTool(ConfigToolDependency):

    tools = ['libgcrypt-config']
    tool_name = 'libgcrypt-config'

    def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__(name, environment, kwargs)
        if not self.is_found:
            return
        self.compile_args = self.get_config_value(['--cflags'], 'compile_args')
        self.link_args = self.get_config_value(['--libs'], 'link_args')
        self.version = self.get_config_value(['--version'], 'version')[0]


class GpgmeDependencyConfigTool(ConfigToolDependency):

    tools = ['gpgme-config']
    tool_name = 'gpg-config'

    def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__(name, environment, kwargs)
        if not self.is_found:
            return
        self.compile_args = self.get_config_value(['--cflags'], 'compile_args')
        self.link_args = self.get_config_value(['--libs'], 'link_args')
        self.version = self.get_config_value(['--version'], 'version')[0]


class ShadercDependency(SystemDependency):

    def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__('shaderc', environment, 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(f'Static library {static_lib!r} not found for dependency '
                                 f'{self.name!r}, may not be statically linked')

                break


class CursesConfigToolDependency(ConfigToolDependency):

    """Use the curses config tools."""

    tool = 'curses-config'
    # ncurses5.4-config is for macOS Catalina
    tools = ['ncursesw6-config', 'ncursesw5-config', 'ncurses6-config', 'ncurses5-config', 'ncurses5.4-config']

    def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None):
        super().__init__(name, env, kwargs, language)
        if not self.is_found:
            return
        self.compile_args = self.get_config_value(['--cflags'], 'compile_args')
        self.link_args = self.get_config_value(['--libs'], 'link_args')


class CursesSystemDependency(SystemDependency):

    """Curses dependency the hard way.

    This replaces hand rolled find_library() and has_header() calls. We
    provide this for portability reasons, there are a large number of curses
    implementations, and the differences between them can be very annoying.
    """

    def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__(name, env, kwargs)

        candidates = [
            ('pdcurses', ['pdcurses/curses.h']),
            ('ncursesw',  ['ncursesw/ncurses.h', 'ncurses.h']),
            ('ncurses',  ['ncurses/ncurses.h', 'ncurses/curses.h', 'ncurses.h']),
            ('curses',  ['curses.h']),
        ]

        # Not sure how else to elegantly break out of both loops
        for lib, headers in candidates:
            l = self.clib_compiler.find_library(lib, env, [])
            if l:
                for header in headers:
                    h = self.clib_compiler.has_header(header, '', env)
                    if h[0]:
                        self.is_found = True
                        self.link_args = l
                        # Not sure how to find version for non-ncurses curses
                        # implementations. The one in illumos/OpenIndiana
                        # doesn't seem to have a version defined in the header.
                        if lib.startswith('ncurses'):
                            v, _ = self.clib_compiler.get_define('NCURSES_VERSION', f'#include <{header}>', env, [], [self])
                            self.version = v.strip('"')
                        if lib.startswith('pdcurses'):
                            v_major, _ = self.clib_compiler.get_define('PDC_VER_MAJOR', f'#include <{header}>', env, [], [self])
                            v_minor, _ = self.clib_compiler.get_define('PDC_VER_MINOR', f'#include <{header}>', env, [], [self])
                            self.version = f'{v_major}.{v_minor}'

                        # Check the version if possible, emit a warning if we can't
                        req = kwargs.get('version')
                        if req:
                            if self.version:
                                self.is_found = mesonlib.version_compare(self.version, req)
                            else:
                                mlog.warning('Cannot determine version of curses to compare against.')

                        if self.is_found:
                            mlog.debug('Curses library:', l)
                            mlog.debug('Curses header:', header)
                            break
            if self.is_found:
                break


class IconvBuiltinDependency(BuiltinDependency):
    def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__(name, env, kwargs)
        self.feature_since = ('0.60.0', "consider checking for `iconv_open` with and without `find_library('iconv')`")
        code = '''#include \n\nint main() {\n    iconv_open("","");\n}''' # [ignore encoding] this is C, not python, Mr. Lint

        if self.clib_compiler.links(code, env)[0]:
            self.is_found = True


class IconvSystemDependency(SystemDependency):
    def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__(name, env, kwargs)
        self.feature_since = ('0.60.0', "consider checking for `iconv_open` with and without find_library('iconv')")

        h = self.clib_compiler.has_header('iconv.h', '', env)
        self.link_args = self.clib_compiler.find_library('iconv', env, [], self.libtype)

        if h[0] and self.link_args:
            self.is_found = True


class IntlBuiltinDependency(BuiltinDependency):
    def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__(name, env, kwargs)
        self.feature_since = ('0.59.0', "consider checking for `ngettext` with and without `find_library('intl')`")
        code = '''#include \n\nint main() {\n    gettext("Hello world");\n}'''

        if self.clib_compiler.links(code, env)[0]:
            self.is_found = True


class IntlSystemDependency(SystemDependency):
    def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__(name, env, kwargs)
        self.feature_since = ('0.59.0', "consider checking for `ngettext` with and without `find_library('intl')`")

        h = self.clib_compiler.has_header('libintl.h', '', env)
        self.link_args = self.clib_compiler.find_library('intl', env, [], self.libtype)

        if h[0] and self.link_args:
            self.is_found = True

            if self.static:
                if not self._add_sub_dependency(iconv_factory(env, self.for_machine, {'static': True})):
                    self.is_found = False
                    return


class OpensslSystemDependency(SystemDependency):
    def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__(name, env, kwargs)

        dependency_kwargs = {
            'method': 'system',
            'static': self.static,
        }
        if not self.clib_compiler.has_header('openssl/ssl.h', '', env)[0]:
            return

        # openssl >= 3 only
        self.version = self.clib_compiler.get_define('OPENSSL_VERSION_STR', '#include ', env, [], [self])[0]
        # openssl < 3 only
        if not self.version:
            version_hex = self.clib_compiler.get_define('OPENSSL_VERSION_NUMBER', '#include ', env, [], [self])[0]
            if not version_hex:
                return
            version_hex = version_hex.rstrip('L')
            version_ints = [((int(version_hex.rstrip('L'), 16) >> 4 + i) & 0xFF) for i in (24, 16, 8, 0)]
            # since this is openssl, the format is 1.2.3a in four parts
            self.version = '.'.join(str(i) for i in version_ints[:3]) + chr(ord('a') + version_ints[3] - 1)

        if name == 'openssl':
            if self._add_sub_dependency(libssl_factory(env, self.for_machine, dependency_kwargs)) and \
                    self._add_sub_dependency(libcrypto_factory(env, self.for_machine, dependency_kwargs)):
                self.is_found = True
            return
        else:
            self.link_args = self.clib_compiler.find_library(name.lstrip('lib'), env, [], self.libtype)
            if not self.link_args:
                return

        if not self.static:
            self.is_found = True
        else:
            if name == 'libssl':
                if self._add_sub_dependency(libcrypto_factory(env, self.for_machine, dependency_kwargs)):
                    self.is_found = True
            elif name == 'libcrypto':
                use_threads = self.clib_compiler.has_header_symbol('openssl/opensslconf.h', 'OPENSSL_THREADS', '', env, dependencies=[self])[0]
                if not use_threads or self._add_sub_dependency(threads_factory(env, self.for_machine, {})):
                    self.is_found = True
                # only relevant on platforms where it is distributed with the libc, in which case it always succeeds
                sublib = self.clib_compiler.find_library('dl', env, [], self.libtype)
                if sublib:
                    self.link_args.extend(sublib)


@factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.SYSTEM})
def curses_factory(env: 'Environment',
                   for_machine: 'mesonlib.MachineChoice',
                   kwargs: T.Dict[str, T.Any],
                   methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']:
    candidates: T.List['DependencyGenerator'] = []

    if DependencyMethods.PKGCONFIG in methods:
        pkgconfig_files = ['pdcurses', 'ncursesw', 'ncurses', 'curses']
        for pkg in pkgconfig_files:
            candidates.append(functools.partial(PkgConfigDependency, pkg, env, kwargs))

    # There are path handling problems with these methods on msys, and they
    # don't apply to windows otherwise (cygwin is handled separately from
    # windows)
    if not env.machines[for_machine].is_windows():
        if DependencyMethods.CONFIG_TOOL in methods:
            candidates.append(functools.partial(CursesConfigToolDependency, 'curses', env, kwargs))

        if DependencyMethods.SYSTEM in methods:
            candidates.append(functools.partial(CursesSystemDependency, 'curses', env, kwargs))

    return candidates
packages['curses'] = curses_factory


@factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM})
def shaderc_factory(env: 'Environment',
                    for_machine: 'mesonlib.MachineChoice',
                    kwargs: T.Dict[str, T.Any],
                    methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']:
    """Custom DependencyFactory for ShaderC.

    ShaderC's odd you get three different libraries from the same build
    thing are just easier to represent as a separate function than
    twisting DependencyFactory even more.
    """
    candidates: T.List['DependencyGenerator'] = []

    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', env.coredata.get_option(mesonlib.OptionKey('prefer_static'))):
            c = [functools.partial(PkgConfigDependency, name, env, kwargs)
                 for name in static_libs + shared_libs]
        else:
            c = [functools.partial(PkgConfigDependency, name, env, kwargs)
                 for name in shared_libs + static_libs]
        candidates.extend(c)

    if DependencyMethods.SYSTEM in methods:
        candidates.append(functools.partial(ShadercDependency, env, kwargs))

    return candidates
packages['shaderc'] = shaderc_factory


packages['cups'] = cups_factory = DependencyFactory(
    'cups',
    [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK, DependencyMethods.CMAKE],
    configtool_class=CupsDependencyConfigTool,
    cmake_name='Cups',
)

packages['dl'] = dl_factory = DependencyFactory(
    'dl',
    [DependencyMethods.BUILTIN, DependencyMethods.SYSTEM],
    builtin_class=DlBuiltinDependency,
    system_class=DlSystemDependency,
)

packages['gpgme'] = gpgme_factory = DependencyFactory(
    'gpgme',
    [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL],
    configtool_class=GpgmeDependencyConfigTool,
)

packages['libgcrypt'] = libgcrypt_factory = DependencyFactory(
    'libgcrypt',
    [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL],
    configtool_class=LibGCryptDependencyConfigTool,
)

packages['libwmf'] = libwmf_factory = DependencyFactory(
    'libwmf',
    [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL],
    configtool_class=LibWmfDependencyConfigTool,
)

packages['pcap'] = pcap_factory = DependencyFactory(
    'pcap',
    [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL],
    configtool_class=PcapDependencyConfigTool,
    pkgconfig_name='libpcap',
)

packages['threads'] = threads_factory = DependencyFactory(
    'threads',
    [DependencyMethods.SYSTEM, DependencyMethods.CMAKE],
    cmake_name='Threads',
    system_class=ThreadDependency,
)

packages['iconv'] = iconv_factory = DependencyFactory(
    'iconv',
    [DependencyMethods.BUILTIN, DependencyMethods.SYSTEM],
    builtin_class=IconvBuiltinDependency,
    system_class=IconvSystemDependency,
)

packages['intl'] = intl_factory = DependencyFactory(
    'intl',
    [DependencyMethods.BUILTIN, DependencyMethods.SYSTEM],
    builtin_class=IntlBuiltinDependency,
    system_class=IntlSystemDependency,
)

packages['openssl'] = openssl_factory = DependencyFactory(
    'openssl',
    [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM, DependencyMethods.CMAKE],
    system_class=OpensslSystemDependency,
    cmake_class=CMakeDependencyFactory('OpenSSL', modules=['OpenSSL::Crypto', 'OpenSSL::SSL']),
)

packages['libcrypto'] = libcrypto_factory = DependencyFactory(
    'libcrypto',
    [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM, DependencyMethods.CMAKE],
    system_class=OpensslSystemDependency,
    cmake_class=CMakeDependencyFactory('OpenSSL', modules=['OpenSSL::Crypto']),
)

packages['libssl'] = libssl_factory = DependencyFactory(
    'libssl',
    [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM, DependencyMethods.CMAKE],
    system_class=OpensslSystemDependency,
    cmake_class=CMakeDependencyFactory('OpenSSL', modules=['OpenSSL::SSL']),
)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/dependencies/mpi.py0000644000175000017500000002141114562742363020771 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import functools
import typing as T
import os
import re

from ..environment import detect_cpu_family
from .base import DependencyMethods, detect_compiler, SystemDependency
from .configtool import ConfigToolDependency
from .detect import packages
from .factory import factory_methods
from .pkgconfig import PkgConfigDependency

if T.TYPE_CHECKING:
    from .factory import DependencyGenerator
    from ..environment import Environment
    from ..mesonlib import MachineChoice


@factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.SYSTEM})
def mpi_factory(env: 'Environment',
                for_machine: 'MachineChoice',
                kwargs: T.Dict[str, T.Any],
                methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']:
    language = kwargs.get('language', 'c')
    if language not in {'c', 'cpp', 'fortran'}:
        # OpenMPI doesn't work without any other languages
        return []

    candidates: T.List['DependencyGenerator'] = []
    compiler = detect_compiler('mpi', env, for_machine, language)
    if not compiler:
        return []
    compiler_is_intel = compiler.get_id() in {'intel', 'intel-cl'}

    # Only OpenMPI has pkg-config, and it doesn't work with the intel compilers
    if DependencyMethods.PKGCONFIG in methods and not compiler_is_intel:
        pkg_name = None
        if language == 'c':
            pkg_name = 'ompi-c'
        elif language == 'cpp':
            pkg_name = 'ompi-cxx'
        elif language == 'fortran':
            pkg_name = 'ompi-fort'
        candidates.append(functools.partial(
            PkgConfigDependency, pkg_name, env, kwargs, language=language))

    if DependencyMethods.CONFIG_TOOL in methods:
        nwargs = kwargs.copy()

        if compiler_is_intel:
            if env.machines[for_machine].is_windows():
                nwargs['version_arg'] = '-v'
                nwargs['returncode_value'] = 3

            if language == 'c':
                tool_names = [os.environ.get('I_MPI_CC'), 'mpiicc']
            elif language == 'cpp':
                tool_names = [os.environ.get('I_MPI_CXX'), 'mpiicpc']
            elif language == 'fortran':
                tool_names = [os.environ.get('I_MPI_F90'), 'mpiifort']

            cls: T.Type[ConfigToolDependency] = IntelMPIConfigToolDependency
        else: # OpenMPI, which doesn't work with intel
            #
            # We try the environment variables for the tools first, but then
            # fall back to the hardcoded names
            if language == 'c':
                tool_names = [os.environ.get('MPICC'), 'mpicc']
            elif language == 'cpp':
                tool_names = [os.environ.get('MPICXX'), 'mpic++', 'mpicxx', 'mpiCC']
            elif language == 'fortran':
                tool_names = [os.environ.get(e) for e in ['MPIFC', 'MPIF90', 'MPIF77']]
                tool_names.extend(['mpifort', 'mpif90', 'mpif77'])

            cls = OpenMPIConfigToolDependency

        tool_names = [t for t in tool_names if t]  # remove empty environment variables
        assert tool_names

        nwargs['tools'] = tool_names
        candidates.append(functools.partial(
            cls, tool_names[0], env, nwargs, language=language))

    if DependencyMethods.SYSTEM in methods:
        candidates.append(functools.partial(
            MSMPIDependency, 'msmpi', env, kwargs, language=language))

    return candidates

packages['mpi'] = mpi_factory


class _MPIConfigToolDependency(ConfigToolDependency):

    def _filter_compile_args(self, args: T.List[str]) -> T.List[str]:
        """
        MPI wrappers return a bunch of garbage args.
        Drop -O2 and everything that is not needed.
        """
        result = []
        multi_args: T.Tuple[str, ...] = ('-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.List[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):
                result.append(f)
                if f in {'-L', '-Xlinker'}:
                    include_next = True
            elif include_next:
                include_next = False
                result.append(f)
        return result

    def _is_link_arg(self, f: str) -> bool:
        if self.clib_compiler.id == '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')))


class IntelMPIConfigToolDependency(_MPIConfigToolDependency):

    """Wrapper around Intel's mpiicc and friends."""

    version_arg = '-v'  # --version is not the same as -v

    def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any],
                 language: T.Optional[str] = None):
        super().__init__(name, env, kwargs, language=language)
        if not self.is_found:
            return

        args = self.get_config_value(['-show'], 'link and compile args')
        self.compile_args = self._filter_compile_args(args)
        self.link_args = self._filter_link_args(args)

    def _sanitize_version(self, out: str) -> str:
        v = re.search(r'(\d{4}) Update (\d)', out)
        if v:
            return '{}.{}'.format(v.group(1), v.group(2))
        return out


class OpenMPIConfigToolDependency(_MPIConfigToolDependency):

    """Wrapper around OpenMPI mpicc and friends."""

    version_arg = '--showme:version'

    def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any],
                 language: T.Optional[str] = None):
        super().__init__(name, env, kwargs, language=language)
        if not self.is_found:
            return

        c_args = self.get_config_value(['--showme:compile'], 'compile_args')
        self.compile_args = self._filter_compile_args(c_args)

        l_args = self.get_config_value(['--showme:link'], 'link_args')
        self.link_args = self._filter_link_args(l_args)

    def _sanitize_version(self, out: str) -> str:
        v = re.search(r'\d+.\d+.\d+', out)
        if v:
            return v.group(0)
        return out


class MSMPIDependency(SystemDependency):

    """The Microsoft MPI."""

    def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any],
                 language: T.Optional[str] = None):
        super().__init__(name, env, kwargs, language=language)
        # MSMPI only supports the C API
        if language not in {'c', 'fortran', None}:
            self.is_found = False
            return
        # MSMPI is only for windows, obviously
        if not self.env.machines[self.for_machine].is_windows():
            return

        incdir = os.environ.get('MSMPI_INC')
        arch = detect_cpu_family(self.env.coredata.compilers.host)
        libdir = None
        if arch == 'x86':
            libdir = os.environ.get('MSMPI_LIB32')
            post = 'x86'
        elif arch == 'x86_64':
            libdir = os.environ.get('MSMPI_LIB64')
            post = 'x64'

        if libdir is None or incdir is None:
            self.is_found = False
            return

        self.is_found = True
        self.link_args = ['-l' + os.path.join(libdir, 'msmpi')]
        self.compile_args = ['-I' + incdir, '-I' + os.path.join(incdir, post)]
        if self.language == 'fortran':
            self.link_args.append('-l' + os.path.join(libdir, 'msmpifec'))
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/dependencies/pkgconfig.py0000644000175000017500000006475214562742363022172 0ustar00jpakkanejpakkane# Copyright 2013-2021 The Meson development team

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

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

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

from pathlib import Path

from .base import ExternalDependency, DependencyException, sort_libpaths, DependencyTypeName
from ..mesonlib import EnvironmentVariables, OptionKey, OrderedSet, PerMachine, Popen_safe, Popen_safe_logged, MachineChoice, join_args
from ..programs import find_external_program, ExternalProgram
from .. import mlog
from pathlib import PurePath
from functools import lru_cache
import re
import os
import shlex
import typing as T

if T.TYPE_CHECKING:
    from typing_extensions import Literal
    from .._typing import ImmutableListProtocol

    from ..environment import Environment
    from ..utils.core import EnvironOrDict
    from ..interpreter.type_checking import PkgConfigDefineType

class PkgConfigInterface:
    '''Base class wrapping a pkg-config implementation'''

    class_impl: PerMachine[T.Union[Literal[False], T.Optional[PkgConfigInterface]]] = PerMachine(False, False)
    class_cli_impl: PerMachine[T.Union[Literal[False], T.Optional[PkgConfigCLI]]] = PerMachine(False, False)

    @staticmethod
    def instance(env: Environment, for_machine: MachineChoice, silent: bool) -> T.Optional[PkgConfigInterface]:
        '''Return a pkg-config implementation singleton'''
        for_machine = for_machine if env.is_cross_build() else MachineChoice.HOST
        impl = PkgConfigInterface.class_impl[for_machine]
        if impl is False:
            impl = PkgConfigCLI(env, for_machine, silent)
            if not impl.found():
                impl = None
            if not impl and not silent:
                mlog.log('Found pkg-config:', mlog.red('NO'))
            PkgConfigInterface.class_impl[for_machine] = impl
        return impl

    @staticmethod
    def _cli(env: Environment, for_machine: MachineChoice, silent: bool = False) -> T.Optional[PkgConfigCLI]:
        '''Return the CLI pkg-config implementation singleton
        Even when we use another implementation internally, external tools might
        still need the CLI implementation.
        '''
        for_machine = for_machine if env.is_cross_build() else MachineChoice.HOST
        impl: T.Union[Literal[False], T.Optional[PkgConfigInterface]] # Help confused mypy
        impl = PkgConfigInterface.instance(env, for_machine, silent)
        if impl and not isinstance(impl, PkgConfigCLI):
            impl = PkgConfigInterface.class_cli_impl[for_machine]
            if impl is False:
                impl = PkgConfigCLI(env, for_machine, silent)
                if not impl.found():
                    impl = None
                PkgConfigInterface.class_cli_impl[for_machine] = impl
        return T.cast('T.Optional[PkgConfigCLI]', impl) # Trust me, mypy

    @staticmethod
    def get_env(env: Environment, for_machine: MachineChoice, uninstalled: bool = False) -> EnvironmentVariables:
        cli = PkgConfigInterface._cli(env, for_machine)
        return cli._get_env(uninstalled) if cli else EnvironmentVariables()

    @staticmethod
    def setup_env(environ: EnvironOrDict, env: Environment, for_machine: MachineChoice,
                  uninstalled: bool = False) -> EnvironOrDict:
        cli = PkgConfigInterface._cli(env, for_machine)
        return cli._setup_env(environ, uninstalled) if cli else environ

    def __init__(self, env: Environment, for_machine: MachineChoice) -> None:
        self.env = env
        self.for_machine = for_machine

    def found(self) -> bool:
        '''Return whether pkg-config is supported'''
        raise NotImplementedError

    def version(self, name: str) -> T.Optional[str]:
        '''Return module version or None if not found'''
        raise NotImplementedError

    def cflags(self, name: str, allow_system: bool = False,
               define_variable: PkgConfigDefineType = None) -> ImmutableListProtocol[str]:
        '''Return module cflags
           @allow_system: If False, remove default system include paths
        '''
        raise NotImplementedError

    def libs(self, name: str, static: bool = False, allow_system: bool = False,
             define_variable: PkgConfigDefineType = None) -> ImmutableListProtocol[str]:
        '''Return module libs
           @static: If True, also include private libraries
           @allow_system: If False, remove default system libraries search paths
        '''
        raise NotImplementedError

    def variable(self, name: str, variable_name: str,
                 define_variable: PkgConfigDefineType) -> T.Optional[str]:
        '''Return module variable or None if variable is not defined'''
        raise NotImplementedError

    def list_all(self) -> ImmutableListProtocol[str]:
        '''Return all available pkg-config modules'''
        raise NotImplementedError

class PkgConfigCLI(PkgConfigInterface):
    '''pkg-config CLI implementation'''

    def __init__(self, env: Environment, for_machine: MachineChoice, silent: bool) -> None:
        super().__init__(env, for_machine)
        self._detect_pkgbin()
        if self.pkgbin and not silent:
            mlog.log('Found pkg-config:', mlog.green('YES'), mlog.bold(f'({self.pkgbin.get_path()})'), mlog.blue(self.pkgbin_version))

    def found(self) -> bool:
        return bool(self.pkgbin)

    @lru_cache(maxsize=None)
    def version(self, name: str) -> T.Optional[str]:
        mlog.debug(f'Determining dependency {name!r} with pkg-config executable {self.pkgbin.get_path()!r}')
        ret, version, _ = self._call_pkgbin(['--modversion', name])
        return version if ret == 0 else None

    @staticmethod
    def _define_variable_args(define_variable: PkgConfigDefineType) -> T.List[str]:
        ret = []
        if define_variable:
            for pair in define_variable:
                ret.append('--define-variable=' + '='.join(pair))
        return ret

    @lru_cache(maxsize=None)
    def cflags(self, name: str, allow_system: bool = False,
               define_variable: PkgConfigDefineType = None) -> ImmutableListProtocol[str]:
        env = None
        if allow_system:
            env = os.environ.copy()
            env['PKG_CONFIG_ALLOW_SYSTEM_CFLAGS'] = '1'
        args: T.List[str] = []
        args += self._define_variable_args(define_variable)
        args += ['--cflags', name]
        ret, out, err = self._call_pkgbin(args, env=env)
        if ret != 0:
            raise DependencyException(f'Could not generate cflags for {name}:\n{err}\n')
        return self._split_args(out)

    @lru_cache(maxsize=None)
    def libs(self, name: str, static: bool = False, allow_system: bool = False,
             define_variable: PkgConfigDefineType = None) -> ImmutableListProtocol[str]:
        env = None
        if allow_system:
            env = os.environ.copy()
            env['PKG_CONFIG_ALLOW_SYSTEM_LIBS'] = '1'
        args: T.List[str] = []
        args += self._define_variable_args(define_variable)
        if static:
            args.append('--static')
        args += ['--libs', name]
        ret, out, err = self._call_pkgbin(args, env=env)
        if ret != 0:
            raise DependencyException(f'Could not generate libs for {name}:\n{err}\n')
        return self._split_args(out)

    @lru_cache(maxsize=None)
    def variable(self, name: str, variable_name: str,
                 define_variable: PkgConfigDefineType) -> T.Optional[str]:
        args: T.List[str] = []
        args += self._define_variable_args(define_variable)
        args += ['--variable=' + variable_name, name]
        ret, out, err = self._call_pkgbin(args)
        if ret != 0:
            raise DependencyException(f'Could not get variable for {name}:\n{err}\n')
        variable = out.strip()
        # pkg-config doesn't distinguish between empty and nonexistent variables
        # use the variable list to check for variable existence
        if not variable:
            ret, out, _ = self._call_pkgbin(['--print-variables', name])
            if not re.search(rf'^{variable_name}$', out, re.MULTILINE):
                return None
        mlog.debug(f'Got pkg-config variable {variable_name} : {variable}')
        return variable

    @lru_cache(maxsize=None)
    def list_all(self) -> ImmutableListProtocol[str]:
        ret, out, err = self._call_pkgbin(['--list-all'])
        if ret != 0:
            raise DependencyException(f'could not list modules:\n{err}\n')
        return [i.split(' ', 1)[0] for i in out.splitlines()]

    @staticmethod
    def _split_args(cmd: str) -> T.List[str]:
        # 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 _detect_pkgbin(self) -> None:
        for potential_pkgbin in find_external_program(
                self.env, self.for_machine, 'pkg-config', 'Pkg-config',
                self.env.default_pkgconfig, allow_default_for_cross=False):
            version_if_ok = self._check_pkgconfig(potential_pkgbin)
            if version_if_ok:
                self.pkgbin = potential_pkgbin
                self.pkgbin_version = version_if_ok
                return
        self.pkgbin = None

    def _check_pkgconfig(self, pkgbin: ExternalProgram) -> T.Optional[str]:
        if not pkgbin.found():
            mlog.log(f'Did not find pkg-config by name {pkgbin.name!r}')
            return None
        command_as_string = ' '.join(pkgbin.get_command())
        try:
            helptext = Popen_safe(pkgbin.get_command() + ['--help'])[1]
            if 'Pure-Perl' in helptext:
                mlog.log(f'Found pkg-config {command_as_string!r} but it is Strawberry Perl and thus broken. Ignoring...')
                return None
            p, out = Popen_safe(pkgbin.get_command() + ['--version'])[0:2]
            if p.returncode != 0:
                mlog.warning(f'Found pkg-config {command_as_string!r} but it failed when ran')
                return None
        except FileNotFoundError:
            mlog.warning(f'We thought we found pkg-config {command_as_string!r} but now it\'s not there. How odd!')
            return None
        except PermissionError:
            msg = f'Found pkg-config {command_as_string!r} but didn\'t have permissions to run it.'
            if not self.env.machines.build.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 _get_env(self, uninstalled: bool = False) -> EnvironmentVariables:
        env = EnvironmentVariables()
        key = OptionKey('pkg_config_path', machine=self.for_machine)
        extra_paths: T.List[str] = self.env.coredata.options[key].value[:]
        if uninstalled:
            uninstalled_path = Path(self.env.get_build_dir(), 'meson-uninstalled').as_posix()
            if uninstalled_path not in extra_paths:
                extra_paths.append(uninstalled_path)
        env.set('PKG_CONFIG_PATH', extra_paths)
        sysroot = self.env.properties[self.for_machine].get_sys_root()
        if sysroot:
            env.set('PKG_CONFIG_SYSROOT_DIR', [sysroot])
        pkg_config_libdir_prop = self.env.properties[self.for_machine].get_pkg_config_libdir()
        if pkg_config_libdir_prop:
            env.set('PKG_CONFIG_LIBDIR', pkg_config_libdir_prop)
        env.set('PKG_CONFIG', [join_args(self.pkgbin.get_command())])
        return env

    def _setup_env(self, env: EnvironOrDict, uninstalled: bool = False) -> T.Dict[str, str]:
        envvars = self._get_env(uninstalled)
        env = envvars.get_env(env)
        # Dump all PKG_CONFIG environment variables
        for key, value in env.items():
            if key.startswith('PKG_'):
                mlog.debug(f'env[{key}]: {value}')
        return env

    def _call_pkgbin(self, args: T.List[str], env: T.Optional[EnvironOrDict] = None) -> T.Tuple[int, str, str]:
        assert isinstance(self.pkgbin, ExternalProgram)
        env = env or os.environ
        env = self._setup_env(env)
        cmd = self.pkgbin.get_command() + args
        p, out, err = Popen_safe_logged(cmd, env=env)
        return p.returncode, out.strip(), err.strip()


class PkgConfigDependency(ExternalDependency):

    def __init__(self, name: str, environment: Environment, kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None) -> None:
        super().__init__(DependencyTypeName('pkgconfig'), environment, kwargs, language=language)
        self.name = name
        self.is_libtool = False
        self.pkgconfig = PkgConfigInterface.instance(self.env, self.for_machine, self.silent)
        if not self.pkgconfig:
            msg = f'Pkg-config for machine {self.for_machine} not found. Giving up.'
            if self.required:
                raise DependencyException(msg)
            mlog.debug(msg)
            return

        version = self.pkgconfig.version(name)
        if version is None:
            return

        self.version = version
        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(f"Pkg-config error with '{name}': {e}")
            if self.required:
                raise
            else:
                self.compile_args = []
                self.link_args = []
                self.is_found = False
                self.reason = e

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

    def _convert_mingw_paths(self, args: ImmutableListProtocol[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 self.env.machines.build.is_windows():
            return args.copy()
        converted = []
        for arg in args:
            pargs: T.Tuple[str, ...] = tuple()
            # 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 _set_cargs(self) -> None:
        allow_system = False
        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
            allow_system = True
        cflags = self.pkgconfig.cflags(self.name, allow_system)
        self.compile_args = self._convert_mingw_paths(cflags)

    def _search_libs(self, libs_in: ImmutableListProtocol[str], raw_libs_in: ImmutableListProtocol[str]) -> T.Tuple[T.List[str], T.List[str]]:
        '''
        @libs_in: PKG_CONFIG_ALLOW_SYSTEM_LIBS=1 pkg-config --libs
        @raw_libs_in: 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[str] = OrderedSet()
        # We also store this raw_link_args on the object later
        raw_link_args = self._convert_mingw_paths(raw_libs_in)
        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: T.List[str] = self.env.coredata.options[OptionKey('pkg_config_path', machine=self.for_machine)].value
        pkg_config_path = self._convert_mingw_paths(pkg_config_path)
        prefix_libpaths = OrderedSet(sort_libpaths(list(prefix_libpaths), pkg_config_path))
        system_libpaths: OrderedSet[str] = OrderedSet()
        full_args = self._convert_mingw_paths(libs_in)
        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[str] = OrderedSet()
        # Track not-found libraries to know whether to add library paths
        libs_notfound = []
        # 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:'):
                # see: https://stackoverflow.com/questions/48532868/gcc-library-option-with-a-colon-llibevent-a
                # also : See the documentation of -lnamespec | --library=namespec in the linker manual
                #                     https://sourceware.org/binutils/docs-2.18/ld/Options.html

                # Don't resolve the same -l:libfoo.a argument again
                if lib in libs_found:
                    continue
                libfilename = lib[3:]
                foundname = None
                for libdir in libpaths:
                    target = os.path.join(libdir, libfilename)
                    if os.path.exists(target):
                        foundname = target
                        break
                if foundname is None:
                    if lib in libs_notfound:
                        continue
                    else:
                        mlog.warning('Library {!r} not found for dependency {!r}, may '
                                     'not be successfully linked'.format(libfilename, self.name))
                    libs_notfound.append(lib)
                else:
                    lib = foundname
            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, self.libtype,
                                                           lib_prefix_warning=False)
                # 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(f'Got a libtools specific "{lib}" dependencies'
                                              'but we could not compute the actual shared'
                                              'library path')
                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) -> None:
        # Force pkg-config to output -L fields even if they are system
        # paths so we can do manual searching with cc.find_library() later.
        libs = self.pkgconfig.libs(self.name, self.static, allow_system=True)
        # 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.
        raw_libs = self.pkgconfig.libs(self.name, self.static, allow_system=False)
        self.link_args, self.raw_link_args = self._search_libs(libs, raw_libs)

    def extract_field(self, la_file: str, fieldname: str) -> T.Optional[str]:
        with open(la_file, encoding='utf-8') 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: str) -> T.Optional[str]:
        return self.extract_field(la_file, 'dlname')

    def extract_libdir_field(self, la_file: str) -> T.Optional[str]:
        return self.extract_field(la_file, 'libdir')

    def extract_libtool_shlib(self, la_file: str) -> T.Optional[str]:
        '''
        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 self.env.machines[self.for_machine].is_darwin():
            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)

    @staticmethod
    def log_tried() -> str:
        return 'pkgconfig'

    def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None,
                     configtool: T.Optional[str] = None, internal: T.Optional[str] = None,
                     default_value: T.Optional[str] = None,
                     pkgconfig_define: PkgConfigDefineType = None) -> str:
        if pkgconfig:
            try:
                variable = self.pkgconfig.variable(self.name, pkgconfig, pkgconfig_define)
                if variable is not None:
                    return variable
            except DependencyException:
                pass
        if default_value is not None:
            return default_value
        raise DependencyException(f'Could not get pkg-config variable and no default provided for {self!r}')
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/dependencies/platform.py0000644000175000017500000000451114562742363022032 0ustar00jpakkanejpakkane# 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 __future__ import annotations

from .base import DependencyTypeName, ExternalDependency, DependencyException
from .detect import packages
from ..mesonlib import MesonException
import typing as T

if T.TYPE_CHECKING:
    from ..environment import Environment

class AppleFrameworks(ExternalDependency):
    def __init__(self, env: 'Environment', kwargs: T.Dict[str, T.Any]) -> None:
        super().__init__(DependencyTypeName('appleframeworks'), env, 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) -> str:
        return ', '.join(self.frameworks)

    @staticmethod
    def log_tried() -> str:
        return 'framework'

packages['appleframeworks'] = AppleFrameworks
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/dependencies/python.py0000644000175000017500000004461214562742363021535 0ustar00jpakkanejpakkane# Copyright 2022 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 __future__ import annotations

import functools, json, os, textwrap
from pathlib import Path
import typing as T

from .. import mesonlib, mlog
from .base import process_method_kw, DependencyMethods, DependencyTypeName, ExternalDependency, SystemDependency
from .configtool import ConfigToolDependency
from .detect import packages
from .factory import DependencyFactory
from .framework import ExtraFrameworkDependency
from .pkgconfig import PkgConfigDependency
from ..environment import detect_cpu_family
from ..programs import ExternalProgram

if T.TYPE_CHECKING:
    from typing_extensions import TypedDict

    from .factory import DependencyGenerator
    from ..environment import Environment
    from ..mesonlib import MachineChoice

    class PythonIntrospectionDict(TypedDict):

        install_paths: T.Dict[str, str]
        is_pypy: bool
        is_venv: bool
        link_libpython: bool
        sysconfig_paths: T.Dict[str, str]
        paths: T.Dict[str, str]
        platform: str
        suffix: str
        limited_api_suffix: str
        variables: T.Dict[str, str]
        version: str

    _Base = ExternalDependency
else:
    _Base = object


class Pybind11ConfigToolDependency(ConfigToolDependency):

    tools = ['pybind11-config']

    # any version of the tool is valid, since this is header-only
    allow_default_for_cross = True

    # pybind11 in 2.10.4 added --version, sanity-check another flag unique to it
    # in the meantime
    skip_version = '--pkgconfigdir'

    def __init__(self, name: str, environment: Environment, kwargs: T.Dict[str, T.Any]):
        super().__init__(name, environment, kwargs)
        if not self.is_found:
            return
        self.compile_args = self.get_config_value(['--includes'], 'compile_args')


class BasicPythonExternalProgram(ExternalProgram):
    def __init__(self, name: str, command: T.Optional[T.List[str]] = None,
                 ext_prog: T.Optional[ExternalProgram] = None):
        if ext_prog is None:
            super().__init__(name, command=command, silent=True)
        else:
            self.name = name
            self.command = ext_prog.command
            self.path = ext_prog.path
            self.cached_version = None

        # We want strong key values, so we always populate this with bogus data.
        # Otherwise to make the type checkers happy we'd have to do .get() for
        # everycall, even though we know that the introspection data will be
        # complete
        self.info: 'PythonIntrospectionDict' = {
            'install_paths': {},
            'is_pypy': False,
            'is_venv': False,
            'link_libpython': False,
            'sysconfig_paths': {},
            'paths': {},
            'platform': 'sentinel',
            'suffix': 'sentinel',
            'limited_api_suffix': 'sentinel',
            'variables': {},
            'version': '0.0',
        }
        self.pure: bool = True

    def _check_version(self, version: str) -> bool:
        if self.name == 'python2':
            return mesonlib.version_compare(version, '< 3.0')
        elif self.name == 'python3':
            return mesonlib.version_compare(version, '>= 3.0')
        return True

    def sanity(self) -> bool:
        # Sanity check, we expect to have something that at least quacks in tune

        import importlib.resources

        with importlib.resources.path('mesonbuild.scripts', 'python_info.py') as f:
            cmd = self.get_command() + [str(f)]
            env = os.environ.copy()
            env['SETUPTOOLS_USE_DISTUTILS'] = 'stdlib'
            p, stdout, stderr = mesonlib.Popen_safe(cmd, env=env)

        try:
            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 info is not None and self._check_version(info['version']):
            self.info = T.cast('PythonIntrospectionDict', info)
            return True
        else:
            return False


class _PythonDependencyBase(_Base):

    def __init__(self, python_holder: 'BasicPythonExternalProgram', embed: bool):
        self.embed = embed
        self.version: str = python_holder.info['version']
        self.platform = python_holder.info['platform']
        self.variables = python_holder.info['variables']
        self.paths = python_holder.info['paths']
        self.is_pypy = python_holder.info['is_pypy']
        # The "-embed" version of python.pc / python-config was introduced in 3.8,
        # and distutils extension linking was changed to be considered a non embed
        # usage. Before then, this dependency always uses the embed=True handling
        # because that is the only one that exists.
        #
        # On macOS and some Linux distros (Debian) distutils doesn't link extensions
        # against libpython, even on 3.7 and below. We call into distutils and
        # mirror its behavior. See https://github.com/mesonbuild/meson/issues/4117
        self.link_libpython = python_holder.info['link_libpython'] or embed
        self.info: T.Optional[T.Dict[str, str]] = None
        if mesonlib.version_compare(self.version, '>= 3.0'):
            self.major_version = 3
        else:
            self.major_version = 2


class PythonPkgConfigDependency(PkgConfigDependency, _PythonDependencyBase):

    def __init__(self, name: str, environment: 'Environment',
                 kwargs: T.Dict[str, T.Any], installation: 'BasicPythonExternalProgram',
                 libpc: bool = False):
        if libpc:
            mlog.debug(f'Searching for {name!r} via pkgconfig lookup in LIBPC')
        else:
            mlog.debug(f'Searching for {name!r} via fallback pkgconfig lookup in default paths')

        PkgConfigDependency.__init__(self, name, environment, kwargs)
        _PythonDependencyBase.__init__(self, installation, kwargs.get('embed', False))

        if libpc and not self.is_found:
            mlog.debug(f'"python-{self.version}" could not be found in LIBPC, this is likely due to a relocated python installation')

        # pkg-config files are usually accurate starting with python 3.8
        if not self.link_libpython and mesonlib.version_compare(self.version, '< 3.8'):
            self.link_args = []


class PythonFrameworkDependency(ExtraFrameworkDependency, _PythonDependencyBase):

    def __init__(self, name: str, environment: 'Environment',
                 kwargs: T.Dict[str, T.Any], installation: 'BasicPythonExternalProgram'):
        ExtraFrameworkDependency.__init__(self, name, environment, kwargs)
        _PythonDependencyBase.__init__(self, installation, kwargs.get('embed', False))


class PythonSystemDependency(SystemDependency, _PythonDependencyBase):

    def __init__(self, name: str, environment: 'Environment',
                 kwargs: T.Dict[str, T.Any], installation: 'BasicPythonExternalProgram'):
        SystemDependency.__init__(self, name, environment, kwargs)
        _PythonDependencyBase.__init__(self, installation, kwargs.get('embed', False))

        # match pkg-config behavior
        if self.link_libpython:
            # link args
            if mesonlib.is_windows():
                self.find_libpy_windows(environment, limited_api=False)
            else:
                self.find_libpy(environment)
        else:
            self.is_found = True

        # 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/
        # https://github.com/python/cpython/pull/100137
        if mesonlib.is_windows() and self.get_windows_python_arch().endswith('64') and mesonlib.version_compare(self.version, '<3.12'):
            self.compile_args += ['-DMS_WIN64=']

        if not self.clib_compiler.has_header('Python.h', '', environment, extra_args=self.compile_args):
            self.is_found = False

    def find_libpy(self, environment: 'Environment') -> None:
        if self.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 = f'python{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 = True

    def get_windows_python_arch(self) -> T.Optional[str]:
        if self.platform.startswith('mingw'):
            if 'x86_64' in self.platform:
                return 'x86_64'
            elif 'i686' in self.platform:
                return 'x86'
            elif 'aarch64' in self.platform:
                return 'aarch64'
            else:
                mlog.log(f'MinGW Python built with unknown platform {self.platform!r}, please file a bug')
                return None
        elif self.platform == 'win32':
            return 'x86'
        elif self.platform in {'win64', 'win-amd64'}:
            return 'x86_64'
        elif self.platform in {'win-arm64'}:
            return 'aarch64'
        mlog.log(f'Unknown Windows Python platform {self.platform!r}')
        return None

    def get_windows_link_args(self, limited_api: bool) -> T.Optional[T.List[str]]:
        if self.platform.startswith('win'):
            vernum = self.variables.get('py_version_nodot')
            verdot = self.variables.get('py_version_short')
            imp_lower = self.variables.get('implementation_lower', 'python')
            if self.static:
                libpath = Path('libs') / f'libpython{vernum}.a'
            else:
                comp = self.get_compiler()
                if comp.id == "gcc":
                    if imp_lower == 'pypy' and verdot == '3.8':
                        # The naming changed between 3.8 and 3.9
                        libpath = Path('libpypy3-c.dll')
                    elif imp_lower == 'pypy':
                        libpath = Path(f'libpypy{verdot}-c.dll')
                    else:
                        libpath = Path(f'python{vernum}.dll')
                else:
                    if limited_api:
                        vernum = vernum[0]
                    libpath = Path('libs') / f'python{vernum}.lib'
                    # For a debug build, pyconfig.h may force linking with
                    # pythonX_d.lib (see meson#10776). This cannot be avoided
                    # and won't work unless we also have a debug build of
                    # Python itself (except with pybind11, which has an ugly
                    # hack to work around this) - so emit a warning to explain
                    # the cause of the expected link error.
                    buildtype = self.env.coredata.get_option(mesonlib.OptionKey('buildtype'))
                    assert isinstance(buildtype, str)
                    debug = self.env.coredata.get_option(mesonlib.OptionKey('debug'))
                    # `debugoptimized` buildtype may not set debug=True currently, see gh-11645
                    is_debug_build = debug or buildtype == 'debug'
                    vscrt_debug = False
                    if mesonlib.OptionKey('b_vscrt') in self.env.coredata.options:
                        vscrt = self.env.coredata.options[mesonlib.OptionKey('b_vscrt')].value
                        if vscrt in {'mdd', 'mtd', 'from_buildtype', 'static_from_buildtype'}:
                            vscrt_debug = True
                    if is_debug_build and vscrt_debug and not self.variables.get('Py_DEBUG'):
                        mlog.warning(textwrap.dedent('''\
                            Using a debug build type with MSVC or an MSVC-compatible compiler
                            when the Python interpreter is not also a debug build will almost
                            certainly result in a failed build. Prefer using a release build
                            type or a debug Python interpreter.
                            '''))
            # base_prefix to allow for virtualenvs.
            lib = Path(self.variables.get('base_prefix')) / libpath
        elif self.platform.startswith('mingw'):
            if self.static:
                libname = self.variables.get('LIBRARY')
            else:
                libname = self.variables.get('LDLIBRARY')
            lib = Path(self.variables.get('LIBDIR')) / libname
        else:
            raise mesonlib.MesonBugException(
                'On a Windows path, but the OS doesn\'t appear to be Windows or MinGW.')
        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: 'Environment', limited_api: bool = False) -> None:
        '''
        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 != pyarch:
            mlog.log('Need', mlog.bold(self.name), f'for {arch}, but found {pyarch}')
            self.is_found = False
            return
        # This can fail if the library is not found
        largs = self.get_windows_link_args(limited_api)
        if largs is None:
            self.is_found = False
            return
        self.link_args = largs
        self.is_found = True

    @staticmethod
    def log_tried() -> str:
        return 'sysconfig'

def python_factory(env: 'Environment', for_machine: 'MachineChoice',
                   kwargs: T.Dict[str, T.Any],
                   installation: T.Optional['BasicPythonExternalProgram'] = None) -> T.List['DependencyGenerator']:
    # We can't use the factory_methods decorator here, as we need to pass the
    # extra installation argument
    methods = process_method_kw({DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM}, kwargs)
    embed = kwargs.get('embed', False)
    candidates: T.List['DependencyGenerator'] = []
    from_installation = installation is not None
    # When not invoked through the python module, default installation.
    if installation is None:
        installation = BasicPythonExternalProgram('python3', mesonlib.python_command)
        installation.sanity()
    pkg_version = installation.info['variables'].get('LDVERSION') or installation.info['version']

    if DependencyMethods.PKGCONFIG in methods:
        if from_installation:
            pkg_libdir = installation.info['variables'].get('LIBPC')
            pkg_embed = '-embed' if embed and mesonlib.version_compare(installation.info['version'], '>=3.8') else ''
            pkg_name = f'python-{pkg_version}{pkg_embed}'

            # If python-X.Y.pc exists in LIBPC, we will try to use it
            def wrap_in_pythons_pc_dir(name: str, env: 'Environment', kwargs: T.Dict[str, T.Any],
                                       installation: 'BasicPythonExternalProgram') -> 'ExternalDependency':
                if not pkg_libdir:
                    # there is no LIBPC, so we can't search in it
                    empty = ExternalDependency(DependencyTypeName('pkgconfig'), env, {})
                    empty.name = 'python'
                    return empty

                old_pkg_libdir = os.environ.pop('PKG_CONFIG_LIBDIR', None)
                old_pkg_path = os.environ.pop('PKG_CONFIG_PATH', None)
                os.environ['PKG_CONFIG_LIBDIR'] = pkg_libdir
                try:
                    return PythonPkgConfigDependency(name, env, kwargs, installation, True)
                finally:
                    def set_env(name: str, value: str) -> None:
                        if value is not None:
                            os.environ[name] = value
                        elif name in os.environ:
                            del os.environ[name]
                    set_env('PKG_CONFIG_LIBDIR', old_pkg_libdir)
                    set_env('PKG_CONFIG_PATH', old_pkg_path)

            candidates.append(functools.partial(wrap_in_pythons_pc_dir, pkg_name, env, kwargs, installation))
            # We only need to check both, if a python install has a LIBPC. It might point to the wrong location,
            # e.g. relocated / cross compilation, but the presence of LIBPC indicates we should definitely look for something.
            if pkg_libdir is not None:
                candidates.append(functools.partial(PythonPkgConfigDependency, pkg_name, env, kwargs, installation))
        else:
            candidates.append(functools.partial(PkgConfigDependency, 'python3', env, kwargs))

    if DependencyMethods.SYSTEM in methods:
        candidates.append(functools.partial(PythonSystemDependency, 'python', env, kwargs, installation))

    if DependencyMethods.EXTRAFRAMEWORK in methods:
        nkwargs = kwargs.copy()
        if mesonlib.version_compare(pkg_version, '>= 3'):
            # There is a python in /System/Library/Frameworks, but that's python 2.x,
            # Python 3 will always be in /Library
            nkwargs['paths'] = ['/Library/Frameworks']
        candidates.append(functools.partial(PythonFrameworkDependency, 'Python', env, nkwargs, installation))

    return candidates

packages['python3'] = python_factory

packages['pybind11'] = pybind11_factory = DependencyFactory(
    'pybind11',
    [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.CMAKE],
    configtool_class=Pybind11ConfigToolDependency,
)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/dependencies/qt.py0000644000175000017500000004713314562742363020641 0ustar00jpakkanejpakkane# Copyright 2013-2017 The Meson development team
# Copyright Ā© 2021 Intel Corporation
# SPDX-license-identifier: Apache-2.0

# 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 __future__ import annotations

"""Dependency finders for the Qt framework."""

import abc
import re
import os
import typing as T

from .base import DependencyException, DependencyMethods
from .configtool import ConfigToolDependency
from .detect import packages
from .framework import ExtraFrameworkDependency
from .pkgconfig import PkgConfigDependency
from .factory import DependencyFactory
from .. import mlog
from .. import mesonlib

if T.TYPE_CHECKING:
    from ..compilers import Compiler
    from ..envconfig import MachineInfo
    from ..environment import Environment
    from ..dependencies import MissingCompiler


def _qt_get_private_includes(mod_inc_dir: str, module: str, mod_version: str) -> T.List[str]:
    # 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 []

    private_dir = os.path.join(mod_inc_dir, mod_version)
    # fallback, let's try to find a directory with the latest version
    if os.path.isdir(mod_inc_dir) and 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))]

        for dirname in sorted(dirs, reverse=True):
            if len(dirname.split('.')) == 3:
                private_dir = dirname
                break
    return [private_dir, os.path.join(private_dir, 'Qt' + module)]


def get_qmake_host_bins(qvars: T.Dict[str, str]) -> str:
    # 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']
    return qvars['QT_INSTALL_BINS']


def get_qmake_host_libexecs(qvars: T.Dict[str, str]) -> T.Optional[str]:
    if 'QT_HOST_LIBEXECS' in qvars:
        return qvars['QT_HOST_LIBEXECS']
    return qvars.get('QT_INSTALL_LIBEXECS')


def _get_modules_lib_suffix(version: str, info: 'MachineInfo', is_debug: bool) -> str:
    """Get the module suffix based on platform and debug type."""
    suffix = ''
    if info.is_windows():
        if is_debug:
            suffix += 'd'
        if version.startswith('4'):
            suffix += '4'
    if info.is_darwin():
        if is_debug:
            suffix += '_debug'
    if mesonlib.version_compare(version, '>= 5.14.0'):
        if info.is_android():
            if info.cpu_family == 'x86':
                suffix += '_x86'
            elif info.cpu_family == 'x86_64':
                suffix += '_x86_64'
            elif info.cpu_family == 'arm':
                suffix += '_armeabi-v7a'
            elif info.cpu_family == 'aarch64':
                suffix += '_arm64-v8a'
            else:
                mlog.warning(f'Android target arch "{info.cpu_family}"" for Qt5 is unknown, '
                             'module detection may not work')
    return suffix


class QtExtraFrameworkDependency(ExtraFrameworkDependency):
    def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any], qvars: T.Dict[str, str], language: T.Optional[str] = None):
        super().__init__(name, env, kwargs, language=language)
        self.mod_name = name[2:]
        self.qt_extra_include_directory = qvars['QT_INSTALL_HEADERS']

    def get_compile_args(self, with_private_headers: bool = False, qt_version: str = "0") -> T.List[str]:
        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)]
            if self.qt_extra_include_directory:
                args += ['-I' + self.qt_extra_include_directory]
            return args
        return []


class _QtBase:

    """Mixin class for shared components between PkgConfig and Qmake."""

    link_args: T.List[str]
    clib_compiler: T.Union['MissingCompiler', 'Compiler']
    env: 'Environment'
    libexecdir: T.Optional[str] = None

    def __init__(self, name: str, kwargs: T.Dict[str, T.Any]):
        self.name = name
        self.qtname = name.capitalize()
        self.qtver = name[-1]
        if self.qtver == "4":
            self.qtpkgname = 'Qt'
        else:
            self.qtpkgname = self.qtname

        self.private_headers = T.cast('bool', kwargs.get('private_headers', False))

        self.requested_modules = mesonlib.stringlistify(mesonlib.extract_as_list(kwargs, 'modules'))
        if not self.requested_modules:
            raise DependencyException('No ' + self.qtname + '  modules specified.')

        self.qtmain = T.cast('bool', kwargs.get('main', False))
        if not isinstance(self.qtmain, bool):
            raise DependencyException('"main" argument must be a boolean')

    def _link_with_qt_winmain(self, is_debug: bool, libdir: T.Union[str, T.List[str]]) -> bool:
        libdir = mesonlib.listify(libdir)  # TODO: shouldn't be necessary
        base_name = self.get_qt_winmain_base_name(is_debug)
        qt_winmain = self.clib_compiler.find_library(base_name, self.env, libdir)
        if qt_winmain:
            self.link_args.append(qt_winmain[0])
            return True
        return False

    def get_qt_winmain_base_name(self, is_debug: bool) -> str:
        return 'qtmaind' if is_debug else 'qtmain'

    def get_exe_args(self, compiler: 'Compiler') -> T.List[str]:
        # 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 log_details(self) -> str:
        return f'modules: {", ".join(sorted(self.requested_modules))}'


class QtPkgConfigDependency(_QtBase, PkgConfigDependency, metaclass=abc.ABCMeta):

    """Specialization of the PkgConfigDependency for Qt."""

    def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]):
        _QtBase.__init__(self, name, kwargs)

        # Always use QtCore as the "main" dependency, since it has the extra
        # pkg-config variables that a user would expect to get. If "Core" is
        # not a requested module, delete the compile and link arguments to
        # avoid linking with something they didn't ask for
        PkgConfigDependency.__init__(self, self.qtpkgname + 'Core', env, kwargs)
        if 'Core' not in self.requested_modules:
            self.compile_args = []
            self.link_args = []

        for m in self.requested_modules:
            mod = PkgConfigDependency(self.qtpkgname + m, self.env, kwargs, language=self.language)
            if not mod.found():
                self.is_found = False
                return
            if self.private_headers:
                qt_inc_dir = mod.get_variable(pkgconfig='includedir')
                mod_private_dir = os.path.join(qt_inc_dir, 'Qt' + m)
                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, mod.version)
                for directory in mod_private_inc:
                    mod.compile_args.append('-I' + directory)
            self._add_sub_dependency([lambda: mod])

        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' + _get_modules_lib_suffix(self.version, self.env.machines[self.for_machine], True)
            is_debug = False
            for arg in self.get_link_args():
                if arg == f'-l{debug_lib_name}' or arg.endswith(f'{debug_lib_name}.lib') or arg.endswith(f'{debug_lib_name}.a'):
                    is_debug = True
                    break
            libdir = self.get_variable(pkgconfig='libdir')
            if not self._link_with_qt_winmain(is_debug, libdir):
                self.is_found = False
                return

        self.bindir = self.get_pkgconfig_host_bins(self)
        if not self.bindir:
            # If exec_prefix is not defined, the pkg-config file is broken
            prefix = self.get_variable(pkgconfig='exec_prefix')
            if prefix:
                self.bindir = os.path.join(prefix, 'bin')

        self.libexecdir = self.get_pkgconfig_host_libexecs(self)

    @staticmethod
    @abc.abstractmethod
    def get_pkgconfig_host_bins(core: PkgConfigDependency) -> T.Optional[str]:
        pass

    @staticmethod
    @abc.abstractmethod
    def get_pkgconfig_host_libexecs(core: PkgConfigDependency) -> T.Optional[str]:
        pass

    @abc.abstractmethod
    def get_private_includes(self, mod_inc_dir: str, module: str) -> T.List[str]:
        pass

    def log_info(self) -> str:
        return 'pkg-config'


class QmakeQtDependency(_QtBase, ConfigToolDependency, metaclass=abc.ABCMeta):

    """Find Qt using Qmake as a config-tool."""

    version_arg = '-v'

    def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]):
        _QtBase.__init__(self, name, kwargs)
        self.tool_name = f'qmake{self.qtver}'
        self.tools = [f'qmake{self.qtver}', f'qmake-{self.name}', 'qmake']

        # Add additional constraints that the Qt version is met, but preserve
        # any version requirements the user has set as well. For example, if Qt5
        # is requested, add "">= 5, < 6", but if the user has ">= 5.6", don't
        # lose that.
        kwargs = kwargs.copy()
        _vers = mesonlib.listify(kwargs.get('version', []))
        _vers.extend([f'>= {self.qtver}', f'< {int(self.qtver) + 1}'])
        kwargs['version'] = _vers

        ConfigToolDependency.__init__(self, name, env, kwargs)
        if not self.found():
            return

        # Query library path, header path, and binary path
        stdo = self.get_config_value(['-query'], 'args')
        qvars: T.Dict[str, str] = {}
        for line in stdo:
            line = line.strip()
            if line == '':
                continue
            k, v = 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, self.requested_modules, kwargs)
            # Sometimes Qt is built not as a framework (for instance, when using conan pkg manager)
            # skip and fall back to normal procedure then
            if self.is_found:
                return
            else:
                mlog.debug("Building for macOS, couldn't find framework, falling back to library search")
        incdir = qvars['QT_INSTALL_HEADERS']
        self.compile_args.append('-I' + incdir)
        libdir = qvars['QT_INSTALL_LIBS']
        # Used by qt.compilers_detect()
        self.bindir = get_qmake_host_bins(qvars)
        self.libexecdir = get_qmake_host_libexecs(qvars)

        # Use the buildtype by default, but look at the b_vscrt option if the
        # compiler supports it.
        is_debug = self.env.coredata.get_option(mesonlib.OptionKey('buildtype')) == 'debug'
        if mesonlib.OptionKey('b_vscrt') in self.env.coredata.options:
            if self.env.coredata.options[mesonlib.OptionKey('b_vscrt')].value in {'mdd', 'mtd'}:
                is_debug = True
        modules_lib_suffix = _get_modules_lib_suffix(self.version, self.env.machines[self.for_machine], is_debug)

        for module in self.requested_modules:
            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(f'-DQT_{define_base}_LIB')

            if self.private_headers:
                priv_inc = self.get_private_includes(mincdir, module)
                for directory in priv_inc:
                    self.compile_args.append('-I' + directory)
            libfiles = self.clib_compiler.find_library(
                self.qtpkgname + module + modules_lib_suffix, self.env,
                mesonlib.listify(libdir)) # TODO: shouldn't be necessary
            if libfiles:
                libfile = libfiles[0]
            else:
                mlog.log("Could not find:", module,
                         self.qtpkgname + module + modules_lib_suffix,
                         'in', libdir)
                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_qt_winmain(is_debug, libdir):
                self.is_found = False

    def _sanitize_version(self, version: str) -> str:
        m = re.search(rf'({self.qtver}(\.\d+)+)', version)
        if m:
            return m.group(0).rstrip('.')
        return version

    def get_variable_args(self, variable_name: str) -> T.List[str]:
        return ['-query', f'{variable_name}']

    @abc.abstractmethod
    def get_private_includes(self, mod_inc_dir: str, module: str) -> T.List[str]:
        pass

    def _framework_detect(self, qvars: T.Dict[str, str], modules: T.List[str], kwargs: T.Dict[str, T.Any]) -> None:
        libdir = qvars['QT_INSTALL_LIBS']

        # ExtraFrameworkDependency doesn't support any methods
        fw_kwargs = kwargs.copy()
        fw_kwargs.pop('method', None)
        fw_kwargs['paths'] = [libdir]

        for m in modules:
            fname = 'Qt' + m
            mlog.debug('Looking for qt framework ' + fname)
            fwdep = QtExtraFrameworkDependency(fname, self.env, fw_kwargs, qvars, language=self.language)
            if fwdep.found():
                self.compile_args.append('-F' + libdir)
                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:
                self.is_found = False
                break
        else:
            self.is_found = True
            # Used by self.compilers_detect()
            self.bindir = get_qmake_host_bins(qvars)
            self.libexecdir = get_qmake_host_libexecs(qvars)

    def log_info(self) -> str:
        return 'qmake'


class Qt6WinMainMixin:

    def get_qt_winmain_base_name(self, is_debug: bool) -> str:
        return 'Qt6EntryPointd' if is_debug else 'Qt6EntryPoint'


class Qt4ConfigToolDependency(QmakeQtDependency):

    def get_private_includes(self, mod_inc_dir: str, module: str) -> T.List[str]:
        return []


class Qt5ConfigToolDependency(QmakeQtDependency):

    def get_private_includes(self, mod_inc_dir: str, module: str) -> T.List[str]:
        return _qt_get_private_includes(mod_inc_dir, module, self.version)


class Qt6ConfigToolDependency(Qt6WinMainMixin, QmakeQtDependency):

    def get_private_includes(self, mod_inc_dir: str, module: str) -> T.List[str]:
        return _qt_get_private_includes(mod_inc_dir, module, self.version)


class Qt4PkgConfigDependency(QtPkgConfigDependency):

    @staticmethod
    def get_pkgconfig_host_bins(core: PkgConfigDependency) -> T.Optional[str]:
        # 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_variable(pkgconfig=f'{application}_location'))
            except mesonlib.MesonException:
                pass
        return None

    def get_private_includes(self, mod_inc_dir: str, module: str) -> T.List[str]:
        return []

    @staticmethod
    def get_pkgconfig_host_libexecs(core: PkgConfigDependency) -> str:
        return None


class Qt5PkgConfigDependency(QtPkgConfigDependency):

    @staticmethod
    def get_pkgconfig_host_bins(core: PkgConfigDependency) -> str:
        return core.get_variable(pkgconfig='host_bins')

    @staticmethod
    def get_pkgconfig_host_libexecs(core: PkgConfigDependency) -> str:
        return None

    def get_private_includes(self, mod_inc_dir: str, module: str) -> T.List[str]:
        return _qt_get_private_includes(mod_inc_dir, module, self.version)


class Qt6PkgConfigDependency(Qt6WinMainMixin, QtPkgConfigDependency):

    def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__(name, env, kwargs)
        if not self.libexecdir:
            mlog.debug(f'detected Qt6 {self.version} pkg-config dependency does not '
                       'have proper tools support, ignoring')
            self.is_found = False

    @staticmethod
    def get_pkgconfig_host_bins(core: PkgConfigDependency) -> str:
        return core.get_variable(pkgconfig='bindir')

    @staticmethod
    def get_pkgconfig_host_libexecs(core: PkgConfigDependency) -> str:
        # Qt6 pkg-config for Qt defines libexecdir from 6.3+
        return core.get_variable(pkgconfig='libexecdir')

    def get_private_includes(self, mod_inc_dir: str, module: str) -> T.List[str]:
        return _qt_get_private_includes(mod_inc_dir, module, self.version)


packages['qt4'] = qt4_factory = DependencyFactory(
    'qt4',
    [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL],
    pkgconfig_class=Qt4PkgConfigDependency,
    configtool_class=Qt4ConfigToolDependency,
)

packages['qt5'] = qt5_factory = DependencyFactory(
    'qt5',
    [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL],
    pkgconfig_class=Qt5PkgConfigDependency,
    configtool_class=Qt5ConfigToolDependency,
)

packages['qt6'] = qt6_factory = DependencyFactory(
    'qt6',
    [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL],
    pkgconfig_class=Qt6PkgConfigDependency,
    configtool_class=Qt6ConfigToolDependency,
)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/dependencies/scalapack.py0000644000175000017500000001337714562742363022142 0ustar00jpakkanejpakkane# Copyright 2013-2020 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 __future__ import annotations

from pathlib import Path
import functools
import os
import typing as T

from ..mesonlib import OptionKey
from .base import DependencyMethods
from .cmake import CMakeDependency
from .detect import packages
from .pkgconfig import PkgConfigDependency
from .factory import factory_methods

if T.TYPE_CHECKING:
    from ..environment import Environment
    from ..mesonlib import MachineChoice
    from .factory import DependencyGenerator


@factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE})
def scalapack_factory(env: 'Environment', for_machine: 'MachineChoice',
                      kwargs: T.Dict[str, T.Any],
                      methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']:
    candidates: T.List['DependencyGenerator'] = []

    if DependencyMethods.PKGCONFIG in methods:
        static_opt = kwargs.get('static', env.coredata.get_option(OptionKey('prefer_static')))
        mkl = 'mkl-static-lp64-iomp' if static_opt else 'mkl-dynamic-lp64-iomp'
        candidates.append(functools.partial(
            MKLPkgConfigDependency, mkl, env, kwargs))

        for pkg in ['scalapack-openmpi', 'scalapack']:
            candidates.append(functools.partial(
                PkgConfigDependency, pkg, env, kwargs))

    if DependencyMethods.CMAKE in methods:
        candidates.append(functools.partial(
            CMakeDependency, 'Scalapack', env, kwargs))

    return candidates

packages['scalapack'] = scalapack_factory


class MKLPkgConfigDependency(PkgConfigDependency):

    """PkgConfigDependency for Intel MKL.

    MKL's pkg-config is pretty much borked in every way. We need to apply a
    bunch of fixups to make it work correctly.
    """

    def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any],
                 language: T.Optional[str] = None):
        _m = os.environ.get('MKLROOT')
        self.__mklroot = Path(_m).resolve() if _m else None

        # We need to call down into the normal super() method even if we don't
        # find mklroot, otherwise we won't have all of the instance variables
        # initialized that meson expects.
        super().__init__(name, env, kwargs, language=language)

        # Doesn't work with gcc on windows, but does on Linux
        if (not self.__mklroot or (env.machines[self.for_machine].is_windows()
                                   and self.clib_compiler.id == 'gcc')):
            self.is_found = False

        # This can happen either because we're using GCC, we couldn't find the
        # mklroot, or the pkg-config couldn't find it.
        if not self.is_found:
            return

        assert self.version != '', 'This should not happen if we didn\'t return above'

        if self.version == 'unknown':
            # At least by 2020 the version is in the pkg-config, just not with
            # the correct name
            v = self.get_variable(pkgconfig='Version', default_value='')

            if not v and self.__mklroot:
                try:
                    v = (
                        self.__mklroot.as_posix()
                        .split('compilers_and_libraries_')[1]
                        .split('/', 1)[0]
                    )
                except IndexError:
                    pass

            if v:
                assert isinstance(v, str)
                self.version = v

    def _set_libs(self) -> None:
        super()._set_libs()

        if self.env.machines[self.for_machine].is_windows():
            suffix = '.lib'
        elif self.static:
            suffix = '.a'
        else:
            suffix = ''
        libdir = self.__mklroot / 'lib/intel64'

        if self.clib_compiler.id == 'gcc':
            for i, a in enumerate(self.link_args):
                # only replace in filename, not in directory names
                dirname, basename = os.path.split(a)
                if 'mkl_intel_lp64' in basename:
                    basename = basename.replace('intel', 'gf')
                    self.link_args[i] = '/' + os.path.join(dirname, basename)
        # MKL pkg-config omits scalapack
        # be sure "-L" and "-Wl" are first if present
        i = 0
        for j, a in enumerate(self.link_args):
            if a.startswith(('-L', '-Wl')):
                i = j + 1
            elif j > 3:
                break
        if self.env.machines[self.for_machine].is_windows() or self.static:
            self.link_args.insert(
                i, str(libdir / ('mkl_scalapack_lp64' + suffix))
            )
            self.link_args.insert(
                i + 1, str(libdir / ('mkl_blacs_intelmpi_lp64' + suffix))
            )
        else:
            self.link_args.insert(i, '-lmkl_scalapack_lp64')
            self.link_args.insert(i + 1, '-lmkl_blacs_intelmpi_lp64')

    def _set_cargs(self) -> None:
        allow_system = False
        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
            allow_system = True
        cflags = self.pkgconfig.cflags(self.name, allow_system, define_variable=(('prefix', self.__mklroot.as_posix()),))
        self.compile_args = self._convert_mingw_paths(cflags)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/dependencies/ui.py0000644000175000017500000002727614562742363020640 0ustar00jpakkanejpakkane# 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.
from __future__ import annotations

import os
import re
import subprocess
import typing as T

from .. import mlog
from .. import mesonlib
from ..compilers.compilers import CrossNoRunException
from ..mesonlib import (
    Popen_safe, extract_as_list, version_compare_many
)
from ..environment import detect_cpu_family

from .base import DependencyException, DependencyMethods, DependencyTypeName, SystemDependency
from .configtool import ConfigToolDependency
from .detect import packages
from .factory import DependencyFactory

if T.TYPE_CHECKING:
    from ..environment import Environment


class GLDependencySystem(SystemDependency):
    def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None:
        super().__init__(name, environment, 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
        elif 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
        else:
            links = self.clib_compiler.find_library('GL', environment, [])
            has_header = self.clib_compiler.has_header('GL/gl.h', '', environment)[0]
            if links and has_header:
                self.is_found = True
                self.link_args = links
            elif links:
                raise DependencyException('Found GL runtime library but no development header files')

class GnuStepDependency(ConfigToolDependency):

    tools = ['gnustep-config']
    tool_name = 'gnustep-config'

    def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None:
        super().__init__('gnustep', environment, kwargs, language='objc')
        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: T.Optional[T.List[str]] = None, returncode: int = 0) -> T.Tuple[T.Optional[T.List[str]], T.Optional[str]]:
        tool = [self.tools[0]]
        try:
            p, out = Popen_safe(tool + ['--help'])[:2]
        except (FileNotFoundError, PermissionError):
            return (None, None)
        if p.returncode != returncode:
            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)

    @staticmethod
    def weird_filter(elems: T.List[str]) -> T.List[str]:
        """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('-')]

    @staticmethod
    def filter_args(args: T.List[str]) -> T.List[str]:
        """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) -> str:
        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

packages['gnustep'] = GnuStepDependency


class SDL2DependencyConfigTool(ConfigToolDependency):

    tools = ['sdl2-config']
    tool_name = 'sdl2-config'

    def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__(name, environment, kwargs)
        if not self.is_found:
            return
        self.compile_args = self.get_config_value(['--cflags'], 'compile_args')
        self.link_args = self.get_config_value(['--libs'], 'link_args')


class WxDependency(ConfigToolDependency):

    tools = ['wx-config-3.0', 'wx-config-3.1', 'wx-config', 'wx-config-gtk3']
    tool_name = 'wx-config'

    def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]):
        super().__init__('WxWidgets', environment, kwargs, language='cpp')
        if not self.is_found:
            return
        self.requested_modules = self.get_requested(kwargs)

        extra_args = []
        if self.static:
            extra_args.append('--static=yes')

            # Check to make sure static is going to work
            err = Popen_safe(self.config + extra_args)[2]
            if 'No config found to match' in err:
                mlog.debug('WxWidgets is missing static libraries.')
                self.is_found = False
                return

        # 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'] + extra_args + self.requested_modules, 'compile_args')
        self.link_args = self.get_config_value(['--libs'] + extra_args + self.requested_modules, 'link_args')

    @staticmethod
    def get_requested(kwargs: T.Dict[str, T.Any]) -> T.List[str]:
        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

packages['wxwidgets'] = WxDependency

class VulkanDependencySystem(SystemDependency):

    def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None) -> None:
        super().__init__(name, environment, kwargs, language=language)

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

            # XXX: this is very odd, and may deserve being removed
            self.type_name = DependencyTypeName('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)
        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.is_found = True
                for lib in libs:
                    self.link_args.append(lib)

        if self.is_found:
            get_version = '''\
#include 
#include 

int main() {
    printf("%i.%i.%i", VK_VERSION_MAJOR(VK_HEADER_VERSION_COMPLETE),
                       VK_VERSION_MINOR(VK_HEADER_VERSION_COMPLETE),
                       VK_VERSION_PATCH(VK_HEADER_VERSION_COMPLETE));
    return 0;
}
'''
            try:
                run = self.clib_compiler.run(get_version, environment, extra_args=self.compile_args)
            except CrossNoRunException:
                run = None
            if run and run.compiled and run.returncode == 0:
                self.version = run.stdout
            elif self.vulkan_sdk:
                # fall back to heuristics: detect version number in path
                # matches the default install path on Windows
                match = re.search(rf'VulkanSDK{re.escape(os.path.sep)}([0-9]+(?:\.[0-9]+)+)', self.vulkan_sdk)
                if match:
                    self.version = match.group(1)
                else:
                    mlog.warning(f'Environment variable VULKAN_SDK={self.vulkan_sdk} is present, but Vulkan version could not be extracted.')

packages['gl'] = gl_factory = DependencyFactory(
    'gl',
    [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM],
    system_class=GLDependencySystem,
)

packages['sdl2'] = sdl2_factory = DependencyFactory(
    'sdl2',
    [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK, DependencyMethods.CMAKE],
    configtool_class=SDL2DependencyConfigTool,
    cmake_name='SDL2',
)

packages['vulkan'] = vulkan_factory = DependencyFactory(
    'vulkan',
    [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM],
    system_class=VulkanDependencySystem,
)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/depfile.py0000644000175000017500000000550514562742363017174 0ustar00jpakkanejpakkane# 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.
from __future__ import annotations

import typing as T


def parse(lines: T.Iterable[str]) -> T.List[T.Tuple[T.List[str], T.List[str]]]:
    rules: T.List[T.Tuple[T.List[str], T.List[str]]] = []
    targets: T.List[str] = []
    deps: T.List[str] = []
    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 in {'\\', '$'}:
                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

class Target(T.NamedTuple):

    deps: T.Set[str]


class DepFile:
    def __init__(self, lines: T.Iterable[str]):
        rules = parse(lines)
        depfile: T.Dict[str, Target] = {}
        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, name: str, visited: T.Optional[T.Set[str]] = None) -> T.List[str]:
        deps: T.Set[str] = set()
        if not visited:
            visited = set()
        if name in visited:
            return []
        visited.add(name)

        target = self.depfile.get(name)
        if not target:
            return []
        deps.update(target.deps)
        for dep in target.deps:
            deps.update(self.get_all_dependencies(dep, visited))
        return sorted(deps)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/envconfig.py0000644000175000017500000003635514562742363017551 0ustar00jpakkanejpakkane# 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.
from __future__ import annotations

from dataclasses import dataclass
import subprocess
import typing as T
from enum import Enum

from . import mesonlib
from .mesonlib import EnvironmentException, HoldableObject
from . import mlog
from pathlib import Path


# 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 and 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',
    'avr',
    'c2000',
    'csky',
    'dspic',
    'e2k',
    'ft32',
    'ia64',
    'loongarch64',
    'm68k',
    'microblaze',
    'mips',
    'mips64',
    'msp430',
    'parisc',
    'pic24',
    'ppc',
    'ppc64',
    'riscv32',
    'riscv64',
    'rl78',
    'rx',
    's390',
    's390x',
    'sh4',
    'sparc',
    'sparc64',
    'sw_64',
    'wasm32',
    'wasm64',
    'x86',
    'x86_64',
)

# It would feel more natural to call this "64_BIT_CPU_FAMILIES", but
# python identifiers cannot start with numbers
CPU_FAMILIES_64_BIT = [
    'aarch64',
    'alpha',
    'ia64',
    'loongarch64',
    'mips64',
    'ppc64',
    'riscv64',
    's390x',
    'sparc64',
    'sw_64',
    'wasm64',
    'x86_64',
]

# Map from language identifiers to environment variables.
ENV_VAR_COMPILER_MAP: T.Mapping[str, str] = {
    # Compilers
    'c': 'CC',
    'cpp': 'CXX',
    'cs': 'CSC',
    'd': 'DC',
    'fortran': 'FC',
    'objc': 'OBJC',
    'objcpp': 'OBJCXX',
    'rust': 'RUSTC',
    'vala': 'VALAC',
    'nasm': 'NASM',

    # Linkers
    'c_ld': 'CC_LD',
    'cpp_ld': 'CXX_LD',
    'd_ld': 'DC_LD',
    'fortran_ld': 'FC_LD',
    'objc_ld': 'OBJC_LD',
    'objcpp_ld': 'OBJCXX_LD',
    'rust_ld': 'RUSTC_LD',
}

# Map from utility names to environment variables.
ENV_VAR_TOOL_MAP: T.Mapping[str, str] = {
    # Binutils
    'ar': 'AR',
    'as': 'AS',
    'ld': 'LD',
    'nm': 'NM',
    'objcopy': 'OBJCOPY',
    'objdump': 'OBJDUMP',
    'ranlib': 'RANLIB',
    'readelf': 'READELF',
    'size': 'SIZE',
    'strings': 'STRINGS',
    'strip': 'STRIP',
    'windres': 'WINDRES',

    # Other tools
    'cmake': 'CMAKE',
    'qmake': 'QMAKE',
    'pkg-config': 'PKG_CONFIG',
    'make': 'MAKE',
    'vapigen': 'VAPIGEN',
    'llvm-config': 'LLVM_CONFIG',
}

ENV_VAR_PROG_MAP = {**ENV_VAR_COMPILER_MAP, **ENV_VAR_TOOL_MAP}

# Deprecated environment variables mapped from the new variable to the old one
# Deprecated in 0.54.0
DEPRECATED_ENV_PROG_MAP: T.Mapping[str, str] = {
    'd_ld': 'D_LD',
    'fortran_ld': 'F_LD',
    'rust_ld': 'RUST_LD',
    'objcpp_ld': 'OBJCPP_LD',
}

class CMakeSkipCompilerTest(Enum):
    ALWAYS = 'always'
    NEVER = 'never'
    DEP_ONLY = 'dep_only'

class Properties:
    def __init__(
            self,
            properties: T.Optional[T.Dict[str, T.Optional[T.Union[str, bool, int, T.List[str]]]]] = None,
    ):
        self.properties = properties or {}

    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 heterogeneous dict annotations it's not practical to
    # narrow them
    def get_stdlib(self, language: str) -> T.Union[str, T.List[str]]:
        stdlib = self.properties[language + '_stdlib']
        if isinstance(stdlib, str):
            return stdlib
        assert isinstance(stdlib, list)
        for i in stdlib:
            assert isinstance(i, str)
        return stdlib

    def get_root(self) -> T.Optional[str]:
        root = self.properties.get('root', None)
        assert root is None or isinstance(root, str)
        return root

    def get_sys_root(self) -> T.Optional[str]:
        sys_root = self.properties.get('sys_root', None)
        assert sys_root is None or isinstance(sys_root, str)
        return sys_root

    def get_pkg_config_libdir(self) -> T.Optional[T.List[str]]:
        p = self.properties.get('pkg_config_libdir', None)
        if p is None:
            return p
        res = mesonlib.listify(p)
        for i in res:
            assert isinstance(i, str)
        return res

    def get_cmake_defaults(self) -> bool:
        if 'cmake_defaults' not in self.properties:
            return True
        res = self.properties['cmake_defaults']
        assert isinstance(res, bool)
        return res

    def get_cmake_toolchain_file(self) -> T.Optional[Path]:
        if 'cmake_toolchain_file' not in self.properties:
            return None
        raw = self.properties['cmake_toolchain_file']
        assert isinstance(raw, str)
        cmake_toolchain_file = Path(raw)
        if not cmake_toolchain_file.is_absolute():
            raise EnvironmentException(f'cmake_toolchain_file ({raw}) is not absolute')
        return cmake_toolchain_file

    def get_cmake_skip_compiler_test(self) -> CMakeSkipCompilerTest:
        if 'cmake_skip_compiler_test' not in self.properties:
            return CMakeSkipCompilerTest.DEP_ONLY
        raw = self.properties['cmake_skip_compiler_test']
        assert isinstance(raw, str)
        try:
            return CMakeSkipCompilerTest(raw)
        except ValueError:
            raise EnvironmentException(
                '"{}" is not a valid value for cmake_skip_compiler_test. Supported values are {}'
                .format(raw, [e.value for e in CMakeSkipCompilerTest]))

    def get_cmake_use_exe_wrapper(self) -> bool:
        if 'cmake_use_exe_wrapper' not in self.properties:
            return True
        res = self.properties['cmake_use_exe_wrapper']
        assert isinstance(res, bool)
        return res

    def get_java_home(self) -> T.Optional[Path]:
        value = T.cast('T.Optional[str]', self.properties.get('java_home'))
        return Path(value) if value else None

    def get_bindgen_clang_args(self) -> T.List[str]:
        value = mesonlib.listify(self.properties.get('bindgen_clang_arguments', []))
        if not all(isinstance(v, str) for v in value):
            raise EnvironmentException('bindgen_clang_arguments must be a string or an array of strings')
        return T.cast('T.List[str]', value)

    def __eq__(self, other: object) -> bool:
        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.Optional[T.Union[str, bool, int, T.List[str]]]:
        return self.properties[key]

    # TODO consider removing so Properties is less freeform
    def __contains__(self, item: T.Union[str, bool, int, T.List[str]]) -> bool:
        return item in self.properties

    # TODO consider removing, for same reasons as above
    def get(self, key: str, default: T.Optional[T.Union[str, bool, int, T.List[str]]] = None) -> T.Optional[T.Union[str, bool, int, T.List[str]]]:
        return self.properties.get(key, default)

@dataclass(unsafe_hash=True)
class MachineInfo(HoldableObject):
    system: str
    cpu_family: str
    cpu: str
    endian: str
    kernel: T.Optional[str]
    subsystem: T.Optional[str]

    def __post_init__(self) -> None:
        self.is_64_bit: bool = self.cpu_family in CPU_FAMILIES_64_BIT

    def __repr__(self) -> str:
        return f''

    @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(
                f'Machine info is currently {literal}\n' +
                'but is missing {}.'.format(minimum_literal - set(literal)))

        cpu_family = literal['cpu_family']
        if cpu_family not in known_cpu_families:
            mlog.warning(f'Unknown CPU family {cpu_family}, please report this at https://github.com/mesonbuild/meson/issues/new')

        endian = literal['endian']
        if endian not in ('little', 'big'):
            mlog.warning(f'Unknown endian {endian}')

        system = literal['system']
        kernel = literal.get('kernel', None)
        subsystem = literal.get('subsystem', None)

        return cls(system, cpu_family, literal['cpu'], endian, kernel, subsystem)

    def is_windows(self) -> bool:
        """
        Machine is windows?
        """
        return self.system == 'windows'

    def is_cygwin(self) -> bool:
        """
        Machine is cygwin?
        """
        return self.system == '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'

    def is_hurd(self) -> bool:
        """
        Machine is GNU/Hurd?
        """
        return self.system == 'gnu'

    def is_aix(self) -> bool:
        """
        Machine is aix?
        """
        return self.system == 'aix'

    def is_irix(self) -> bool:
        """Machine is IRIX?"""
        return self.system.startswith('irix')

    # 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:

    def __init__(
            self,
            binaries: T.Optional[T.Dict[str, T.Union[str, T.List[str]]]] = None,
    ):
        self.binaries: T.Dict[str, T.List[str]] = {}
        if binaries:
            for name, command in binaries.items():
                if not isinstance(command, (list, str)):
                    raise mesonlib.MesonException(
                        f'Invalid type {command!r} for entry {name!r} in cross file')
                self.binaries[name] = mesonlib.listify(command)
            if 'pkgconfig' in self.binaries:
                if 'pkg-config' not in self.binaries:
                    mlog.deprecation('"pkgconfig" entry is deprecated and should be replaced by "pkg-config"', fatal=False)
                    self.binaries['pkg-config'] = self.binaries['pkgconfig']
                elif self.binaries['pkgconfig'] != self.binaries['pkg-config']:
                    raise mesonlib.MesonException('Mismatched pkgconfig and pkg-config binaries in the machine file.')
                else:
                    # Both are defined with the same value, this is allowed
                    # for backward compatibility.
                    # FIXME: We should still print deprecation warning if the
                    # project targets Meson >= 1.3.0, but we have no way to know
                    # that here.
                    pass
                del self.binaries['pkgconfig']

    @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']

    @staticmethod
    def detect_sccache() -> T.List[str]:
        try:
            subprocess.check_call(['sccache', '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        except (OSError, subprocess.CalledProcessError):
            return []
        return ['sccache']

    @staticmethod
    def detect_compiler_cache() -> T.List[str]:
        # Sccache is "newer" so it is assumed that people would prefer it by default.
        cache = BinaryTable.detect_sccache()
        if cache:
            return cache
        return BinaryTable.detect_ccache()

    @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()
        elif compiler[0] == 'sccache':
            compiler = compiler[1:]
            ccache = cls.detect_sccache()
        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 binary in cross/native file and fallback to environment.

        Returns command with args as list if found, Returns `None` if nothing is
        found.
        """
        command = self.binaries.get(name)
        if not command:
            return None
        elif not command[0].strip():
            return None
        return command

class CMakeVariables:
    def __init__(self, variables: T.Optional[T.Dict[str, T.Any]] = None) -> None:
        variables = variables or {}
        self.variables: T.Dict[str, T.List[str]] = {}

        for key, value in variables.items():
            value = mesonlib.listify(value)
            for i in value:
                if not isinstance(i, str):
                    raise EnvironmentException(f"Value '{i}' of CMake variable '{key}' defined in a machine file is a {type(i).__name__} and not a str")
            self.variables[key] = value

    def get_variables(self) -> T.Dict[str, T.List[str]]:
        return self.variables
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/environment.py0000644000175000017500000011714214562742363020131 0ustar00jpakkanejpakkane# Copyright 2012-2020 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 __future__ import annotations

import itertools
import os, platform, re, sys, shutil
import typing as T
import collections

from . import coredata
from . import mesonlib
from .mesonlib import (
    MesonException, MachineChoice, Popen_safe, PerMachine,
    PerMachineDefaultable, PerThreeMachineDefaultable, split_args, quote_arg, OptionKey,
    search_version, MesonBugException
)
from . import mlog
from .programs import ExternalProgram

from .envconfig import (
    BinaryTable, MachineInfo, Properties, known_cpu_families, CMakeVariables,
)
from . import compilers
from .compilers import (
    is_assembly,
    is_header,
    is_library,
    is_llvm_ir,
    is_object,
    is_source,
)

from functools import lru_cache
from mesonbuild import envconfig

if T.TYPE_CHECKING:
    import argparse
    from configparser import ConfigParser

    from .compilers import Compiler
    from .wrap.wrap import Resolver

    CompilersDict = T.Dict[str, Compiler]


build_filename = 'meson.build'


def _get_env_var(for_machine: MachineChoice, is_cross: bool, var_name: str) -> T.Optional[str]:
    """
    Returns the exact env var and the value.
    """
    candidates = PerMachine(
        # The prefixed build version takes priority, but if we are native
        # compiling we fall back on the unprefixed host version. This
        # allows native builds to never need to worry about the 'BUILD_*'
        # ones.
        ([var_name + '_FOR_BUILD'] if is_cross else [var_name]),
        # Always just the unprefixed host versions
        [var_name]
    )[for_machine]
    for var in candidates:
        value = os.environ.get(var)
        if value is not None:
            break
    else:
        formatted = ', '.join([f'{var!r}' for var in candidates])
        mlog.debug(f'None of {formatted} are defined in the environment, not changing global flags.')
        return None
    mlog.debug(f'Using {var!r} from environment with value: {value!r}')
    return value


def detect_gcovr(min_version: str = '3.3', log: bool = 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, found
    return None, None

def detect_lcov(log: bool = False):
    lcov_exe = 'lcov'
    try:
        p, found = Popen_safe([lcov_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 found:
        if log:
            mlog.log('Found lcov-{} at {}'.format(found, quote_arg(shutil.which(lcov_exe))))
        return lcov_exe, found
    return None, None

def detect_llvm_cov():
    tools = get_llvm_tool_names('llvm-cov')
    for tool in tools:
        if mesonlib.exe_exists([tool, '--version']):
            return tool
    return None

def find_coverage_tools() -> T.Tuple[T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str]]:
    gcovr_exe, gcovr_version = detect_gcovr()

    llvm_cov_exe = detect_llvm_cov()

    lcov_exe, lcov_version = detect_lcov()
    genhtml_exe = 'genhtml'

    if not mesonlib.exe_exists([genhtml_exe, '--version']):
        genhtml_exe = None

    return gcovr_exe, gcovr_version, lcov_exe, lcov_version, genhtml_exe, llvm_cov_exe

def detect_ninja(version: str = '1.8.2', log: bool = False) -> T.List[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.8.2', log: bool = False) -> T.Tuple[T.List[str], str]:
    env_ninja = os.environ.get('NINJA', None)
    for n in [env_ninja] if env_ninja else ['ninja', 'ninja-build', 'samu']:
        prog = ExternalProgram(n, silent=True)
        if not prog.found():
            continue
        try:
            p, found = Popen_safe(prog.command + ['--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):
            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,
                         ' '.join([quote_arg(x) for x in prog.command])))
            return (prog.command, 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)
        '-17',  '17',
        '-16',  '16',
        '-15',  '15',
        '-14',  '14',
        '-13',  '13',
        '-12',  '12',
        '-11',  '11',
        '-10',  '10',
        '-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',
        '-15',    # Debian development snapshot
        '-devel', # FreeBSD development snapshot
    ]
    names: T.List[str] = []
    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: T.List[str] = []
    if 'SCANBUILD' in os.environ:
        exelist = split_args(os.environ['SCANBUILD'])

    else:
        tools = get_llvm_tool_names('scan-build')
        for tool in tools:
            which = shutil.which(tool)
            if which is not None:
                exelist = [which]
                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_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 = mesonlib.windows_detect_native_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 in {'x86', '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: str) -> bool:
    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() or mesonlib.is_qnx() or mesonlib.is_aix():
        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 == 'arm64':
        trial = 'aarch64'
    elif trial.startswith('aarch64'):
        # This can be `aarch64_be`
        trial = 'aarch64'
    elif trial.startswith('arm') or trial.startswith('earm'):
        trial = 'arm'
    elif trial.startswith(('powerpc64', 'ppc64')):
        trial = 'ppc64'
    elif trial.startswith(('powerpc', 'ppc')) or trial in {'macppc', 'power macintosh'}:
        trial = 'ppc'
    elif trial in {'amd64', 'x64', 'i86pc'}:
        trial = 'x86_64'
    elif trial in {'sun4u', 'sun4v'}:
        trial = 'sparc64'
    elif trial.startswith('mips'):
        if '64' not in trial:
            trial = 'mips'
        else:
            trial = 'mips64'
    elif trial in {'ip30', 'ip35'}:
        trial = 'mips64'

    # 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'
    elif trial == 'ppc':
        # AIX always returns powerpc, check here for 64-bit
        if any_compiler_has_define(compilers, '__64BIT__'):
            trial = 'ppc64'
    # MIPS64 is able to run MIPS32 code natively, so there is a chance that
    # such mixture mentioned above exists.
    elif trial == 'mips64':
        if compilers and not any_compiler_has_define(compilers, '__mips64'):
            trial = 'mips'

    if trial not in known_cpu_families:
        mlog.warning(f'Unknown CPU family {trial!r}, please report this at '
                     'https://github.com/mesonbuild/meson/issues/new with the '
                     'output of `uname -a` and `cat /proc/cpuinfo`')

    return trial

def detect_cpu(compilers: CompilersDict) -> str:
    if mesonlib.is_windows():
        trial = detect_windows_arch(compilers)
    elif mesonlib.is_freebsd() or mesonlib.is_netbsd() or mesonlib.is_openbsd() or mesonlib.is_aix():
        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.startswith('aarch64') or trial.startswith('arm64'):
        # Same check as above for cpu_family
        if any_compiler_has_define(compilers, '__arm__'):
            trial = 'arm'
        else:
            # for aarch64_be
            trial = 'aarch64'
    elif trial.startswith('earm'):
        trial = 'arm'
    elif trial == 'e2k':
        # Make more precise CPU detection for Elbrus platform.
        trial = platform.processor().lower()
    elif trial.startswith('mips'):
        if '64' not in trial:
            trial = 'mips'
        else:
            if compilers and not any_compiler_has_define(compilers, '__mips64'):
                trial = 'mips'
            else:
                trial = 'mips64'
    elif trial == 'ppc':
        # AIX always returns powerpc, check here for 64-bit
        if any_compiler_has_define(compilers, '__64BIT__'):
            trial = 'ppc64'

    # Add more quirks here as bugs are reported. Keep in sync with
    # detect_cpu_family() above.
    return trial

KERNEL_MAPPINGS: T.Mapping[str, str] = {'freebsd': 'freebsd',
                                        'openbsd': 'openbsd',
                                        'netbsd': 'netbsd',
                                        'windows': 'nt',
                                        'android': 'linux',
                                        'linux': 'linux',
                                        'cygwin': 'nt',
                                        'darwin': 'xnu',
                                        'dragonfly': 'dragonfly',
                                        'haiku': 'haiku',
                                        }

def detect_kernel(system: str) -> T.Optional[str]:
    if system == 'sunos':
        # Solaris 5.10 uname doesn't support the -o switch, and illumos started
        # with version 5.11 so shortcut the logic to report 'solaris' in such
        # cases where the version is 5.10 or below.
        if mesonlib.version_compare(platform.uname().release, '<=5.10'):
            return 'solaris'
        # This needs to be /usr/bin/uname because gnu-uname could be installed and
        # won't provide the necessary information
        p, out, _ = Popen_safe(['/usr/bin/uname', '-o'])
        if p.returncode != 0:
            raise MesonException('Failed to run "/usr/bin/uname -o"')
        out = out.lower().strip()
        if out not in {'illumos', 'solaris'}:
            mlog.warning(f'Got an unexpected value for kernel on a SunOS derived platform, expcted either "illumos" or "solaris", but got "{out}".'
                         "Please open a Meson issue with the OS you're running and the value detected for your kernel.")
            return None
        return out
    return KERNEL_MAPPINGS.get(system, None)

def detect_subsystem(system: str) -> T.Optional[str]:
    if system == 'darwin':
        return 'macos'
    return system

def detect_system() -> str:
    if sys.platform == 'cygwin':
        return 'cygwin'
    return platform.system().lower()

def detect_msys2_arch() -> T.Optional[str]:
    return os.environ.get('MSYSTEM_CARCH', 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.
    """
    system = detect_system()
    return MachineInfo(
        system,
        detect_cpu_family(compilers) if compilers is not None else None,
        detect_cpu(compilers) if compilers is not None else None,
        sys.byteorder,
        detect_kernel(system),
        detect_subsystem(system))

# 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')) or \
        ((true_build_cpu_family == 'mips64') and (machine_info.cpu_family == 'mips')) or \
        ((true_build_cpu_family == 'aarch64') and (machine_info.cpu_family == 'arm'))

class Environment:
    private_dir = 'meson-private'
    log_dir = 'meson-logs'
    info_dir = 'meson-info'

    def __init__(self, source_dir: str, build_dir: str, options: 'argparse.Namespace') -> None:
        self.source_dir = source_dir
        self.build_dir = build_dir
        # Do not try to create build directories when build_dir is none.
        # This reduced mode is used by the --buildoptions introspector
        if build_dir is not None:
            self.scratch_dir = os.path.join(build_dir, Environment.private_dir)
            self.log_dir = os.path.join(build_dir, Environment.log_dir)
            self.info_dir = os.path.join(build_dir, Environment.info_dir)
            os.makedirs(self.scratch_dir, exist_ok=True)
            os.makedirs(self.log_dir, exist_ok=True)
            os.makedirs(self.info_dir, exist_ok=True)
            try:
                self.coredata: coredata.CoreData = coredata.load(self.get_build_dir(), suggest_reconfigure=False)
                self.first_invocation = False
            except FileNotFoundError:
                self.create_new_coredata(options)
            except coredata.MesonVersionMismatchException as e:
                # This is routine, but tell the user the update happened
                mlog.log('Regenerating configuration from scratch:', str(e))
                coredata.read_cmd_line_file(self.build_dir, options)
                self.create_new_coredata(options)
            except MesonException as e:
                # If we stored previous command line options, we can recover from
                # a broken/outdated coredata.
                if os.path.isfile(coredata.get_cmd_line_file(self.build_dir)):
                    mlog.warning('Regenerating configuration from scratch.', fatal=False)
                    mlog.log('Reason:', mlog.red(str(e)))
                    coredata.read_cmd_line_file(self.build_dir, options)
                    self.create_new_coredata(options)
                else:
                    raise MesonException(f'{str(e)} Try regenerating using "meson setup --wipe".')
        else:
            # Just create a fresh coredata in this case
            self.scratch_dir = ''
            self.create_new_coredata(options)

        ## locally bind some unfrozen configuration

        # Stores machine infos, the only *three* machine one because we have a
        # target machine info on for the user (Meson never cares about the
        # target machine.)
        machines: PerThreeMachineDefaultable[MachineInfo] = PerThreeMachineDefaultable()

        # Similar to coredata.compilers, but lower level in that there is no
        # meta data, only names/paths.
        binaries: PerMachineDefaultable[BinaryTable] = PerMachineDefaultable()

        # Misc other properties about each machine.
        properties: PerMachineDefaultable[Properties] = PerMachineDefaultable()

        # CMake toolchain variables
        cmakevars: PerMachineDefaultable[CMakeVariables] = PerMachineDefaultable()

        ## Setup build machine defaults

        # Will be fully initialized later using compilers later.
        machines.build = detect_machine_info()

        # Just uses hard-coded defaults and environment variables. Might be
        # overwritten by a native file.
        binaries.build = BinaryTable()
        properties.build = Properties()

        # Options with the key parsed into an OptionKey type.
        #
        # Note that order matters because of 'buildtype', if it is after
        # 'optimization' and 'debug' keys, it override them.
        self.options: T.MutableMapping[OptionKey, T.Union[str, T.List[str]]] = collections.OrderedDict()

        ## Read in native file(s) to override build machine configuration

        if self.coredata.config_files is not None:
            config = coredata.parse_machine_files(self.coredata.config_files, self.source_dir)
            binaries.build = BinaryTable(config.get('binaries', {}))
            properties.build = Properties(config.get('properties', {}))
            cmakevars.build = CMakeVariables(config.get('cmake', {}))
            self._load_machine_file_options(
                config, properties.build,
                MachineChoice.BUILD if self.coredata.cross_files else MachineChoice.HOST)

        ## Read in cross file(s) to override host machine configuration

        if self.coredata.cross_files:
            config = coredata.parse_machine_files(self.coredata.cross_files, self.source_dir)
            properties.host = Properties(config.get('properties', {}))
            binaries.host = BinaryTable(config.get('binaries', {}))
            cmakevars.host = CMakeVariables(config.get('cmake', {}))
            if 'host_machine' in config:
                machines.host = MachineInfo.from_literal(config['host_machine'])
            if 'target_machine' in config:
                machines.target = MachineInfo.from_literal(config['target_machine'])
            # Keep only per machine options from the native file. The cross
            # file takes precedence over all other options.
            for key, value in list(self.options.items()):
                if self.coredata.is_per_machine_option(key):
                    self.options[key.as_build()] = value
            self._load_machine_file_options(config, properties.host, MachineChoice.HOST)

        ## "freeze" now initialized configuration, and "save" to the class.

        self.machines = machines.default_missing()
        self.binaries = binaries.default_missing()
        self.properties = properties.default_missing()
        self.cmakevars = cmakevars.default_missing()

        # Command line options override those from cross/native files
        self.options.update(options.cmd_line_options)

        # Take default value from env if not set in cross/native files or command line.
        self._set_default_options_from_env()
        self._set_default_binaries_from_env()
        self._set_default_properties_from_env()

        # Warn if the user is using two different ways of setting build-type
        # options that override each other
        bt = OptionKey('buildtype')
        db = OptionKey('debug')
        op = OptionKey('optimization')
        if bt in self.options and (db in self.options or op in self.options):
            mlog.warning('Recommend using either -Dbuildtype or -Doptimization + -Ddebug. '
                         'Using both is redundant since they override each other. '
                         'See: https://mesonbuild.com/Builtin-options.html#build-type-options',
                         fatal=False)

        exe_wrapper = self.lookup_binary_entry(MachineChoice.HOST, 'exe_wrapper')
        if exe_wrapper is not None:
            self.exe_wrapper = ExternalProgram.from_bin_list(self, MachineChoice.HOST, 'exe_wrapper')
        else:
            self.exe_wrapper = None

        self.default_cmake = ['cmake']
        self.default_pkgconfig = ['pkg-config']
        self.wrap_resolver: T.Optional['Resolver'] = None

    def _load_machine_file_options(self, config: 'ConfigParser', properties: Properties, machine: MachineChoice) -> None:
        """Read the contents of a Machine file and put it in the options store."""

        # Look for any options in the deprecated paths section, warn about
        # those, then assign them. They will be overwritten by the ones in the
        # "built-in options" section if they're in both sections.
        paths = config.get('paths')
        if paths:
            mlog.deprecation('The [paths] section is deprecated, use the [built-in options] section instead.')
            for k, v in paths.items():
                self.options[OptionKey.from_string(k).evolve(machine=machine)] = v

        # Next look for compiler options in the "properties" section, this is
        # also deprecated, and these will also be overwritten by the "built-in
        # options" section. We need to remove these from this section, as well.
        deprecated_properties: T.Set[str] = set()
        for lang in compilers.all_languages:
            deprecated_properties.add(lang + '_args')
            deprecated_properties.add(lang + '_link_args')
        for k, v in properties.properties.copy().items():
            if k in deprecated_properties:
                mlog.deprecation(f'{k} in the [properties] section of the machine file is deprecated, use the [built-in options] section.')
                self.options[OptionKey.from_string(k).evolve(machine=machine)] = v
                del properties.properties[k]

        for section, values in config.items():
            if ':' in section:
                subproject, section = section.split(':')
            else:
                subproject = ''
            if section == 'built-in options':
                for k, v in values.items():
                    key = OptionKey.from_string(k)
                    # If we're in the cross file, and there is a `build.foo` warn about that. Later we'll remove it.
                    if machine is MachineChoice.HOST and key.machine is not machine:
                        mlog.deprecation('Setting build machine options in cross files, please use a native file instead, this will be removed in meson 0.60', once=True)
                    if key.subproject:
                        raise MesonException('Do not set subproject options in [built-in options] section, use [subproject:built-in options] instead.')
                    self.options[key.evolve(subproject=subproject, machine=machine)] = v
            elif section == 'project options' and machine is MachineChoice.HOST:
                # Project options are only for the host machine, we don't want
                # to read these from the native file
                for k, v in values.items():
                    # Project options are always for the host machine
                    key = OptionKey.from_string(k)
                    if key.subproject:
                        raise MesonException('Do not set subproject options in [built-in options] section, use [subproject:built-in options] instead.')
                    self.options[key.evolve(subproject=subproject)] = v

    def _set_default_options_from_env(self) -> None:
        opts: T.List[T.Tuple[str, str]] = (
            [(v, f'{k}_args') for k, v in compilers.compilers.CFLAGS_MAPPING.items()] +
            [
                ('PKG_CONFIG_PATH', 'pkg_config_path'),
                ('CMAKE_PREFIX_PATH', 'cmake_prefix_path'),
                ('LDFLAGS', 'ldflags'),
                ('CPPFLAGS', 'cppflags'),
            ]
        )

        env_opts: T.DefaultDict[OptionKey, T.List[str]] = collections.defaultdict(list)

        for (evar, keyname), for_machine in itertools.product(opts, MachineChoice):
            p_env = _get_env_var(for_machine, self.is_cross_build(), evar)
            if p_env is not None:
                # these may contain duplicates, which must be removed, else
                # a duplicates-in-array-option warning arises.
                if keyname == 'cmake_prefix_path':
                    if self.machines[for_machine].is_windows():
                        # Cannot split on ':' on Windows because its in the drive letter
                        _p_env = p_env.split(os.pathsep)
                    else:
                        # https://github.com/mesonbuild/meson/issues/7294
                        _p_env = re.split(r':|;', p_env)
                    p_list = list(mesonlib.OrderedSet(_p_env))
                elif keyname == 'pkg_config_path':
                    p_list = list(mesonlib.OrderedSet(p_env.split(os.pathsep)))
                else:
                    p_list = split_args(p_env)
                p_list = [e for e in p_list if e]  # filter out any empty elements

                # Take env vars only on first invocation, if the env changes when
                # reconfiguring it gets ignored.
                # FIXME: We should remember if we took the value from env to warn
                # if it changes on future invocations.
                if self.first_invocation:
                    if keyname == 'ldflags':
                        key = OptionKey('link_args', machine=for_machine, lang='c')  # needs a language to initialize properly
                        for lang in compilers.compilers.LANGUAGES_USING_LDFLAGS:
                            key = key.evolve(lang=lang)
                            env_opts[key].extend(p_list)
                    elif keyname == 'cppflags':
                        key = OptionKey('env_args', machine=for_machine, lang='c')
                        for lang in compilers.compilers.LANGUAGES_USING_CPPFLAGS:
                            key = key.evolve(lang=lang)
                            env_opts[key].extend(p_list)
                    else:
                        key = OptionKey.from_string(keyname).evolve(machine=for_machine)
                        if evar in compilers.compilers.CFLAGS_MAPPING.values():
                            # If this is an environment variable, we have to
                            # store it separately until the compiler is
                            # instantiated, as we don't know whether the
                            # compiler will want to use these arguments at link
                            # time and compile time (instead of just at compile
                            # time) until we're instantiating that `Compiler`
                            # object. This is required so that passing
                            # `-Dc_args=` on the command line and `$CFLAGS`
                            # have subtly different behavior. `$CFLAGS` will be
                            # added to the linker command line if the compiler
                            # acts as a linker driver, `-Dc_args` will not.
                            #
                            # We still use the original key as the base here, as
                            # we want to inherit the machine and the compiler
                            # language
                            key = key.evolve('env_args')
                        env_opts[key].extend(p_list)

        # Only store options that are not already in self.options,
        # otherwise we'd override the machine files
        for k, v in env_opts.items():
            if k not in self.options:
                self.options[k] = v

    def _set_default_binaries_from_env(self) -> None:
        """Set default binaries from the environment.

        For example, pkg-config can be set via PKG_CONFIG, or in the machine
        file. We want to set the default to the env variable.
        """
        opts = itertools.chain(envconfig.DEPRECATED_ENV_PROG_MAP.items(),
                               envconfig.ENV_VAR_PROG_MAP.items())

        for (name, evar), for_machine in itertools.product(opts, MachineChoice):
            p_env = _get_env_var(for_machine, self.is_cross_build(), evar)
            if p_env is not None:
                if os.path.exists(p_env):
                    self.binaries[for_machine].binaries.setdefault(name, [p_env])
                else:
                    self.binaries[for_machine].binaries.setdefault(name, mesonlib.split_args(p_env))

    def _set_default_properties_from_env(self) -> None:
        """Properties which can also be set from the environment."""
        # name, evar, split
        opts: T.List[T.Tuple[str, T.List[str], bool]] = [
            ('boost_includedir', ['BOOST_INCLUDEDIR'], False),
            ('boost_librarydir', ['BOOST_LIBRARYDIR'], False),
            ('boost_root', ['BOOST_ROOT', 'BOOSTROOT'], True),
            ('java_home', ['JAVA_HOME'], False),
        ]

        for (name, evars, split), for_machine in itertools.product(opts, MachineChoice):
            for evar in evars:
                p_env = _get_env_var(for_machine, self.is_cross_build(), evar)
                if p_env is not None:
                    if split:
                        self.properties[for_machine].properties.setdefault(name, p_env.split(os.pathsep))
                    else:
                        self.properties[for_machine].properties.setdefault(name, p_env)
                    break

    def create_new_coredata(self, options: 'argparse.Namespace') -> None:
        # WARNING: Don't use any values from coredata in __init__. It gets
        # re-initialized with project options by the interpreter during
        # build file parsing.
        # meson_command is used by the regenchecker script, which runs meson
        self.coredata = coredata.CoreData(options, self.scratch_dir, mesonlib.get_meson_command())
        self.first_invocation = True

    def is_cross_build(self, when_building_for: MachineChoice = MachineChoice.HOST) -> bool:
        return self.coredata.is_cross_build(when_building_for)

    def dump_coredata(self) -> str:
        return coredata.save(self.coredata, self.get_build_dir())

    def get_log_dir(self) -> str:
        return self.log_dir

    def get_coredata(self) -> coredata.CoreData:
        return self.coredata

    @staticmethod
    def get_build_command(unbuffered: bool = False) -> T.List[str]:
        cmd = mesonlib.get_meson_command()
        if cmd is None:
            raise MesonBugException('No command?')
        cmd = cmd.copy()
        if unbuffered and 'python' in os.path.basename(cmd[0]):
            cmd.insert(1, '-u')
        return cmd

    def is_header(self, fname: 'mesonlib.FileOrString') -> bool:
        return is_header(fname)

    def is_source(self, fname: 'mesonlib.FileOrString') -> bool:
        return is_source(fname)

    def is_assembly(self, fname: 'mesonlib.FileOrString') -> bool:
        return is_assembly(fname)

    def is_llvm_ir(self, fname: 'mesonlib.FileOrString') -> bool:
        return is_llvm_ir(fname)

    def is_object(self, fname: 'mesonlib.FileOrString') -> bool:
        return is_object(fname)

    @lru_cache(maxsize=None)
    def is_library(self, fname: mesonlib.FileOrString):
        return is_library(fname)

    def lookup_binary_entry(self, for_machine: MachineChoice, name: str) -> T.Optional[T.List[str]]:
        return self.binaries[for_machine].lookup_entry(name)

    def get_scratch_dir(self) -> str:
        return self.scratch_dir

    def get_source_dir(self) -> str:
        return self.source_dir

    def get_build_dir(self) -> str:
        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_jar_dir(self) -> str:
        """Install dir for JAR files"""
        return f"{self.get_datadir()}/java"

    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_option(OptionKey('prefix'))

    def get_libdir(self) -> str:
        return self.coredata.get_option(OptionKey('libdir'))

    def get_libexecdir(self) -> str:
        return self.coredata.get_option(OptionKey('libexecdir'))

    def get_bindir(self) -> str:
        return self.coredata.get_option(OptionKey('bindir'))

    def get_includedir(self) -> str:
        return self.coredata.get_option(OptionKey('includedir'))

    def get_mandir(self) -> str:
        return self.coredata.get_option(OptionKey('mandir'))

    def get_datadir(self) -> str:
        return self.coredata.get_option(OptionKey('datadir'))

    def get_compiler_system_lib_dirs(self, for_machine: MachineChoice) -> T.List[str]:
        for comp in self.coredata.compilers[for_machine].values():
            if comp.id == 'clang':
                index = 1
                break
            elif comp.id == 'gcc':
                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 get_compiler_system_include_dirs(self, for_machine: MachineChoice) -> T.List[str]:
        for comp in self.coredata.compilers[for_machine].values():
            if comp.id == 'clang':
                break
            elif comp.id == 'gcc':
                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 []
        return comp.get_default_include_dirs()

    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) -> T.Optional[ExternalProgram]:
        if not self.need_exe_wrapper():
            return None
        return self.exe_wrapper
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.6866386
meson-1.3.2/mesonbuild/interpreter/0000755000175000017500000000000014562742414017545 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/interpreter/__init__.py0000644000175000017500000000342214562742363021662 0ustar00jpakkanejpakkane# SPDX-license-identifier: Apache-2.0
# Copyright 2012-2021 The Meson development team
# Copyright Ā© 2021 Intel Corporation

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

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

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

"""Meson interpreter."""

__all__ = [
    'Interpreter',
    'permitted_dependency_kwargs',

    'CompilerHolder',

    'ExecutableHolder',
    'BuildTargetHolder',
    'CustomTargetHolder',
    'CustomTargetIndexHolder',
    'MachineHolder',
    'Test',
    'ConfigurationDataHolder',
    'SubprojectHolder',
    'DependencyHolder',
    'GeneratedListHolder',
    'ExternalProgramHolder',
    'extract_required_kwarg',

    'ArrayHolder',
    'BooleanHolder',
    'DictHolder',
    'IntegerHolder',
    'StringHolder',
]

from .interpreter import Interpreter, permitted_dependency_kwargs
from .compiler import CompilerHolder
from .interpreterobjects import (ExecutableHolder, BuildTargetHolder, CustomTargetHolder,
                                 CustomTargetIndexHolder, MachineHolder, Test,
                                 ConfigurationDataHolder, SubprojectHolder, DependencyHolder,
                                 GeneratedListHolder, ExternalProgramHolder,
                                 extract_required_kwarg)

from .primitives import (
    ArrayHolder,
    BooleanHolder,
    DictHolder,
    IntegerHolder,
    StringHolder,
)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0
meson-1.3.2/mesonbuild/interpreter/compiler.py0000644000175000017500000012467114562742373021750 0ustar00jpakkanejpakkane# SPDX-License-Identifier: Apache-2.0
# Copyright 2012-2021 The Meson development team
# Copyright Ā© 2021 Intel Corporation
from __future__ import annotations

import collections
import enum
import functools
import os
import itertools
import typing as T

from .. import build
from .. import coredata
from .. import dependencies
from .. import mesonlib
from .. import mlog
from ..compilers import SUFFIX_TO_LANG
from ..compilers.compilers import CompileCheckMode
from ..interpreterbase import (ObjectHolder, noPosargs, noKwargs,
                               FeatureNew, FeatureNewKwargs, disablerIfNotFound,
                               InterpreterException)
from ..interpreterbase.decorators import ContainerTypeInfo, typed_kwargs, KwargInfo, typed_pos_args
from ..mesonlib import OptionKey
from .interpreterobjects import (extract_required_kwarg, extract_search_dirs)
from .type_checking import REQUIRED_KW, in_set_validator, NoneType

if T.TYPE_CHECKING:
    from ..interpreter import Interpreter
    from ..compilers import Compiler, RunResult
    from ..interpreterbase import TYPE_var, TYPE_kwargs
    from .kwargs import ExtractRequired, ExtractSearchDirs
    from .interpreter.interpreter import SourceOutputs
    from ..mlog import TV_LoggableList

    from typing_extensions import TypedDict, Literal

    class GetSupportedArgumentKw(TypedDict):

        checked: Literal['warn', 'require', 'off']

    class AlignmentKw(TypedDict):

        prefix: str
        args: T.List[str]
        dependencies: T.List[dependencies.Dependency]

    class BaseCompileKW(TypedDict):
        no_builtin_args: bool
        include_directories: T.List[build.IncludeDirs]
        args: T.List[str]

    class CompileKW(BaseCompileKW):

        name: str
        dependencies: T.List[dependencies.Dependency]
        werror: bool

    class CommonKW(BaseCompileKW):

        prefix: str
        dependencies: T.List[dependencies.Dependency]

    class ComputeIntKW(CommonKW):

        guess: T.Optional[int]
        high: T.Optional[int]
        low: T.Optional[int]

    class HeaderKW(CommonKW, ExtractRequired):
        pass

    class HasKW(CommonKW, ExtractRequired):
        pass

    class HasArgumentKW(ExtractRequired):
        pass

    class FindLibraryKW(ExtractRequired, ExtractSearchDirs):

        disabler: bool
        has_headers: T.List[str]
        static: bool

        # This list must be all of the `HeaderKW` values with `header_`
        # prepended to the key
        header_args: T.List[str]
        header_dependencies: T.List[dependencies.Dependency]
        header_include_directories: T.List[build.IncludeDirs]
        header_no_builtin_args: bool
        header_prefix: str
        header_required: T.Union[bool, coredata.UserFeatureOption]

    class PreprocessKW(TypedDict):
        output: str
        compile_args: T.List[str]
        include_directories: T.List[build.IncludeDirs]
        dependencies: T.List[dependencies.Dependency]


class _TestMode(enum.Enum):

    """Whether we're doing a compiler or linker check."""

    COMPILER = 0
    LINKER = 1


class TryRunResultHolder(ObjectHolder['RunResult']):
    def __init__(self, res: 'RunResult', interpreter: 'Interpreter'):
        super().__init__(res, interpreter)
        self.methods.update({'returncode': self.returncode_method,
                             'compiled': self.compiled_method,
                             'stdout': self.stdout_method,
                             'stderr': self.stderr_method,
                             })

    @noPosargs
    @noKwargs
    def returncode_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> int:
        return self.held_object.returncode

    @noPosargs
    @noKwargs
    def compiled_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool:
        return self.held_object.compiled

    @noPosargs
    @noKwargs
    def stdout_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
        return self.held_object.stdout

    @noPosargs
    @noKwargs
    def stderr_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
        return self.held_object.stderr


_ARGS_KW: KwargInfo[T.List[str]] = KwargInfo(
    'args',
    ContainerTypeInfo(list, str),
    listify=True,
    default=[],
)
_DEPENDENCIES_KW: KwargInfo[T.List['dependencies.Dependency']] = KwargInfo(
    'dependencies',
    ContainerTypeInfo(list, dependencies.Dependency),
    listify=True,
    default=[],
)
_INCLUDE_DIRS_KW: KwargInfo[T.List[build.IncludeDirs]] = KwargInfo(
    'include_directories',
    ContainerTypeInfo(list, build.IncludeDirs),
    default=[],
    listify=True,
)
_PREFIX_KW: KwargInfo[str] = KwargInfo(
    'prefix',
    (str, ContainerTypeInfo(list, str)),
    default='',
    since_values={list: '1.0.0'},
    convertor=lambda x: '\n'.join(x) if isinstance(x, list) else x)

_NO_BUILTIN_ARGS_KW = KwargInfo('no_builtin_args', bool, default=False)
_NAME_KW = KwargInfo('name', str, default='')
_WERROR_KW = KwargInfo('werror', bool, default=False, since='1.3.0')

# Many of the compiler methods take this kwarg signature exactly, this allows
# simplifying the `typed_kwargs` calls
_COMMON_KWS: T.List[KwargInfo] = [_ARGS_KW, _DEPENDENCIES_KW, _INCLUDE_DIRS_KW, _PREFIX_KW, _NO_BUILTIN_ARGS_KW]

# Common methods of compiles, links, runs, and similar
_COMPILES_KWS: T.List[KwargInfo] = [_NAME_KW, _ARGS_KW, _DEPENDENCIES_KW, _INCLUDE_DIRS_KW, _NO_BUILTIN_ARGS_KW,
                                    _WERROR_KW]

_HEADER_KWS: T.List[KwargInfo] = [REQUIRED_KW.evolve(since='0.50.0', default=False), *_COMMON_KWS]
_HAS_REQUIRED_KW = REQUIRED_KW.evolve(since='1.3.0', default=False)

class CompilerHolder(ObjectHolder['Compiler']):
    preprocess_uid: T.Dict[str, itertools.count] = collections.defaultdict(itertools.count)

    def __init__(self, compiler: 'Compiler', interpreter: 'Interpreter'):
        super().__init__(compiler, interpreter)
        self.environment = self.env
        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,
                             'has_define': self.has_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,
                             'symbols_have_underscore_prefix': self.symbols_have_underscore_prefix_method,
                             'get_argument_syntax': self.get_argument_syntax_method,
                             'preprocess': self.preprocess_method,
                             })

    @property
    def compiler(self) -> 'Compiler':
        return self.held_object

    def _dep_msg(self, deps: T.List['dependencies.Dependency'], compile_only: bool, endl: str) -> str:
        msg_single = 'with dependency {}'
        msg_many = 'with dependencies {}'
        names = []
        for d in deps:
            if isinstance(d, dependencies.InternalDependency):
                FeatureNew.single_use('compiler method "dependencies" kwarg with internal dep', '0.57.0', self.subproject,
                                      location=self.current_node)
                continue
            if isinstance(d, dependencies.ExternalLibrary):
                if compile_only:
                    continue
                name = '-l' + d.name
            else:
                name = d.name
            names.append(name)
        if not names:
            return endl
        tpl = msg_many if len(names) > 1 else msg_single
        if endl is None:
            endl = ''
        return tpl.format(', '.join(names)) + endl

    @noPosargs
    @noKwargs
    def version_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
        return self.compiler.version

    @noPosargs
    @noKwargs
    def cmd_array_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> T.List[str]:
        return self.compiler.exelist

    def _determine_args(self, kwargs: BaseCompileKW,
                        mode: CompileCheckMode = CompileCheckMode.LINK) -> T.List[str]:
        args: T.List[str] = []
        for i in kwargs['include_directories']:
            for idir in i.to_string_list(self.environment.get_source_dir(), self.environment.get_build_dir()):
                args.extend(self.compiler.get_include_args(idir, False))
        if not kwargs['no_builtin_args']:
            opts = coredata.OptionsView(self.environment.coredata.options, self.subproject)
            args += self.compiler.get_option_compile_args(opts)
            if mode is CompileCheckMode.LINK:
                args.extend(self.compiler.get_option_link_args(opts))
        if kwargs.get('werror', False):
            args.extend(self.compiler.get_werror_args())
        args.extend(kwargs['args'])
        return args

    def _determine_dependencies(self, deps: T.List['dependencies.Dependency'], compile_only: bool = False, endl: str = ':') -> T.Tuple[T.List['dependencies.Dependency'], str]:
        deps = dependencies.get_leaf_external_dependencies(deps)
        return deps, self._dep_msg(deps, compile_only, endl)

    @typed_pos_args('compiler.alignment', str)
    @typed_kwargs(
        'compiler.alignment',
        _PREFIX_KW,
        _ARGS_KW,
        _DEPENDENCIES_KW,
    )
    def alignment_method(self, args: T.Tuple[str], kwargs: 'AlignmentKw') -> int:
        typename = args[0]
        deps, msg = self._determine_dependencies(kwargs['dependencies'], compile_only=self.compiler.is_cross)
        result, cached = self.compiler.alignment(typename, kwargs['prefix'], self.environment,
                                                 extra_args=kwargs['args'],
                                                 dependencies=deps)
        cached_msg = mlog.blue('(cached)') if cached else ''
        mlog.log('Checking for alignment of',
                 mlog.bold(typename, True), msg, mlog.bold(str(result)), cached_msg)
        return result

    @typed_pos_args('compiler.run', (str, mesonlib.File))
    @typed_kwargs('compiler.run', *_COMPILES_KWS)
    def run_method(self, args: T.Tuple['mesonlib.FileOrString'], kwargs: 'CompileKW') -> 'RunResult':
        code = args[0]
        if isinstance(code, mesonlib.File):
            self.interpreter.add_build_def_file(code)
            code = mesonlib.File.from_absolute_file(
                code.rel_to_builddir(self.environment.source_dir))
        testname = kwargs['name']
        extra_args = functools.partial(self._determine_args, kwargs)
        deps, msg = self._determine_dependencies(kwargs['dependencies'], compile_only=False, endl=None)
        result = self.compiler.run(code, self.environment, extra_args=extra_args,
                                   dependencies=deps)
        if testname:
            if not result.compiled:
                h = mlog.red('DID NOT COMPILE')
            elif result.returncode == 0:
                h = mlog.green('YES')
            else:
                h = mlog.red(f'NO ({result.returncode})')
            mlog.log('Checking if', mlog.bold(testname, True), msg, 'runs:', h)
        return result

    @noPosargs
    @noKwargs
    def get_id_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
        return self.compiler.get_id()

    @noPosargs
    @noKwargs
    @FeatureNew('compiler.get_linker_id', '0.53.0')
    def get_linker_id_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
        return self.compiler.get_linker_id()

    @noPosargs
    @noKwargs
    def symbols_have_underscore_prefix_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool:
        '''
        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)

    @typed_pos_args('compiler.has_member', str, str)
    @typed_kwargs('compiler.has_member', _HAS_REQUIRED_KW, *_COMMON_KWS)
    def has_member_method(self, args: T.Tuple[str, str], kwargs: 'HasKW') -> bool:
        typename, membername = args
        disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False)
        if disabled:
            mlog.log('Type', mlog.bold(typename, True), 'has member', mlog.bold(membername, True), 'skipped: feature', mlog.bold(feature), 'disabled')
            return False
        extra_args = functools.partial(self._determine_args, kwargs)
        deps, msg = self._determine_dependencies(kwargs['dependencies'])
        had, cached = self.compiler.has_members(typename, [membername], kwargs['prefix'],
                                                self.environment,
                                                extra_args=extra_args,
                                                dependencies=deps)
        cached_msg = mlog.blue('(cached)') if cached else ''
        if required and not had:
            raise InterpreterException(f'{self.compiler.get_display_language()} member {membername!r} of type {typename!r} not usable')
        elif 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_msg)
        return had

    @typed_pos_args('compiler.has_members', str, varargs=str, min_varargs=1)
    @typed_kwargs('compiler.has_members', _HAS_REQUIRED_KW, *_COMMON_KWS)
    def has_members_method(self, args: T.Tuple[str, T.List[str]], kwargs: 'HasKW') -> bool:
        typename, membernames = args
        members = mlog.bold(', '.join([f'"{m}"' for m in membernames]))
        disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False)
        if disabled:
            mlog.log('Type', mlog.bold(typename, True), 'has members', members, 'skipped: feature', mlog.bold(feature), 'disabled')
            return False
        extra_args = functools.partial(self._determine_args, kwargs)
        deps, msg = self._determine_dependencies(kwargs['dependencies'])
        had, cached = self.compiler.has_members(typename, membernames, kwargs['prefix'],
                                                self.environment,
                                                extra_args=extra_args,
                                                dependencies=deps)
        cached_msg = mlog.blue('(cached)') if cached else ''
        if required and not had:
            # print members as array: ['member1', 'member2']
            raise InterpreterException(f'{self.compiler.get_display_language()} members {membernames!r} of type {typename!r} not usable')
        elif had:
            hadtxt = mlog.green('YES')
        else:
            hadtxt = mlog.red('NO')
        mlog.log('Checking whether type', mlog.bold(typename, True),
                 'has members', members, msg, hadtxt, cached_msg)
        return had

    @typed_pos_args('compiler.has_function', str)
    @typed_kwargs('compiler.has_function', _HAS_REQUIRED_KW, *_COMMON_KWS)
    def has_function_method(self, args: T.Tuple[str], kwargs: 'HasKW') -> bool:
        funcname = args[0]
        disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False)
        if disabled:
            mlog.log('Has function', mlog.bold(funcname, True), 'skipped: feature', mlog.bold(feature), 'disabled')
            return False
        extra_args = self._determine_args(kwargs)
        deps, msg = self._determine_dependencies(kwargs['dependencies'], compile_only=False)
        had, cached = self.compiler.has_function(funcname, kwargs['prefix'], self.environment,
                                                 extra_args=extra_args,
                                                 dependencies=deps)
        cached_msg = mlog.blue('(cached)') if cached else ''
        if required and not had:
            raise InterpreterException(f'{self.compiler.get_display_language()} function {funcname!r} not usable')
        elif had:
            hadtxt = mlog.green('YES')
        else:
            hadtxt = mlog.red('NO')
        mlog.log('Checking for function', mlog.bold(funcname, True), msg, hadtxt, cached_msg)
        return had

    @typed_pos_args('compiler.has_type', str)
    @typed_kwargs('compiler.has_type', _HAS_REQUIRED_KW, *_COMMON_KWS)
    def has_type_method(self, args: T.Tuple[str], kwargs: 'HasKW') -> bool:
        typename = args[0]
        disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False)
        if disabled:
            mlog.log('Has type', mlog.bold(typename, True), 'skipped: feature', mlog.bold(feature), 'disabled')
            return False
        extra_args = functools.partial(self._determine_args, kwargs)
        deps, msg = self._determine_dependencies(kwargs['dependencies'])
        had, cached = self.compiler.has_type(typename, kwargs['prefix'], self.environment,
                                             extra_args=extra_args, dependencies=deps)
        cached_msg = mlog.blue('(cached)') if cached else ''
        if required and not had:
            raise InterpreterException(f'{self.compiler.get_display_language()} type {typename!r} not usable')
        elif had:
            hadtxt = mlog.green('YES')
        else:
            hadtxt = mlog.red('NO')
        mlog.log('Checking for type', mlog.bold(typename, True), msg, hadtxt, cached_msg)
        return had

    @FeatureNew('compiler.compute_int', '0.40.0')
    @typed_pos_args('compiler.compute_int', str)
    @typed_kwargs(
        'compiler.compute_int',
        KwargInfo('low', (int, NoneType)),
        KwargInfo('high', (int, NoneType)),
        KwargInfo('guess', (int, NoneType)),
        *_COMMON_KWS,
    )
    def compute_int_method(self, args: T.Tuple[str], kwargs: 'ComputeIntKW') -> int:
        expression = args[0]
        extra_args = functools.partial(self._determine_args, kwargs)
        deps, msg = self._determine_dependencies(kwargs['dependencies'], compile_only=self.compiler.is_cross)
        res = self.compiler.compute_int(expression, kwargs['low'], kwargs['high'],
                                        kwargs['guess'], kwargs['prefix'],
                                        self.environment, extra_args=extra_args,
                                        dependencies=deps)
        mlog.log('Computing int of', mlog.bold(expression, True), msg, res)
        return res

    @typed_pos_args('compiler.sizeof', str)
    @typed_kwargs('compiler.sizeof', *_COMMON_KWS)
    def sizeof_method(self, args: T.Tuple[str], kwargs: 'CommonKW') -> int:
        element = args[0]
        extra_args = functools.partial(self._determine_args, kwargs)
        deps, msg = self._determine_dependencies(kwargs['dependencies'], compile_only=self.compiler.is_cross)
        esize, cached = self.compiler.sizeof(element, kwargs['prefix'], self.environment,
                                             extra_args=extra_args, dependencies=deps)
        cached_msg = mlog.blue('(cached)') if cached else ''
        mlog.log('Checking for size of',
                 mlog.bold(element, True), msg, mlog.bold(str(esize)), cached_msg)
        return esize

    @FeatureNew('compiler.get_define', '0.40.0')
    @typed_pos_args('compiler.get_define', str)
    @typed_kwargs('compiler.get_define', *_COMMON_KWS)
    def get_define_method(self, args: T.Tuple[str], kwargs: 'CommonKW') -> str:
        element = args[0]
        extra_args = functools.partial(self._determine_args, kwargs)
        deps, msg = self._determine_dependencies(kwargs['dependencies'])
        value, cached = self.compiler.get_define(element, kwargs['prefix'], self.environment,
                                                 extra_args=extra_args,
                                                 dependencies=deps)
        cached_msg = mlog.blue('(cached)') if cached else ''
        value_msg = '(undefined)' if value is None else value
        mlog.log('Fetching value of define', mlog.bold(element, True), msg, value_msg, cached_msg)
        return value if value is not None else ''

    @FeatureNew('compiler.has_define', '1.3.0')
    @typed_pos_args('compiler.has_define', str)
    @typed_kwargs('compiler.has_define', *_COMMON_KWS)
    def has_define_method(self, args: T.Tuple[str], kwargs: 'CommonKW') -> bool:
        define_name = args[0]
        extra_args = functools.partial(self._determine_args, kwargs)
        deps, msg = self._determine_dependencies(kwargs['dependencies'], endl=None)
        value, cached = self.compiler.get_define(define_name, kwargs['prefix'], self.environment,
                                                 extra_args=extra_args,
                                                 dependencies=deps)
        cached_msg = mlog.blue('(cached)') if cached else ''
        h = mlog.green('YES') if value is not None else mlog.red('NO')
        mlog.log('Checking if define', mlog.bold(define_name, True), msg, 'exists:', h, cached_msg)

        return value is not None

    @typed_pos_args('compiler.compiles', (str, mesonlib.File))
    @typed_kwargs('compiler.compiles', *_COMPILES_KWS)
    def compiles_method(self, args: T.Tuple['mesonlib.FileOrString'], kwargs: 'CompileKW') -> bool:
        code = args[0]
        if isinstance(code, mesonlib.File):
            if code.is_built:
                FeatureNew.single_use('compiler.compiles with file created at setup time', '1.2.0', self.subproject,
                                      'It was broken and either errored or returned false.', self.current_node)
            self.interpreter.add_build_def_file(code)
            code = mesonlib.File.from_absolute_file(
                code.absolute_path(self.environment.source_dir, self.environment.build_dir))
        testname = kwargs['name']
        extra_args = functools.partial(self._determine_args, kwargs)
        deps, msg = self._determine_dependencies(kwargs['dependencies'], endl=None)
        result, cached = self.compiler.compiles(code, self.environment,
                                                extra_args=extra_args,
                                                dependencies=deps)
        if testname:
            if result:
                h = mlog.green('YES')
            else:
                h = mlog.red('NO')
            cached_msg = mlog.blue('(cached)') if cached else ''
            mlog.log('Checking if', mlog.bold(testname, True), msg, 'compiles:', h, cached_msg)
        return result

    @typed_pos_args('compiler.links', (str, mesonlib.File))
    @typed_kwargs('compiler.links', *_COMPILES_KWS)
    def links_method(self, args: T.Tuple['mesonlib.FileOrString'], kwargs: 'CompileKW') -> bool:
        code = args[0]
        compiler = None
        if isinstance(code, mesonlib.File):
            if code.is_built:
                FeatureNew.single_use('compiler.links with file created at setup time', '1.2.0', self.subproject,
                                      'It was broken and either errored or returned false.', self.current_node)
            self.interpreter.add_build_def_file(code)
            code = mesonlib.File.from_absolute_file(
                code.absolute_path(self.environment.source_dir, self.environment.build_dir))
            suffix = code.suffix
            if suffix not in self.compiler.file_suffixes:
                for_machine = self.compiler.for_machine
                clist = self.interpreter.coredata.compilers[for_machine]
                if suffix not in SUFFIX_TO_LANG:
                    # just pass it to the compiler driver
                    mlog.warning(f'Unknown suffix for test file {code}')
                elif SUFFIX_TO_LANG[suffix] not in clist:
                    mlog.warning(f'Passed {SUFFIX_TO_LANG[suffix]} source to links method, not specified for {for_machine.get_lower_case_name()} machine.')
                else:
                    compiler = clist[SUFFIX_TO_LANG[suffix]]

        testname = kwargs['name']
        extra_args = functools.partial(self._determine_args, kwargs)
        deps, msg = self._determine_dependencies(kwargs['dependencies'], compile_only=False)
        result, cached = self.compiler.links(code, self.environment,
                                             compiler=compiler,
                                             extra_args=extra_args,
                                             dependencies=deps)
        cached_msg = mlog.blue('(cached)') if cached else ''
        if testname:
            if result:
                h = mlog.green('YES')
            else:
                h = mlog.red('NO')
            mlog.log('Checking if', mlog.bold(testname, True), msg, 'links:', h, cached_msg)
        return result

    @FeatureNew('compiler.check_header', '0.47.0')
    @typed_pos_args('compiler.check_header', str)
    @typed_kwargs('compiler.check_header', *_HEADER_KWS)
    def check_header_method(self, args: T.Tuple[str], kwargs: 'HeaderKW') -> bool:
        hname = args[0]
        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['dependencies'])
        haz, cached = self.compiler.check_header(hname, kwargs['prefix'], self.environment,
                                                 extra_args=extra_args,
                                                 dependencies=deps)
        cached_msg = mlog.blue('(cached)') if cached else ''
        if required and not haz:
            raise InterpreterException(f'{self.compiler.get_display_language()} header {hname!r} not usable')
        elif haz:
            h = mlog.green('YES')
        else:
            h = mlog.red('NO')
        mlog.log('Check usable header', mlog.bold(hname, True), msg, h, cached_msg)
        return haz

    def _has_header_impl(self, hname: str, kwargs: 'HeaderKW') -> bool:
        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['dependencies'])
        haz, cached = self.compiler.has_header(hname, kwargs['prefix'], self.environment,
                                               extra_args=extra_args, dependencies=deps)
        cached_msg = mlog.blue('(cached)') if cached else ''
        if required and not haz:
            raise InterpreterException(f'{self.compiler.get_display_language()} header {hname!r} not found')
        elif haz:
            h = mlog.green('YES')
        else:
            h = mlog.red('NO')
        mlog.log('Has header', mlog.bold(hname, True), msg, h, cached_msg)
        return haz

    @typed_pos_args('compiler.has_header', str)
    @typed_kwargs('compiler.has_header', *_HEADER_KWS)
    def has_header_method(self, args: T.Tuple[str], kwargs: 'HeaderKW') -> bool:
        return self._has_header_impl(args[0], kwargs)

    @typed_pos_args('compiler.has_header_symbol', str, str)
    @typed_kwargs('compiler.has_header_symbol', *_HEADER_KWS)
    def has_header_symbol_method(self, args: T.Tuple[str, str], kwargs: 'HeaderKW') -> bool:
        hname, symbol = args
        disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False)
        if disabled:
            mlog.log('Header', mlog.bold(hname, True), 'has symbol', 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['dependencies'])
        haz, cached = self.compiler.has_header_symbol(hname, symbol, kwargs['prefix'], self.environment,
                                                      extra_args=extra_args,
                                                      dependencies=deps)
        if required and not haz:
            raise InterpreterException(f'{self.compiler.get_display_language()} symbol {symbol} not found in header {hname}')
        elif haz:
            h = mlog.green('YES')
        else:
            h = mlog.red('NO')
        cached_msg = mlog.blue('(cached)') if cached else ''
        mlog.log('Header', mlog.bold(hname, True), 'has symbol', mlog.bold(symbol, True), msg, h, cached_msg)
        return haz

    def notfound_library(self, libname: str) -> 'dependencies.ExternalLibrary':
        lib = dependencies.ExternalLibrary(libname, None,
                                           self.environment,
                                           self.compiler.language,
                                           silent=True)
        return lib

    @disablerIfNotFound
    @typed_pos_args('compiler.find_library', str)
    @typed_kwargs(
        'compiler.find_library',
        KwargInfo('required', (bool, coredata.UserFeatureOption), default=True),
        KwargInfo('has_headers', ContainerTypeInfo(list, str), listify=True, default=[], since='0.50.0'),
        KwargInfo('static', (bool, NoneType), since='0.51.0'),
        KwargInfo('disabler', bool, default=False, since='0.49.0'),
        KwargInfo('dirs', ContainerTypeInfo(list, str), listify=True, default=[]),
        *(k.evolve(name=f'header_{k.name}') for k in _HEADER_KWS)
    )
    def find_library_method(self, args: T.Tuple[str], kwargs: 'FindLibraryKW') -> 'dependencies.ExternalLibrary':
        # TODO add dependencies support?
        libname = args[0]

        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)

        # This could be done with a comprehension, but that confuses the type
        # checker, and having it check this seems valuable
        has_header_kwargs: 'HeaderKW' = {
            'required': required,
            'args': kwargs['header_args'],
            'dependencies': kwargs['header_dependencies'],
            'include_directories': kwargs['header_include_directories'],
            'prefix': kwargs['header_prefix'],
            'no_builtin_args': kwargs['header_no_builtin_args'],
        }
        for h in kwargs['has_headers']:
            if not self._has_header_impl(h, has_header_kwargs):
                return self.notfound_library(libname)

        search_dirs = extract_search_dirs(kwargs)

        prefer_static = self.environment.coredata.get_option(OptionKey('prefer_static'))
        if kwargs['static'] is True:
            libtype = mesonlib.LibType.STATIC
        elif kwargs['static'] is False:
            libtype = mesonlib.LibType.SHARED
        elif prefer_static:
            libtype = mesonlib.LibType.PREFER_STATIC
        else:
            libtype = mesonlib.LibType.PREFER_SHARED
        linkargs = self.compiler.find_library(libname, self.environment, search_dirs, libtype)
        if required and not linkargs:
            if libtype == mesonlib.LibType.PREFER_SHARED:
                libtype_s = 'shared or static'
            else:
                libtype_s = libtype.name.lower()
            raise InterpreterException('{} {} library {!r} not found'
                                       .format(self.compiler.get_display_language(),
                                               libtype_s, libname))
        lib = dependencies.ExternalLibrary(libname, linkargs, self.environment,
                                           self.compiler.language)
        return lib

    def _has_argument_impl(self, arguments: T.Union[str, T.List[str]],
                           mode: _TestMode = _TestMode.COMPILER,
                           kwargs: T.Optional['ExtractRequired'] = None) -> bool:
        """Shared implementation for methods checking compiler and linker arguments."""
        # This simplifies the callers
        if isinstance(arguments, str):
            arguments = [arguments]
        logargs: TV_LoggableList = [
            'Compiler for',
            self.compiler.get_display_language(),
            'supports{}'.format(' link' if mode is _TestMode.LINKER else ''),
            'arguments {}:'.format(' '.join(arguments)),
        ]
        kwargs = kwargs or {'required': False}
        disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False)
        if disabled:
            logargs += ['skipped: feature', mlog.bold(feature), 'disabled']
            mlog.log(*logargs)
            return False
        test = self.compiler.has_multi_link_arguments if mode is _TestMode.LINKER else self.compiler.has_multi_arguments
        result, cached = test(arguments, self.environment)
        if required and not result:
            logargs += ['not usable']
            raise InterpreterException(*logargs)
        logargs += [
            mlog.green('YES') if result else mlog.red('NO'),
            mlog.blue('(cached)') if cached else '',
        ]
        mlog.log(*logargs)
        return result

    @typed_pos_args('compiler.has_argument', str)
    @typed_kwargs('compiler.has_argument', _HAS_REQUIRED_KW)
    def has_argument_method(self, args: T.Tuple[str], kwargs: 'HasArgumentKW') -> bool:
        return self._has_argument_impl([args[0]], kwargs=kwargs)

    @typed_pos_args('compiler.has_multi_arguments', varargs=str)
    @typed_kwargs('compiler.has_multi_arguments', _HAS_REQUIRED_KW)
    @FeatureNew('compiler.has_multi_arguments', '0.37.0')
    def has_multi_arguments_method(self, args: T.Tuple[T.List[str]], kwargs: 'HasArgumentKW') -> bool:
        return self._has_argument_impl(args[0], kwargs=kwargs)

    @FeatureNew('compiler.get_supported_arguments', '0.43.0')
    @typed_pos_args('compiler.get_supported_arguments', varargs=str)
    @typed_kwargs(
        'compiler.get_supported_arguments',
        KwargInfo('checked', str, default='off', since='0.59.0',
                  validator=in_set_validator({'warn', 'require', 'off'})),
    )
    def get_supported_arguments_method(self, args: T.Tuple[T.List[str]], kwargs: 'GetSupportedArgumentKw') -> T.List[str]:
        supported_args: T.List[str] = []
        checked = kwargs['checked']

        for arg in args[0]:
            if not self._has_argument_impl([arg]):
                msg = f'Compiler for {self.compiler.get_display_language()} does not support "{arg}"'
                if checked == 'warn':
                    mlog.warning(msg)
                elif checked == 'require':
                    raise mesonlib.MesonException(msg)
            else:
                supported_args.append(arg)
        return supported_args

    @noKwargs
    @typed_pos_args('compiler.first_supported_argument', varargs=str)
    def first_supported_argument_method(self, args: T.Tuple[T.List[str]], kwargs: 'TYPE_kwargs') -> T.List[str]:
        for arg in args[0]:
            if self._has_argument_impl([arg]):
                mlog.log('First supported argument:', mlog.bold(arg))
                return [arg]
        mlog.log('First supported argument:', mlog.red('None'))
        return []

    @FeatureNew('compiler.has_link_argument', '0.46.0')
    @typed_pos_args('compiler.has_link_argument', str)
    @typed_kwargs('compiler.has_link_argument', _HAS_REQUIRED_KW)
    def has_link_argument_method(self, args: T.Tuple[str], kwargs: 'HasArgumentKW') -> bool:
        return self._has_argument_impl([args[0]], mode=_TestMode.LINKER, kwargs=kwargs)

    @FeatureNew('compiler.has_multi_link_argument', '0.46.0')
    @typed_pos_args('compiler.has_multi_link_argument', varargs=str)
    @typed_kwargs('compiler.has_multi_link_argument', _HAS_REQUIRED_KW)
    def has_multi_link_arguments_method(self, args: T.Tuple[T.List[str]], kwargs: 'HasArgumentKW') -> bool:
        return self._has_argument_impl(args[0], mode=_TestMode.LINKER, kwargs=kwargs)

    @FeatureNew('compiler.get_supported_link_arguments', '0.46.0')
    @noKwargs
    @typed_pos_args('compiler.get_supported_link_arguments', varargs=str)
    def get_supported_link_arguments_method(self, args: T.Tuple[T.List[str]], kwargs: 'TYPE_kwargs') -> T.List[str]:
        supported_args: T.List[str] = []
        for arg in args[0]:
            if self._has_argument_impl([arg], mode=_TestMode.LINKER):
                supported_args.append(arg)
        return supported_args

    @FeatureNew('compiler.first_supported_link_argument_method', '0.46.0')
    @noKwargs
    @typed_pos_args('compiler.first_supported_link_argument', varargs=str)
    def first_supported_link_argument_method(self, args: T.Tuple[T.List[str]], kwargs: 'TYPE_kwargs') -> T.List[str]:
        for arg in args[0]:
            if self._has_argument_impl([arg], mode=_TestMode.LINKER):
                mlog.log('First supported link argument:', mlog.bold(arg))
                return [arg]
        mlog.log('First supported link argument:', mlog.red('None'))
        return []

    def _has_function_attribute_impl(self, attr: str, kwargs: T.Optional['ExtractRequired'] = None) -> bool:
        """Common helper for function attribute testing."""
        logargs: TV_LoggableList = [
            f'Compiler for {self.compiler.get_display_language()} supports function attribute {attr}:',
        ]
        kwargs = kwargs or {'required': False}
        disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False)
        if disabled:
            logargs += ['skipped: feature', mlog.bold(feature), 'disabled']
            mlog.log(*logargs)
            return False
        had, cached = self.compiler.has_func_attribute(attr, self.environment)
        if required and not had:
            logargs += ['not usable']
            raise InterpreterException(*logargs)
        logargs += [
            mlog.green('YES') if had else mlog.red('NO'),
            mlog.blue('(cached)') if cached else ''
        ]
        mlog.log(*logargs)
        return had

    @FeatureNew('compiler.has_function_attribute', '0.48.0')
    @typed_pos_args('compiler.has_function_attribute', str)
    @typed_kwargs('compiler.has_function_attribute', _HAS_REQUIRED_KW)
    def has_func_attribute_method(self, args: T.Tuple[str], kwargs: 'HasArgumentKW') -> bool:
        return self._has_function_attribute_impl(args[0], kwargs)

    @FeatureNew('compiler.get_supported_function_attributes', '0.48.0')
    @noKwargs
    @typed_pos_args('compiler.get_supported_function_attributes', varargs=str)
    def get_supported_function_attributes_method(self, args: T.Tuple[T.List[str]], kwargs: 'TYPE_kwargs') -> T.List[str]:
        return [a for a in args[0] if self._has_function_attribute_impl(a)]

    @FeatureNew('compiler.get_argument_syntax_method', '0.49.0')
    @noPosargs
    @noKwargs
    def get_argument_syntax_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
        return self.compiler.get_argument_syntax()

    @FeatureNew('compiler.preprocess', '0.64.0')
    @FeatureNewKwargs('compiler.preprocess', '1.3.2', ['compile_args'], extra_message='compile_args were ignored before this version')
    @typed_pos_args('compiler.preprocess', varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList), min_varargs=1)
    @typed_kwargs(
        'compiler.preprocess',
        KwargInfo('output', str, default='@PLAINNAME@.i'),
        KwargInfo('compile_args', ContainerTypeInfo(list, str), listify=True, default=[]),
        _INCLUDE_DIRS_KW,
        _DEPENDENCIES_KW.evolve(since='1.1.0'),
    )
    def preprocess_method(self, args: T.Tuple[T.List['mesonlib.FileOrString']], kwargs: 'PreprocessKW') -> T.List[build.CustomTargetIndex]:
        compiler = self.compiler.get_preprocessor()
        sources: 'SourceOutputs' = self.interpreter.source_strings_to_files(args[0])
        if any(isinstance(s, (build.CustomTarget, build.CustomTargetIndex, build.GeneratedList)) for s in sources):
            FeatureNew.single_use('compiler.preprocess with generated sources', '1.1.0', self.subproject,
                                  location=self.current_node)

        tg_counter = next(self.preprocess_uid[self.interpreter.subdir])
        if tg_counter > 0:
            FeatureNew.single_use('compiler.preprocess used multiple times', '1.1.0', self.subproject,
                                  location=self.current_node)
        tg_name = f'preprocessor_{tg_counter}'
        tg = build.CompileTarget(
            tg_name,
            self.interpreter.subdir,
            self.subproject,
            self.environment,
            sources,
            kwargs['output'],
            compiler,
            self.interpreter.backend,
            kwargs['compile_args'],
            kwargs['include_directories'],
            kwargs['dependencies'])
        self.interpreter.add_target(tg.name, tg)
        # Expose this target as list of its outputs, so user can pass them to
        # other targets, list outputs, etc.
        private_dir = os.path.relpath(self.interpreter.backend.get_target_private_dir(tg), self.interpreter.subdir)
        return [build.CustomTargetIndex(tg, os.path.join(private_dir, o)) for o in tg.outputs]
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336264.0
meson-1.3.2/mesonbuild/interpreter/dependencyfallbacks.py0000644000175000017500000004623714516507010024102 0ustar00jpakkanejpakkanefrom __future__ import annotations

from .interpreterobjects import extract_required_kwarg
from .. import mlog
from .. import dependencies
from .. import build
from ..wrap import WrapMode
from ..mesonlib import OptionKey, extract_as_list, stringlistify, version_compare_many, listify
from ..dependencies import Dependency, DependencyException, NotFoundDependency
from ..interpreterbase import (MesonInterpreterObject, FeatureNew,
                               InterpreterException, InvalidArguments)

import typing as T
if T.TYPE_CHECKING:
    from .interpreter import Interpreter
    from ..interpreterbase import TYPE_nkwargs, TYPE_nvar
    from .interpreterobjects import SubprojectHolder


class DependencyFallbacksHolder(MesonInterpreterObject):
    def __init__(self, interpreter: 'Interpreter', names: T.List[str], allow_fallback: T.Optional[bool] = None,
                 default_options: T.Optional[T.Dict[OptionKey, str]] = None) -> None:
        super().__init__(subproject=interpreter.subproject)
        self.interpreter = interpreter
        self.subproject = interpreter.subproject
        self.coredata = interpreter.coredata
        self.build = interpreter.build
        self.environment = interpreter.environment
        self.wrap_resolver = interpreter.environment.wrap_resolver
        self.allow_fallback = allow_fallback
        self.subproject_name: T.Optional[str] = None
        self.subproject_varname: T.Optional[str] = None
        self.subproject_kwargs = {'default_options': default_options or {}}
        self.names: T.List[str] = []
        self.forcefallback: bool = False
        self.nofallback: bool = False
        for name in names:
            if not name:
                raise InterpreterException('dependency_fallbacks empty name \'\' is not allowed')
            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.')
            if name in self.names:
                raise InterpreterException(f'dependency_fallbacks name {name!r} is duplicated')
            self.names.append(name)
        self._display_name = self.names[0] if self.names else '(anonymous)'

    def set_fallback(self, fbinfo: T.Optional[T.Union[T.List[str], str]]) -> None:
        # Legacy: This converts dependency()'s fallback kwargs.
        if fbinfo is None:
            return
        if self.allow_fallback is not None:
            raise InvalidArguments('"fallback" and "allow_fallback" arguments are mutually exclusive')
        fbinfo = stringlistify(fbinfo)
        if len(fbinfo) == 0:
            # dependency('foo', fallback: []) is the same as dependency('foo', allow_fallback: false)
            self.allow_fallback = False
            return
        if len(fbinfo) == 1:
            FeatureNew.single_use('Fallback without variable name', '0.53.0', self.subproject)
            subp_name, varname = fbinfo[0], None
        elif len(fbinfo) == 2:
            subp_name, varname = fbinfo
        else:
            raise InterpreterException('Fallback info must have one or two items.')
        self._subproject_impl(subp_name, varname)

    def _subproject_impl(self, subp_name: str, varname: str) -> None:
        assert self.subproject_name is None
        self.subproject_name = subp_name
        self.subproject_varname = varname

    def _do_dependency_cache(self, kwargs: TYPE_nkwargs, func_args: TYPE_nvar, func_kwargs: TYPE_nkwargs) -> T.Optional[Dependency]:
        name = func_args[0]
        cached_dep = self._get_cached_dep(name, kwargs)
        if cached_dep:
            self._verify_fallback_consistency(cached_dep)
        return cached_dep

    def _do_dependency(self, kwargs: TYPE_nkwargs, func_args: TYPE_nvar, func_kwargs: TYPE_nkwargs) -> T.Optional[Dependency]:
        # Note that there is no df.dependency() method, this is called for names
        # given as positional arguments to dependency_fallbacks(name1, ...).
        # We use kwargs from the dependency() function, for things like version,
        # module, etc.
        name = func_args[0]
        self._handle_featurenew_dependencies(name)
        dep = dependencies.find_external_dependency(name, self.environment, kwargs)
        if dep.found():
            for_machine = self.interpreter.machine_from_native_kwarg(kwargs)
            identifier = dependencies.get_dep_identifier(name, kwargs)
            self.coredata.deps[for_machine].put(identifier, dep)
            return dep
        return None

    def _do_existing_subproject(self, kwargs: TYPE_nkwargs, func_args: TYPE_nvar, func_kwargs: TYPE_nkwargs) -> T.Optional[Dependency]:
        subp_name = func_args[0]
        varname = self.subproject_varname
        if subp_name and self._get_subproject(subp_name):
            return self._get_subproject_dep(subp_name, varname, kwargs)
        return None

    def _do_subproject(self, kwargs: TYPE_nkwargs, func_args: TYPE_nvar, func_kwargs: TYPE_nkwargs) -> T.Optional[Dependency]:
        if self.forcefallback:
            mlog.log('Looking for a fallback subproject for the dependency',
                     mlog.bold(self._display_name), 'because:\nUse of fallback dependencies is forced.')
        elif self.nofallback:
            mlog.log('Not looking for a fallback subproject for the dependency',
                     mlog.bold(self._display_name), 'because:\nUse of fallback dependencies is disabled.')
            return None
        else:
            mlog.log('Looking for a fallback subproject for the dependency',
                     mlog.bold(self._display_name))

        # dependency('foo', static: true) should implicitly add
        # default_options: ['default_library=static']
        static = kwargs.get('static')
        default_options = func_kwargs.get('default_options', {})
        if static is not None and 'default_library' not in default_options:
            default_library = 'static' if static else 'shared'
            mlog.log(f'Building fallback subproject with default_library={default_library}')
            default_options[OptionKey('default_library')] = default_library
            func_kwargs['default_options'] = default_options

        # Configure the subproject
        subp_name = self.subproject_name
        varname = self.subproject_varname
        func_kwargs.setdefault('version', [])
        if 'default_options' in kwargs and isinstance(kwargs['default_options'], str):
            func_kwargs['default_options'] = listify(kwargs['default_options'])
        self.interpreter.do_subproject(subp_name, func_kwargs)
        return self._get_subproject_dep(subp_name, varname, kwargs)

    def _get_subproject(self, subp_name: str) -> T.Optional[SubprojectHolder]:
        sub = self.interpreter.subprojects.get(subp_name)
        if sub and sub.found():
            return sub
        return None

    def _get_subproject_dep(self, subp_name: str, varname: str, kwargs: TYPE_nkwargs) -> T.Optional[Dependency]:
        # Verify the subproject is found
        subproject = self._get_subproject(subp_name)
        if not subproject:
            mlog.log('Dependency', mlog.bold(self._display_name), 'from subproject',
                     mlog.bold(subp_name), 'found:', mlog.red('NO'),
                     mlog.blue('(subproject failed to configure)'))
            return None

        # The subproject has been configured. If for any reason the dependency
        # cannot be found in this subproject we have to return not-found object
        # instead of None, because we don't want to continue the lookup on the
        # system.

        # Check if the subproject overridden at least one of the names we got.
        cached_dep = None
        for name in self.names:
            cached_dep = self._get_cached_dep(name, kwargs)
            if cached_dep:
                break

        # If we have cached_dep we did all the checks and logging already in
        # self._get_cached_dep().
        if cached_dep:
            self._verify_fallback_consistency(cached_dep)
            return cached_dep

        # Legacy: Use the variable name if provided instead of relying on the
        # subproject to override one of our dependency names
        if not varname:
            # If no variable name is specified, check if the wrap file has one.
            # If the wrap file has a variable name, better use it because the
            # subproject most probably is not using meson.override_dependency().
            for name in self.names:
                varname = self.wrap_resolver.get_varname(subp_name, name)
                if varname:
                    break
        if not varname:
            mlog.warning(f'Subproject {subp_name!r} did not override {self._display_name!r} dependency and no variable name specified')
            mlog.log('Dependency', mlog.bold(self._display_name), 'from subproject',
                     mlog.bold(subproject.subdir), 'found:', mlog.red('NO'))
            return self._notfound_dependency()

        var_dep = self._get_subproject_variable(subproject, varname) or self._notfound_dependency()
        if not var_dep.found():
            mlog.log('Dependency', mlog.bold(self._display_name), 'from subproject',
                     mlog.bold(subproject.subdir), 'found:', mlog.red('NO'))
            return var_dep

        wanted = stringlistify(kwargs.get('version', []))
        found = var_dep.get_version()
        if not self._check_version(wanted, found):
            mlog.log('Dependency', mlog.bold(self._display_name), 'from subproject',
                     mlog.bold(subproject.subdir), 'found:', mlog.red('NO'),
                     'found', mlog.normal_cyan(found), 'but need:',
                     mlog.bold(', '.join([f"'{e}'" for e in wanted])))
            return self._notfound_dependency()

        mlog.log('Dependency', mlog.bold(self._display_name), 'from subproject',
                 mlog.bold(subproject.subdir), 'found:', mlog.green('YES'),
                 mlog.normal_cyan(found) if found else None)
        return var_dep

    def _get_cached_dep(self, name: str, kwargs: TYPE_nkwargs) -> T.Optional[Dependency]:
        # Unlike other methods, this one returns not-found dependency instead
        # of None in the case the dependency is cached as not-found, or if cached
        # version does not match. In that case we don't want to continue with
        # other candidates.
        for_machine = self.interpreter.machine_from_native_kwarg(kwargs)
        identifier = dependencies.get_dep_identifier(name, kwargs)
        wanted_vers = stringlistify(kwargs.get('version', []))

        override = self.build.dependency_overrides[for_machine].get(identifier)
        if override:
            info = [mlog.blue('(overridden)' if override.explicit else '(cached)')]
            cached_dep = override.dep
            # We don't implicitly override not-found dependencies, but user could
            # have explicitly called meson.override_dependency() with a not-found
            # dep.
            if not cached_dep.found():
                mlog.log('Dependency', mlog.bold(self._display_name),
                         'found:', mlog.red('NO'), *info)
                return cached_dep
        elif self.forcefallback and self.subproject_name:
            cached_dep = None
        else:
            info = [mlog.blue('(cached)')]
            cached_dep = self.coredata.deps[for_machine].get(identifier)

        if cached_dep:
            found_vers = cached_dep.get_version()
            if not self._check_version(wanted_vers, found_vers):
                if not override:
                    # We cached this dependency on disk from a previous run,
                    # but it could got updated on the system in the meantime.
                    return None
                mlog.log('Dependency', mlog.bold(name),
                         'found:', mlog.red('NO'),
                         'found', mlog.normal_cyan(found_vers), 'but need:',
                         mlog.bold(', '.join([f"'{e}'" for e in wanted_vers])),
                         *info)
                return self._notfound_dependency()
            if found_vers:
                info = [mlog.normal_cyan(found_vers), *info]
            mlog.log('Dependency', mlog.bold(self._display_name),
                     'found:', mlog.green('YES'), *info)
            return cached_dep
        return None

    def _get_subproject_variable(self, subproject: SubprojectHolder, varname: str) -> T.Optional[Dependency]:
        try:
            var_dep = subproject.get_variable_method([varname], {})
        except InvalidArguments:
            var_dep = None
        if not isinstance(var_dep, Dependency):
            mlog.warning(f'Variable {varname!r} in the subproject {subproject.subdir!r} is',
                         'not found' if var_dep is None else 'not a dependency object')
            return None
        return var_dep

    def _verify_fallback_consistency(self, cached_dep: Dependency) -> None:
        subp_name = self.subproject_name
        varname = self.subproject_varname
        subproject = self._get_subproject(subp_name)
        if subproject and varname:
            var_dep = self._get_subproject_variable(subproject, varname)
            if var_dep and cached_dep.found() and var_dep != cached_dep:
                mlog.warning(f'Inconsistency: Subproject has overridden the dependency with another variable than {varname!r}')

    def _handle_featurenew_dependencies(self, name: str) -> None:
        'Do a feature check on dependencies used by this subproject'
        if name == 'mpi':
            FeatureNew.single_use('MPI Dependency', '0.42.0', self.subproject)
        elif name == 'pcap':
            FeatureNew.single_use('Pcap Dependency', '0.42.0', self.subproject)
        elif name == 'vulkan':
            FeatureNew.single_use('Vulkan Dependency', '0.42.0', self.subproject)
        elif name == 'libwmf':
            FeatureNew.single_use('LibWMF Dependency', '0.44.0', self.subproject)
        elif name == 'openmp':
            FeatureNew.single_use('OpenMP Dependency', '0.46.0', self.subproject)

    def _notfound_dependency(self) -> NotFoundDependency:
        return NotFoundDependency(self.names[0] if self.names else '', self.environment)

    @staticmethod
    def _check_version(wanted: T.List[str], found: str) -> bool:
        if not wanted:
            return True
        return not (found == 'undefined' or not version_compare_many(found, wanted)[0])

    def _get_candidates(self) -> T.List[T.Tuple[T.Callable[[TYPE_nkwargs, TYPE_nvar, TYPE_nkwargs], T.Optional[Dependency]], TYPE_nvar, TYPE_nkwargs]]:
        candidates = []
        # 1. check if any of the names is cached already.
        for name in self.names:
            candidates.append((self._do_dependency_cache, [name], {}))
        # 2. check if the subproject fallback has already been configured.
        if self.subproject_name:
            candidates.append((self._do_existing_subproject, [self.subproject_name], self.subproject_kwargs))
        # 3. check external dependency if we are not forced to use subproject
        if not self.forcefallback or not self.subproject_name:
            for name in self.names:
                candidates.append((self._do_dependency, [name], {}))
        # 4. configure the subproject
        if self.subproject_name:
            candidates.append((self._do_subproject, [self.subproject_name], self.subproject_kwargs))
        return candidates

    def lookup(self, kwargs: TYPE_nkwargs, force_fallback: bool = False) -> Dependency:
        mods = extract_as_list(kwargs, 'modules')
        if mods:
            self._display_name += ' (modules: {})'.format(', '.join(str(i) for i in mods))

        disabled, required, feature = extract_required_kwarg(kwargs, self.subproject)
        if disabled:
            mlog.log('Dependency', mlog.bold(self._display_name), 'skipped: feature', mlog.bold(feature), 'disabled')
            return self._notfound_dependency()

        # Check if usage of the subproject fallback is forced
        wrap_mode = self.coredata.get_option(OptionKey('wrap_mode'))
        assert isinstance(wrap_mode, WrapMode), 'for mypy'
        force_fallback_for = self.coredata.get_option(OptionKey('force_fallback_for'))
        assert isinstance(force_fallback_for, list), 'for mypy'
        self.nofallback = wrap_mode == WrapMode.nofallback
        self.forcefallback = (force_fallback or
                              wrap_mode == WrapMode.forcefallback or
                              any(name in force_fallback_for for name in self.names) or
                              self.subproject_name in force_fallback_for)

        # Add an implicit subproject fallback if none has been set explicitly,
        # unless implicit fallback is not allowed.
        # Legacy: self.allow_fallback can be None when that kwarg is not defined
        # in dependency('name'). In that case we don't want to use implicit
        # fallback when required is false because user will typically fallback
        # manually using cc.find_library() for example.
        if not self.subproject_name and self.allow_fallback is not False:
            for name in self.names:
                subp_name, varname = self.wrap_resolver.find_dep_provider(name)
                if subp_name:
                    self.forcefallback |= subp_name in force_fallback_for
                    if self.forcefallback or self.allow_fallback is True or required or self._get_subproject(subp_name):
                        self._subproject_impl(subp_name, varname)
                    break

        candidates = self._get_candidates()

        # writing just "dependency('')" is an error, because it can only fail
        if not candidates and required:
            raise InvalidArguments('Dependency is required but has no candidates.')

        # Try all candidates, only the last one is really required.
        last = len(candidates) - 1
        for i, item in enumerate(candidates):
            func, func_args, func_kwargs = item
            func_kwargs['required'] = required and (i == last)
            kwargs['required'] = required and (i == last)
            dep = func(kwargs, func_args, func_kwargs)
            if dep and dep.found():
                # Override this dependency to have consistent results in subsequent
                # dependency lookups.
                for name in self.names:
                    for_machine = self.interpreter.machine_from_native_kwarg(kwargs)
                    identifier = dependencies.get_dep_identifier(name, kwargs)
                    if identifier not in self.build.dependency_overrides[for_machine]:
                        self.build.dependency_overrides[for_machine][identifier] = \
                            build.DependencyOverride(dep, self.interpreter.current_node, explicit=False)
                return dep
            elif required and (dep or i == last):
                # This was the last candidate or the dependency has been cached
                # as not-found, or cached dependency version does not match,
                # otherwise func() would have returned None instead.
                raise DependencyException(f'Dependency {self._display_name!r} is required but not found.')
            elif dep:
                # Same as above, but the dependency is not required.
                return dep
        return self._notfound_dependency()
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0
meson-1.3.2/mesonbuild/interpreter/interpreter.py0000644000175000017500000053627214562742373022505 0ustar00jpakkanejpakkane# Copyright 2012-2021 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

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

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

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 .. import envconfig
from ..wrap import wrap, WrapMode
from .. import mesonlib
from ..mesonlib import (EnvironmentVariables, ExecutableSerialisation, MesonBugException, MesonException, HoldableObject,
                        FileMode, MachineChoice, OptionKey, listify,
                        extract_as_list, has_path_sep, path_is_in_root, PerMachine)
from ..programs import ExternalProgram, NonExistingExternalProgram
from ..dependencies import Dependency
from ..depfile import DepFile
from ..interpreterbase import ContainerTypeInfo, InterpreterBase, KwargInfo, typed_kwargs, typed_pos_args
from ..interpreterbase import noPosargs, noKwargs, permittedKwargs, noArgsFlattening, noSecondLevelHolderResolving, unholder_return
from ..interpreterbase import InterpreterException, InvalidArguments, InvalidCode, SubdirDoneRequest
from ..interpreterbase import Disabler, disablerIfNotFound
from ..interpreterbase import FeatureNew, FeatureDeprecated, FeatureBroken, FeatureNewKwargs
from ..interpreterbase import ObjectHolder, ContextManagerObject
from ..interpreterbase import stringifyUserArguments
from ..modules import ExtensionModule, ModuleObject, MutableModuleObject, NewExtensionModule, NotFoundExtensionModule
from ..optinterpreter import optname_regex

from . import interpreterobjects as OBJ
from . import compiler as compilerOBJ
from .mesonmain import MesonMain
from .dependencyfallbacks import DependencyFallbacksHolder
from .interpreterobjects import (
    SubprojectHolder,
    Test,
    RunProcess,
    extract_required_kwarg,
    extract_search_dirs,
    NullSubprojectInterpreter,
)
from .type_checking import (
    BUILD_TARGET_KWS,
    COMMAND_KW,
    CT_BUILD_ALWAYS,
    CT_BUILD_ALWAYS_STALE,
    CT_BUILD_BY_DEFAULT,
    CT_INPUT_KW,
    CT_INSTALL_DIR_KW,
    EXECUTABLE_KWS,
    JAR_KWS,
    LIBRARY_KWS,
    MULTI_OUTPUT_KW,
    OUTPUT_KW,
    DEFAULT_OPTIONS,
    DEPENDENCIES_KW,
    DEPENDS_KW,
    DEPEND_FILES_KW,
    DEPFILE_KW,
    DISABLER_KW,
    D_MODULE_VERSIONS_KW,
    ENV_KW,
    ENV_METHOD_KW,
    ENV_SEPARATOR_KW,
    INCLUDE_DIRECTORIES,
    INSTALL_KW,
    INSTALL_DIR_KW,
    INSTALL_MODE_KW,
    INSTALL_FOLLOW_SYMLINKS,
    LINK_WITH_KW,
    LINK_WHOLE_KW,
    CT_INSTALL_TAG_KW,
    INSTALL_TAG_KW,
    LANGUAGE_KW,
    NATIVE_KW,
    PRESERVE_PATH_KW,
    REQUIRED_KW,
    SHARED_LIB_KWS,
    SHARED_MOD_KWS,
    DEPENDENCY_SOURCES_KW,
    SOURCES_VARARGS,
    STATIC_LIB_KWS,
    VARIABLES_KW,
    TEST_KWS,
    NoneType,
    in_set_validator,
    env_convertor_with_method
)
from . import primitives as P_OBJ

from pathlib import Path
from enum import Enum
import os
import shutil
import uuid
import re
import stat
import collections
import typing as T
import textwrap
import importlib
import copy

if T.TYPE_CHECKING:
    import argparse

    from . import kwargs as kwtypes
    from ..backend.backends import Backend
    from ..interpreterbase.baseobjects import InterpreterObject, TYPE_var, TYPE_kwargs
    from ..programs import OverrideProgram
    from .type_checking import SourcesVarargsType

    # Input source types passed to Targets
    SourceInputs = T.Union[mesonlib.File, build.GeneratedList, build.BuildTarget, build.BothLibraries,
                           build.CustomTargetIndex, build.CustomTarget, build.GeneratedList,
                           build.ExtractedObjects, str]
    # Input source types passed to the build.Target classes
    SourceOutputs = T.Union[mesonlib.File, build.GeneratedList,
                            build.BuildTarget, build.CustomTargetIndex, build.CustomTarget,
                            build.ExtractedObjects, build.GeneratedList, build.StructuredSources]

    BuildTargetSource = T.Union[mesonlib.FileOrString, build.GeneratedTypes, build.StructuredSources]

    ProgramVersionFunc = T.Callable[[T.Union[ExternalProgram, build.Executable, OverrideProgram]], str]


def _project_version_validator(value: T.Union[T.List, str, mesonlib.File, None]) -> T.Optional[str]:
    if isinstance(value, list):
        if len(value) != 1:
            return 'when passed as array must have a length of 1'
        elif not isinstance(value[0], mesonlib.File):
            return 'when passed as array must contain a File'
    return None

class Summary:
    def __init__(self, project_name: str, project_version: str):
        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: str, values: T.Dict[str, T.Any], bool_yn: bool,
                    list_sep: T.Optional[str], subproject: str) -> None:
        for k, v in values.items():
            if k in self.sections[section]:
                raise InterpreterException(f'Summary section {section!r} already have key {k!r}')
            formatted_values = []
            for i in listify(v):
                if isinstance(i, bool):
                    if bool_yn:
                        formatted_values.append(mlog.green('YES') if i else mlog.red('NO'))
                    else:
                        formatted_values.append('true' if i else 'false')
                elif isinstance(i, (str, int)):
                    formatted_values.append(str(i))
                elif isinstance(i, (ExternalProgram, Dependency)):
                    FeatureNew.single_use('dependency or external program in summary', '0.57.0', subproject)
                    formatted_values.append(i.summary_value())
                elif isinstance(i, Disabler):
                    FeatureNew.single_use('disabler in summary', '0.64.0', subproject)
                    formatted_values.append(mlog.red('NO'))
                elif isinstance(i, coredata.UserOption):
                    FeatureNew.single_use('feature option in summary', '0.58.0', subproject)
                    formatted_values.append(i.printable_value())
                else:
                    m = 'Summary value in section {!r}, key {!r}, must be string, integer, boolean, dependency, disabler, or external program'
                    raise InterpreterException(m.format(section, k))
            self.sections[section][k] = (formatted_values, list_sep)
            self.max_key_len = max(self.max_key_len, len(k))

    def 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():
                v, list_sep = v
                padding = self.max_key_len - len(k)
                end = ' ' if v else ''
                mlog.log(' ' * 3, k + ' ' * padding + ':', end=end)
                indent = self.max_key_len + 6
                self.dump_value(v, list_sep, indent)
        mlog.log('')  # newline

    def dump_value(self, arr, list_sep, indent):
        lines_sep = '\n' + ' ' * indent
        if list_sep is None:
            mlog.log(*arr, sep=lines_sep, display_timestamp=False)
            return
        max_len = shutil.get_terminal_size().columns
        line = []
        line_len = indent
        lines_sep = list_sep.rstrip() + lines_sep
        for v in arr:
            v_len = len(v) + len(list_sep)
            if line and line_len + v_len > max_len:
                mlog.log(*line, sep=list_sep, end=lines_sep)
                line_len = indent
                line = []
            line.append(v)
            line_len += v_len
        mlog.log(*line, sep=list_sep, display_timestamp=False)

known_library_kwargs = (
    build.known_shlib_kwargs |
    build.known_stlib_kwargs |
    {f'{l}_shared_args' for l in compilers.all_languages - {'java'}} |
    {f'{l}_static_args' for l in compilers.all_languages - {'java'}}
)

known_build_target_kwargs = (
    known_library_kwargs |
    build.known_exe_kwargs |
    build.known_jar_kwargs |
    {'target_type'}
)

class InterpreterRuleRelaxation(Enum):
    ''' Defines specific relaxations of the Meson rules.

    This is intended to be used for automatically converted
    projects (CMake subprojects, build system mixing) that
    generate a Meson AST via introspection, etc.
    '''

    ALLOW_BUILD_DIR_FILE_REFERENCES = 1

permitted_dependency_kwargs = {
    'allow_fallback',
    'cmake_args',
    'cmake_module_path',
    'cmake_package_version',
    'components',
    'default_options',
    'fallback',
    'include_type',
    'language',
    'main',
    'method',
    'modules',
    'native',
    'not_found_message',
    'optional_modules',
    'private_headers',
    'required',
    'static',
    'version',
}

implicit_check_false_warning = """You should add the boolean check kwarg to the run_command call.
         It currently defaults to false,
         but it will default to true in future releases of meson.
         See also: https://github.com/mesonbuild/meson/issues/9300"""
class Interpreter(InterpreterBase, HoldableObject):

    def __init__(
                self,
                _build: build.Build,
                backend: T.Optional[Backend] = None,
                subproject: str = '',
                subdir: str = '',
                subproject_dir: str = 'subprojects',
                default_project_options: T.Optional[T.Dict[OptionKey, str]] = None,
                mock: bool = False,
                ast: T.Optional[mparser.CodeBlockNode] = None,
                is_translated: bool = False,
                relaxations: T.Optional[T.Set[InterpreterRuleRelaxation]] = None,
                user_defined_options: T.Optional['argparse.Namespace'] = None,
            ) -> None:
        super().__init__(_build.environment.get_source_dir(), subdir, subproject)
        self.active_projectname = ''
        self.build = _build
        self.environment = self.build.environment
        self.coredata = self.environment.get_coredata()
        self.backend = backend
        self.summary: T.Dict[str, 'Summary'] = {}
        self.modules: T.Dict[str, NewExtensionModule] = {}
        # 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.relaxations = relaxations or set()
        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(self.build, self)})
        self.generators: T.List[build.Generator] = []
        self.processed_buildfiles: T.Set[str] = set()
        self.project_args_frozen = False
        self.global_args_frozen = False  # implies self.project_args_frozen
        self.subprojects: T.Dict[str, SubprojectHolder] = {}
        self.subproject_stack: T.List[str] = []
        self.configure_file_outputs: T.Dict[str, int] = {}
        # 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: T.Dict[OptionKey, str] = {}
        self.build_func_dict()
        self.build_holder_map()
        self.user_defined_options = user_defined_options
        self.compilers: PerMachine[T.Dict[str, 'compilers.Compiler']] = PerMachine({}, {})

        # build_def_files needs to be defined before parse_project is called
        #
        # For non-meson subprojects, we'll be using the ast. Even if it does
        # exist we don't want to add a dependency on it, it's autogenerated
        # from the actual build files, and is just for reference.
        self.build_def_files: mesonlib.OrderedSet[str] = mesonlib.OrderedSet()
        build_filename = os.path.join(self.subdir, environment.build_filename)
        if not is_translated:
            self.build_def_files.add(build_filename)
        if not mock:
            self.parse_project()
        self._redetect_machines()

    def __getnewargs_ex__(self) -> T.Tuple[T.Tuple[object], T.Dict[str, object]]:
        raise MesonBugException('This class is unpicklable')

    def _redetect_machines(self) -> None:
        # 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'] = \
            OBJ.MachineHolder(self.build.environment.machines.build, self)
        self.builtin['host_machine'] = \
            OBJ.MachineHolder(self.build.environment.machines.host, self)
        self.builtin['target_machine'] = \
            OBJ.MachineHolder(self.build.environment.machines.target, self)

    def build_func_dict(self) -> None:
        self.funcs.update({'add_global_arguments': self.func_add_global_arguments,
                           'add_global_link_arguments': self.func_add_global_link_arguments,
                           'add_languages': self.func_add_languages,
                           'add_project_arguments': self.func_add_project_arguments,
                           'add_project_dependencies': self.func_add_project_dependencies,
                           'add_project_link_arguments': self.func_add_project_link_arguments,
                           'add_test_setup': self.func_add_test_setup,
                           'alias_target': self.func_alias_target,
                           'assert': self.func_assert,
                           'benchmark': self.func_benchmark,
                           'both_libraries': self.func_both_lib,
                           'build_target': self.func_build_target,
                           'configuration_data': self.func_configuration_data,
                           'configure_file': self.func_configure_file,
                           'custom_target': self.func_custom_target,
                           'debug': self.func_debug,
                           '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,
                           'files': self.func_files,
                           'find_program': self.func_find_program,
                           'generator': self.func_generator,
                           'get_option': self.func_get_option,
                           'get_variable': self.func_get_variable,
                           'import': self.func_import,
                           'include_directories': self.func_include_directories,
                           'install_data': self.func_install_data,
                           'install_emptydir': self.func_install_emptydir,
                           'install_headers': self.func_install_headers,
                           'install_man': self.func_install_man,
                           'install_subdir': self.func_install_subdir,
                           'install_symlink': self.func_install_symlink,
                           '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,
                           'option': self.func_option,
                           'project': self.func_project,
                           'range': self.func_range,
                           'run_command': self.func_run_command,
                           'run_target': self.func_run_target,
                           'set_variable': self.func_set_variable,
                           'structured_sources': self.func_structured_sources,
                           'subdir': self.func_subdir,
                           'shared_library': self.func_shared_lib,
                           'shared_module': self.func_shared_module,
                           'static_library': self.func_static_lib,
                           'subdir_done': self.func_subdir_done,
                           'subproject': self.func_subproject,
                           'summary': self.func_summary,
                           'test': self.func_test,
                           'unset_variable': self.func_unset_variable,
                           'vcs_tag': self.func_vcs_tag,
                           'warning': self.func_warning,
                           })
        if 'MESON_UNIT_TEST' in os.environ:
            self.funcs.update({'exception': self.func_exception})
        if 'MESON_RUNNING_IN_PROJECT_TESTS' in os.environ:
            self.funcs.update({'expect_error': self.func_expect_error})

    def build_holder_map(self) -> None:
        '''
            Build a mapping of `HoldableObject` types to their corresponding
            `ObjectHolder`s. This mapping is used in `InterpreterBase` to automatically
            holderify all returned values from methods and functions.
        '''
        self.holder_map.update({
            # Primitives
            list: P_OBJ.ArrayHolder,
            dict: P_OBJ.DictHolder,
            int: P_OBJ.IntegerHolder,
            bool: P_OBJ.BooleanHolder,
            str: P_OBJ.StringHolder,
            P_OBJ.MesonVersionString: P_OBJ.MesonVersionStringHolder,
            P_OBJ.DependencyVariableString: P_OBJ.DependencyVariableStringHolder,
            P_OBJ.OptionString: P_OBJ.OptionStringHolder,

            # Meson types
            mesonlib.File: OBJ.FileHolder,
            build.SharedLibrary: OBJ.SharedLibraryHolder,
            build.StaticLibrary: OBJ.StaticLibraryHolder,
            build.BothLibraries: OBJ.BothLibrariesHolder,
            build.SharedModule: OBJ.SharedModuleHolder,
            build.Executable: OBJ.ExecutableHolder,
            build.Jar: OBJ.JarHolder,
            build.CustomTarget: OBJ.CustomTargetHolder,
            build.CustomTargetIndex: OBJ.CustomTargetIndexHolder,
            build.Generator: OBJ.GeneratorHolder,
            build.GeneratedList: OBJ.GeneratedListHolder,
            build.ExtractedObjects: OBJ.GeneratedObjectsHolder,
            build.RunTarget: OBJ.RunTargetHolder,
            build.AliasTarget: OBJ.AliasTargetHolder,
            build.Headers: OBJ.HeadersHolder,
            build.Man: OBJ.ManHolder,
            build.EmptyDir: OBJ.EmptyDirHolder,
            build.Data: OBJ.DataHolder,
            build.SymlinkData: OBJ.SymlinkDataHolder,
            build.InstallDir: OBJ.InstallDirHolder,
            build.IncludeDirs: OBJ.IncludeDirsHolder,
            mesonlib.EnvironmentVariables: OBJ.EnvironmentVariablesHolder,
            build.StructuredSources: OBJ.StructuredSourcesHolder,
            compilers.RunResult: compilerOBJ.TryRunResultHolder,
            dependencies.ExternalLibrary: OBJ.ExternalLibraryHolder,
            coredata.UserFeatureOption: OBJ.FeatureOptionHolder,
            envconfig.MachineInfo: OBJ.MachineHolder,
            build.ConfigurationData: OBJ.ConfigurationDataHolder,
        })

        '''
            Build a mapping of `HoldableObject` base classes to their
            corresponding `ObjectHolder`s. The difference to `self.holder_map`
            is that the keys here define an upper bound instead of requiring an
            exact match.

            The mappings defined here are only used when there was no direct hit
            found in `self.holder_map`.
        '''
        self.bound_holder_map.update({
            dependencies.Dependency: OBJ.DependencyHolder,
            ExternalProgram: OBJ.ExternalProgramHolder,
            compilers.Compiler: compilerOBJ.CompilerHolder,
            ModuleObject: OBJ.ModuleObjectHolder,
            MutableModuleObject: OBJ.MutableModuleObjectHolder,
        })

    def append_holder_map(self, held_type: T.Type[mesonlib.HoldableObject], holder_type: T.Type[ObjectHolder]) -> None:
        '''
            Adds one additional mapping to the `holder_map`.

            The intended use for this function is in the `initialize` method of
            modules to register custom object holders.
        '''
        self.holder_map.update({
            held_type: holder_type
        })

    def process_new_values(self, invalues: T.List[T.Union[TYPE_var, ExecutableSerialisation]]) -> None:
        invalues = listify(invalues)
        for v in invalues:
            if isinstance(v, ObjectHolder):
                raise InterpreterException('Modules must not return ObjectHolders')
            if isinstance(v, (build.BuildTarget, build.CustomTarget, build.RunTarget)):
                self.add_target(v.name, v)
            elif isinstance(v, list):
                self.process_new_values(v)
            elif isinstance(v, ExecutableSerialisation):
                v.subproject = self.subproject
                self.build.install_scripts.append(v)
            elif isinstance(v, build.Data):
                self.build.data.append(v)
            elif isinstance(v, build.SymlinkData):
                self.build.symlinks.append(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 isinstance(v, build.InstallDir):
                self.build.install_dirs.append(v)
            elif isinstance(v, Test):
                self.build.tests.append(v)
            elif isinstance(v, (int, str, bool, Disabler, ObjectHolder, build.GeneratedList,
                                ExternalProgram, build.ConfigurationData)):
                pass
            else:
                raise InterpreterException(f'Module returned a value of unknown type {v!r}.')

    def handle_meson_version(self, pv: str, location: mparser.BaseNode) -> None:
        if not mesonlib.version_compare(coredata.stable_version, pv):
            raise InterpreterException.from_node(f'Meson version is {coredata.version} but project requires {pv}', node=location)
        mesonlib.project_meson_versions[self.subproject] = pv

    def handle_meson_version_from_ast(self) -> None:
        if not self.ast.lines:
            return
        project = self.ast.lines[0]
        # first line is always project()
        if not isinstance(project, mparser.FunctionNode):
            return
        for kw, val in project.args.kwargs.items():
            assert isinstance(kw, mparser.IdNode), 'for mypy'
            if kw.value == 'meson_version':
                # mypy does not understand "and isinstance"
                if isinstance(val, mparser.BaseStringNode):
                    self.handle_meson_version(val.value, val)

    def get_build_def_files(self) -> mesonlib.OrderedSet[str]:
        return self.build_def_files

    def add_build_def_file(self, f: mesonlib.FileOrString) -> None:
        # 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 = Path(self.environment.get_source_dir())
            builddir = Path(self.environment.get_build_dir())
            try:
                f_ = Path(f).resolve()
            except OSError:
                f_ = Path(f)
                s = f_.stat()
                if (hasattr(s, 'st_file_attributes') and
                        s.st_file_attributes & stat.FILE_ATTRIBUTE_REPARSE_POINT != 0 and
                        s.st_reparse_tag == stat.IO_REPARSE_TAG_APPEXECLINK):
                    # This is a Windows Store link which we can't
                    # resolve, so just do our best otherwise.
                    f_ = f_.parent.resolve() / f_.name
                else:
                    raise
            if builddir in f_.parents:
                return
            if srcdir in f_.parents:
                f_ = f_.relative_to(srcdir)
            f = str(f_)
        else:
            return
        if f not in self.build_def_files:
            self.build_def_files.add(f)

    def get_variables(self) -> T.Dict[str, InterpreterObject]:
        return self.variables

    def check_stdlibs(self) -> None:
        machine_choices = [MachineChoice.HOST]
        if self.coredata.is_cross_build():
            machine_choices.append(MachineChoice.BUILD)
        for for_machine in machine_choices:
            props = self.build.environment.properties[for_machine]
            for l in self.coredata.compilers[for_machine].keys():
                try:
                    di = mesonlib.stringlistify(props.get_stdlib(l))
                except KeyError:
                    continue
                if len(di) == 1:
                    FeatureNew.single_use('stdlib without variable name', '0.56.0', self.subproject, location=self.current_node)
                kwargs = {'native': for_machine is MachineChoice.BUILD,
                          }
                name = l + '_stdlib'
                df = DependencyFallbacksHolder(self, [name])
                df.set_fallback(di)
                dep = df.lookup(kwargs, force_fallback=True)
                self.build.stdlibs[for_machine][l] = dep

    @typed_pos_args('import', str)
    @typed_kwargs(
        'import',
        REQUIRED_KW.evolve(since='0.59.0'),
        DISABLER_KW.evolve(since='0.59.0'),
    )
    @disablerIfNotFound
    def func_import(self, node: mparser.BaseNode, args: T.Tuple[str],
                    kwargs: 'kwtypes.FuncImportModule') -> T.Union[ExtensionModule, NewExtensionModule, NotFoundExtensionModule]:
        modname = args[0]
        disabled, required, _ = extract_required_kwarg(kwargs, self.subproject)
        if disabled:
            return NotFoundExtensionModule(modname)

        expect_unstable = False
        # Some tests use "unstable_" instead of "unstable-", and that happens to work because
        # of implementation details
        if modname.startswith(('unstable-', 'unstable_')):
            if modname.startswith('unstable_'):
                mlog.deprecation(f'Importing unstable modules as "{modname}" instead of "{modname.replace("_", "-", 1)}"',
                                 location=node)
            real_modname = modname[len('unstable') + 1:]  # + 1 to handle the - or _
            expect_unstable = True
        else:
            real_modname = modname

        if real_modname in self.modules:
            return self.modules[real_modname]
        try:
            module = importlib.import_module(f'mesonbuild.modules.{real_modname}')
        except ImportError:
            if required:
                raise InvalidArguments(f'Module "{modname}" does not exist')
            ext_module = NotFoundExtensionModule(real_modname)
        else:
            ext_module = module.initialize(self)
            assert isinstance(ext_module, (ExtensionModule, NewExtensionModule))
            self.build.modules.append(real_modname)
        if ext_module.INFO.added:
            FeatureNew.single_use(f'module {ext_module.INFO.name}', ext_module.INFO.added, self.subproject, location=node)
        if ext_module.INFO.deprecated:
            FeatureDeprecated.single_use(f'module {ext_module.INFO.name}', ext_module.INFO.deprecated, self.subproject, location=node)
        if expect_unstable and not ext_module.INFO.unstable and ext_module.INFO.stabilized is None:
            raise InvalidArguments(f'Module {ext_module.INFO.name} has never been unstable, remove "unstable-" prefix.')
        if ext_module.INFO.stabilized is not None:
            if expect_unstable:
                FeatureDeprecated.single_use(
                    f'module {ext_module.INFO.name} has been stabilized',
                    ext_module.INFO.stabilized, self.subproject,
                    'drop "unstable-" prefix from the module name',
                    location=node)
            else:
                FeatureNew.single_use(
                    f'module {ext_module.INFO.name} as stable module',
                    ext_module.INFO.stabilized, self.subproject,
                    f'Consider either adding "unstable-" to the module name, or updating the meson required version to ">= {ext_module.INFO.stabilized}"',
                    location=node)
        elif ext_module.INFO.unstable:
            if not expect_unstable:
                if required:
                    raise InvalidArguments(f'Module "{ext_module.INFO.name}" has not been stabilized, and must be imported as unstable-{ext_module.INFO.name}')
                ext_module = NotFoundExtensionModule(real_modname)
            else:
                mlog.warning(f'Module {ext_module.INFO.name} has no backwards or forwards compatibility and might not exist in future releases.', location=node, fatal=False)

        self.modules[real_modname] = ext_module
        return ext_module

    @typed_pos_args('files', varargs=str)
    @noKwargs
    def func_files(self, node: mparser.FunctionNode, args: T.Tuple[T.List[str]], kwargs: 'TYPE_kwargs') -> T.List[mesonlib.File]:
        return self.source_strings_to_files(args[0])

    @noPosargs
    @typed_kwargs(
        'declare_dependency',
        KwargInfo('compile_args', ContainerTypeInfo(list, str), listify=True, default=[]),
        INCLUDE_DIRECTORIES.evolve(name='d_import_dirs', since='0.62.0'),
        D_MODULE_VERSIONS_KW.evolve(since='0.62.0'),
        KwargInfo('link_args', ContainerTypeInfo(list, str), listify=True, default=[]),
        DEPENDENCIES_KW,
        INCLUDE_DIRECTORIES,
        LINK_WITH_KW,
        LINK_WHOLE_KW.evolve(since='0.46.0'),
        DEPENDENCY_SOURCES_KW,
        KwargInfo('extra_files', ContainerTypeInfo(list, (mesonlib.File, str)), listify=True, default=[], since='1.2.0'),
        VARIABLES_KW.evolve(since='0.54.0', since_values={list: '0.56.0'}),
        KwargInfo('version', (str, NoneType)),
        KwargInfo('objects', ContainerTypeInfo(list, build.ExtractedObjects), listify=True, default=[], since='1.1.0'),
    )
    def func_declare_dependency(self, node: mparser.BaseNode, args: T.List[TYPE_var],
                                kwargs: kwtypes.FuncDeclareDependency) -> dependencies.Dependency:
        deps = kwargs['dependencies']
        incs = self.extract_incdirs(kwargs)
        libs = kwargs['link_with']
        libs_whole = kwargs['link_whole']
        objects = kwargs['objects']
        sources = self.source_strings_to_files(kwargs['sources'])
        extra_files = self.source_strings_to_files(kwargs['extra_files'])
        compile_args = kwargs['compile_args']
        link_args = kwargs['link_args']
        variables = kwargs['variables']
        version = kwargs['version']
        if version is None:
            version = self.project_version
        d_module_versions = kwargs['d_module_versions']
        d_import_dirs = self.extract_incdirs(kwargs, 'd_import_dirs')
        srcdir = Path(self.environment.source_dir)
        # convert variables which refer to an -uninstalled.pc style datadir
        for k, v in variables.items():
            try:
                p = Path(v)
            except ValueError:
                continue
            else:
                if not self.is_subproject() and srcdir / self.subproject_dir in p.parents:
                    continue
                if p.is_absolute() and p.is_dir() and srcdir / self.root_subdir in [p] + list(Path(os.path.abspath(p)).parents):
                    variables[k] = P_OBJ.DependencyVariableString(v)

        dep = dependencies.InternalDependency(version, incs, compile_args,
                                              link_args, libs, libs_whole, sources, extra_files,
                                              deps, variables, d_module_versions, d_import_dirs,
                                              objects)
        return dep

    @typed_pos_args('assert', bool, optargs=[str])
    @noKwargs
    def func_assert(self, node: mparser.FunctionNode, args: T.Tuple[bool, T.Optional[str]],
                    kwargs: 'TYPE_kwargs') -> None:
        value, message = args
        if message is None:
            FeatureNew.single_use('assert function without message argument', '0.53.0', self.subproject, location=node)

        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(f'Expected {argcount} arguments, got {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.')

    # Executables aren't actually accepted, but we allow them here to allow for
    # better error messages when overridden
    @typed_pos_args(
        'run_command',
        (build.Executable, ExternalProgram, compilers.Compiler, mesonlib.File, str),
        varargs=(build.Executable, ExternalProgram, compilers.Compiler, mesonlib.File, str))
    @typed_kwargs(
        'run_command',
        KwargInfo('check', (bool, NoneType), since='0.47.0'),
        KwargInfo('capture', bool, default=True, since='0.47.0'),
        ENV_KW.evolve(since='0.50.0'),
    )
    def func_run_command(self, node: mparser.BaseNode,
                         args: T.Tuple[T.Union[build.Executable, ExternalProgram, compilers.Compiler, mesonlib.File, str],
                                       T.List[T.Union[build.Executable, ExternalProgram, compilers.Compiler, mesonlib.File, str]]],
                         kwargs: 'kwtypes.RunCommand') -> RunProcess:
        return self.run_command_impl(args, kwargs)

    def run_command_impl(self,
                         args: T.Tuple[T.Union[build.Executable, ExternalProgram, compilers.Compiler, mesonlib.File, str],
                                       T.List[T.Union[build.Executable, ExternalProgram, compilers.Compiler, mesonlib.File, str]]],
                         kwargs: 'kwtypes.RunCommand',
                         in_builddir: bool = False) -> RunProcess:
        cmd, cargs = args
        capture = kwargs['capture']
        env = kwargs['env']
        srcdir = self.environment.get_source_dir()
        builddir = self.environment.get_build_dir()

        check = kwargs['check']
        if check is None:
            mlog.warning(implicit_check_false_warning, once=True)
            check = False

        overridden_msg = ('Program {!r} was overridden with the compiled '
                          'executable {!r} and therefore cannot be used during '
                          'configuration')
        expanded_args: T.List[str] = []
        if isinstance(cmd, build.Executable):
            for name, exe in self.build.find_overrides.items():
                if cmd == exe:
                    progname = name
                    break
            else:
                raise InterpreterException(f'Program {cmd.description()!r} is a compiled executable and therefore cannot be used during configuration')
            raise InterpreterException(overridden_msg.format(progname, cmd.description()))
        if isinstance(cmd, ExternalProgram):
            if not cmd.found():
                raise InterpreterException(f'command {cmd.get_name()!r} not found or not executable')
        elif isinstance(cmd, compilers.Compiler):
            exelist = cmd.get_exelist()
            cmd = exelist[0]
            prog = ExternalProgram(cmd, silent=True)
            if not prog.found():
                raise InterpreterException(f'Program {cmd!r} not found or not executable')
            cmd = prog
            expanded_args = exelist[1:]
        else:
            if isinstance(cmd, mesonlib.File):
                cmd = cmd.absolute_path(srcdir, builddir)
            # 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(f'Program or command {cmd!r} not found or not executable')
            cmd = prog
        for a in 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, ExternalProgram):
                expanded_args.append(a.get_path())
            elif isinstance(a, compilers.Compiler):
                FeatureNew.single_use('Compiler object as a variadic argument to `run_command`', '0.61.0', self.subproject, location=self.current_node)
                prog = ExternalProgram(a.exelist[0], silent=True)
                if not prog.found():
                    raise InterpreterException(f'Program {cmd!r} not found or not executable')
                expanded_args.append(prog.get_path())
            else:
                raise InterpreterException(overridden_msg.format(a.name, cmd.description()))

        # 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)

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

    @typed_pos_args('subproject', str)
    @typed_kwargs(
        'subproject',
        REQUIRED_KW,
        DEFAULT_OPTIONS.evolve(since='0.38.0'),
        KwargInfo('version', ContainerTypeInfo(list, str), default=[], listify=True),
    )
    def func_subproject(self, nodes: mparser.BaseNode, args: T.Tuple[str], kwargs: kwtypes.Subproject) -> SubprojectHolder:
        kw: kwtypes.DoSubproject = {
            'required': kwargs['required'],
            'default_options': kwargs['default_options'],
            'version': kwargs['version'],
            'options': None,
            'cmake_options': [],
        }
        return self.do_subproject(args[0], kw)

    def disabled_subproject(self, subp_name: str, disabled_feature: T.Optional[str] = None,
                            exception: T.Optional[Exception] = None) -> SubprojectHolder:
        sub = SubprojectHolder(NullSubprojectInterpreter(), os.path.join(self.subproject_dir, subp_name),
                               disabled_feature=disabled_feature, exception=exception)
        self.subprojects[subp_name] = sub
        return sub

    def do_subproject(self, subp_name: str, kwargs: kwtypes.DoSubproject, force_method: T.Optional[wrap.Method] = None) -> SubprojectHolder:
        disabled, required, feature = extract_required_kwarg(kwargs, self.subproject)
        if disabled:
            mlog.log('Subproject', mlog.bold(subp_name), ':', 'skipped: feature', mlog.bold(feature), 'disabled')
            return self.disabled_subproject(subp_name, disabled_feature=feature)

        default_options = {k.evolve(subproject=subp_name): v for k, v in kwargs['default_options'].items()}

        if subp_name == '':
            raise InterpreterException('Subproject name must not be empty.')
        if subp_name[0] == '.':
            raise InterpreterException('Subproject name must not start with a period.')
        if '..' in subp_name:
            raise InterpreterException('Subproject name must not contain a ".." path segment.')
        if os.path.isabs(subp_name):
            raise InterpreterException('Subproject name must not be an absolute path.')
        if has_path_sep(subp_name):
            mlog.warning('Subproject name has a path separator. This may cause unexpected behaviour.',
                         location=self.current_node)
        if subp_name in self.subproject_stack:
            fullstack = self.subproject_stack + [subp_name]
            incpath = ' => '.join(fullstack)
            raise InvalidCode(f'Recursive include of subprojects: {incpath}.')
        if subp_name in self.subprojects:
            subproject = self.subprojects[subp_name]
            if required and not subproject.found():
                raise InterpreterException(f'Subproject "{subproject.subdir}" required but not found.')
            if kwargs['version']:
                pv = self.build.subprojects[subp_name]
                wanted = kwargs['version']
                if pv == 'undefined' or not mesonlib.version_compare_many(pv, wanted)[0]:
                    raise InterpreterException(f'Subproject {subp_name} version is {pv} but {wanted} required.')
            return subproject

        r = self.environment.wrap_resolver
        try:
            subdir, method = r.resolve(subp_name, force_method)
        except wrap.WrapException as e:
            if not required:
                mlog.log(e)
                mlog.log('Subproject ', mlog.bold(subp_name), 'is buildable:', mlog.red('NO'), '(disabling)')
                return self.disabled_subproject(subp_name, exception=e)
            raise e

        os.makedirs(os.path.join(self.build.environment.get_build_dir(), subdir), exist_ok=True)
        self.global_args_frozen = True

        stack = ':'.join(self.subproject_stack + [subp_name])
        m = ['\nExecuting subproject', mlog.bold(stack)]
        if method != 'meson':
            m += ['method', mlog.bold(method)]
        mlog.log(*m, '\n', nested=False)

        methods_map: T.Dict[wrap.Method, T.Callable[[str, str, T.Dict[OptionKey, str, kwtypes.DoSubproject]], SubprojectHolder]] = {
            'meson': self._do_subproject_meson,
            'cmake': self._do_subproject_cmake,
            'cargo': self._do_subproject_cargo,
        }

        try:
            return methods_map[method](subp_name, subdir, default_options, kwargs)
        # Invalid code is always an error
        except InvalidCode:
            raise
        except Exception as e:
            if not required:
                with mlog.nested(subp_name):
                    # 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(subdir), 'is buildable:', mlog.red('NO'), '(disabling)')
                return self.disabled_subproject(subp_name, exception=e)
            raise e

    def _do_subproject_meson(self, subp_name: str, subdir: str,
                             default_options: T.Dict[OptionKey, str],
                             kwargs: kwtypes.DoSubproject,
                             ast: T.Optional[mparser.CodeBlockNode] = None,
                             build_def_files: T.Optional[T.List[str]] = None,
                             relaxations: T.Optional[T.Set[InterpreterRuleRelaxation]] = None) -> SubprojectHolder:
        with mlog.nested(subp_name):
            if ast:
                # Debug print the generated meson file
                from ..ast import AstIndentationGenerator, AstPrinter
                printer = AstPrinter(update_ast_line_nos=True)
                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", encoding='utf-8') as f:
                    f.write(printer.result)
                mlog.log('Generated Meson AST:', meson_filename)
                mlog.cmd_ci_include(meson_filename)

            new_build = self.build.copy()
            subi = Interpreter(new_build, self.backend, subp_name, subdir, self.subproject_dir,
                               default_options, ast=ast, is_translated=(ast is not None),
                               relaxations=relaxations,
                               user_defined_options=self.user_defined_options)
            # Those lists are shared by all interpreters. That means that
            # even if the subproject fails, any modification that the subproject
            # made to those lists will affect the parent project.
            subi.subprojects = self.subprojects
            subi.modules = self.modules
            subi.holder_map = self.holder_map
            subi.bound_holder_map = self.bound_holder_map
            subi.summary = self.summary

            subi.subproject_stack = self.subproject_stack + [subp_name]
            current_active = self.active_projectname
            with mlog.nested_warnings():
                subi.run()
                subi_warnings = mlog.get_warning_count()
            mlog.log('Subproject', mlog.bold(subp_name), 'finished.')

        mlog.log()

        if kwargs['version']:
            pv = subi.project_version
            wanted = kwargs['version']
            if pv == 'undefined' or not mesonlib.version_compare_many(pv, wanted)[0]:
                raise InterpreterException(f'Subproject {subp_name} version is {pv} but {wanted} required.')
        self.active_projectname = current_active
        self.subprojects.update(subi.subprojects)
        self.subprojects[subp_name] = SubprojectHolder(subi, subdir, warnings=subi_warnings,
                                                       callstack=self.subproject_stack)
        # Duplicates are possible when subproject uses files from project root
        if build_def_files:
            self.build_def_files.update(build_def_files)
        # We always need the subi.build_def_files, to propagate sub-sub-projects
        self.build_def_files.update(subi.build_def_files)
        self.build.merge(subi.build)
        self.build.subprojects[subp_name] = subi.project_version
        return self.subprojects[subp_name]

    def _do_subproject_cmake(self, subp_name: str, subdir: str,
                             default_options: T.Dict[OptionKey, str],
                             kwargs: kwtypes.DoSubproject) -> SubprojectHolder:
        from ..cmake import CMakeInterpreter
        with mlog.nested(subp_name):
            prefix = self.coredata.options[OptionKey('prefix')].value

            from ..modules.cmake import CMakeSubprojectOptions
            options = kwargs.get('options') or CMakeSubprojectOptions()
            cmake_options = kwargs.get('cmake_options', []) + options.cmake_options
            cm_int = CMakeInterpreter(Path(subdir), Path(prefix), self.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(options.target_options)
            result = self._do_subproject_meson(
                    subp_name, subdir, default_options,
                    kwargs, ast,
                    [str(f) for f in cm_int.bs_files],
                    relaxations={
                        InterpreterRuleRelaxation.ALLOW_BUILD_DIR_FILE_REFERENCES,
                    }
            )
            result.cm_interpreter = cm_int
        return result

    def _do_subproject_cargo(self, subp_name: str, subdir: str,
                             default_options: T.Dict[OptionKey, str],
                             kwargs: kwtypes.DoSubproject) -> SubprojectHolder:
        from .. import cargo
        FeatureNew.single_use('Cargo subproject', '1.3.0', self.subproject, location=self.current_node)
        with mlog.nested(subp_name):
            ast = cargo.interpret(subp_name, subdir, self.environment)
            return self._do_subproject_meson(
                subp_name, subdir, default_options, kwargs, ast,
                # FIXME: Are there other files used by cargo interpreter?
                [os.path.join(subdir, 'Cargo.toml')])

    def get_option_internal(self, optname: str) -> coredata.UserOption:
        key = OptionKey.from_string(optname).evolve(subproject=self.subproject)

        if not key.is_project():
            for opts in [self.coredata.options, compilers.base_options]:
                v = opts.get(key)
                if v is None or v.yielding:
                    v = opts.get(key.as_root())
                if v is not None:
                    assert isinstance(v, coredata.UserOption), 'for mypy'
                    return v

        try:
            opt = self.coredata.options[key]
            if opt.yielding and key.subproject and key.as_root() in self.coredata.options:
                popt = self.coredata.options[key.as_root()]
                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(optname, opt_type, self.subproject, popt_type),
                                 location=self.current_node)
            return opt
        except KeyError:
            pass

        raise InterpreterException(f'Tried to access unknown option {optname!r}.')

    @typed_pos_args('get_option', str)
    @noKwargs
    def func_get_option(self, nodes: mparser.BaseNode, args: T.Tuple[str],
                        kwargs: 'TYPE_kwargs') -> T.Union[coredata.UserOption, 'TYPE_var']:
        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.')

        if optname_regex.search(optname.split('.', maxsplit=1)[-1]) is not None:
            raise InterpreterException(f'Invalid option name {optname!r}')

        opt = self.get_option_internal(optname)
        if isinstance(opt, coredata.UserFeatureOption):
            opt.name = optname
            return opt
        elif isinstance(opt, coredata.UserOption):
            if isinstance(opt.value, str):
                return P_OBJ.OptionString(opt.value, f'{{{optname}}}')
            return opt.value
        return opt

    @typed_pos_args('configuration_data', optargs=[dict])
    @noKwargs
    def func_configuration_data(self, node: mparser.BaseNode, args: T.Tuple[T.Optional[T.Dict[str, T.Any]]],
                                kwargs: 'TYPE_kwargs') -> build.ConfigurationData:
        initial_values = args[0]
        if initial_values is not None:
            FeatureNew.single_use('configuration_data dictionary', '0.49.0', self.subproject, location=node)
            for k, v in initial_values.items():
                if not isinstance(v, (str, int, bool)):
                    raise InvalidArguments(
                        f'"configuration_data": initial value dictionary key "{k!r}"" must be "str | int | bool", not "{v!r}"')
        return build.ConfigurationData(initial_values)

    def set_backend(self) -> None:
        # The backend is already set when parsing subprojects
        if self.backend is not None:
            return
        from ..backend import backends

        if OptionKey('genvslite') in self.user_defined_options.cmd_line_options.keys():
            # Use of the '--genvslite vsxxxx' option ultimately overrides any '--backend xxx'
            # option the user may specify.
            backend_name = self.coredata.get_option(OptionKey('genvslite'))
            self.backend = backends.get_genvslite_backend(backend_name, self.build, self)
        else:
            backend_name = self.coredata.get_option(OptionKey('backend'))
            self.backend = backends.get_backend_from_name(backend_name, self.build, self)

        if self.backend is None:
            raise InterpreterException(f'Unknown backend "{backend_name}".')
        if backend_name != self.backend.name:
            if self.backend.name.startswith('vs'):
                mlog.log('Auto detected Visual Studio backend:', mlog.bold(self.backend.name))
            if not self.environment.first_invocation:
                raise MesonBugException(f'Backend changed from {backend_name} to {self.backend.name}')
            self.coredata.set_option(OptionKey('backend'), self.backend.name, first_invocation=True)

        # 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_name)

        options = {k: v for k, v in self.environment.options.items() if k.is_backend()}
        self.coredata.set_options(options)

    @typed_pos_args('project', str, varargs=str)
    @typed_kwargs(
        'project',
        DEFAULT_OPTIONS,
        KwargInfo('meson_version', (str, NoneType)),
        KwargInfo(
            'version',
            (str, mesonlib.File, NoneType, list),
            default='undefined',
            validator=_project_version_validator,
            convertor=lambda x: x[0] if isinstance(x, list) else x,
        ),
        KwargInfo('license', (ContainerTypeInfo(list, str), NoneType), default=None, listify=True),
        KwargInfo('license_files', ContainerTypeInfo(list, str), default=[], listify=True, since='1.1.0'),
        KwargInfo('subproject_dir', str, default='subprojects'),
    )
    def func_project(self, node: mparser.FunctionNode, args: T.Tuple[str, T.List[str]], kwargs: 'kwtypes.Project') -> None:
        proj_name, proj_langs = args
        if ':' in proj_name:
            raise InvalidArguments(f"Project name {proj_name!r} must not contain ':'")

        # This needs to be evaluated as early as possible, as meson uses this
        # for things like deprecation testing.
        if kwargs['meson_version']:
            self.handle_meson_version(kwargs['meson_version'], node)

        # Load "meson.options" before "meson_options.txt", and produce a warning if
        # it is being used with an old version. I have added check that if both
        # exist the warning isn't raised
        option_file = os.path.join(self.source_root, self.subdir, 'meson.options')
        old_option_file = os.path.join(self.source_root, self.subdir, 'meson_options.txt')

        if os.path.exists(option_file):
            if os.path.exists(old_option_file):
                if os.path.samefile(option_file, old_option_file):
                    mlog.debug("Not warning about meson.options with version minimum < 1.1 because meson_options.txt also exists")
                else:
                    raise MesonException("meson.options and meson_options.txt both exist, but are not the same file.")
            else:
                FeatureNew.single_use('meson.options file', '1.1', self.subproject, 'Use meson_options.txt instead')
        else:
            option_file = old_option_file
        if os.path.exists(option_file):
            oi = optinterpreter.OptionInterpreter(self.subproject)
            oi.process(option_file)
            self.coredata.update_project_options(oi.options)
            self.add_build_def_file(option_file)

        if self.subproject:
            self.project_default_options = {k.evolve(subproject=self.subproject): v
                                            for k, v in kwargs['default_options'].items()}
        else:
            self.project_default_options = kwargs['default_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.
        #
        # If this is the first invocation we always need to initialize
        # builtins, if this is a subproject that is new in a re-invocation we
        # need to initialize builtins for that
        if self.environment.first_invocation or (self.subproject != '' and self.subproject not in self.coredata.initialized_subprojects):
            default_options = self.project_default_options.copy()
            default_options.update(self.default_project_options)
            self.coredata.init_builtins(self.subproject)
            self.coredata.initialized_subprojects.add(self.subproject)
        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

        version = kwargs['version']
        if isinstance(version, mesonlib.File):
            FeatureNew.single_use('version from file', '0.57.0', self.subproject, location=node)
            self.add_build_def_file(version)
            ifname = version.absolute_path(self.environment.source_dir,
                                           self.environment.build_dir)
            try:
                ver_data = Path(ifname).read_text(encoding='utf-8').split('\n')
            except FileNotFoundError:
                raise InterpreterException('Version file not found.')
            if len(ver_data) == 2 and ver_data[1] == '':
                ver_data = ver_data[0:1]
            if len(ver_data) != 1:
                raise InterpreterException('Version file must contain exactly one line of text.')
            self.project_version = ver_data[0]
        else:
            self.project_version = version

        if self.build.project_version is None:
            self.build.project_version = self.project_version

        if kwargs['license'] is None:
            proj_license = ['unknown']
            if kwargs['license_files']:
                raise InvalidArguments('Project `license` name must be specified when `license_files` is set')
        else:
            proj_license = kwargs['license']
        proj_license_files = []
        for i in self.source_strings_to_files(kwargs['license_files']):
            ifname = i.absolute_path(self.environment.source_dir,
                                     self.environment.build_dir)
            proj_license_files.append((ifname, i))
        self.build.dep_manifest[proj_name] = build.DepManifest(self.project_version, proj_license,
                                                               proj_license_files, self.subproject)
        if self.subproject in self.build.projects:
            raise InvalidCode('Second call to project().')

        # spdirname is the subproject_dir for this project, relative to self.subdir.
        # self.subproject_dir is the subproject_dir for the main project, relative to top source dir.
        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.')
        if not self.is_subproject():
            self.subproject_dir = spdirname
        self.build.subproject_dir = self.subproject_dir

        # Load wrap files from this (sub)project.
        wrap_mode = self.coredata.get_option(OptionKey('wrap_mode'))
        if not self.is_subproject() or wrap_mode != WrapMode.nopromote:
            subdir = os.path.join(self.subdir, spdirname)
            r = wrap.Resolver(self.environment.get_source_dir(), subdir, self.subproject, wrap_mode)
            if self.is_subproject():
                self.environment.wrap_resolver.merge_wraps(r)
            else:
                self.environment.wrap_resolver = r

        self.build.projects[self.subproject] = proj_name
        mlog.log('Project name:', mlog.bold(proj_name))
        mlog.log('Project version:', mlog.bold(self.project_version))

        if not self.is_subproject():
            # We have to activate VS before adding languages and before calling
            # self.set_backend() otherwise it wouldn't be able to detect which
            # vs backend version we need. But after setting default_options in case
            # the project sets vs backend by default.
            backend = self.coredata.get_option(OptionKey('backend'))
            vsenv = self.coredata.get_option(OptionKey('vsenv'))
            force_vsenv = vsenv or backend.startswith('vs')
            mesonlib.setup_vsenv(force_vsenv)

        self.add_languages(proj_langs, True, MachineChoice.HOST)
        self.add_languages(proj_langs, False, MachineChoice.BUILD)

        self.set_backend()
        if not self.is_subproject():
            self.check_stdlibs()

    @typed_kwargs('add_languages', KwargInfo('native', (bool, NoneType), since='0.54.0'), REQUIRED_KW)
    @typed_pos_args('add_languages', varargs=str)
    def func_add_languages(self, node: mparser.FunctionNode, args: T.Tuple[T.List[str]], kwargs: 'kwtypes.FuncAddLanguages') -> bool:
        langs = args[0]
        disabled, required, feature = extract_required_kwarg(kwargs, self.subproject)
        native = kwargs['native']

        if disabled:
            for lang in sorted(langs, key=compilers.sort_clink):
                mlog.log('Compiler for language', mlog.bold(lang), 'skipped: feature', mlog.bold(feature), 'disabled')
            return False
        if native is not None:
            return self.add_languages(langs, required, self.machine_from_native_kwarg(kwargs))
        else:
            # absent 'native' means 'both' for backwards compatibility
            tv = FeatureNew.get_target_version(self.subproject)
            if FeatureNew.check_version(tv, '0.54.0'):
                mlog.warning('add_languages is missing native:, assuming languages are wanted for both host and build.',
                             location=node)

            success = self.add_languages(langs, False, MachineChoice.BUILD)
            success &= self.add_languages(langs, required, MachineChoice.HOST)
            return success

    def _stringify_user_arguments(self, args: T.List[TYPE_var], func_name: str) -> T.List[str]:
        try:
            return [stringifyUserArguments(i, self.subproject) for i in args]
        except InvalidArguments as e:
            raise InvalidArguments(f'{func_name}(): {str(e)}')

    @noArgsFlattening
    @noKwargs
    def func_message(self, node: mparser.BaseNode, args, kwargs):
        if len(args) > 1:
            FeatureNew.single_use('message with more than one argument', '0.54.0', self.subproject, location=node)
        args_str = self._stringify_user_arguments(args, 'message')
        self.message_impl(args_str)

    def message_impl(self, args):
        mlog.log(mlog.bold('Message:'), *args)

    @noArgsFlattening
    @FeatureNew('summary', '0.53.0')
    @typed_pos_args('summary', (str, dict), optargs=[object])
    @typed_kwargs(
        'summary',
        KwargInfo('section', str, default=''),
        KwargInfo('bool_yn', bool, default=False),
        KwargInfo('list_sep', (str, NoneType), since='0.54.0')
    )
    def func_summary(self, node: mparser.BaseNode, args: T.Tuple[T.Union[str, T.Dict[str, T.Any]], T.Optional[T.Any]],
                     kwargs: 'kwtypes.Summary') -> None:
        if args[1] is None:
            if not isinstance(args[0], dict):
                raise InterpreterException('Summary first argument must be dictionary.')
            values = args[0]
        else:
            if not isinstance(args[0], str):
                raise InterpreterException('Summary first argument must be string.')
            values = {args[0]: args[1]}
        self.summary_impl(kwargs['section'], values, kwargs)

    def summary_impl(self, section: str, values, kwargs: 'kwtypes.Summary') -> None:
        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['bool_yn'], kwargs['list_sep'], self.subproject)

    def _print_summary(self) -> None:
        # Add automatic 'Subprojects' section in main project.
        all_subprojects = collections.OrderedDict()
        for name, subp in sorted(self.subprojects.items()):
            value = [subp.found()]
            if subp.disabled_feature:
                value += [f'Feature {subp.disabled_feature!r} disabled']
            elif subp.exception:
                value += [str(subp.exception)]
            elif subp.warnings > 0:
                value += [f'{subp.warnings} warnings']
            if subp.callstack:
                stack = ' => '.join(subp.callstack)
                value += [f'(from {stack})']
            all_subprojects[name] = value
        if all_subprojects:
            self.summary_impl('Subprojects', all_subprojects,
                              {'bool_yn': True,
                               'list_sep': ' ',
                               })
        # Add automatic section with all user defined options
        if self.user_defined_options:
            values = collections.OrderedDict()
            if self.user_defined_options.cross_file:
                values['Cross files'] = self.user_defined_options.cross_file
            if self.user_defined_options.native_file:
                values['Native files'] = self.user_defined_options.native_file
            sorted_options = sorted(self.user_defined_options.cmd_line_options.items())
            values.update({str(k): v for k, v in sorted_options})
            if values:
                self.summary_impl('User defined options', values, {'bool_yn': False, 'list_sep': None})
        # Print all summaries, main project last.
        mlog.log('')  # newline
        main_summary = self.summary.pop('', None)
        for subp_name, summary in sorted(self.summary.items()):
            if self.subprojects[subp_name].found():
                summary.dump()
        if main_summary:
            main_summary.dump()

    @noArgsFlattening
    @FeatureNew('warning', '0.44.0')
    @noKwargs
    def func_warning(self, node, args, kwargs):
        if len(args) > 1:
            FeatureNew.single_use('warning with more than one argument', '0.54.0', self.subproject, location=node)
        args_str = self._stringify_user_arguments(args, 'warning')
        mlog.warning(*args_str, location=node)

    @noArgsFlattening
    @noKwargs
    def func_error(self, node, args, kwargs):
        if len(args) > 1:
            FeatureNew.single_use('error with more than one argument', '0.58.0', self.subproject, location=node)
        args_str = self._stringify_user_arguments(args, 'error')
        raise InterpreterException('Problem encountered: ' + ' '.join(args_str))

    @noArgsFlattening
    @FeatureNew('debug', '0.63.0')
    @noKwargs
    def func_debug(self, node, args, kwargs):
        args_str = self._stringify_user_arguments(args, 'debug')
        mlog.debug('Debug:', *args_str)

    @noKwargs
    @noPosargs
    def func_exception(self, node, args, kwargs):
        raise RuntimeError('unit test traceback :)')

    @typed_pos_args('expect_error', str)
    @typed_kwargs(
        'expect_error',
        KwargInfo('how', str, default='literal', validator=in_set_validator({'literal', 're'})),
    )
    def func_expect_error(self, node: mparser.BaseNode, args: T.Tuple[str], kwargs: TYPE_kwargs) -> ContextManagerObject:
        class ExpectErrorObject(ContextManagerObject):
            def __init__(self, msg: str, how: str, subproject: str) -> None:
                super().__init__(subproject)
                self.msg = msg
                self.how = how

            def __exit__(self, exc_type, exc_val, exc_tb):
                if exc_val is None:
                    raise InterpreterException('Expecting an error but code block succeeded')
                if isinstance(exc_val, mesonlib.MesonException):
                    msg = str(exc_val)
                    if (self.how == 'literal' and self.msg != msg) or \
                       (self.how == 're' and not re.match(self.msg, msg)):
                        raise InterpreterException(f'Expecting error {self.msg!r} but got {msg!r}')
                    return True
        return ExpectErrorObject(args[0], kwargs['how'], self.subproject)

    def add_languages(self, args: T.List[str], required: bool, for_machine: MachineChoice) -> bool:
        success = self.add_languages_for(args, required, for_machine)
        if not self.coredata.is_cross_build():
            self.coredata.copy_build_options_from_regular_ones()
        self._redetect_machines()
        return success

    def should_skip_sanity_check(self, for_machine: MachineChoice) -> bool:
        should = self.environment.properties.host.get('skip_sanity_check', False)
        if not isinstance(should, bool):
            raise InterpreterException('Option skip_sanity_check must be a boolean.')
        if for_machine != MachineChoice.HOST and not should:
            return False
        if not self.environment.is_cross_build() and not should:
            return False
        return should

    def add_languages_for(self, args: T.List[str], required: bool, for_machine: MachineChoice) -> bool:
        args = [a.lower() for a in args]
        langs = set(self.compilers[for_machine].keys())
        langs.update(args)
        # We'd really like to add cython's default language here, but it can't
        # actually be done because the cython compiler hasn't been initialized,
        # so we can't actually get the option yet. Because we can't know what
        # compiler to add by default, and we don't want to add unnecessary
        # compilers we don't add anything for cython here, and instead do it
        # When the first cython target using a particular language is used.
        if 'vala' in langs and 'c' not in langs:
            FeatureNew.single_use('Adding Vala language without C', '0.59.0', self.subproject, location=self.current_node)
            args.append('c')
        if 'nasm' in langs:
            FeatureNew.single_use('Adding NASM language', '0.64.0', self.subproject, location=self.current_node)

        success = True
        for lang in sorted(args, key=compilers.sort_clink):
            if lang in self.compilers[for_machine]:
                continue
            machine_name = for_machine.get_lower_case_name()
            comp = self.coredata.compilers[for_machine].get(lang)
            if not comp:
                try:
                    skip_sanity_check = self.should_skip_sanity_check(for_machine)
                    if skip_sanity_check:
                        mlog.log('Cross compiler sanity tests disabled via the cross file.', once=True)
                    comp = compilers.detect_compiler_for(self.environment, lang, for_machine, skip_sanity_check)
                    if comp is None:
                        raise InvalidArguments(f'Tried to use unknown language "{lang}".')
                except mesonlib.MesonException:
                    if not required:
                        mlog.log('Compiler for language',
                                 mlog.bold(lang), 'for the', machine_name,
                                 'machine not found.')
                        success = False
                        continue
                    else:
                        raise

            # Add per-subproject compiler options. They inherit value from main project.
            if self.subproject:
                options = {}
                for k in comp.get_options():
                    v = copy.copy(self.coredata.options[k])
                    k = k.evolve(subproject=self.subproject)
                    options[k] = v
                self.coredata.add_compiler_options(options, lang, for_machine, self.environment)

            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)
            self.compilers[for_machine][lang] = comp

        return success

    def program_from_file_for(self, for_machine: MachineChoice, prognames: T.List[mesonlib.FileOrString]
                              ) -> T.Optional[ExternalProgram]:
        for p in prognames:
            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(self.environment, for_machine, p)
            # if the machine file specified something, it may be a regular
            # not-found program but we still want to return that
            if not isinstance(prog, NonExistingExternalProgram):
                return prog
        return None

    def program_from_system(self, args: T.List[mesonlib.FileOrString], search_dirs: T.List[str],
                            extra_info: T.List[mlog.TV_Loggable]) -> T.Optional[ExternalProgram]:
        # 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(f'find_program only accepts strings and files, not {exename!r}')
            extprog = ExternalProgram(exename, search_dir=search_dir,
                                      extra_search_dirs=extra_search_dirs,
                                      silent=True)
            if extprog.found():
                extra_info.append(f"({' '.join(extprog.get_command())})")
                return extprog
        return None

    def program_from_overrides(self, command_names: T.List[mesonlib.FileOrString],
                               extra_info: T.List['mlog.TV_Loggable']
                               ) -> T.Optional[T.Union[ExternalProgram, OverrideProgram, build.Executable]]:
        for name in command_names:
            if not isinstance(name, str):
                continue
            if name in self.build.find_overrides:
                exe = self.build.find_overrides[name]
                extra_info.append(mlog.blue('(overridden)'))
                return exe
        return None

    def store_name_lookups(self, command_names: T.List[mesonlib.FileOrString]) -> None:
        for name in command_names:
            if isinstance(name, str):
                self.build.searched_programs.add(name)

    def add_find_program_override(self, name: str, exe: T.Union[build.Executable, ExternalProgram, 'OverrideProgram']) -> None:
        if name in self.build.searched_programs:
            raise InterpreterException(f'Tried to override finding of executable "{name}" which has already been found.')
        if name in self.build.find_overrides:
            raise InterpreterException(f'Tried to override executable "{name}" which has already been overridden.')
        self.build.find_overrides[name] = exe

    def notfound_program(self, args: T.List[mesonlib.FileOrString]) -> ExternalProgram:
        return NonExistingExternalProgram(' '.join(
            [a if isinstance(a, str) else a.absolute_path(self.environment.source_dir, self.environment.build_dir)
             for a in args]))

    # TODO update modules to always pass `for_machine`. It is bad-form to assume
    # the host machine.
    def find_program_impl(self, args: T.List[mesonlib.FileOrString],
                          for_machine: MachineChoice = MachineChoice.HOST,
                          default_options: T.Optional[T.Dict[OptionKey, T.Union[str, int, bool, T.List[str]]]] = None,
                          required: bool = True, silent: bool = True,
                          wanted: T.Union[str, T.List[str]] = '',
                          search_dirs: T.Optional[T.List[str]] = None,
                          version_func: T.Optional[ProgramVersionFunc] = None
                          ) -> T.Union['ExternalProgram', 'build.Executable', 'OverrideProgram']:
        args = mesonlib.listify(args)

        extra_info: T.List[mlog.TV_Loggable] = []
        progobj = self.program_lookup(args, for_machine, default_options, required, search_dirs, wanted, version_func, extra_info)
        if progobj is None or not self.check_program_version(progobj, wanted, version_func, extra_info):
            progobj = self.notfound_program(args)

        if isinstance(progobj, ExternalProgram) and not progobj.found():
            if not silent:
                mlog.log('Program', mlog.bold(progobj.get_name()), 'found:', mlog.red('NO'), *extra_info)
            if required:
                m = 'Program {!r} not found or not executable'
                raise InterpreterException(m.format(progobj.get_name()))
            return progobj

        # Only store successful lookups
        self.store_name_lookups(args)
        if not silent:
            mlog.log('Program', mlog.bold(progobj.name), 'found:', mlog.green('YES'), *extra_info)
        if isinstance(progobj, build.Executable):
            progobj.was_returned_by_find_program = True
        return progobj

    def program_lookup(self, args: T.List[mesonlib.FileOrString], for_machine: MachineChoice,
                       default_options: T.Optional[T.Dict[OptionKey, T.Union[str, int, bool, T.List[str]]]],
                       required: bool,
                       search_dirs: T.List[str],
                       wanted: T.Union[str, T.List[str]],
                       version_func: T.Optional[ProgramVersionFunc],
                       extra_info: T.List[mlog.TV_Loggable]
                       ) -> T.Optional[T.Union[ExternalProgram, build.Executable, OverrideProgram]]:
        progobj = self.program_from_overrides(args, extra_info)
        if progobj:
            return progobj

        if args[0] == 'meson':
            # Override find_program('meson') to return what we were invoked with
            return ExternalProgram('meson', self.environment.get_build_command(), silent=True)

        fallback = None
        wrap_mode = self.coredata.get_option(OptionKey('wrap_mode'))
        if wrap_mode != WrapMode.nofallback and self.environment.wrap_resolver:
            fallback = self.environment.wrap_resolver.find_program_provider(args)
        if fallback and wrap_mode == WrapMode.forcefallback:
            return self.find_program_fallback(fallback, args, default_options, required, extra_info)

        progobj = self.program_from_file_for(for_machine, args)
        if progobj is None:
            progobj = self.program_from_system(args, search_dirs, extra_info)
        if progobj is None and args[0].endswith('python3'):
            prog = ExternalProgram('python3', mesonlib.python_command, silent=True)
            progobj = prog if prog.found() else None

        if progobj and not self.check_program_version(progobj, wanted, version_func, extra_info):
            progobj = None

        if progobj is None and fallback and required:
            progobj = self.notfound_program(args)
            mlog.log('Program', mlog.bold(progobj.get_name()), 'found:', mlog.red('NO'), *extra_info)
            extra_info.clear()
            progobj = self.find_program_fallback(fallback, args, default_options, required, extra_info)

        return progobj

    def check_program_version(self, progobj: T.Union[ExternalProgram, build.Executable, OverrideProgram],
                              wanted: T.Union[str, T.List[str]],
                              version_func: T.Optional[ProgramVersionFunc],
                              extra_info: T.List[mlog.TV_Loggable]) -> bool:
        if wanted:
            if version_func:
                version = version_func(progobj)
            elif isinstance(progobj, build.Executable):
                if progobj.subproject:
                    interp = self.subprojects[progobj.subproject].held_object
                else:
                    interp = self
                assert isinstance(interp, Interpreter)
                version = interp.project_version
            else:
                version = progobj.get_version(self)
            is_found, not_found, _ = mesonlib.version_compare_many(version, wanted)
            if not is_found:
                extra_info[:0] = ['found', mlog.normal_cyan(version), 'but need:',
                                  mlog.bold(', '.join([f"'{e}'" for e in not_found]))]
                return False
            extra_info.insert(0, mlog.normal_cyan(version))
        return True

    def find_program_fallback(self, fallback: str, args: T.List[mesonlib.FileOrString],
                              default_options: T.Dict[OptionKey, T.Union[str, int, bool, T.List[str]]],
                              required: bool, extra_info: T.List[mlog.TV_Loggable]
                              ) -> T.Optional[T.Union[ExternalProgram, build.Executable, OverrideProgram]]:
        mlog.log('Fallback to subproject', mlog.bold(fallback), 'which provides program',
                 mlog.bold(' '.join(args)))
        sp_kwargs: kwtypes.DoSubproject = {
            'required': required,
            'default_options': default_options or {},
            'version': [],
            'cmake_options': [],
            'options': None,
        }
        self.do_subproject(fallback, sp_kwargs)
        return self.program_from_overrides(args, extra_info)

    @typed_pos_args('find_program', varargs=(str, mesonlib.File), min_varargs=1)
    @typed_kwargs(
        'find_program',
        DISABLER_KW.evolve(since='0.49.0'),
        NATIVE_KW,
        REQUIRED_KW,
        KwargInfo('dirs', ContainerTypeInfo(list, str), default=[], listify=True, since='0.53.0'),
        KwargInfo('version', ContainerTypeInfo(list, str), default=[], listify=True, since='0.52.0'),
        DEFAULT_OPTIONS.evolve(since='1.3.0')
    )
    @disablerIfNotFound
    def func_find_program(self, node: mparser.BaseNode, args: T.Tuple[T.List[mesonlib.FileOrString]],
                          kwargs: 'kwtypes.FindProgram',
                          ) -> T.Union['build.Executable', ExternalProgram, 'OverrideProgram']:
        disabled, required, feature = extract_required_kwarg(kwargs, self.subproject)
        if disabled:
            mlog.log('Program', mlog.bold(' '.join(args[0])), 'skipped: feature', mlog.bold(feature), 'disabled')
            return self.notfound_program(args[0])

        search_dirs = extract_search_dirs(kwargs)
        default_options = kwargs['default_options']
        return self.find_program_impl(args[0], kwargs['native'], default_options=default_options, required=required,
                                      silent=False, wanted=kwargs['version'],
                                      search_dirs=search_dirs)

    # When adding kwargs, please check if they make sense in dependencies.get_dep_identifier()
    @FeatureNewKwargs('dependency', '0.57.0', ['cmake_package_version'])
    @FeatureNewKwargs('dependency', '0.56.0', ['allow_fallback'])
    @FeatureNewKwargs('dependency', '0.54.0', ['components'])
    @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'])
    @disablerIfNotFound
    @permittedKwargs(permitted_dependency_kwargs)
    @typed_pos_args('dependency', varargs=str, min_varargs=1)
    @typed_kwargs('dependency', DEFAULT_OPTIONS.evolve(since='0.38.0'), allow_unknown=True)
    def func_dependency(self, node: mparser.BaseNode, args: T.Tuple[T.List[str]], kwargs) -> Dependency:
        # Replace '' by empty list of names
        names = [n for n in args[0] if n]
        if len(names) > 1:
            FeatureNew('dependency with more than one name', '0.60.0').use(self.subproject)
        allow_fallback = kwargs.get('allow_fallback')
        if allow_fallback is not None and not isinstance(allow_fallback, bool):
            raise InvalidArguments('"allow_fallback" argument must be boolean')
        fallback = kwargs.get('fallback')
        default_options = kwargs.get('default_options')
        df = DependencyFallbacksHolder(self, names, allow_fallback, default_options)
        df.set_fallback(fallback)
        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 = df.lookup(kwargs)
        except Exception:
            if not_found_message:
                self.message_impl([not_found_message])
            raise
        assert isinstance(d, Dependency)
        if not d.found() and not_found_message:
            self.message_impl([not_found_message])
        # Ensure the correct include type
        if 'include_type' in kwargs:
            wanted = kwargs['include_type']
            if not isinstance(wanted, str):
                raise InvalidArguments('The `include_type` kwarg must be a string')
            actual = d.get_include_type()
            if wanted != actual:
                mlog.debug(f'Current include type of {args[0]} is {actual}. Converting to requested {wanted}')
                d = d.generate_system_dependency(wanted)
        if d.feature_since is not None:
            version, extra_msg = d.feature_since
            FeatureNew.single_use(f'dep {d.name!r} custom lookup', version, self.subproject, extra_msg, node)
        for f in d.featurechecks:
            f.use(self.subproject, node)
        return d

    @FeatureNew('disabler', '0.44.0')
    @noKwargs
    @noPosargs
    def func_disabler(self, node, args, kwargs):
        return Disabler()

    @permittedKwargs(build.known_exe_kwargs)
    @typed_pos_args('executable', str, varargs=SOURCES_VARARGS)
    @typed_kwargs('executable', *EXECUTABLE_KWS, allow_unknown=True)
    def func_executable(self, node: mparser.BaseNode,
                        args: T.Tuple[str, SourcesVarargsType],
                        kwargs: kwtypes.Executable) -> build.Executable:
        return self.build_target(node, args, kwargs, build.Executable)

    @permittedKwargs(build.known_stlib_kwargs)
    @typed_pos_args('static_library', str, varargs=SOURCES_VARARGS)
    @typed_kwargs('static_library', *STATIC_LIB_KWS, allow_unknown=True)
    def func_static_lib(self, node: mparser.BaseNode,
                        args: T.Tuple[str, SourcesVarargsType],
                        kwargs: kwtypes.StaticLibrary) -> build.StaticLibrary:
        return self.build_target(node, args, kwargs, build.StaticLibrary)

    @permittedKwargs(build.known_shlib_kwargs)
    @typed_pos_args('shared_library', str, varargs=SOURCES_VARARGS)
    @typed_kwargs('shared_library', *SHARED_LIB_KWS, allow_unknown=True)
    def func_shared_lib(self, node: mparser.BaseNode,
                        args: T.Tuple[str, SourcesVarargsType],
                        kwargs: kwtypes.SharedLibrary) -> build.SharedLibrary:
        holder = self.build_target(node, args, kwargs, build.SharedLibrary)
        holder.shared_library_only = True
        return holder

    @permittedKwargs(known_library_kwargs)
    @typed_pos_args('both_libraries', str, varargs=SOURCES_VARARGS)
    @typed_kwargs('both_libraries', *LIBRARY_KWS, allow_unknown=True)
    def func_both_lib(self, node: mparser.BaseNode,
                      args: T.Tuple[str, SourcesVarargsType],
                      kwargs: kwtypes.Library) -> build.BothLibraries:
        return self.build_both_libraries(node, args, kwargs)

    @FeatureNew('shared_module', '0.37.0')
    @permittedKwargs(build.known_shmod_kwargs)
    @typed_pos_args('shared_module', str, varargs=SOURCES_VARARGS)
    @typed_kwargs('shared_module', *SHARED_MOD_KWS, allow_unknown=True)
    def func_shared_module(self, node: mparser.BaseNode,
                           args: T.Tuple[str, SourcesVarargsType],
                           kwargs: kwtypes.SharedModule) -> build.SharedModule:
        return self.build_target(node, args, kwargs, build.SharedModule)

    @permittedKwargs(known_library_kwargs)
    @typed_pos_args('library', str, varargs=SOURCES_VARARGS)
    @typed_kwargs('library', *LIBRARY_KWS, allow_unknown=True)
    def func_library(self, node: mparser.BaseNode,
                     args: T.Tuple[str, SourcesVarargsType],
                     kwargs: kwtypes.Library) -> build.Executable:
        return self.build_library(node, args, kwargs)

    @permittedKwargs(build.known_jar_kwargs)
    @typed_pos_args('jar', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.ExtractedObjects, build.BuildTarget))
    @typed_kwargs('jar', *JAR_KWS, allow_unknown=True)
    def func_jar(self, node: mparser.BaseNode,
                 args: T.Tuple[str, T.List[T.Union[str, mesonlib.File, build.GeneratedTypes]]],
                 kwargs: kwtypes.Jar) -> build.Jar:
        return self.build_target(node, args, kwargs, build.Jar)

    @FeatureNewKwargs('build_target', '0.40.0', ['link_whole', 'override_options'])
    @permittedKwargs(known_build_target_kwargs)
    @typed_pos_args('build_target', str, varargs=SOURCES_VARARGS)
    @typed_kwargs('build_target', *BUILD_TARGET_KWS, allow_unknown=True)
    def func_build_target(self, node: mparser.BaseNode,
                          args: T.Tuple[str, SourcesVarargsType],
                          kwargs: kwtypes.BuildTarget
                          ) -> T.Union[build.Executable, build.StaticLibrary, build.SharedLibrary,
                                       build.SharedModule, build.BothLibraries, build.Jar]:
        target_type = kwargs['target_type']
        if target_type == 'executable':
            return self.build_target(node, args, kwargs, build.Executable)
        elif target_type == 'shared_library':
            return self.build_target(node, args, kwargs, build.SharedLibrary)
        elif target_type == 'shared_module':
            return self.build_target(node, args, kwargs, build.SharedModule)
        elif target_type == 'static_library':
            return self.build_target(node, args, kwargs, build.StaticLibrary)
        elif target_type == 'both_libraries':
            return self.build_both_libraries(node, args, kwargs)
        elif target_type == 'library':
            return self.build_library(node, args, kwargs)
        return self.build_target(node, args, kwargs, build.Jar)

    @noPosargs
    @typed_kwargs(
        'vcs_tag',
        CT_INPUT_KW.evolve(required=True),
        MULTI_OUTPUT_KW,
        # Cannot use the COMMAND_KW because command is allowed to be empty
        KwargInfo(
            'command',
            ContainerTypeInfo(list, (str, build.BuildTarget, build.CustomTarget, build.CustomTargetIndex, ExternalProgram, mesonlib.File)),
            listify=True,
            default=[],
        ),
        KwargInfo('fallback', (str, NoneType)),
        KwargInfo('replace_string', str, default='@VCS_TAG@'),
    )
    def func_vcs_tag(self, node: mparser.BaseNode, args: T.List['TYPE_var'], kwargs: 'kwtypes.VcsTag') -> build.CustomTarget:
        if kwargs['fallback'] is None:
            FeatureNew.single_use('Optional fallback in vcs_tag', '0.41.0', self.subproject, location=node)
        fallback = kwargs['fallback'] or self.project_version
        replace_string = kwargs['replace_string']
        regex_selector = '(.*)' # default regex selector for custom command: use complete output
        vcs_cmd = kwargs['command']
        source_dir = os.path.normpath(os.path.join(self.environment.get_source_dir(), self.subdir))
        if vcs_cmd:
            if isinstance(vcs_cmd[0], (str, mesonlib.File)):
                if isinstance(vcs_cmd[0], mesonlib.File):
                    FeatureNew.single_use('vcs_tag with file as the first argument', '0.62.0', self.subproject, location=node)
                maincmd = self.find_program_impl(vcs_cmd[0], required=False)
                if maincmd.found():
                    vcs_cmd[0] = maincmd
            else:
                FeatureNew.single_use('vcs_tag with custom_tgt, external_program, or exe as the first argument', '0.63.0', self.subproject, location=node)
        else:
            vcs = mesonlib.detect_vcs(source_dir)
            if vcs:
                mlog.log('Found {} repository at {}'.format(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...

        self._validate_custom_target_outputs(len(kwargs['input']) > 1, kwargs['output'], "vcs_tag")

        cmd = self.environment.get_build_command() + \
            ['--internal',
             'vcstagger',
             '@INPUT0@',
             '@OUTPUT0@',
             fallback,
             source_dir,
             replace_string,
             regex_selector] + vcs_cmd

        tg = build.CustomTarget(
            kwargs['output'][0],
            self.subdir,
            self.subproject,
            self.environment,
            cmd,
            self.source_strings_to_files(kwargs['input']),
            kwargs['output'],
            build_by_default=True,
            build_always_stale=True,
        )
        self.add_target(tg.name, tg)
        return tg

    @FeatureNew('subdir_done', '0.46.0')
    @noPosargs
    @noKwargs
    def func_subdir_done(self, node: mparser.BaseNode, args: TYPE_var, kwargs: TYPE_kwargs) -> T.NoReturn:
        raise SubdirDoneRequest()

    @staticmethod
    def _validate_custom_target_outputs(has_multi_in: bool, outputs: T.Iterable[str], name: str) -> None:
        """Checks for additional invalid values in a custom_target output.

        This cannot be done with typed_kwargs because it requires the number of
        inputs.
        """
        for out in outputs:
            if has_multi_in and ('@PLAINNAME@' in out or '@BASENAME@' in out):
                raise InvalidArguments(f'{name}: output cannot contain "@PLAINNAME@" or "@BASENAME@" '
                                       'when there is more than one input (we can\'t know which to use)')

    @typed_pos_args('custom_target', optargs=[str])
    @typed_kwargs(
        'custom_target',
        COMMAND_KW,
        CT_BUILD_ALWAYS,
        CT_BUILD_ALWAYS_STALE,
        CT_BUILD_BY_DEFAULT,
        CT_INPUT_KW,
        CT_INSTALL_DIR_KW,
        CT_INSTALL_TAG_KW,
        MULTI_OUTPUT_KW,
        DEPENDS_KW,
        DEPEND_FILES_KW,
        DEPFILE_KW,
        ENV_KW.evolve(since='0.57.0'),
        INSTALL_KW,
        INSTALL_MODE_KW.evolve(since='0.47.0'),
        KwargInfo('feed', bool, default=False, since='0.59.0'),
        KwargInfo('capture', bool, default=False),
        KwargInfo('console', bool, default=False, since='0.48.0'),
    )
    def func_custom_target(self, node: mparser.FunctionNode, args: T.Tuple[str],
                           kwargs: 'kwtypes.CustomTarget') -> build.CustomTarget:
        if kwargs['depfile'] and ('@BASENAME@' in kwargs['depfile'] or '@PLAINNAME@' in kwargs['depfile']):
            FeatureNew.single_use('substitutions in custom_target depfile', '0.47.0', self.subproject, location=node)
        install_mode = self._warn_kwarg_install_mode_sticky(kwargs['install_mode'])

        # Don't mutate the kwargs

        build_by_default = kwargs['build_by_default']
        build_always_stale = kwargs['build_always_stale']
        # Remap build_always to build_by_default and build_always_stale
        if kwargs['build_always'] is not None and kwargs['build_always_stale'] is not None:
            raise InterpreterException('CustomTarget: "build_always" and "build_always_stale" are mutually exclusive')

        if build_by_default is None and kwargs['install']:
            build_by_default = True

        elif kwargs['build_always'] is not None:
            if build_by_default is None:
                build_by_default = kwargs['build_always']
            build_always_stale = kwargs['build_by_default']

        # These are nullable so that we can know whether they're explicitly
        # set or not. If they haven't been overwritten, set them to their true
        # default
        if build_by_default is None:
            build_by_default = False
        if build_always_stale is None:
            build_always_stale = False

        name = args[0]
        if name is None:
            # name will default to first output, but we cannot do that yet because
            # they could need substitutions (e.g. @BASENAME@) first. CustomTarget()
            # will take care of setting a proper default but name must be an empty
            # string in the meantime.
            FeatureNew.single_use('custom_target() with no name argument', '0.60.0', self.subproject, location=node)
            name = ''
        inputs = self.source_strings_to_files(kwargs['input'], strict=False)
        command = kwargs['command']
        if command and isinstance(command[0], str):
            command[0] = self.find_program_impl([command[0]])

        if len(inputs) > 1 and kwargs['feed']:
            raise InvalidArguments('custom_target: "feed" keyword argument can only be used with a single input')
        if len(kwargs['output']) > 1 and kwargs['capture']:
            raise InvalidArguments('custom_target: "capture" keyword argument can only be used with a single output')
        if kwargs['capture'] and kwargs['console']:
            raise InvalidArguments('custom_target: "capture" and "console" keyword arguments are mutually exclusive')
        for c in command:
            if kwargs['capture'] and isinstance(c, str) and '@OUTPUT@' in c:
                raise InvalidArguments('custom_target: "capture" keyword argument cannot be used with "@OUTPUT@"')
            if kwargs['feed'] and isinstance(c, str) and '@INPUT@' in c:
                raise InvalidArguments('custom_target: "feed" keyword argument cannot be used with "@INPUT@"')
        if kwargs['install'] and not kwargs['install_dir']:
            raise InvalidArguments('custom_target: "install_dir" keyword argument must be set when "install" is true.')
        if len(kwargs['install_dir']) > 1:
            FeatureNew.single_use('multiple install_dir for custom_target', '0.40.0', self.subproject, location=node)
        if len(kwargs['install_tag']) not in {0, 1, len(kwargs['output'])}:
            raise InvalidArguments('custom_target: install_tag argument must have 0 or 1 outputs, '
                                   'or the same number of elements as the output keyword argument. '
                                   f'(there are {len(kwargs["install_tag"])} install_tags, '
                                   f'and {len(kwargs["output"])} outputs)')

        for t in kwargs['output']:
            self.validate_forbidden_targets(t)
        self._validate_custom_target_outputs(len(inputs) > 1, kwargs['output'], "custom_target")

        tg = build.CustomTarget(
            name,
            self.subdir,
            self.subproject,
            self.environment,
            command,
            inputs,
            kwargs['output'],
            build_always_stale=build_always_stale,
            build_by_default=build_by_default,
            capture=kwargs['capture'],
            console=kwargs['console'],
            depend_files=kwargs['depend_files'],
            depfile=kwargs['depfile'],
            extra_depends=kwargs['depends'],
            env=kwargs['env'],
            feed=kwargs['feed'],
            install=kwargs['install'],
            install_dir=kwargs['install_dir'],
            install_mode=install_mode,
            install_tag=kwargs['install_tag'],
            backend=self.backend)
        self.add_target(tg.name, tg)
        return tg

    @typed_pos_args('run_target', str)
    @typed_kwargs(
        'run_target',
        COMMAND_KW,
        DEPENDS_KW,
        ENV_KW.evolve(since='0.57.0'),
    )
    def func_run_target(self, node: mparser.FunctionNode, args: T.Tuple[str],
                        kwargs: 'kwtypes.RunTarget') -> build.RunTarget:
        all_args = kwargs['command'].copy()

        for i in listify(all_args):
            if isinstance(i, ExternalProgram) and not i.found():
                raise InterpreterException(f'Tried to use non-existing executable {i.name!r}')
        if isinstance(all_args[0], str):
            all_args[0] = self.find_program_impl([all_args[0]])
        name = args[0]
        tg = build.RunTarget(name, all_args, kwargs['depends'], self.subdir, self.subproject, self.environment,
                             kwargs['env'])
        self.add_target(name, tg)
        return tg

    @FeatureNew('alias_target', '0.52.0')
    @typed_pos_args('alias_target', str, varargs=build.Target, min_varargs=1)
    @noKwargs
    def func_alias_target(self, node: mparser.BaseNode, args: T.Tuple[str, T.List[build.Target]],
                          kwargs: 'TYPE_kwargs') -> build.AliasTarget:
        name, deps = args
        if any(isinstance(d, build.RunTarget) for d in deps):
            FeatureNew.single_use('alias_target that depends on run_targets', '0.60.0', self.subproject)
        tg = build.AliasTarget(name, deps, self.subdir, self.subproject, self.environment)
        self.add_target(name, tg)
        return tg

    @typed_pos_args('generator', (build.Executable, ExternalProgram))
    @typed_kwargs(
        'generator',
        KwargInfo('arguments', ContainerTypeInfo(list, str, allow_empty=False), required=True, listify=True),
        KwargInfo('output', ContainerTypeInfo(list, str, allow_empty=False), required=True, listify=True),
        DEPFILE_KW,
        DEPENDS_KW,
        KwargInfo('capture', bool, default=False, since='0.43.0'),
    )
    def func_generator(self, node: mparser.FunctionNode,
                       args: T.Tuple[T.Union[build.Executable, ExternalProgram]],
                       kwargs: 'kwtypes.FuncGenerator') -> build.Generator:
        for rule in kwargs['output']:
            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('"output" must not contain a directory separator.')
        if len(kwargs['output']) > 1:
            for o in kwargs['output']:
                if '@OUTPUT@' in o:
                    raise InvalidArguments('Tried to use @OUTPUT@ in a rule with more than one output.')

        gen = build.Generator(args[0], **kwargs)
        self.generators.append(gen)
        return gen

    @typed_pos_args('benchmark', str, (build.Executable, build.Jar, ExternalProgram, mesonlib.File))
    @typed_kwargs('benchmark', *TEST_KWS)
    def func_benchmark(self, node: mparser.BaseNode,
                       args: T.Tuple[str, T.Union[build.Executable, build.Jar, ExternalProgram, mesonlib.File]],
                       kwargs: 'kwtypes.FuncBenchmark') -> None:
        self.add_test(node, args, kwargs, False)

    @typed_pos_args('test', str, (build.Executable, build.Jar, ExternalProgram, mesonlib.File))
    @typed_kwargs('test', *TEST_KWS, KwargInfo('is_parallel', bool, default=True))
    def func_test(self, node: mparser.BaseNode,
                  args: T.Tuple[str, T.Union[build.Executable, build.Jar, ExternalProgram, mesonlib.File]],
                  kwargs: 'kwtypes.FuncTest') -> None:
        self.add_test(node, args, kwargs, True)

    def unpack_env_kwarg(self, kwargs: T.Union[EnvironmentVariables, T.Dict[str, 'TYPE_var'], T.List['TYPE_var'], str]) -> EnvironmentVariables:
        envlist = kwargs.get('env')
        if envlist is None:
            return EnvironmentVariables()
        msg = ENV_KW.validator(envlist)
        if msg:
            raise InvalidArguments(f'"env": {msg}')
        return ENV_KW.convertor(envlist)

    def make_test(self, node: mparser.BaseNode,
                  args: T.Tuple[str, T.Union[build.Executable, build.Jar, ExternalProgram, mesonlib.File]],
                  kwargs: 'kwtypes.BaseTest') -> Test:
        name = args[0]
        if ':' in name:
            mlog.deprecation(f'":" is not allowed in test name "{name}", it has been replaced with "_"',
                             location=node)
            name = name.replace(':', '_')
        exe = args[1]
        if isinstance(exe, ExternalProgram):
            if not exe.found():
                raise InvalidArguments('Tried to use not-found external program as test exe')
        elif isinstance(exe, mesonlib.File):
            exe = self.find_program_impl([exe])

        env = self.unpack_env_kwarg(kwargs)

        if kwargs['timeout'] <= 0:
            FeatureNew.single_use('test() timeout <= 0', '0.57.0', self.subproject, location=node)

        prj = self.subproject if self.is_subproject() else self.build.project_name

        suite: T.List[str] = []
        for s in kwargs['suite']:
            if s:
                s = ':' + s
            suite.append(prj.replace(' ', '_').replace(':', '_') + s)

        return Test(name,
                    prj,
                    suite,
                    exe,
                    kwargs['depends'],
                    kwargs.get('is_parallel', False),
                    kwargs['args'],
                    env,
                    kwargs['should_fail'],
                    kwargs['timeout'],
                    kwargs['workdir'],
                    kwargs['protocol'],
                    kwargs['priority'],
                    kwargs['verbose'])

    def add_test(self, node: mparser.BaseNode,
                 args: T.Tuple[str, T.Union[build.Executable, build.Jar, ExternalProgram, mesonlib.File]],
                 kwargs: T.Dict[str, T.Any], is_base_test: bool):
        t = self.make_test(node, args, kwargs)
        if is_base_test:
            self.build.tests.append(t)
            mlog.debug('Adding test', mlog.bold(t.name, True))
        else:
            self.build.benchmarks.append(t)
            mlog.debug('Adding benchmark', mlog.bold(t.name, True))

    @typed_pos_args('install_headers', varargs=(str, mesonlib.File))
    @typed_kwargs(
        'install_headers',
        PRESERVE_PATH_KW,
        KwargInfo('subdir', (str, NoneType)),
        INSTALL_MODE_KW.evolve(since='0.47.0'),
        INSTALL_DIR_KW,
        INSTALL_FOLLOW_SYMLINKS,
    )
    def func_install_headers(self, node: mparser.BaseNode,
                             args: T.Tuple[T.List['mesonlib.FileOrString']],
                             kwargs: 'kwtypes.FuncInstallHeaders') -> build.Headers:
        install_mode = self._warn_kwarg_install_mode_sticky(kwargs['install_mode'])
        source_files = self.source_strings_to_files(args[0])
        install_subdir = kwargs['subdir']
        if install_subdir is not None:
            if kwargs['install_dir'] is not None:
                raise InterpreterException('install_headers: cannot specify both "install_dir" and "subdir". Use only "install_dir".')
            if os.path.isabs(install_subdir):
                mlog.deprecation('Subdir keyword must not be an absolute path. This will be a hard error in the next release.')
        else:
            install_subdir = ''

        dirs = collections.defaultdict(list)
        ret_headers = []
        if kwargs['preserve_path']:
            for file in source_files:
                dirname = os.path.dirname(file.fname)
                dirs[dirname].append(file)
        else:
            dirs[''].extend(source_files)

        for childdir in dirs:
            h = build.Headers(dirs[childdir], os.path.join(install_subdir, childdir), kwargs['install_dir'],
                              install_mode, self.subproject,
                              follow_symlinks=kwargs['follow_symlinks'])
            ret_headers.append(h)
            self.build.headers.append(h)

        return ret_headers

    @typed_pos_args('install_man', varargs=(str, mesonlib.File))
    @typed_kwargs(
        'install_man',
        KwargInfo('locale', (str, NoneType), since='0.58.0'),
        INSTALL_MODE_KW.evolve(since='0.47.0'),
        INSTALL_DIR_KW,
    )
    def func_install_man(self, node: mparser.BaseNode,
                         args: T.Tuple[T.List['mesonlib.FileOrString']],
                         kwargs: 'kwtypes.FuncInstallMan') -> build.Man:
        install_mode = self._warn_kwarg_install_mode_sticky(kwargs['install_mode'])
        # We just need to narrow this, because the input is limited to files and
        # Strings as inputs, so only Files will be returned
        sources = self.source_strings_to_files(args[0])
        for s in sources:
            try:
                num = int(s.rsplit('.', 1)[-1])
            except (IndexError, ValueError):
                num = 0
            if not 1 <= num <= 9:
                raise InvalidArguments('Man file must have a file extension of a number between 1 and 9')

        m = build.Man(sources, kwargs['install_dir'], install_mode,
                      self.subproject, kwargs['locale'])
        self.build.man.append(m)

        return m

    @FeatureNew('install_emptydir', '0.60.0')
    @typed_kwargs(
        'install_emptydir',
        INSTALL_MODE_KW,
        KwargInfo('install_tag', (str, NoneType), since='0.62.0')
    )
    def func_install_emptydir(self, node: mparser.BaseNode, args: T.Tuple[str], kwargs) -> None:
        d = build.EmptyDir(args[0], kwargs['install_mode'], self.subproject, kwargs['install_tag'])
        self.build.emptydir.append(d)

        return d

    @FeatureNew('install_symlink', '0.61.0')
    @typed_pos_args('symlink_name', str)
    @typed_kwargs(
        'install_symlink',
        KwargInfo('pointing_to', str, required=True),
        KwargInfo('install_dir', str, required=True),
        INSTALL_TAG_KW,
    )
    def func_install_symlink(self, node: mparser.BaseNode,
                             args: T.Tuple[T.List[str]],
                             kwargs) -> build.SymlinkData:
        name = args[0] # Validation while creating the SymlinkData object
        target = kwargs['pointing_to']
        l = build.SymlinkData(target, name, kwargs['install_dir'],
                              self.subproject, kwargs['install_tag'])
        self.build.symlinks.append(l)
        return l

    @FeatureNew('structured_sources', '0.62.0')
    @typed_pos_args('structured_sources', object, optargs=[dict])
    @noKwargs
    @noArgsFlattening
    def func_structured_sources(
            self, node: mparser.BaseNode,
            args: T.Tuple[object, T.Optional[T.Dict[str, object]]],
            kwargs: 'TYPE_kwargs') -> build.StructuredSources:
        valid_types = (str, mesonlib.File, build.GeneratedList, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList)
        sources: T.Dict[str, T.List[T.Union[mesonlib.File, 'build.GeneratedTypes']]] = collections.defaultdict(list)

        for arg in mesonlib.listify(args[0]):
            if not isinstance(arg, valid_types):
                raise InvalidArguments(f'structured_sources: type "{type(arg)}" is not valid')
            if isinstance(arg, str):
                arg = mesonlib.File.from_source_file(self.environment.source_dir, self.subdir, arg)
            sources[''].append(arg)
        if args[1]:
            if '' in args[1]:
                raise InvalidArguments('structured_sources: keys to dictionary argument may not be an empty string.')
            for k, v in args[1].items():
                for arg in mesonlib.listify(v):
                    if not isinstance(arg, valid_types):
                        raise InvalidArguments(f'structured_sources: type "{type(arg)}" is not valid')
                    if isinstance(arg, str):
                        arg = mesonlib.File.from_source_file(self.environment.source_dir, self.subdir, arg)
                    sources[k].append(arg)
        return build.StructuredSources(sources)

    @typed_pos_args('subdir', str)
    @typed_kwargs(
        'subdir',
        KwargInfo(
            'if_found',
            ContainerTypeInfo(list, object),
            validator=lambda a: 'Objects must have a found() method' if not all(hasattr(x, 'found') for x in a) else None,
            since='0.44.0',
            default=[],
            listify=True,
        ),
    )
    def func_subdir(self, node: mparser.BaseNode, args: T.Tuple[str], kwargs: 'kwtypes.Subdir') -> None:
        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().')
        if args[0] == '':
            raise InvalidArguments("The argument given to subdir() is the empty string ''. This is prohibited.")
        for i in kwargs['if_found']:
            if not i.found():
                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)
        build_file = os.path.join(symlinkless_dir, 'meson.build')
        if build_file in self.processed_buildfiles:
            raise InvalidArguments(f'Tried to enter directory "{subdir}", which has already been visited.')
        self.processed_buildfiles.add(build_file)
        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.add(buildfilename)
        absname = os.path.join(self.environment.get_source_dir(), buildfilename)
        if not os.path.isfile(absname):
            self.subdir = prev_subdir
            raise InterpreterException(f"Nonexistent build file '{buildfilename!s}'")
        with open(absname, encoding='utf-8') as f:
            code = f.read()
        assert isinstance(code, str)
        try:
            codeblock = mparser.Parser(code, absname).parse()
        except mesonlib.MesonException as me:
            me.file = absname
            raise me
        try:
            self.evaluate_codeblock(codeblock)
        except SubdirDoneRequest:
            pass
        self.subdir = prev_subdir

    # This is either ignored on basically any OS nowadays, or silently gets
    # ignored (Solaris) or triggers an "illegal operation" error (FreeBSD).
    # It was likely added "because it exists", but should never be used. In
    # theory it is useful for directories, but we never apply modes to
    # directories other than in install_emptydir.
    def _warn_kwarg_install_mode_sticky(self, mode: FileMode) -> None:
        if mode.perms > 0 and mode.perms & stat.S_ISVTX:
            mlog.deprecation('install_mode with the sticky bit on a file does not do anything and will '
                             'be ignored since Meson 0.64.0', location=self.current_node)
            perms = stat.filemode(mode.perms - stat.S_ISVTX)[1:]
            return FileMode(perms, mode.owner, mode.group)
        else:
            return mode

    @typed_pos_args('install_data', varargs=(str, mesonlib.File))
    @typed_kwargs(
        'install_data',
        KwargInfo('sources', ContainerTypeInfo(list, (str, mesonlib.File)), listify=True, default=[]),
        KwargInfo('rename', ContainerTypeInfo(list, str), default=[], listify=True, since='0.46.0'),
        INSTALL_MODE_KW.evolve(since='0.38.0'),
        INSTALL_TAG_KW.evolve(since='0.60.0'),
        INSTALL_DIR_KW,
        PRESERVE_PATH_KW.evolve(since='0.64.0'),
        INSTALL_FOLLOW_SYMLINKS,
    )
    def func_install_data(self, node: mparser.BaseNode,
                          args: T.Tuple[T.List['mesonlib.FileOrString']],
                          kwargs: 'kwtypes.FuncInstallData') -> build.Data:
        sources = self.source_strings_to_files(args[0] + kwargs['sources'])
        rename = kwargs['rename'] or None
        if rename:
            if len(rename) != len(sources):
                raise InvalidArguments(
                    '"rename" and "sources" argument lists must be the same length if "rename" is given. '
                    f'Rename has {len(rename)} elements and sources has {len(sources)}.')

        install_dir = kwargs['install_dir']
        if not install_dir:
            subdir = self.active_projectname
            install_dir = P_OBJ.OptionString(os.path.join(self.environment.get_datadir(), subdir), os.path.join('{datadir}', subdir))
            if self.is_subproject():
                FeatureNew.single_use('install_data() without install_dir inside of a subproject', '1.3.0', self.subproject,
                                      'This was broken and would install to the project name of the parent project instead',
                                      node)
            if kwargs['preserve_path']:
                FeatureNew.single_use('install_data() with preserve_path and without install_dir', '1.3.0', self.subproject,
                                      'This was broken and would not add the project name to the install path',
                                      node)

        install_mode = self._warn_kwarg_install_mode_sticky(kwargs['install_mode'])
        return self.install_data_impl(sources, install_dir, install_mode, rename, kwargs['install_tag'],
                                      preserve_path=kwargs['preserve_path'],
                                      follow_symlinks=kwargs['follow_symlinks'])

    def install_data_impl(self, sources: T.List[mesonlib.File], install_dir: str,
                          install_mode: FileMode, rename: T.Optional[str],
                          tag: T.Optional[str],
                          install_data_type: T.Optional[str] = None,
                          preserve_path: bool = False,
                          follow_symlinks: T.Optional[bool] = None) -> build.Data:
        install_dir_name = install_dir.optname if isinstance(install_dir, P_OBJ.OptionString) else install_dir
        dirs = collections.defaultdict(list)
        if preserve_path:
            for file in sources:
                dirname = os.path.dirname(file.fname)
                dirs[dirname].append(file)
        else:
            dirs[''].extend(sources)

        ret_data = []
        for childdir, files in dirs.items():
            d = build.Data(files, os.path.join(install_dir, childdir), os.path.join(install_dir_name, childdir),
                           install_mode, self.subproject, rename, tag, install_data_type,
                           follow_symlinks)
            ret_data.append(d)

        self.build.data.extend(ret_data)
        return ret_data

    @typed_pos_args('install_subdir', str)
    @typed_kwargs(
        'install_subdir',
        KwargInfo('install_dir', str, required=True),
        KwargInfo('strip_directory', bool, default=False),
        KwargInfo('exclude_files', ContainerTypeInfo(list, str),
                  default=[], listify=True, since='0.42.0',
                  validator=lambda x: 'cannot be absolute' if any(os.path.isabs(d) for d in x) else None),
        KwargInfo('exclude_directories', ContainerTypeInfo(list, str),
                  default=[], listify=True, since='0.42.0',
                  validator=lambda x: 'cannot be absolute' if any(os.path.isabs(d) for d in x) else None),
        INSTALL_MODE_KW.evolve(since='0.38.0'),
        INSTALL_TAG_KW.evolve(since='0.60.0'),
        INSTALL_FOLLOW_SYMLINKS,
    )
    def func_install_subdir(self, node: mparser.BaseNode, args: T.Tuple[str],
                            kwargs: 'kwtypes.FuncInstallSubdir') -> build.InstallDir:
        exclude = (set(kwargs['exclude_files']), set(kwargs['exclude_directories']))

        srcdir = os.path.join(self.environment.source_dir, self.subdir, args[0])
        if not os.path.isdir(srcdir) or not any(os.listdir(srcdir)):
            FeatureNew.single_use('install_subdir with empty directory', '0.47.0', self.subproject, location=node)
            FeatureDeprecated.single_use('install_subdir with empty directory', '0.60.0', self.subproject,
                                         'It worked by accident and is buggy. Use install_emptydir instead.', node)
        install_mode = self._warn_kwarg_install_mode_sticky(kwargs['install_mode'])

        idir_name = kwargs['install_dir']
        if isinstance(idir_name, P_OBJ.OptionString):
            idir_name = idir_name.optname

        idir = build.InstallDir(
            self.subdir,
            args[0],
            kwargs['install_dir'],
            idir_name,
            install_mode,
            exclude,
            kwargs['strip_directory'],
            self.subproject,
            install_tag=kwargs['install_tag'],
            follow_symlinks=kwargs['follow_symlinks'])
        self.build.install_dirs.append(idir)
        return idir

    @noPosargs
    @typed_kwargs(
        'configure_file',
        DEPFILE_KW.evolve(since='0.52.0'),
        INSTALL_MODE_KW.evolve(since='0.47.0,'),
        INSTALL_TAG_KW.evolve(since='0.60.0'),
        KwargInfo('capture', bool, default=False, since='0.41.0'),
        KwargInfo(
            'command',
            (ContainerTypeInfo(list, (build.Executable, ExternalProgram, compilers.Compiler, mesonlib.File, str), allow_empty=False), NoneType),
            listify=True,
        ),
        KwargInfo(
            'configuration',
            (ContainerTypeInfo(dict, (str, int, bool)), build.ConfigurationData, NoneType),
        ),
        KwargInfo(
            'copy', bool, default=False, since='0.47.0',
            deprecated='0.64.0', deprecated_message='Use fs.copyfile instead',
        ),
        KwargInfo('encoding', str, default='utf-8', since='0.47.0'),
        KwargInfo('format', str, default='meson', since='0.46.0',
                  validator=in_set_validator({'meson', 'cmake', 'cmake@'})),
        KwargInfo(
            'input',
            ContainerTypeInfo(list, (mesonlib.File, str)),
            listify=True,
            default=[],
        ),
        # Cannot use shared implementation until None backwards compat is dropped
        KwargInfo('install', (bool, NoneType), since='0.50.0'),
        KwargInfo('install_dir', (str, bool), default='',
                  validator=lambda x: 'must be `false` if boolean' if x is True else None),
        OUTPUT_KW,
        KwargInfo('output_format', str, default='c', since='0.47.0', since_values={'json': '1.3.0'},
                  validator=in_set_validator({'c', 'json', 'nasm'})),
        KwargInfo('macro_name', (str, NoneType), default=None, since='1.3.0'),
    )
    def func_configure_file(self, node: mparser.BaseNode, args: T.List[TYPE_var],
                            kwargs: kwtypes.ConfigureFile):
        actions = sorted(x for x in ['configuration', 'command', 'copy']
                         if kwargs[x] not in [None, False])
        num_actions = len(actions)
        if num_actions == 0:
            raise InterpreterException('Must specify an action with one of these '
                                       'keyword arguments: \'configuration\', '
                                       '\'command\', or \'copy\'.')
        elif num_actions == 2:
            raise InterpreterException('Must not specify both {!r} and {!r} '
                                       'keyword arguments since they are '
                                       'mutually exclusive.'.format(*actions))
        elif num_actions == 3:
            raise InterpreterException('Must specify one of {!r}, {!r}, and '
                                       '{!r} keyword arguments since they are '
                                       'mutually exclusive.'.format(*actions))

        if kwargs['capture'] and not kwargs['command']:
            raise InvalidArguments('configure_file: "capture" keyword requires "command" keyword.')

        install_mode = self._warn_kwarg_install_mode_sticky(kwargs['install_mode'])

        fmt = kwargs['format']
        output_format = kwargs['output_format']
        depfile = kwargs['depfile']

        # Validate input
        inputs = self.source_strings_to_files(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 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 = f"{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
        (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 kwargs['configuration'] is not None:
            conf = kwargs['configuration']
            if isinstance(conf, dict):
                FeatureNew.single_use('configure_file.configuration dictionary', '0.49.0', self.subproject, location=node)
                for k, v in conf.items():
                    if not isinstance(v, (str, int, bool)):
                        raise InvalidArguments(
                            f'"configuration_data": initial value dictionary key "{k!r}"" must be "str | int | bool", not "{v!r}"')
                conf = build.ConfigurationData(conf)
            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['encoding']
                missing_variables, confdata_useless = \
                    mesonlib.do_conf_file(inputs_abs[0], ofile_abs, conf,
                                          fmt, file_encoding, self.subproject)
                if missing_variables:
                    var_list = ", ".join(repr(m) for m in sorted(missing_variables))
                    mlog.warning(
                        f"The variable(s) {var_list} in the input file '{inputs[0]}' are not "
                        "present in the given configuration data.", location=node)
                if confdata_useless:
                    ifbase = os.path.basename(inputs_abs[0])
                    tv = FeatureNew.get_target_version(self.subproject)
                    if FeatureNew.check_version(tv, '0.47.0'):
                        mlog.warning('Got an empty configuration_data() object and found no '
                                     f'substitutions in the input file {ifbase!r}. If you want to '
                                     'copy a file to the build dir, use the \'copy:\' keyword '
                                     'argument added in 0.47.0', location=node)
            else:
                macro_name = kwargs['macro_name']
                mesonlib.dump_conf_header(ofile_abs, conf, output_format, macro_name)
            conf.used = True
        elif kwargs['command'] is not None:
            if len(inputs) > 1:
                FeatureNew.single_use('multiple inputs in configure_file()', '0.52.0', self.subproject, location=node)
            # 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')
            cmd, *args = _cmd
            res = self.run_command_impl((cmd, args),
                                        {'capture': True, 'check': True, 'env': EnvironmentVariables()},
                                        True)
            if kwargs['capture']:
                dst_tmp = ofile_abs + '~'
                file_encoding = kwargs['encoding']
                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, encoding='utf-8') as f:
                    df = DepFile(f.readlines())
                    deps = df.get_all_dependencies(ofile_fname)
                    for dep in deps:
                        self.add_build_def_file(dep)

        elif kwargs['copy']:
            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.copy2(inputs_abs[0], ofile_abs)

        # 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['install_dir']
        if idir is False:
            idir = ''
            FeatureDeprecated.single_use('configure_file install_dir: false', '0.50.0',
                                         self.subproject, 'Use the `install:` kwarg instead', location=node)
        install = kwargs['install'] if kwargs['install'] is not None else idir != ''
        if install:
            if not idir:
                raise InterpreterException(
                    '"install_dir" must be specified when "install" in a configure_file is true')
            idir_name = idir
            if isinstance(idir_name, P_OBJ.OptionString):
                idir_name = idir_name.optname
            cfile = mesonlib.File.from_built_file(ofile_path, ofile_fname)
            install_tag = kwargs['install_tag']
            self.build.data.append(build.Data([cfile], idir, idir_name, install_mode, self.subproject,
                                              install_tag=install_tag, data_type='configure'))
        return mesonlib.File.from_built_file(self.subdir, output)

    def extract_incdirs(self, kwargs, key: str = 'include_directories') -> T.List[build.IncludeDirs]:
        prospectives = extract_as_list(kwargs, key)
        if key == 'include_directories':
            for i in prospectives:
                if isinstance(i, str):
                    FeatureNew.single_use('include_directories kwarg of type string', '0.50.0', self.subproject,
                                          f'Use include_directories({i!r}) instead', location=self.current_node)
                    break

        result: T.List[build.IncludeDirs] = []
        for p in prospectives:
            if isinstance(p, build.IncludeDirs):
                result.append(p)
            elif isinstance(p, str):
                result.append(self.build_incdir_object([p]))
            else:
                raise InterpreterException('Include directory objects can only be created from strings or include directories.')
        return result

    @typed_pos_args('include_directories', varargs=str)
    @typed_kwargs('include_directories', KwargInfo('is_system', bool, default=False))
    def func_include_directories(self, node: mparser.BaseNode, args: T.Tuple[T.List[str]],
                                 kwargs: 'kwtypes.FuncIncludeDirectories') -> build.IncludeDirs:
        return self.build_incdir_object(args[0], kwargs['is_system'])

    def build_incdir_object(self, incdir_strings: T.List[str], is_system: bool = False) -> build.IncludeDirs:
        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 path_is_in_root(Path(a), Path(src_root)):
                raise InvalidArguments(textwrap.dedent('''\
                    Tried to form an absolute path to a dir in the source tree.
                    You should not do that but use relative paths instead, for
                    directories that are part of your project.

                    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.

                    Note that this error message can also be triggered by
                    external dependencies being installed within your source
                    tree - it's not recommended to do this.
                    '''))
            else:
                try:
                    self.validate_within_subproject(self.subdir, a)
                except InterpreterException:
                    mlog.warning('include_directories sandbox violation!', location=self.current_node)
                    print(textwrap.dedent(f'''\
                        The project is trying to access the directory {a!r} which belongs to a different
                        subproject. This is a problem as it hardcodes the relative paths of these two projects.
                        This makes it impossible to compile the project in any other directory layout and also
                        prevents the subproject from changing its own directory layout.

                        Instead of poking directly at the internals the subproject should be executed and
                        it should set a variable that the caller can then use. Something like:

                        # In subproject
                        some_dep = declare_dependency(include_directories: include_directories('include'))

                        # In subproject wrap file
                        [provide]
                        some = some_dep

                        # In parent project
                        some_dep = dependency('some')
                        executable(..., dependencies: [some_dep])

                        This warning will become a hard error in a future Meson release.
                        '''))
            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(f'Include dir {a} does not exist.')
        i = build.IncludeDirs(self.subdir, incdir_strings, is_system)
        return i

    @typed_pos_args('add_test_setup', str)
    @typed_kwargs(
        'add_test_setup',
        KwargInfo('exe_wrapper', ContainerTypeInfo(list, (str, ExternalProgram)), listify=True, default=[]),
        KwargInfo('gdb', bool, default=False),
        KwargInfo('timeout_multiplier', int, default=1),
        KwargInfo('exclude_suites', ContainerTypeInfo(list, str), listify=True, default=[], since='0.57.0'),
        KwargInfo('is_default', bool, default=False, since='0.49.0'),
        ENV_KW,
    )
    def func_add_test_setup(self, node: mparser.BaseNode, args: T.Tuple[str], kwargs: 'kwtypes.AddTestSetup') -> None:
        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 = f'{(self.subproject if self.subproject else self.build.project_name)}:{setup_name}'

        exe_wrapper: T.List[str] = []
        for i in kwargs['exe_wrapper']:
            if isinstance(i, str):
                exe_wrapper.append(i)
            else:
                if not i.found():
                    raise InterpreterException('Tried to use non-found executable.')
                exe_wrapper += i.get_command()

        timeout_multiplier = kwargs['timeout_multiplier']
        if timeout_multiplier <= 0:
            FeatureNew('add_test_setup() timeout_multiplier <= 0', '0.57.0').use(self.subproject)

        if kwargs['is_default']:
            if self.build.test_setup_default_name is not None:
                raise InterpreterException(f'{self.build.test_setup_default_name!r} is already set as default. '
                                           'is_default can be set to true only once')
            self.build.test_setup_default_name = setup_name
        self.build.test_setups[setup_name] = build.TestSetup(exe_wrapper, kwargs['gdb'], timeout_multiplier, kwargs['env'],
                                                             kwargs['exclude_suites'])

    @typed_pos_args('add_global_arguments', varargs=str)
    @typed_kwargs('add_global_arguments', NATIVE_KW, LANGUAGE_KW)
    def func_add_global_arguments(self, node: mparser.FunctionNode, args: T.Tuple[T.List[str]], kwargs: 'kwtypes.FuncAddProjectArgs') -> None:
        self._add_global_arguments(node, self.build.global_args[kwargs['native']], args[0], kwargs)

    @typed_pos_args('add_global_link_arguments', varargs=str)
    @typed_kwargs('add_global_arguments', NATIVE_KW, LANGUAGE_KW)
    def func_add_global_link_arguments(self, node: mparser.FunctionNode, args: T.Tuple[T.List[str]], kwargs: 'kwtypes.FuncAddProjectArgs') -> None:
        self._add_global_arguments(node, self.build.global_link_args[kwargs['native']], args[0], kwargs)

    @typed_pos_args('add_project_arguments', varargs=str)
    @typed_kwargs('add_project_arguments', NATIVE_KW, LANGUAGE_KW)
    def func_add_project_arguments(self, node: mparser.FunctionNode, args: T.Tuple[T.List[str]], kwargs: 'kwtypes.FuncAddProjectArgs') -> None:
        self._add_project_arguments(node, self.build.projects_args[kwargs['native']], args[0], kwargs)

    @typed_pos_args('add_project_link_arguments', varargs=str)
    @typed_kwargs('add_global_arguments', NATIVE_KW, LANGUAGE_KW)
    def func_add_project_link_arguments(self, node: mparser.FunctionNode, args: T.Tuple[T.List[str]], kwargs: 'kwtypes.FuncAddProjectArgs') -> None:
        self._add_project_arguments(node, self.build.projects_link_args[kwargs['native']], args[0], kwargs)

    @FeatureNew('add_project_dependencies', '0.63.0')
    @typed_pos_args('add_project_dependencies', varargs=dependencies.Dependency)
    @typed_kwargs('add_project_dependencies', NATIVE_KW, LANGUAGE_KW)
    def func_add_project_dependencies(self, node: mparser.FunctionNode, args: T.Tuple[T.List[dependencies.Dependency]], kwargs: 'kwtypes.FuncAddProjectArgs') -> None:
        for_machine = kwargs['native']
        for lang in kwargs['language']:
            if lang not in self.compilers[for_machine]:
                raise InvalidCode(f'add_project_dependencies() called before add_language() for language "{lang}"')

        for d in dependencies.get_leaf_external_dependencies(args[0]):
            compile_args = list(d.get_compile_args())
            system_incdir = d.get_include_type() == 'system'
            for i in d.get_include_dirs():
                for lang in kwargs['language']:
                    comp = self.coredata.compilers[for_machine][lang]
                    for idir in i.to_string_list(self.environment.get_source_dir(), self.environment.get_build_dir()):
                        compile_args.extend(comp.get_include_args(idir, system_incdir))

            self._add_project_arguments(node, self.build.projects_args[for_machine], compile_args, kwargs)
            self._add_project_arguments(node, self.build.projects_link_args[for_machine], d.get_link_args(), kwargs)

    def _warn_about_builtin_args(self, args: T.List[str]) -> None:
        # -Wpedantic is deliberately not included, since some people want to use it but not use -Wextra
        # see e.g.
        # https://github.com/mesonbuild/meson/issues/3275#issuecomment-641354956
        # https://github.com/mesonbuild/meson/issues/3742
        warnargs = ('/W1', '/W2', '/W3', '/W4', '/Wall', '-Wall', '-Wextra')
        optargs = ('-O0', '-O2', '-O3', '-Os', '-Oz', '/O1', '/O2', '/Os')
        for arg in args:
            if arg in warnargs:
                mlog.warning(f'Consider using the built-in warning_level option instead of using "{arg}".',
                             location=self.current_node)
            elif arg in optargs:
                mlog.warning(f'Consider using the built-in optimization level instead of using "{arg}".',
                             location=self.current_node)
            elif arg == '-Werror':
                mlog.warning(f'Consider using the built-in werror option instead of using "{arg}".',
                             location=self.current_node)
            elif arg == '-g':
                mlog.warning(f'Consider using the built-in debug option instead of using "{arg}".',
                             location=self.current_node)
            elif arg.startswith('-fsanitize'):
                mlog.warning(f'Consider using the built-in option for sanitizers instead of using "{arg}".',
                             location=self.current_node)
            elif arg.startswith('-std=') or arg.startswith('/std:'):
                mlog.warning(f'Consider using the built-in option for language standard version instead of using "{arg}".',
                             location=self.current_node)

    def _add_global_arguments(self, node: mparser.FunctionNode, argsdict: T.Dict[str, T.List[str]],
                              args: T.List[str], kwargs: 'kwtypes.FuncAddProjectArgs') -> None:
        if self.is_subproject():
            msg = f'Function \'{node.func_name.value}\' 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.'
            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: mparser.FunctionNode, argsdict: T.Dict[str, T.Dict[str, T.List[str]]],
                               args: T.List[str], kwargs: 'kwtypes.FuncAddProjectArgs') -> None:
        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: mparser.FunctionNode, argsdict: T.Dict[str, T.List[str]],
                       args_frozen: bool, args: T.List[str], kwargs: 'kwtypes.FuncAddProjectArgs') -> None:
        if args_frozen:
            msg = f'Tried to use \'{node.func_name.value}\' after a build target has been declared.\n' \
                  'This is not permitted. Please declare all arguments before your targets.'
            raise InvalidCode(msg)

        self._warn_about_builtin_args(args)

        for lang in kwargs['language']:
            argsdict[lang] = argsdict.get(lang, []) + args

    @noArgsFlattening
    @typed_pos_args('environment', optargs=[(str, list, dict)])
    @typed_kwargs('environment', ENV_METHOD_KW, ENV_SEPARATOR_KW.evolve(since='0.62.0'))
    def func_environment(self, node: mparser.FunctionNode, args: T.Tuple[T.Union[None, str, T.List['TYPE_var'], T.Dict[str, 'TYPE_var']]],
                         kwargs: 'TYPE_kwargs') -> EnvironmentVariables:
        init = args[0]
        if init is not None:
            FeatureNew.single_use('environment positional arguments', '0.52.0', self.subproject, location=node)
            msg = ENV_KW.validator(init)
            if msg:
                raise InvalidArguments(f'"environment": {msg}')
            if isinstance(init, dict) and any(i for i in init.values() if isinstance(i, list)):
                FeatureNew.single_use('List of string in dictionary value', '0.62.0', self.subproject, location=node)
            return env_convertor_with_method(init, kwargs['method'], kwargs['separator'])
        return EnvironmentVariables()

    @typed_pos_args('join_paths', varargs=str, min_varargs=1)
    @noKwargs
    def func_join_paths(self, node: mparser.BaseNode, args: T.Tuple[T.List[str]], kwargs: 'TYPE_kwargs') -> str:
        parts = args[0]
        other = os.path.join('', *parts[1:]).replace('\\', '/')
        ret = os.path.join(*parts).replace('\\', '/')
        if isinstance(parts[0], P_OBJ.DependencyVariableString) and '..' not in other:
            return P_OBJ.DependencyVariableString(ret)
        elif isinstance(parts[0], P_OBJ.OptionString):
            name = os.path.join(parts[0].optname, other)
            return P_OBJ.OptionString(ret, name)
        else:
            return ret

    def run(self) -> None:
        super().run()
        mlog.log('Build targets in project:', mlog.bold(str(len(self.build.targets))))
        FeatureNew.report(self.subproject)
        FeatureDeprecated.report(self.subproject)
        FeatureBroken.report(self.subproject)
        if not self.is_subproject():
            self.print_extra_warnings()
            self._print_summary()

    def print_extra_warnings(self) -> None:
        # 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) -> None:
        if OptionKey('b_lundef') not in self.coredata.options:
            return
        if OptionKey('b_sanitize') not in self.coredata.options:
            return
        if (self.coredata.options[OptionKey('b_lundef')].value and
                self.coredata.options[OptionKey('b_sanitize')].value != 'none'):
            value = self.coredata.options[OptionKey('b_sanitize')].value
            mlog.warning(textwrap.dedent(f'''\
                    Trying to use {value} sanitizer on Clang with b_lundef.
                    This will probably not work.
                    Try setting b_lundef to false instead.'''),
                location=self.current_node)  # noqa: E128

    # 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):
        srcdir = Path(self.environment.source_dir)
        builddir = Path(self.environment.build_dir)
        if isinstance(fname, P_OBJ.DependencyVariableString):
            def validate_installable_file(fpath: Path) -> bool:
                installablefiles: T.Set[Path] = set()
                for d in self.build.data:
                    for s in d.sources:
                        installablefiles.add(Path(s.absolute_path(srcdir, builddir)))
                installabledirs = [str(Path(srcdir, s.source_subdir)) for s in self.build.install_dirs]
                if fpath in installablefiles:
                    return True
                for d in installabledirs:
                    if str(fpath).startswith(d):
                        return True
                return False

            norm = Path(fname)
            # variables built from a dep.get_variable are allowed to refer to
            # subproject files, as long as they are scheduled to be installed.
            if validate_installable_file(norm):
                return
        norm = Path(os.path.abspath(Path(srcdir, subdir, fname)))
        if os.path.isdir(norm):
            inputtype = 'directory'
        else:
            inputtype = 'file'
        if InterpreterRuleRelaxation.ALLOW_BUILD_DIR_FILE_REFERENCES in self.relaxations and builddir in norm.parents:
            return
        if srcdir not in norm.parents:
            # Grabbing files outside the source tree is ok.
            # This is for vendor stuff like:
            #
            # /opt/vendorsdk/src/file_with_license_restrictions.c
            return
        project_root = Path(srcdir, self.root_subdir)
        subproject_dir = project_root / self.subproject_dir
        if norm == project_root:
            return
        if project_root not in norm.parents:
            raise InterpreterException(f'Sandbox violation: Tried to grab {inputtype} {norm.name} outside current (sub)project.')
        if subproject_dir == norm or subproject_dir in norm.parents:
            raise InterpreterException(f'Sandbox violation: Tried to grab {inputtype} {norm.name} from a nested subproject.')

    @T.overload
    def source_strings_to_files(self, sources: T.List['mesonlib.FileOrString'], strict: bool = True) -> T.List['mesonlib.File']: ...

    @T.overload
    def source_strings_to_files(self, sources: T.List['mesonlib.FileOrString'], strict: bool = False) -> T.List['mesonlib.FileOrString']: ... # noqa: F811

    @T.overload
    def source_strings_to_files(self, sources: T.List[T.Union[mesonlib.FileOrString, build.GeneratedTypes]]) -> T.List[T.Union[mesonlib.File, build.GeneratedTypes]]: ... # noqa: F811

    @T.overload
    def source_strings_to_files(self, sources: T.List['SourceInputs'], strict: bool = True) -> T.List['SourceOutputs']: ... # noqa: F811

    @T.overload
    def source_strings_to_files(self, sources: T.List[SourcesVarargsType], strict: bool = True) -> T.List['SourceOutputs']: ... # noqa: F811

    def source_strings_to_files(self, sources: T.List['SourceInputs'], strict: bool = True) -> T.List['SourceOutputs']: # noqa: F811
        """Lower inputs to a list of Targets and Files, replacing any strings.

        :param sources: A raw (Meson DSL) list of inputs (targets, files, and
            strings)
        :raises InterpreterException: if any of the inputs are of an invalid type
        :return: A list of Targets and Files
        """
        mesonlib.check_direntry_issues(sources)
        if not isinstance(sources, list):
            sources = [sources]
        results: T.List['SourceOutputs'] = []
        for s in sources:
            if isinstance(s, str):
                if not strict and s.startswith(self.environment.get_build_dir()):
                    results.append(s)
                    mlog.warning(f'Source item {s!r} cannot be converted to File object, because it is a generated file. '
                                 'This will become a hard error in the future.', location=self.current_node)
                else:
                    self.validate_within_subproject(self.subdir, s)
                    results.append(mesonlib.File.from_source_file(self.environment.source_dir, self.subdir, s))
            elif isinstance(s, mesonlib.File):
                results.append(s)
            elif isinstance(s, (build.GeneratedList, build.BuildTarget,
                                build.CustomTargetIndex, build.CustomTarget,
                                build.ExtractedObjects, build.StructuredSources)):
                results.append(s)
            else:
                raise InterpreterException(f'Source item is {s!r} instead of '
                                           'string or File-type object')
        return results

    @staticmethod
    def validate_forbidden_targets(name: str) -> None:
        if name.startswith('meson-internal__'):
            raise InvalidArguments("Target names starting with 'meson-internal__' are reserved "
                                   "for Meson's internal use. Please rename.")
        if name.startswith('meson-') and '.' not in name:
            raise InvalidArguments("Target names starting with 'meson-' and without a file extension "
                                   "are reserved for Meson's internal use. Please rename.")
        if name in coredata.FORBIDDEN_TARGET_NAMES:
            raise InvalidArguments(f"Target name '{name}' is reserved for Meson's "
                                   "internal use. Please rename.")

    def add_target(self, name: str, tobj: build.Target) -> None:
        if self.backend.name == 'none':
            raise InterpreterException('Install-only backend cannot generate target rules, try using `--backend=ninja`.')
        if name == '':
            raise InterpreterException('Target name must not be empty.')
        if name.strip() == '':
            raise InterpreterException('Target name must not consist only of whitespace.')
        if has_path_sep(name):
            pathseg = os.path.join(self.subdir, os.path.split(name)[0])
            if os.path.exists(os.path.join(self.source_root, pathseg)):
                raise InvalidArguments(textwrap.dedent(f'''\
                    Target "{name}" has a path segment pointing to directory "{pathseg}". This is an error.
                    To define a target that builds in that directory you must define it
                    in the meson.build file in that directory.
            '''))
        self.validate_forbidden_targets(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()
        subdir = tobj.get_subdir()
        namedir = (name, subdir)

        if idname in self.build.targets:
            raise InvalidCode(f'Tried to create target "{name}", but a target of that name already exists.')

        if isinstance(tobj, build.Executable) and namedir in self.build.targetnames:
            FeatureNew.single_use(f'multiple executables with the same name, "{tobj.name}", but different suffixes in the same directory',
                                  '1.3.0', self.subproject, location=self.current_node)

        if isinstance(tobj, build.BuildTarget):
            self.add_languages(tobj.missing_languages, True, tobj.for_machine)
            tobj.process_compilers_late()
            self.add_stdlib_info(tobj)

        self.build.targets[idname] = tobj
        # Only need to add executables to this set
        if isinstance(tobj, build.Executable):
            self.build.targetnames.update([namedir])
        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: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType], kwargs: kwtypes.Library) -> build.BothLibraries:
        shared_lib = self.build_target(node, args, kwargs, build.SharedLibrary)
        static_lib = self.build_target(node, args, kwargs, build.StaticLibrary)

        if self.backend.name == 'xcode':
            # Xcode is a bit special in that you can't (at least for the moment)
            # form a library only from object file inputs. The simple but inefficient
            # solution is to use the sources directly. This will lead to them being
            # built twice. This is unfortunate and slow, but at least it works.
            # Feel free to submit patches to get this fixed if it is an
            # issue for you.
            reuse_object_files = False
        elif shared_lib.uses_rust():
            # FIXME: rustc supports generating both libraries in a single invocation,
            # but for now compile twice.
            reuse_object_files = False
        elif any(k.endswith(('static_args', 'shared_args')) and v for k, v in kwargs.items()):
            # Ensure not just the keyword arguments exist, but that they are non-empty.
            reuse_object_files = False
        else:
            reuse_object_files = static_lib.pic

        if reuse_object_files:
            # Replace sources with objects from the shared library to avoid
            # building them twice. We post-process the static library instead of
            # removing sources from args because sources could also come from
            # any InternalDependency, see BuildTarget.add_deps().
            static_lib.objects.append(build.ExtractedObjects(shared_lib, shared_lib.sources, shared_lib.generated, []))
            static_lib.sources = []
            static_lib.generated = []
            # Compilers with no corresponding sources confuses the backend.
            # Keep only compilers used for linking
            static_lib.compilers = {k: v for k, v in static_lib.compilers.items() if k in compilers.clink_langs}

        return build.BothLibraries(shared_lib, static_lib)

    def build_library(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType], kwargs: kwtypes.Library):
        default_library = self.coredata.get_option(OptionKey('default_library', subproject=self.subproject))
        assert isinstance(default_library, str), 'for mypy'
        if default_library == 'shared':
            return self.build_target(node, args, T.cast('kwtypes.StaticLibrary', kwargs), build.SharedLibrary)
        elif default_library == 'static':
            return self.build_target(node, args, T.cast('kwtypes.SharedLibrary', kwargs), build.StaticLibrary)
        elif default_library == 'both':
            return self.build_both_libraries(node, args, kwargs)
        else:
            raise InterpreterException(f'Unknown default_library value: {default_library}.')

    def __convert_file_args(self, raw: T.List[mesonlib.FileOrString]) -> T.Tuple[T.List[mesonlib.File], T.List[str]]:
        """Convert raw target arguments from File | str to File.

        This removes files from the command line and replaces them with string
        values, but adds the files to depends list

        :param raw: the raw arguments
        :return: A tuple of file dependencies and raw arguments
        """
        depend_files: T.List[mesonlib.File] = []
        args: T.List[str] = []
        build_to_source = mesonlib.relpath(self.environment.get_source_dir(),
                                           self.environment.get_build_dir())

        for a in raw:
            if isinstance(a, mesonlib.File):
                depend_files.append(a)
                args.append(a.rel_to_builddir(build_to_source))
            else:
                args.append(a)

        return depend_files, args

    def __process_language_args(self, kwargs: T.Dict[str, T.List[mesonlib.FileOrString]]) -> None:
        """Convert split language args into a combined dictionary.

        The Meson DSL takes arguments in the form `_args : args`, but in the
        build layer we store these in a single dictionary as `{: args}`.
        This function extracts the arguments from the DSL format and prepares
        them for the IR.
        """
        d = kwargs.setdefault('depend_files', [])
        new_args: T.DefaultDict[str, T.List[str]] = collections.defaultdict(list)

        for l in compilers.all_languages:
            deps, args = self.__convert_file_args(kwargs[f'{l}_args'])
            new_args[l] = args
            d.extend(deps)
        kwargs['language_args'] = new_args

    @T.overload
    def build_target(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType],
                     kwargs: kwtypes.Executable, targetclass: T.Type[build.Executable]) -> build.Executable: ...

    @T.overload
    def build_target(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType],
                     kwargs: kwtypes.StaticLibrary, targetclass: T.Type[build.StaticLibrary]) -> build.StaticLibrary: ...

    @T.overload
    def build_target(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType],
                     kwargs: kwtypes.SharedLibrary, targetclass: T.Type[build.SharedLibrary]) -> build.SharedLibrary: ...

    @T.overload
    def build_target(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType],
                     kwargs: kwtypes.SharedModule, targetclass: T.Type[build.SharedModule]) -> build.SharedModule: ...

    @T.overload
    def build_target(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType],
                     kwargs: kwtypes.Jar, targetclass: T.Type[build.Jar]) -> build.Jar: ...

    def build_target(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType],
                     kwargs: T.Union[kwtypes.Executable, kwtypes.StaticLibrary, kwtypes.SharedLibrary, kwtypes.SharedModule, kwtypes.Jar],
                     targetclass: T.Type[T.Union[build.Executable, build.StaticLibrary, build.SharedModule, build.SharedLibrary, build.Jar]]
                     ) -> T.Union[build.Executable, build.StaticLibrary, build.SharedModule, build.SharedLibrary, build.Jar]:
        name, sources = args
        for_machine = kwargs['native']
        if kwargs.get('rust_crate_type') == 'proc-macro':
            # Silently force to native because that's the only sensible value
            # and rust_crate_type is deprecated any way.
            for_machine = MachineChoice.BUILD
        # Avoid mutating, since there could be other references to sources
        sources = sources + kwargs['sources']
        if any(isinstance(s, build.BuildTarget) for s in sources):
            FeatureBroken.single_use('passing references to built targets as a source file', '1.1.0', self.subproject,
                                     'Consider using `link_with` or `link_whole` if you meant to link, or dropping them as otherwise they are ignored.',
                                     node)
        if any(isinstance(s, build.ExtractedObjects) for s in sources):
            FeatureBroken.single_use('passing object files as sources', '1.1.0', self.subproject,
                                     'Pass these to the `objects` keyword instead, they are ignored when passed as sources.',
                                     node)
        # Go ahead and drop these here, since they're only allowed through for
        # backwards compatibility anyway
        sources = [s for s in sources
                   if not isinstance(s, (build.BuildTarget, build.ExtractedObjects))]

        # due to lack of type checking, these are "allowed" for legacy reasons
        if not isinstance(kwargs['install'], bool):
            FeatureBroken.single_use('install kwarg with non-boolean value', '1.3.0', self.subproject,
                                     'This was never intended to work, and is essentially the same as using `install: true` regardless of value.',
                                     node)

        sources = self.source_strings_to_files(sources)
        objs = kwargs['objects']
        kwargs['dependencies'] = extract_as_list(kwargs, 'dependencies')
        kwargs['extra_files'] = self.source_strings_to_files(kwargs['extra_files'])
        self.check_sources_exist(os.path.join(self.source_root, self.subdir), sources)
        if targetclass not in {build.Executable, build.SharedLibrary, build.SharedModule, build.StaticLibrary, build.Jar}:
            mlog.debug('Unknown target type:', str(targetclass))
            raise RuntimeError('Unreachable code')
        self.__process_language_args(kwargs)
        if targetclass is build.StaticLibrary:
            for lang in compilers.all_languages - {'java'}:
                deps, args = self.__convert_file_args(kwargs.get(f'{lang}_static_args', []))
                kwargs['language_args'][lang].extend(args)
                kwargs['depend_files'].extend(deps)
        elif targetclass is build.SharedLibrary:
            for lang in compilers.all_languages - {'java'}:
                deps, args = self.__convert_file_args(kwargs.get(f'{lang}_shared_args', []))
                kwargs['language_args'][lang].extend(args)
                kwargs['depend_files'].extend(deps)
        if targetclass is not build.Jar:
            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 | {'language_args'}}

        srcs: T.List['SourceInputs'] = []
        struct: T.Optional[build.StructuredSources] = build.StructuredSources()
        for s in sources:
            if isinstance(s, build.StructuredSources):
                struct = struct + s
            else:
                srcs.append(s)

        if not struct:
            struct = None
        else:
            # Validate that we won't end up with two outputs with the same name.
            # i.e, don't allow:
            # [structured_sources('foo/bar.rs'), structured_sources('bar/bar.rs')]
            for v in struct.sources.values():
                outputs: T.Set[str] = set()
                for f in v:
                    o: T.List[str]
                    if isinstance(f, str):
                        o = [os.path.basename(f)]
                    elif isinstance(f, mesonlib.File):
                        o = [f.fname]
                    else:
                        o = f.get_outputs()
                    conflicts = outputs.intersection(o)
                    if conflicts:
                        raise InvalidArguments.from_node(
                            f"Conflicting sources in structured sources: {', '.join(sorted(conflicts))}",
                            node=node)
                    outputs.update(o)

        kwargs['include_directories'] = self.extract_incdirs(kwargs)

        if targetclass is build.Executable:
            kwargs = T.cast('kwtypes.Executable', kwargs)
            if kwargs['gui_app'] is not None:
                if kwargs['win_subsystem'] is not None:
                    raise InvalidArguments.from_node(
                        'Executable got both "gui_app", and "win_subsystem" arguments, which are mutually exclusive',
                        node=node)
                if kwargs['gui_app']:
                    kwargs['win_subsystem'] = 'windows'
            if kwargs['win_subsystem'] is None:
                kwargs['win_subsystem'] = 'console'

            if kwargs['implib']:
                if kwargs['export_dynamic'] is False:
                    FeatureDeprecated.single_use('implib overrides explict export_dynamic off', '1.3.0', self.subprojct,
                                                 'Do not set ths if want export_dynamic disabled if implib is enabled',
                                                 location=node)
                kwargs['export_dynamic'] = True
            elif kwargs['export_dynamic']:
                if kwargs['implib'] is False:
                    raise InvalidArguments('"implib" keyword" must not be false if "export_dynamic" is set and not false.')
                kwargs['implib'] = True
            if kwargs['export_dynamic'] is None:
                kwargs['export_dynamic'] = False
            if kwargs['implib'] is None:
                kwargs['implib'] = False

        target = targetclass(name, self.subdir, self.subproject, for_machine, srcs, struct, objs,
                             self.environment, self.compilers[for_machine], kwargs)

        self.add_target(name, target)
        self.project_args_frozen = True
        return target

    def kwarg_strings_to_includedirs(self, kwargs: kwtypes._BuildTarget) -> None:
        if kwargs['d_import_dirs']:
            items = kwargs['d_import_dirs']
            cleaned_items: T.List[build.IncludeDirs] = []
            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 add_stdlib_info(self, target):
        for l in target.compilers.keys():
            dep = self.build.stdlibs[target.for_machine].get(l, None)
            if dep:
                target.add_deps(dep)

    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(f'Tried to add non-existing source file {s}.')

    # Only permit object extraction from the same subproject
    def validate_extraction(self, buildtarget: mesonlib.HoldableObject) -> None:
        if self.subproject != buildtarget.subproject:
            raise InterpreterException('Tried to extract objects from a different subproject.')

    def is_subproject(self) -> bool:
        return self.subproject != ''

    @typed_pos_args('set_variable', str, object)
    @noKwargs
    @noArgsFlattening
    @noSecondLevelHolderResolving
    def func_set_variable(self, node: mparser.BaseNode, args: T.Tuple[str, object], kwargs: 'TYPE_kwargs') -> None:
        varname, value = args
        self.set_variable(varname, value, holderify=True)

    @typed_pos_args('get_variable', (str, Disabler), optargs=[object])
    @noKwargs
    @noArgsFlattening
    @unholder_return
    def func_get_variable(self, node: mparser.BaseNode, args: T.Tuple[T.Union[str, Disabler], T.Optional[object]],
                          kwargs: 'TYPE_kwargs') -> 'TYPE_var':
        varname, fallback = args
        if isinstance(varname, Disabler):
            return varname

        try:
            return self.variables[varname]
        except KeyError:
            if fallback is not None:
                return self._holderify(fallback)
        raise InterpreterException(f'Tried to get unknown variable "{varname}".')

    @typed_pos_args('is_variable', str)
    @noKwargs
    def func_is_variable(self, node: mparser.BaseNode, args: T.Tuple[str], kwargs: 'TYPE_kwargs') -> bool:
        return args[0] in self.variables

    @FeatureNew('unset_variable', '0.60.0')
    @typed_pos_args('unset_variable', str)
    @noKwargs
    def func_unset_variable(self, node: mparser.BaseNode, args: T.Tuple[str], kwargs: 'TYPE_kwargs') -> None:
        varname = args[0]
        try:
            del self.variables[varname]
        except KeyError:
            raise InterpreterException(f'Tried to unset unknown variable "{varname}".')

    @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')
    @typed_pos_args('is_disabler', object)
    @noKwargs
    def func_is_disabler(self, node: mparser.BaseNode, args: T.Tuple[object], kwargs: 'TYPE_kwargs') -> bool:
        return isinstance(args[0], Disabler)

    @noKwargs
    @FeatureNew('range', '0.58.0')
    @typed_pos_args('range', int, optargs=[int, int])
    def func_range(self, node, args: T.Tuple[int, T.Optional[int], T.Optional[int]], kwargs: T.Dict[str, T.Any]) -> P_OBJ.RangeHolder:
        start, stop, step = args
        # Just like Python's range, we allow range(stop), range(start, stop), or
        # range(start, stop, step)
        if stop is None:
            stop = start
            start = 0
        if step is None:
            step = 1
        # This is more strict than Python's range()
        if start < 0:
            raise InterpreterException('start cannot be negative')
        if stop < start:
            raise InterpreterException('stop cannot be less than start')
        if step < 1:
            raise InterpreterException('step must be >=1')
        return P_OBJ.RangeHolder(start, stop, step, subproject=self.subproject)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/interpreter/interpreterobjects.py0000644000175000017500000013317414562742363024050 0ustar00jpakkanejpakkanefrom __future__ import annotations
import os
import shlex
import subprocess
import copy
import textwrap

from pathlib import Path, PurePath

from .. import mesonlib
from .. import coredata
from .. import build
from .. import mlog

from ..modules import ModuleReturnValue, ModuleObject, ModuleState, ExtensionModule
from ..backend.backends import TestProtocol
from ..interpreterbase import (
                               ContainerTypeInfo, KwargInfo, MesonOperator,
                               MesonInterpreterObject, ObjectHolder, MutableInterpreterObject,
                               FeatureNew, FeatureDeprecated,
                               typed_pos_args, typed_kwargs, typed_operator,
                               noArgsFlattening, noPosargs, noKwargs, unholder_return,
                               flatten, resolve_second_level_holders, InterpreterException, InvalidArguments, InvalidCode)
from ..interpreter.type_checking import NoneType, ENV_KW, ENV_SEPARATOR_KW, PKGCONFIG_DEFINE_KW
from ..dependencies import Dependency, ExternalLibrary, InternalDependency
from ..programs import ExternalProgram
from ..mesonlib import HoldableObject, OptionKey, listify, Popen_safe

import typing as T

if T.TYPE_CHECKING:
    from . import kwargs
    from ..cmake.interpreter import CMakeInterpreter
    from ..envconfig import MachineInfo
    from ..interpreterbase import FeatureCheckBase, InterpreterObject, SubProject, TYPE_var, TYPE_kwargs, TYPE_nvar, TYPE_nkwargs
    from .interpreter import Interpreter

    from typing_extensions import TypedDict

    class EnvironmentSeparatorKW(TypedDict):

        separator: str

_ERROR_MSG_KW: KwargInfo[T.Optional[str]] = KwargInfo('error_message', (str, NoneType))


def extract_required_kwarg(kwargs: 'kwargs.ExtractRequired',
                           subproject: 'SubProject',
                           feature_check: T.Optional[FeatureCheckBase] = None,
                           default: bool = True) -> T.Tuple[bool, bool, T.Optional[str]]:
    val = kwargs.get('required', default)
    disabled = False
    required = False
    feature: T.Optional[str] = None
    if isinstance(val, coredata.UserFeatureOption):
        if not feature_check:
            feature_check = FeatureNew('User option "feature"', '0.47.0')
        feature_check.use(subproject)
        feature = val.name
        if val.is_disabled():
            disabled = True
        elif val.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.
    # TODO: this should be removed, and those callers should learn about FeatureOptions
    kwargs['required'] = required

    return disabled, required, feature

def extract_search_dirs(kwargs: 'kwargs.ExtractSearchDirs') -> T.List[str]:
    search_dirs_str = mesonlib.stringlistify(kwargs.get('dirs', []))
    search_dirs = [Path(d).expanduser() for d in search_dirs_str]
    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(f'Search directory {d} is not an absolute path.')
    return [str(s) for s in search_dirs]

class FeatureOptionHolder(ObjectHolder[coredata.UserFeatureOption]):
    def __init__(self, option: coredata.UserFeatureOption, interpreter: 'Interpreter'):
        super().__init__(option, interpreter)
        if option and option.is_auto():
            # TODO: we need to cast here because options is not a TypedDict
            auto = T.cast('coredata.UserFeatureOption', self.env.coredata.options[OptionKey('auto_features')])
            self.held_object = copy.copy(auto)
            self.held_object.name = option.name
        self.methods.update({'enabled': self.enabled_method,
                             'disabled': self.disabled_method,
                             'allowed': self.allowed_method,
                             'auto': self.auto_method,
                             'require': self.require_method,
                             'disable_auto_if': self.disable_auto_if_method,
                             'enable_auto_if': self.enable_auto_if_method,
                             'disable_if': self.disable_if_method,
                             'enable_if': self.enable_if_method,
                             })

    @property
    def value(self) -> str:
        return 'disabled' if not self.held_object else self.held_object.value

    def as_disabled(self) -> coredata.UserFeatureOption:
        disabled = copy.deepcopy(self.held_object)
        disabled.value = 'disabled'
        return disabled

    def as_enabled(self) -> coredata.UserFeatureOption:
        enabled = copy.deepcopy(self.held_object)
        enabled.value = 'enabled'
        return enabled

    @noPosargs
    @noKwargs
    def enabled_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool:
        return self.value == 'enabled'

    @noPosargs
    @noKwargs
    def disabled_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool:
        return self.value == 'disabled'

    @noPosargs
    @noKwargs
    @FeatureNew('feature_option.allowed()', '0.59.0')
    def allowed_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool:
        return self.value != 'disabled'

    @noPosargs
    @noKwargs
    def auto_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool:
        return self.value == 'auto'

    def _disable_if(self, condition: bool, message: T.Optional[str]) -> coredata.UserFeatureOption:
        if not condition:
            return copy.deepcopy(self.held_object)

        if self.value == 'enabled':
            err_msg = f'Feature {self.held_object.name} cannot be enabled'
            if message:
                err_msg += f': {message}'
            raise InterpreterException(err_msg)
        return self.as_disabled()

    @FeatureNew('feature_option.require()', '0.59.0')
    @typed_pos_args('feature_option.require', bool)
    @typed_kwargs(
        'feature_option.require',
        _ERROR_MSG_KW,
    )
    def require_method(self, args: T.Tuple[bool], kwargs: 'kwargs.FeatureOptionRequire') -> coredata.UserFeatureOption:
        return self._disable_if(not args[0], kwargs['error_message'])

    @FeatureNew('feature_option.disable_if()', '1.1.0')
    @typed_pos_args('feature_option.disable_if', bool)
    @typed_kwargs(
        'feature_option.disable_if',
        _ERROR_MSG_KW,
    )
    def disable_if_method(self, args: T.Tuple[bool], kwargs: 'kwargs.FeatureOptionRequire') -> coredata.UserFeatureOption:
        return self._disable_if(args[0], kwargs['error_message'])

    @FeatureNew('feature_option.enable_if()', '1.1.0')
    @typed_pos_args('feature_option.enable_if', bool)
    @typed_kwargs(
        'feature_option.enable_if',
        _ERROR_MSG_KW,
    )
    def enable_if_method(self, args: T.Tuple[bool], kwargs: 'kwargs.FeatureOptionRequire') -> coredata.UserFeatureOption:
        if not args[0]:
            return copy.deepcopy(self.held_object)

        if self.value == 'disabled':
            err_msg = f'Feature {self.held_object.name} cannot be disabled'
            if kwargs['error_message']:
                err_msg += f': {kwargs["error_message"]}'
            raise InterpreterException(err_msg)
        return self.as_enabled()

    @FeatureNew('feature_option.disable_auto_if()', '0.59.0')
    @noKwargs
    @typed_pos_args('feature_option.disable_auto_if', bool)
    def disable_auto_if_method(self, args: T.Tuple[bool], kwargs: TYPE_kwargs) -> coredata.UserFeatureOption:
        return copy.deepcopy(self.held_object) if self.value != 'auto' or not args[0] else self.as_disabled()

    @FeatureNew('feature_option.enable_auto_if()', '1.1.0')
    @noKwargs
    @typed_pos_args('feature_option.enable_auto_if', bool)
    def enable_auto_if_method(self, args: T.Tuple[bool], kwargs: TYPE_kwargs) -> coredata.UserFeatureOption:
        return self.as_enabled() if self.value == 'auto' and args[0] else copy.deepcopy(self.held_object)


class RunProcess(MesonInterpreterObject):

    def __init__(self,
                 cmd: ExternalProgram,
                 args: T.List[str],
                 env: mesonlib.EnvironmentVariables,
                 source_dir: str,
                 build_dir: str,
                 subdir: str,
                 mesonintrospect: T.List[str],
                 in_builddir: bool = False,
                 check: bool = False,
                 capture: bool = True) -> None:
        super().__init__()
        if not isinstance(cmd, ExternalProgram):
            raise AssertionError('BUG: RunProcess must be passed an ExternalProgram')
        self.capture = capture
        self.returncode, self.stdout, self.stderr = self.run_command(cmd, args, env, source_dir, build_dir, subdir, mesonintrospect, in_builddir, check)
        self.methods.update({'returncode': self.returncode_method,
                             'stdout': self.stdout_method,
                             'stderr': self.stderr_method,
                             })

    def run_command(self,
                    cmd: ExternalProgram,
                    args: T.List[str],
                    env: mesonlib.EnvironmentVariables,
                    source_dir: str,
                    build_dir: str,
                    subdir: str,
                    mesonintrospect: T.List[str],
                    in_builddir: bool,
                    check: bool = False) -> T.Tuple[int, str, str]:
        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:', mesonlib.join_args(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(mesonlib.join_args(command_array), p.returncode))

            return p.returncode, o, e
        except FileNotFoundError:
            raise InterpreterException('Could not execute command `%s`.' % mesonlib.join_args(command_array))

    @noPosargs
    @noKwargs
    def returncode_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> int:
        return self.returncode

    @noPosargs
    @noKwargs
    def stdout_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return self.stdout

    @noPosargs
    @noKwargs
    def stderr_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return self.stderr

class EnvironmentVariablesHolder(ObjectHolder[mesonlib.EnvironmentVariables], MutableInterpreterObject):

    def __init__(self, obj: mesonlib.EnvironmentVariables, interpreter: 'Interpreter'):
        super().__init__(obj, interpreter)
        self.methods.update({'set': self.set_method,
                             'append': self.append_method,
                             'prepend': self.prepend_method,
                             })

    def __repr__(self) -> str:
        repr_str = "<{0}: {1}>"
        return repr_str.format(self.__class__.__name__, self.held_object.envvars)

    def __deepcopy__(self, memo: T.Dict[str, object]) -> 'EnvironmentVariablesHolder':
        # Avoid trying to copy the interpreter
        return EnvironmentVariablesHolder(copy.deepcopy(self.held_object), self.interpreter)

    def warn_if_has_name(self, name: str) -> None:
        # Multiple append/prepend operations was not supported until 0.58.0.
        if self.held_object.has_name(name):
            m = f'Overriding previous value of environment variable {name!r} with a new one'
            FeatureNew(m, '0.58.0').use(self.subproject, self.current_node)

    @typed_pos_args('environment.set', str, varargs=str, min_varargs=1)
    @typed_kwargs('environment.set', ENV_SEPARATOR_KW)
    def set_method(self, args: T.Tuple[str, T.List[str]], kwargs: 'EnvironmentSeparatorKW') -> None:
        name, values = args
        self.held_object.set(name, values, kwargs['separator'])

    @typed_pos_args('environment.append', str, varargs=str, min_varargs=1)
    @typed_kwargs('environment.append', ENV_SEPARATOR_KW)
    def append_method(self, args: T.Tuple[str, T.List[str]], kwargs: 'EnvironmentSeparatorKW') -> None:
        name, values = args
        self.warn_if_has_name(name)
        self.held_object.append(name, values, kwargs['separator'])

    @typed_pos_args('environment.prepend', str, varargs=str, min_varargs=1)
    @typed_kwargs('environment.prepend', ENV_SEPARATOR_KW)
    def prepend_method(self, args: T.Tuple[str, T.List[str]], kwargs: 'EnvironmentSeparatorKW') -> None:
        name, values = args
        self.warn_if_has_name(name)
        self.held_object.prepend(name, values, kwargs['separator'])


_CONF_DATA_SET_KWS: KwargInfo[T.Optional[str]] = KwargInfo('description', (str, NoneType))


class ConfigurationDataHolder(ObjectHolder[build.ConfigurationData], MutableInterpreterObject):

    def __init__(self, obj: build.ConfigurationData, interpreter: 'Interpreter'):
        super().__init__(obj, interpreter)
        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,
                             'keys': self.keys_method,
                             'get_unquoted': self.get_unquoted_method,
                             'merge_from': self.merge_from_method,
                             })

    def __deepcopy__(self, memo: T.Dict) -> 'ConfigurationDataHolder':
        return ConfigurationDataHolder(copy.deepcopy(self.held_object), self.interpreter)

    def is_used(self) -> bool:
        return self.held_object.used

    def __check_used(self) -> None:
        if self.is_used():
            raise InterpreterException("Can not set values on configuration object that has been used.")

    @typed_pos_args('configuration_data.set', str, (str, int, bool))
    @typed_kwargs('configuration_data.set', _CONF_DATA_SET_KWS)
    def set_method(self, args: T.Tuple[str, T.Union[str, int, bool]], kwargs: 'kwargs.ConfigurationDataSet') -> None:
        self.__check_used()
        self.held_object.values[args[0]] = (args[1], kwargs['description'])

    @typed_pos_args('configuration_data.set_quoted', str, str)
    @typed_kwargs('configuration_data.set_quoted', _CONF_DATA_SET_KWS)
    def set_quoted_method(self, args: T.Tuple[str, str], kwargs: 'kwargs.ConfigurationDataSet') -> None:
        self.__check_used()
        escaped_val = '\\"'.join(args[1].split('"'))
        self.held_object.values[args[0]] = (f'"{escaped_val}"', kwargs['description'])

    @typed_pos_args('configuration_data.set10', str, (int, bool))
    @typed_kwargs('configuration_data.set10', _CONF_DATA_SET_KWS)
    def set10_method(self, args: T.Tuple[str, T.Union[int, bool]], kwargs: 'kwargs.ConfigurationDataSet') -> None:
        self.__check_used()
        # bool is a subclass of int, so we need to check for bool explicitly.
        # We already have typed_pos_args checking that this is either a bool or
        # an int.
        if not isinstance(args[1], bool):
            mlog.deprecation('configuration_data.set10 with number. the `set10` '
                             'method should only be used with booleans',
                             location=self.interpreter.current_node)
            if args[1] < 0:
                mlog.warning('Passing a number that is less than 0 may not have the intended result, '
                             'as meson will treat all non-zero values as true.',
                             location=self.interpreter.current_node)
        self.held_object.values[args[0]] = (int(args[1]), kwargs['description'])

    @typed_pos_args('configuration_data.has', (str, int, bool))
    @noKwargs
    def has_method(self, args: T.Tuple[T.Union[str, int, bool]], kwargs: TYPE_kwargs) -> bool:
        return args[0] in self.held_object.values

    @FeatureNew('configuration_data.get()', '0.38.0')
    @typed_pos_args('configuration_data.get', str, optargs=[(str, int, bool)])
    @noKwargs
    def get_method(self, args: T.Tuple[str, T.Optional[T.Union[str, int, bool]]],
                   kwargs: TYPE_kwargs) -> T.Union[str, int, bool]:
        name = args[0]
        if name in self.held_object:
            return self.held_object.get(name)[0]
        elif args[1] is not None:
            return args[1]
        raise InterpreterException(f'Entry {name} not in configuration data.')

    @FeatureNew('configuration_data.get_unquoted()', '0.44.0')
    @typed_pos_args('configuration_data.get_unquoted', str, optargs=[(str, int, bool)])
    @noKwargs
    def get_unquoted_method(self, args: T.Tuple[str, T.Optional[T.Union[str, int, bool]]],
                            kwargs: TYPE_kwargs) -> T.Union[str, int, bool]:
        name = args[0]
        if name in self.held_object:
            val = self.held_object.get(name)[0]
        elif args[1] is not None:
            val = args[1]
        else:
            raise InterpreterException(f'Entry {name} not in configuration data.')
        if isinstance(val, str) and val[0] == '"' and val[-1] == '"':
            return val[1:-1]
        return val

    def get(self, name: str) -> T.Tuple[T.Union[str, int, bool], T.Optional[str]]:
        return self.held_object.values[name]

    @FeatureNew('configuration_data.keys()', '0.57.0')
    @noPosargs
    @noKwargs
    def keys_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.List[str]:
        return sorted(self.keys())

    def keys(self) -> T.List[str]:
        return list(self.held_object.values.keys())

    @typed_pos_args('configuration_data.merge_from', build.ConfigurationData)
    @noKwargs
    def merge_from_method(self, args: T.Tuple[build.ConfigurationData], kwargs: TYPE_kwargs) -> None:
        from_object = args[0]
        self.held_object.values.update(from_object.values)


_PARTIAL_DEP_KWARGS = [
    KwargInfo('compile_args', bool, default=False),
    KwargInfo('link_args',    bool, default=False),
    KwargInfo('links',        bool, default=False),
    KwargInfo('includes',     bool, default=False),
    KwargInfo('sources',      bool, default=False),
]

class DependencyHolder(ObjectHolder[Dependency]):
    def __init__(self, dep: Dependency, interpreter: 'Interpreter'):
        super().__init__(dep, interpreter)
        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,
                             'as_link_whole': self.as_link_whole_method,
                             })

    def found(self) -> bool:
        return self.found_method([], {})

    @noPosargs
    @noKwargs
    def type_name_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return self.held_object.type_name

    @noPosargs
    @noKwargs
    def found_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool:
        if self.held_object.type_name == 'internal':
            return True
        return self.held_object.found()

    @noPosargs
    @noKwargs
    def version_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return self.held_object.get_version()

    @noPosargs
    @noKwargs
    def name_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return self.held_object.get_name()

    @FeatureDeprecated('dependency.get_pkgconfig_variable', '0.56.0',
                       'use dependency.get_variable(pkgconfig : ...) instead')
    @typed_pos_args('dependency.get_pkgconfig_variable', str)
    @typed_kwargs(
        'dependency.get_pkgconfig_variable',
        KwargInfo('default', str, default=''),
        PKGCONFIG_DEFINE_KW.evolve(name='define_variable')
    )
    def pkgconfig_method(self, args: T.Tuple[str], kwargs: 'kwargs.DependencyPkgConfigVar') -> str:
        from ..dependencies.pkgconfig import PkgConfigDependency
        if not isinstance(self.held_object, PkgConfigDependency):
            raise InvalidArguments(f'{self.held_object.get_name()!r} is not a pkgconfig dependency')
        if kwargs['define_variable'] and len(kwargs['define_variable']) > 1:
            FeatureNew.single_use('dependency.get_pkgconfig_variable keyword argument "define_variable"  with more than one pair',
                                  '1.3.0', self.subproject, location=self.current_node)
        return self.held_object.get_variable(
            pkgconfig=args[0],
            default_value=kwargs['default'],
            pkgconfig_define=kwargs['define_variable'],
        )

    @FeatureNew('dependency.get_configtool_variable', '0.44.0')
    @FeatureDeprecated('dependency.get_configtool_variable', '0.56.0',
                       'use dependency.get_variable(configtool : ...) instead')
    @noKwargs
    @typed_pos_args('dependency.get_config_tool_variable', str)
    def configtool_method(self, args: T.Tuple[str], kwargs: TYPE_kwargs) -> str:
        from ..dependencies.configtool import ConfigToolDependency
        if not isinstance(self.held_object, ConfigToolDependency):
            raise InvalidArguments(f'{self.held_object.get_name()!r} is not a config-tool dependency')
        return self.held_object.get_variable(
            configtool=args[0],
            default_value='',
        )

    @FeatureNew('dependency.partial_dependency', '0.46.0')
    @noPosargs
    @typed_kwargs('dependency.partial_dependency', *_PARTIAL_DEP_KWARGS)
    def partial_dependency_method(self, args: T.List[TYPE_nvar], kwargs: 'kwargs.DependencyMethodPartialDependency') -> Dependency:
        pdep = self.held_object.get_partial_dependency(**kwargs)
        return pdep

    @FeatureNew('dependency.get_variable', '0.51.0')
    @typed_pos_args('dependency.get_variable', optargs=[str])
    @typed_kwargs(
        'dependency.get_variable',
        KwargInfo('cmake', (str, NoneType)),
        KwargInfo('pkgconfig', (str, NoneType)),
        KwargInfo('configtool', (str, NoneType)),
        KwargInfo('internal', (str, NoneType), since='0.54.0'),
        KwargInfo('default_value', (str, NoneType)),
        PKGCONFIG_DEFINE_KW,
    )
    def variable_method(self, args: T.Tuple[T.Optional[str]], kwargs: 'kwargs.DependencyGetVariable') -> str:
        default_varname = args[0]
        if default_varname is not None:
            FeatureNew('Positional argument to dependency.get_variable()', '0.58.0').use(self.subproject, self.current_node)
        if kwargs['pkgconfig_define'] and len(kwargs['pkgconfig_define']) > 1:
            FeatureNew.single_use('dependency.get_variable keyword argument "pkgconfig_define" with more than one pair',
                                  '1.3.0', self.subproject, 'In previous versions, this silently returned a malformed value.',
                                  self.current_node)
        return self.held_object.get_variable(
            cmake=kwargs['cmake'] or default_varname,
            pkgconfig=kwargs['pkgconfig'] or default_varname,
            configtool=kwargs['configtool'] or default_varname,
            internal=kwargs['internal'] or default_varname,
            default_value=kwargs['default_value'],
            pkgconfig_define=kwargs['pkgconfig_define'],
        )

    @FeatureNew('dependency.include_type', '0.52.0')
    @noPosargs
    @noKwargs
    def include_type_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return self.held_object.get_include_type()

    @FeatureNew('dependency.as_system', '0.52.0')
    @noKwargs
    @typed_pos_args('dependency.as_system', optargs=[str])
    def as_system_method(self, args: T.Tuple[T.Optional[str]], kwargs: TYPE_kwargs) -> Dependency:
        return self.held_object.generate_system_dependency(args[0] or 'system')

    @FeatureNew('dependency.as_link_whole', '0.56.0')
    @noKwargs
    @noPosargs
    def as_link_whole_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> Dependency:
        if not isinstance(self.held_object, InternalDependency):
            raise InterpreterException('as_link_whole method is only supported on declare_dependency() objects')
        new_dep = self.held_object.generate_link_whole_dependency()
        return new_dep

_EXTPROG = T.TypeVar('_EXTPROG', bound=ExternalProgram)

class _ExternalProgramHolder(ObjectHolder[_EXTPROG]):
    def __init__(self, ep: _EXTPROG, interpreter: 'Interpreter') -> None:
        super().__init__(ep, interpreter)
        self.methods.update({'found': self.found_method,
                             'path': self.path_method,
                             'version': self.version_method,
                             'full_path': self.full_path_method})

    @noPosargs
    @noKwargs
    def found_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool:
        return self.found()

    @noPosargs
    @noKwargs
    @FeatureDeprecated('ExternalProgram.path', '0.55.0',
                       'use ExternalProgram.full_path() instead')
    def path_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return self._full_path()

    @noPosargs
    @noKwargs
    @FeatureNew('ExternalProgram.full_path', '0.55.0')
    def full_path_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return self._full_path()

    def _full_path(self) -> str:
        if not self.found():
            raise InterpreterException('Unable to get the path of a not-found external program')
        path = self.held_object.get_path()
        assert path is not None
        return path

    @noPosargs
    @noKwargs
    @FeatureNew('ExternalProgram.version', '0.62.0')
    def version_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        if not self.found():
            raise InterpreterException('Unable to get the version of a not-found external program')
        try:
            return self.held_object.get_version(self.interpreter)
        except mesonlib.MesonException:
            return 'unknown'

    def found(self) -> bool:
        return self.held_object.found()

class ExternalProgramHolder(_ExternalProgramHolder[ExternalProgram]):
    pass

class ExternalLibraryHolder(ObjectHolder[ExternalLibrary]):
    def __init__(self, el: ExternalLibrary, interpreter: 'Interpreter'):
        super().__init__(el, interpreter)
        self.methods.update({'found': self.found_method,
                             'type_name': self.type_name_method,
                             'partial_dependency': self.partial_dependency_method,
                             })

    @noPosargs
    @noKwargs
    def type_name_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return self.held_object.type_name

    @noPosargs
    @noKwargs
    def found_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool:
        return self.held_object.found()

    @FeatureNew('dependency.partial_dependency', '0.46.0')
    @noPosargs
    @typed_kwargs('dependency.partial_dependency', *_PARTIAL_DEP_KWARGS)
    def partial_dependency_method(self, args: T.List[TYPE_nvar], kwargs: 'kwargs.DependencyMethodPartialDependency') -> Dependency:
        pdep = self.held_object.get_partial_dependency(**kwargs)
        return pdep

# A machine that's statically known from the cross file
class MachineHolder(ObjectHolder['MachineInfo']):
    def __init__(self, machine_info: 'MachineInfo', interpreter: 'Interpreter'):
        super().__init__(machine_info, interpreter)
        self.methods.update({'system': self.system_method,
                             'cpu': self.cpu_method,
                             'cpu_family': self.cpu_family_method,
                             'endian': self.endian_method,
                             'kernel': self.kernel_method,
                             'subsystem': self.subsystem_method,
                             })

    @noPosargs
    @noKwargs
    def cpu_family_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return self.held_object.cpu_family

    @noPosargs
    @noKwargs
    def cpu_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return self.held_object.cpu

    @noPosargs
    @noKwargs
    def system_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return self.held_object.system

    @noPosargs
    @noKwargs
    def endian_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return self.held_object.endian

    @noPosargs
    @noKwargs
    def kernel_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        if self.held_object.kernel is not None:
            return self.held_object.kernel
        raise InterpreterException('Kernel not defined or could not be autodetected.')

    @noPosargs
    @noKwargs
    def subsystem_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        if self.held_object.subsystem is not None:
            return self.held_object.subsystem
        raise InterpreterException('Subsystem not defined or could not be autodetected.')


class IncludeDirsHolder(ObjectHolder[build.IncludeDirs]):
    pass

class FileHolder(ObjectHolder[mesonlib.File]):
    pass

class HeadersHolder(ObjectHolder[build.Headers]):
    pass

class DataHolder(ObjectHolder[build.Data]):
    pass

class SymlinkDataHolder(ObjectHolder[build.SymlinkData]):
    pass

class InstallDirHolder(ObjectHolder[build.InstallDir]):
    pass

class ManHolder(ObjectHolder[build.Man]):
    pass

class EmptyDirHolder(ObjectHolder[build.EmptyDir]):
    pass

class GeneratedObjectsHolder(ObjectHolder[build.ExtractedObjects]):
    pass

class Test(MesonInterpreterObject):
    def __init__(self, name: str, project: str, suite: T.List[str],
                 exe: T.Union[ExternalProgram, build.Executable, build.CustomTarget],
                 depends: T.List[T.Union[build.CustomTarget, build.BuildTarget]],
                 is_parallel: bool,
                 cmd_args: T.List[T.Union[str, mesonlib.File, build.Target]],
                 env: mesonlib.EnvironmentVariables,
                 should_fail: bool, timeout: int, workdir: T.Optional[str], protocol: str,
                 priority: int, verbose: bool):
        super().__init__()
        self.name = name
        self.suite = listify(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 = TestProtocol.from_str(protocol)
        self.priority = priority
        self.verbose = verbose

    def get_exe(self) -> T.Union[ExternalProgram, build.Executable, build.CustomTarget]:
        return self.exe

    def get_name(self) -> str:
        return self.name

class NullSubprojectInterpreter(HoldableObject):
    pass

# TODO: This should really be an `ObjectHolder`, but the additional stuff in this
#       class prevents this. Thus, this class should be split into a pure
#       `ObjectHolder` and a class specifically for storing in `Interpreter`.
class SubprojectHolder(MesonInterpreterObject):

    def __init__(self, subinterpreter: T.Union['Interpreter', NullSubprojectInterpreter],
                 subdir: str,
                 warnings: int = 0,
                 disabled_feature: T.Optional[str] = None,
                 exception: T.Optional[Exception] = None,
                 callstack: T.Optional[T.List[str]] = None) -> None:
        super().__init__()
        self.held_object = subinterpreter
        self.warnings = warnings
        self.disabled_feature = disabled_feature
        self.exception = exception
        self.subdir = PurePath(subdir).as_posix()
        self.cm_interpreter: T.Optional[CMakeInterpreter] = None
        self.callstack = callstack
        self.methods.update({'get_variable': self.get_variable_method,
                             'found': self.found_method,
                             })

    @noPosargs
    @noKwargs
    def found_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool:
        return self.found()

    def found(self) -> bool:
        return not isinstance(self.held_object, NullSubprojectInterpreter)

    @noKwargs
    @noArgsFlattening
    @unholder_return
    def get_variable_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.Union[TYPE_var, InterpreterObject]:
        if len(args) < 1 or len(args) > 2:
            raise InterpreterException('Get_variable takes one or two arguments.')
        if isinstance(self.held_object, NullSubprojectInterpreter):  # == not self.found()
            raise InterpreterException(f'Subproject "{self.subdir}" disabled can\'t get_variable on it.')
        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 self.held_object._holderify(args[1])

        raise InvalidArguments(f'Requested variable "{varname}" not found.')

class ModuleObjectHolder(ObjectHolder[ModuleObject]):
    def method_call(self, method_name: str, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> TYPE_var:
        modobj = self.held_object
        method = modobj.methods.get(method_name)
        if not method:
            raise InvalidCode(f'Unknown method {method_name!r} in object.')
        if not getattr(method, 'no-args-flattening', False):
            args = flatten(args)
        if not getattr(method, 'no-second-level-holder-flattening', False):
            args, kwargs = resolve_second_level_holders(args, kwargs)
        state = ModuleState(self.interpreter)
        # Many modules do for example self.interpreter.find_program_impl(),
        # so we have to ensure they use the current interpreter and not the one
        # that first imported that module, otherwise it will use outdated
        # overrides.
        if isinstance(modobj, ExtensionModule):
            modobj.interpreter = self.interpreter
        ret = method(state, args, kwargs)
        if isinstance(ret, ModuleReturnValue):
            self.interpreter.process_new_values(ret.new_objects)
            ret = ret.return_value
        return ret

class MutableModuleObjectHolder(ModuleObjectHolder, MutableInterpreterObject):
    def __deepcopy__(self, memo: T.Dict[int, T.Any]) -> 'MutableModuleObjectHolder':
        # Deepcopy only held object, not interpreter
        modobj = copy.deepcopy(self.held_object, memo)
        return MutableModuleObjectHolder(modobj, self.interpreter)


_BuildTarget = T.TypeVar('_BuildTarget', bound=T.Union[build.BuildTarget, build.BothLibraries])

class BuildTargetHolder(ObjectHolder[_BuildTarget]):
    def __init__(self, target: _BuildTarget, interp: 'Interpreter'):
        super().__init__(target, interp)
        self.methods.update({'extract_objects': self.extract_objects_method,
                             'extract_all_objects': self.extract_all_objects_method,
                             'name': self.name_method,
                             'get_id': self.get_id_method,
                             'outdir': self.outdir_method,
                             'full_path': self.full_path_method,
                             'path': self.path_method,
                             'found': self.found_method,
                             'private_dir_include': self.private_dir_include_method,
                             })

    def __repr__(self) -> str:
        r = '<{} {}: {}>'
        h = self.held_object
        assert isinstance(h, build.BuildTarget)
        return r.format(self.__class__.__name__, h.get_id(), h.filename)

    @property
    def _target_object(self) -> build.BuildTarget:
        if isinstance(self.held_object, build.BothLibraries):
            return self.held_object.get_default_object()
        assert isinstance(self.held_object, build.BuildTarget)
        return self.held_object

    def is_cross(self) -> bool:
        return not self._target_object.environment.machines.matches_build_machine(self._target_object.for_machine)

    @noPosargs
    @noKwargs
    def found_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool:
        if not (isinstance(self.held_object, build.Executable) and self.held_object.was_returned_by_find_program):
            FeatureNew.single_use('BuildTarget.found', '0.59.0', subproject=self.held_object.subproject)
        return True

    @noPosargs
    @noKwargs
    def private_dir_include_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> build.IncludeDirs:
        return build.IncludeDirs('', [], False, [self.interpreter.backend.get_target_private_dir(self._target_object)])

    @noPosargs
    @noKwargs
    def full_path_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return self.interpreter.backend.get_target_filename_abs(self._target_object)

    @noPosargs
    @noKwargs
    @FeatureDeprecated('BuildTarget.path', '0.55.0', 'Use BuildTarget.full_path instead')
    def path_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return self.interpreter.backend.get_target_filename_abs(self._target_object)

    @noPosargs
    @noKwargs
    def outdir_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return self.interpreter.backend.get_target_dir(self._target_object)

    @noKwargs
    @typed_pos_args('extract_objects', varargs=(mesonlib.File, str, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList))
    def extract_objects_method(self, args: T.Tuple[T.List[T.Union[mesonlib.FileOrString, 'build.GeneratedTypes']]], kwargs: TYPE_nkwargs) -> build.ExtractedObjects:
        return self._target_object.extract_objects(args[0])

    @noPosargs
    @typed_kwargs(
        'extract_all_objects',
        KwargInfo(
            'recursive', bool, default=False, since='0.46.0',
            not_set_warning=textwrap.dedent('''\
                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.
            ''')
        )
    )
    def extract_all_objects_method(self, args: T.List[TYPE_nvar], kwargs: 'kwargs.BuildTargeMethodExtractAllObjects') -> build.ExtractedObjects:
        return self._target_object.extract_all_objects(kwargs['recursive'])

    @noPosargs
    @noKwargs
    @FeatureDeprecated('BuildTarget.get_id', '1.2.0',
                       'This was never formally documented and does not seem to have a real world use. ' +
                       'See https://github.com/mesonbuild/meson/pull/6061')
    def get_id_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return self._target_object.get_id()

    @FeatureNew('name', '0.54.0')
    @noPosargs
    @noKwargs
    def name_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return self._target_object.name

class ExecutableHolder(BuildTargetHolder[build.Executable]):
    pass

class StaticLibraryHolder(BuildTargetHolder[build.StaticLibrary]):
    pass

class SharedLibraryHolder(BuildTargetHolder[build.SharedLibrary]):
    pass

class BothLibrariesHolder(BuildTargetHolder[build.BothLibraries]):
    def __init__(self, libs: build.BothLibraries, interp: 'Interpreter'):
        # FIXME: This build target always represents the shared library, but
        # that should be configurable.
        super().__init__(libs, interp)
        self.methods.update({'get_shared_lib': self.get_shared_lib_method,
                             'get_static_lib': self.get_static_lib_method,
                             })

    def __repr__(self) -> str:
        r = '<{} {}: {}, {}: {}>'
        h1 = self.held_object.shared
        h2 = self.held_object.static
        return r.format(self.__class__.__name__, h1.get_id(), h1.filename, h2.get_id(), h2.filename)

    @noPosargs
    @noKwargs
    def get_shared_lib_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> build.SharedLibrary:
        return self.held_object.shared

    @noPosargs
    @noKwargs
    def get_static_lib_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> build.StaticLibrary:
        return self.held_object.static

class SharedModuleHolder(BuildTargetHolder[build.SharedModule]):
    pass

class JarHolder(BuildTargetHolder[build.Jar]):
    pass

class CustomTargetIndexHolder(ObjectHolder[build.CustomTargetIndex]):
    def __init__(self, target: build.CustomTargetIndex, interp: 'Interpreter'):
        super().__init__(target, interp)
        self.methods.update({'full_path': self.full_path_method,
                             })

    @FeatureNew('custom_target[i].full_path', '0.54.0')
    @noPosargs
    @noKwargs
    def full_path_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        assert self.interpreter.backend is not None
        return self.interpreter.backend.get_target_filename_abs(self.held_object)

_CT = T.TypeVar('_CT', bound=build.CustomTarget)

class _CustomTargetHolder(ObjectHolder[_CT]):
    def __init__(self, target: _CT, interp: 'Interpreter'):
        super().__init__(target, interp)
        self.methods.update({'full_path': self.full_path_method,
                             'to_list': self.to_list_method,
                             })

        self.operators.update({
            MesonOperator.INDEX: self.op_index,
        })

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

    @noPosargs
    @noKwargs
    def full_path_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return self.interpreter.backend.get_target_filename_abs(self.held_object)

    @FeatureNew('custom_target.to_list', '0.54.0')
    @noPosargs
    @noKwargs
    def to_list_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.List[build.CustomTargetIndex]:
        result = []
        for i in self.held_object:
            result.append(i)
        return result

    @noKwargs
    @typed_operator(MesonOperator.INDEX, int)
    def op_index(self, other: int) -> build.CustomTargetIndex:
        try:
            return self.held_object[other]
        except IndexError:
            raise InvalidArguments(f'Index {other} out of bounds of custom target {self.held_object.name} output of size {len(self.held_object)}.')

class CustomTargetHolder(_CustomTargetHolder[build.CustomTarget]):
    pass

class RunTargetHolder(ObjectHolder[build.RunTarget]):
    pass

class AliasTargetHolder(ObjectHolder[build.AliasTarget]):
    pass

class GeneratedListHolder(ObjectHolder[build.GeneratedList]):
    pass

class GeneratorHolder(ObjectHolder[build.Generator]):
    def __init__(self, gen: build.Generator, interpreter: 'Interpreter'):
        super().__init__(gen, interpreter)
        self.methods.update({'process': self.process_method})

    @typed_pos_args('generator.process', min_varargs=1, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList))
    @typed_kwargs(
        'generator.process',
        KwargInfo('preserve_path_from', (str, NoneType), since='0.45.0'),
        KwargInfo('extra_args', ContainerTypeInfo(list, str), listify=True, default=[]),
        ENV_KW.evolve(since='1.3.0')
    )
    def process_method(self,
                       args: T.Tuple[T.List[T.Union[str, mesonlib.File, 'build.GeneratedTypes']]],
                       kwargs: 'kwargs.GeneratorProcess') -> build.GeneratedList:
        preserve_path_from = kwargs['preserve_path_from']
        if preserve_path_from is not None:
            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.')

        if any(isinstance(a, (build.CustomTarget, build.CustomTargetIndex, build.GeneratedList)) for a in args[0]):
            FeatureNew.single_use(
                'Calling generator.process with CustomTarget or Index of CustomTarget.',
                '0.57.0', self.interpreter.subproject)

        gl = self.held_object.process_files(args[0], self.interpreter,
                                            preserve_path_from, extra_args=kwargs['extra_args'], env=kwargs['env'])

        return gl


class StructuredSourcesHolder(ObjectHolder[build.StructuredSources]):

    def __init__(self, sources: build.StructuredSources, interp: 'Interpreter'):
        super().__init__(sources, interp)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336271.0
meson-1.3.2/mesonbuild/interpreter/kwargs.py0000644000175000017500000003172714516507017021424 0ustar00jpakkanejpakkane# SPDX-License-Identifier: Apache-2.0
# Copyright Ā© 2021 The Meson Developers
# Copyright Ā© 2021 Intel Corporation
from __future__ import annotations

"""Keyword Argument type annotations."""

import typing as T

from typing_extensions import TypedDict, Literal, Protocol, NotRequired

from .. import build
from .. import coredata
from ..compilers import Compiler
from ..dependencies.base import Dependency
from ..mesonlib import EnvironmentVariables, MachineChoice, File, FileMode, FileOrString, OptionKey
from ..modules.cmake import CMakeSubprojectOptions
from ..programs import ExternalProgram
from .type_checking import PkgConfigDefineType, SourcesVarargsType

class FuncAddProjectArgs(TypedDict):

    """Keyword Arguments for the add_*_arguments family of arguments.

    including `add_global_arguments`, `add_project_arguments`, and their
    link variants

    Because of the use of a convertor function, we get the native keyword as
    a MachineChoice instance already.
    """

    native: MachineChoice
    language: T.List[str]


class BaseTest(TypedDict):

    """Shared base for the Rust module."""

    args: T.List[T.Union[str, File, build.Target]]
    should_fail: bool
    timeout: int
    workdir: T.Optional[str]
    depends: T.List[T.Union[build.CustomTarget, build.BuildTarget]]
    priority: int
    env: EnvironmentVariables
    suite: T.List[str]


class FuncBenchmark(BaseTest):

    """Keyword Arguments shared between `test` and `benchmark`."""

    protocol: Literal['exitcode', 'tap', 'gtest', 'rust']


class FuncTest(FuncBenchmark):

    """Keyword Arguments for `test`

    `test` only adds the `is_parallel` argument over benchmark, so inheritance
    is helpful here.
    """

    is_parallel: bool


class ExtractRequired(TypedDict):

    """Keyword Arguments consumed by the `extract_required_kwargs` function.

    Any function that uses the `required` keyword argument which accepts either
    a boolean or a feature option should inherit it's arguments from this class.
    """

    required: T.Union[bool, coredata.UserFeatureOption]


class ExtractSearchDirs(TypedDict):

    """Keyword arguments consumed by the `extract_search_dirs` function.

    See the not in `ExtractRequired`
    """

    dirs: T.List[str]


class FuncGenerator(TypedDict):

    """Keyword rguments for the generator function."""

    arguments: T.List[str]
    output: T.List[str]
    depfile: T.Optional[str]
    capture:  bool
    depends: T.List[T.Union[build.BuildTarget, build.CustomTarget]]


class GeneratorProcess(TypedDict):

    """Keyword Arguments for generator.process."""

    preserve_path_from: T.Optional[str]
    extra_args: T.List[str]
    env: EnvironmentVariables

class DependencyMethodPartialDependency(TypedDict):

    """ Keyword Arguments for the dep.partial_dependency methods """

    compile_args: bool
    link_args: bool
    links: bool
    includes: bool
    sources: bool

class BuildTargeMethodExtractAllObjects(TypedDict):
    recursive: bool

class FuncInstallSubdir(TypedDict):

    install_dir: str
    strip_directory: bool
    exclude_files: T.List[str]
    exclude_directories: T.List[str]
    install_mode: FileMode
    follow_symlinks: T.Optional[bool]


class FuncInstallData(TypedDict):

    install_dir: str
    sources: T.List[FileOrString]
    rename: T.List[str]
    install_mode: FileMode
    follow_symlinks: T.Optional[bool]


class FuncInstallHeaders(TypedDict):

    install_dir: T.Optional[str]
    install_mode: FileMode
    subdir: T.Optional[str]
    follow_symlinks: T.Optional[bool]


class FuncInstallMan(TypedDict):

    install_dir: T.Optional[str]
    install_mode: FileMode
    locale: T.Optional[str]


class FuncImportModule(ExtractRequired):

    disabler: bool


class FuncIncludeDirectories(TypedDict):

    is_system: bool

class FuncAddLanguages(ExtractRequired):

    native: T.Optional[bool]

class RunTarget(TypedDict):

    command: T.List[T.Union[str, build.BuildTarget, build.CustomTarget, ExternalProgram, File]]
    depends: T.List[T.Union[build.BuildTarget, build.CustomTarget]]
    env: EnvironmentVariables


class CustomTarget(TypedDict):

    build_always: bool
    build_always_stale: T.Optional[bool]
    build_by_default: T.Optional[bool]
    capture: bool
    command: T.List[T.Union[str, build.BuildTarget, build.CustomTarget,
                            build.CustomTargetIndex, ExternalProgram, File]]
    console: bool
    depend_files: T.List[FileOrString]
    depends: T.List[T.Union[build.BuildTarget, build.CustomTarget]]
    depfile: T.Optional[str]
    env: EnvironmentVariables
    feed: bool
    input: T.List[T.Union[str, build.BuildTarget, build.CustomTarget, build.CustomTargetIndex,
                          build.ExtractedObjects, build.GeneratedList, ExternalProgram, File]]
    install: bool
    install_dir: T.List[T.Union[str, T.Literal[False]]]
    install_mode: FileMode
    install_tag: T.List[T.Optional[str]]
    output: T.List[str]

class AddTestSetup(TypedDict):

    exe_wrapper: T.List[T.Union[str, ExternalProgram]]
    gdb: bool
    timeout_multiplier: int
    is_default: bool
    exclude_suites: T.List[str]
    env: EnvironmentVariables


class Project(TypedDict):

    version: T.Optional[FileOrString]
    meson_version: T.Optional[str]
    default_options: T.Dict[OptionKey, T.Union[str, int, bool, T.List[str]]]
    license: T.List[str]
    subproject_dir: str


class _FoundProto(Protocol):

    """Protocol for subdir arguments.

    This allows us to define any object that has a found(self) -> bool method
    """

    def found(self) -> bool: ...


class Subdir(TypedDict):

    if_found: T.List[_FoundProto]


class Summary(TypedDict):

    section: str
    bool_yn: bool
    list_sep: T.Optional[str]


class FindProgram(ExtractRequired, ExtractSearchDirs):

    default_options: T.Dict[OptionKey, T.Union[str, int, bool, T.List[str]]]
    native: MachineChoice
    version: T.List[str]


class RunCommand(TypedDict):

    check: bool
    capture: T.Optional[bool]
    env: EnvironmentVariables


class FeatureOptionRequire(TypedDict):

    error_message: T.Optional[str]


class DependencyPkgConfigVar(TypedDict):

    default: T.Optional[str]
    define_variable: PkgConfigDefineType


class DependencyGetVariable(TypedDict):

    cmake: T.Optional[str]
    pkgconfig: T.Optional[str]
    configtool: T.Optional[str]
    internal: T.Optional[str]
    default_value: T.Optional[str]
    pkgconfig_define: PkgConfigDefineType


class ConfigurationDataSet(TypedDict):

    description: T.Optional[str]

class VcsTag(TypedDict):

    command: T.List[T.Union[str, build.BuildTarget, build.CustomTarget,
                            build.CustomTargetIndex, ExternalProgram, File]]
    fallback: T.Optional[str]
    input: T.List[T.Union[str, build.BuildTarget, build.CustomTarget, build.CustomTargetIndex,
                          build.ExtractedObjects, build.GeneratedList, ExternalProgram, File]]
    output: T.List[str]
    replace_string: str


class ConfigureFile(TypedDict):

    output: str
    capture: bool
    format: T.Literal['meson', 'cmake', 'cmake@']
    output_format: T.Literal['c', 'json', 'nasm']
    depfile: T.Optional[str]
    install: T.Optional[bool]
    install_dir: T.Union[str, T.Literal[False]]
    install_mode: FileMode
    install_tag: T.Optional[str]
    encoding: str
    command: T.Optional[T.List[T.Union[build.Executable, ExternalProgram, Compiler, File, str]]]
    input: T.List[FileOrString]
    configuration: T.Optional[T.Union[T.Dict[str, T.Union[str, int, bool]], build.ConfigurationData]]
    macro_name: T.Optional[str]


class Subproject(ExtractRequired):

    default_options: T.Dict[OptionKey, T.Union[str, int, bool, T.List[str]]]
    version: T.List[str]


class DoSubproject(ExtractRequired):

    default_options: T.Dict[OptionKey, T.Union[str, int, bool, T.List[str]]]
    version: T.List[str]
    cmake_options: T.List[str]
    options: T.Optional[CMakeSubprojectOptions]


class _BaseBuildTarget(TypedDict):

    """Arguments used by all BuildTarget like functions.

    This really exists because Jar is so different than all of the other
    BuildTarget functions.
    """

    build_by_default: bool
    build_rpath: str
    extra_files: T.List[FileOrString]
    gnu_symbol_visibility: str
    install: bool
    install_mode: FileMode
    install_rpath: str
    implicit_include_directories: bool
    link_depends: T.List[T.Union[str, File, build.CustomTarget, build.CustomTargetIndex, build.BuildTarget]]
    link_language: T.Optional[str]
    name_prefix: T.Optional[str]
    name_suffix: T.Optional[str]
    native: MachineChoice
    objects: T.List[build.ObjectTypes]
    override_options: T.Dict[OptionKey, T.Union[str, int, bool, T.List[str]]]
    depend_files: NotRequired[T.List[File]]
    resources: T.List[str]


class _BuildTarget(_BaseBuildTarget):

    """Arguments shared by non-JAR functions"""

    d_debug: T.List[T.Union[str, int]]
    d_import_dirs: T.List[T.Union[str, build.IncludeDirs]]
    d_module_versions: T.List[T.Union[str, int]]
    d_unittest: bool
    rust_dependency_map: T.Dict[str, str]
    sources: SourcesVarargsType
    c_args: T.List[str]
    cpp_args: T.List[str]
    cuda_args: T.List[str]
    fortran_args: T.List[str]
    d_args: T.List[str]
    objc_args: T.List[str]
    objcpp_args: T.List[str]
    rust_args: T.List[str]
    vala_args: T.List[T.Union[str, File]]  # Yes, Vala is really special
    cs_args: T.List[str]
    swift_args: T.List[str]
    cython_args: T.List[str]
    nasm_args: T.List[str]
    masm_args: T.List[str]


class _LibraryMixin(TypedDict):

    rust_abi: T.Optional[Literal['c', 'rust']]


class Executable(_BuildTarget):

    export_dynamic: T.Optional[bool]
    gui_app: T.Optional[bool]
    implib: T.Optional[T.Union[str, bool]]
    pie: T.Optional[bool]
    vs_module_defs: T.Optional[T.Union[str, File, build.CustomTarget, build.CustomTargetIndex]]
    win_subsystem: T.Optional[str]


class _StaticLibMixin(TypedDict):

    prelink: bool
    pic: T.Optional[bool]


class StaticLibrary(_BuildTarget, _StaticLibMixin, _LibraryMixin):
    pass


class _SharedLibMixin(TypedDict):

    darwin_versions: T.Optional[T.Tuple[str, str]]
    soversion: T.Optional[str]
    version: T.Optional[str]
    vs_module_defs: T.Optional[T.Union[str, File, build.CustomTarget, build.CustomTargetIndex]]


class SharedLibrary(_BuildTarget, _SharedLibMixin, _LibraryMixin):
    pass


class SharedModule(_BuildTarget, _LibraryMixin):

    vs_module_defs: T.Optional[T.Union[str, File, build.CustomTarget, build.CustomTargetIndex]]


class Library(_BuildTarget, _SharedLibMixin, _StaticLibMixin, _LibraryMixin):

    """For library, both_library, and as a base for build_target"""

    c_static_args: NotRequired[T.List[str]]
    c_shared_args: NotRequired[T.List[str]]
    cpp_static_args: NotRequired[T.List[str]]
    cpp_shared_args: NotRequired[T.List[str]]
    cuda_static_args: NotRequired[T.List[str]]
    cuda_shared_args: NotRequired[T.List[str]]
    fortran_static_args: NotRequired[T.List[str]]
    fortran_shared_args: NotRequired[T.List[str]]
    d_static_args: NotRequired[T.List[str]]
    d_shared_args: NotRequired[T.List[str]]
    objc_static_args: NotRequired[T.List[str]]
    objc_shared_args: NotRequired[T.List[str]]
    objcpp_static_args: NotRequired[T.List[str]]
    objcpp_shared_args: NotRequired[T.List[str]]
    rust_static_args: NotRequired[T.List[str]]
    rust_shared_args: NotRequired[T.List[str]]
    vala_static_args: NotRequired[T.List[T.Union[str, File]]]  # Yes, Vala is really special
    vala_shared_args: NotRequired[T.List[T.Union[str, File]]]  # Yes, Vala is really special
    cs_static_args: NotRequired[T.List[str]]
    cs_shared_args: NotRequired[T.List[str]]
    swift_static_args: NotRequired[T.List[str]]
    swift_shared_args: NotRequired[T.List[str]]
    cython_static_args: NotRequired[T.List[str]]
    cython_shared_args: NotRequired[T.List[str]]
    nasm_static_args: NotRequired[T.List[str]]
    nasm_shared_args: NotRequired[T.List[str]]
    masm_static_args: NotRequired[T.List[str]]
    masm_shared_args: NotRequired[T.List[str]]


class BuildTarget(Library):

    target_type: Literal['executable', 'shared_library', 'static_library',
                         'shared_module', 'both_libraries', 'library', 'jar']


class Jar(_BaseBuildTarget):

    main_class: str
    java_resources: T.Optional[build.StructuredSources]
    sources: T.Union[str, File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.ExtractedObjects, build.BuildTarget]
    java_args: T.List[str]


class FuncDeclareDependency(TypedDict):

    compile_args: T.List[str]
    d_import_dirs: T.List[T.Union[build.IncludeDirs, str]]
    d_module_versions: T.List[T.Union[str, int]]
    dependencies: T.List[Dependency]
    extra_files: T.List[FileOrString]
    include_directories: T.List[T.Union[build.IncludeDirs, str]]
    link_args: T.List[str]
    link_whole: T.List[T.Union[build.StaticLibrary, build.CustomTarget, build.CustomTargetIndex]]
    link_with: T.List[build.LibTypes]
    objects: T.List[build.ExtractedObjects]
    sources: T.List[T.Union[FileOrString, build.GeneratedTypes]]
    variables: T.Dict[str, str]
    version: T.Optional[str]
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0
meson-1.3.2/mesonbuild/interpreter/mesonmain.py0000644000175000017500000005461014562742373022117 0ustar00jpakkanejpakkane# SPDX-License-Identifier: Apache-2.0
# Copyright 2012-2021 The Meson development team
# Copyright Ā© 2021 Intel Corporation
from __future__ import annotations

import os
import typing as T

from .. import mesonlib
from .. import dependencies
from .. import build
from .. import mlog, coredata

from ..mesonlib import MachineChoice, OptionKey
from ..programs import OverrideProgram, ExternalProgram
from ..interpreter.type_checking import ENV_KW, ENV_METHOD_KW, ENV_SEPARATOR_KW, env_convertor_with_method
from ..interpreterbase import (MesonInterpreterObject, FeatureNew, FeatureDeprecated,
                               typed_pos_args,  noArgsFlattening, noPosargs, noKwargs,
                               typed_kwargs, KwargInfo, InterpreterException)
from .primitives import MesonVersionString
from .type_checking import NATIVE_KW, NoneType

if T.TYPE_CHECKING:
    from typing_extensions import Literal, TypedDict

    from ..compilers import Compiler
    from ..interpreterbase import TYPE_kwargs, TYPE_var
    from ..mesonlib import ExecutableSerialisation
    from .interpreter import Interpreter

    class FuncOverrideDependency(TypedDict):

        native: mesonlib.MachineChoice
        static: T.Optional[bool]

    class AddInstallScriptKW(TypedDict):

        skip_if_destdir: bool
        install_tag: str
        dry_run: bool

    class NativeKW(TypedDict):

        native: mesonlib.MachineChoice

    class AddDevenvKW(TypedDict):
        method: Literal['set', 'prepend', 'append']
        separator: str


class MesonMain(MesonInterpreterObject):
    def __init__(self, build: 'build.Build', interpreter: 'Interpreter'):
        super().__init__(subproject=interpreter.subproject)
        self.build = build
        self.interpreter = interpreter
        self.methods.update({'add_devenv': self.add_devenv_method,
                             'add_dist_script': self.add_dist_script_method,
                             'add_install_script': self.add_install_script_method,
                             'add_postconf_script': self.add_postconf_script_method,
                             'backend': self.backend_method,
                             'build_options': self.build_options_method,
                             'build_root': self.build_root_method,
                             'can_run_host_binaries': self.can_run_host_binaries_method,
                             'current_source_dir': self.current_source_dir_method,
                             'current_build_dir': self.current_build_dir_method,
                             'get_compiler': self.get_compiler_method,
                             'get_cross_property': self.get_cross_property_method,
                             'get_external_property': self.get_external_property_method,
                             'global_build_root': self.global_build_root_method,
                             'global_source_root': self.global_source_root_method,
                             'has_exe_wrapper': self.has_exe_wrapper_method,
                             'has_external_property': self.has_external_property_method,
                             'install_dependency_manifest': self.install_dependency_manifest_method,
                             'is_cross_build': self.is_cross_build_method,
                             'is_subproject': self.is_subproject_method,
                             'is_unity': self.is_unity_method,
                             'override_dependency': self.override_dependency_method,
                             'override_find_program': self.override_find_program_method,
                             'project_build_root': self.project_build_root_method,
                             'project_license': self.project_license_method,
                             'project_license_files': self.project_license_files_method,
                             'project_name': self.project_name_method,
                             'project_source_root': self.project_source_root_method,
                             'project_version': self.project_version_method,
                             'source_root': self.source_root_method,
                             'version': self.version_method,
                             })

    def _find_source_script(
            self, name: str, prog: T.Union[str, mesonlib.File, build.Executable, ExternalProgram],
            args: T.List[str]) -> 'ExecutableSerialisation':
        largs: T.List[T.Union[str, build.Executable, ExternalProgram]] = []

        if isinstance(prog, (build.Executable, ExternalProgram)):
            FeatureNew.single_use(f'Passing executable/found program object to script parameter of {name}',
                                  '0.55.0', self.subproject, location=self.current_node)
            largs.append(prog)
        else:
            if isinstance(prog, mesonlib.File):
                FeatureNew.single_use(f'Passing file object to script parameter of {name}',
                                      '0.57.0', self.subproject, location=self.current_node)
            found = self.interpreter.find_program_impl([prog])
            largs.append(found)

        largs.extend(args)
        es = self.interpreter.backend.get_executable_serialisation(largs, verbose=True)
        es.subproject = self.interpreter.subproject
        return es

    def _process_script_args(
            self, name: str, args: T.Sequence[T.Union[
                str, mesonlib.File, build.BuildTarget, build.CustomTarget,
                build.CustomTargetIndex,
                ExternalProgram,
            ]]) -> T.List[str]:
        script_args = []  # T.List[str]
        new = False
        for a in args:
            if isinstance(a, str):
                script_args.append(a)
            elif isinstance(a, mesonlib.File):
                new = True
                script_args.append(a.rel_to_builddir(self.interpreter.environment.source_dir))
            elif isinstance(a, (build.BuildTarget, build.CustomTarget, build.CustomTargetIndex)):
                new = True
                script_args.extend([os.path.join(a.get_subdir(), o) for o in a.get_outputs()])

                # This feels really hacky, but I'm not sure how else to fix
                # this without completely rewriting install script handling.
                # This is complicated by the fact that the install target
                # depends on all.
                if isinstance(a, build.CustomTargetIndex):
                    a.target.build_by_default = True
                else:
                    a.build_by_default = True
            else:
                script_args.extend(a.command)
                new = True

        if new:
            FeatureNew.single_use(
                f'Calling "{name}" with File, CustomTarget, Index of CustomTarget, '
                'Executable, or ExternalProgram',
                '0.55.0', self.interpreter.subproject, location=self.current_node)
        return script_args

    @typed_pos_args(
        'meson.add_install_script',
        (str, mesonlib.File, build.Executable, ExternalProgram),
        varargs=(str, mesonlib.File, build.BuildTarget, build.CustomTarget, build.CustomTargetIndex, ExternalProgram)
    )
    @typed_kwargs(
        'meson.add_install_script',
        KwargInfo('skip_if_destdir', bool, default=False, since='0.57.0'),
        KwargInfo('install_tag', (str, NoneType), since='0.60.0'),
        KwargInfo('dry_run', bool, default=False, since='1.1.0'),
    )
    def add_install_script_method(
            self,
            args: T.Tuple[T.Union[str, mesonlib.File, build.Executable, ExternalProgram],
                          T.List[T.Union[str, mesonlib.File, build.BuildTarget, build.CustomTarget, build.CustomTargetIndex, ExternalProgram]]],
            kwargs: 'AddInstallScriptKW') -> None:
        script_args = self._process_script_args('add_install_script', args[1])
        script = self._find_source_script('add_install_script', args[0], script_args)
        script.skip_if_destdir = kwargs['skip_if_destdir']
        script.tag = kwargs['install_tag']
        script.dry_run = kwargs['dry_run']
        self.build.install_scripts.append(script)

    @typed_pos_args(
        'meson.add_postconf_script',
        (str, mesonlib.File, ExternalProgram),
        varargs=(str, mesonlib.File, ExternalProgram)
    )
    @noKwargs
    def add_postconf_script_method(
            self,
            args: T.Tuple[T.Union[str, mesonlib.File, ExternalProgram],
                          T.List[T.Union[str, mesonlib.File, ExternalProgram]]],
            kwargs: 'TYPE_kwargs') -> None:
        script_args = self._process_script_args('add_postconf_script', args[1])
        script = self._find_source_script('add_postconf_script', args[0], script_args)
        self.build.postconf_scripts.append(script)

    @typed_pos_args(
        'meson.add_dist_script',
        (str, mesonlib.File, ExternalProgram),
        varargs=(str, mesonlib.File, ExternalProgram)
    )
    @noKwargs
    @FeatureNew('meson.add_dist_script', '0.48.0')
    def add_dist_script_method(
            self,
            args: T.Tuple[T.Union[str, mesonlib.File, ExternalProgram],
                          T.List[T.Union[str, mesonlib.File, ExternalProgram]]],
            kwargs: 'TYPE_kwargs') -> None:
        if args[1]:
            FeatureNew.single_use('Calling "add_dist_script" with multiple arguments',
                                  '0.49.0', self.interpreter.subproject, location=self.current_node)
        if self.interpreter.subproject != '':
            FeatureNew.single_use('Calling "add_dist_script" in a subproject',
                                  '0.58.0', self.interpreter.subproject, location=self.current_node)
        script_args = self._process_script_args('add_dist_script', args[1])
        script = self._find_source_script('add_dist_script', args[0], script_args)
        self.build.dist_scripts.append(script)

    @noPosargs
    @noKwargs
    def current_source_dir_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
        src = self.interpreter.environment.source_dir
        sub = self.interpreter.subdir
        if sub == '':
            return src
        return os.path.join(src, sub)

    @noPosargs
    @noKwargs
    def current_build_dir_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
        src = self.interpreter.environment.build_dir
        sub = self.interpreter.subdir
        if sub == '':
            return src
        return os.path.join(src, sub)

    @noPosargs
    @noKwargs
    def backend_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
        return self.interpreter.backend.name

    @noPosargs
    @noKwargs
    @FeatureDeprecated('meson.source_root', '0.56.0', 'use meson.project_source_root() or meson.global_source_root() instead.')
    def source_root_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
        return self.interpreter.environment.source_dir

    @noPosargs
    @noKwargs
    @FeatureDeprecated('meson.build_root', '0.56.0', 'use meson.project_build_root() or meson.global_build_root() instead.')
    def build_root_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
        return self.interpreter.environment.build_dir

    @noPosargs
    @noKwargs
    @FeatureNew('meson.project_source_root', '0.56.0')
    def project_source_root_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
        src = self.interpreter.environment.source_dir
        sub = self.interpreter.root_subdir
        if sub == '':
            return src
        return os.path.join(src, sub)

    @noPosargs
    @noKwargs
    @FeatureNew('meson.project_build_root', '0.56.0')
    def project_build_root_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
        src = self.interpreter.environment.build_dir
        sub = self.interpreter.root_subdir
        if sub == '':
            return src
        return os.path.join(src, sub)

    @noPosargs
    @noKwargs
    @FeatureNew('meson.global_source_root', '0.58.0')
    def global_source_root_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
        return self.interpreter.environment.source_dir

    @noPosargs
    @noKwargs
    @FeatureNew('meson.global_build_root', '0.58.0')
    def global_build_root_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
        return self.interpreter.environment.build_dir

    @noPosargs
    @noKwargs
    @FeatureDeprecated('meson.has_exe_wrapper', '0.55.0', 'use meson.can_run_host_binaries instead.')
    def has_exe_wrapper_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool:
        return self._can_run_host_binaries_impl()

    @noPosargs
    @noKwargs
    @FeatureNew('meson.can_run_host_binaries', '0.55.0')
    def can_run_host_binaries_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool:
        return self._can_run_host_binaries_impl()

    def _can_run_host_binaries_impl(self) -> bool:
        return not (
            self.build.environment.is_cross_build() and
            self.build.environment.need_exe_wrapper() and
            self.build.environment.exe_wrapper is None
        )

    @noPosargs
    @noKwargs
    def is_cross_build_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool:
        return self.build.environment.is_cross_build()

    @typed_pos_args('meson.get_compiler', str)
    @typed_kwargs('meson.get_compiler', NATIVE_KW)
    def get_compiler_method(self, args: T.Tuple[str], kwargs: 'NativeKW') -> 'Compiler':
        cname = args[0]
        for_machine = kwargs['native']
        clist = self.interpreter.coredata.compilers[for_machine]
        try:
            return clist[cname]
        except KeyError:
            raise InterpreterException(f'Tried to access compiler for language "{cname}", not specified for {for_machine.get_lower_case_name()} machine.')

    @noPosargs
    @noKwargs
    def is_unity_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool:
        optval = self.interpreter.environment.coredata.get_option(OptionKey('unity'))
        return optval == 'on' or (optval == 'subprojects' and self.interpreter.is_subproject())

    @noPosargs
    @noKwargs
    def is_subproject_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool:
        return self.interpreter.is_subproject()

    @typed_pos_args('meson.install_dependency_manifest', str)
    @noKwargs
    def install_dependency_manifest_method(self, args: T.Tuple[str], kwargs: 'TYPE_kwargs') -> None:
        self.build.dep_manifest_name = args[0]

    @FeatureNew('meson.override_find_program', '0.46.0')
    @typed_pos_args('meson.override_find_program', str, (mesonlib.File, ExternalProgram, build.Executable))
    @noKwargs
    def override_find_program_method(self, args: T.Tuple[str, T.Union[mesonlib.File, ExternalProgram, build.Executable]], kwargs: 'TYPE_kwargs') -> None:
        name, exe = args
        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(f'Tried to override {name} with a file that does not exist.')
            exe = OverrideProgram(name, [abspath])
        self.interpreter.add_find_program_override(name, exe)

    @typed_kwargs(
        'meson.override_dependency',
        NATIVE_KW,
        KwargInfo('static', (bool, NoneType), since='0.60.0'),
    )
    @typed_pos_args('meson.override_dependency', str, dependencies.Dependency)
    @FeatureNew('meson.override_dependency', '0.54.0')
    def override_dependency_method(self, args: T.Tuple[str, dependencies.Dependency], kwargs: 'FuncOverrideDependency') -> None:
        name, dep = args
        if not name:
            raise InterpreterException('First argument must be a string and cannot be empty')

        optkey = OptionKey('default_library', subproject=self.interpreter.subproject)
        default_library = self.interpreter.coredata.get_option(optkey)
        assert isinstance(default_library, str), 'for mypy'
        static = kwargs['static']
        if static is None:
            # We don't know if dep represents a static or shared library, could
            # be a mix of both. We assume it is following default_library
            # value.
            self._override_dependency_impl(name, dep, kwargs, static=None)
            if default_library == 'static':
                self._override_dependency_impl(name, dep, kwargs, static=True)
            elif default_library == 'shared':
                self._override_dependency_impl(name, dep, kwargs, static=False)
            else:
                self._override_dependency_impl(name, dep, kwargs, static=True)
                self._override_dependency_impl(name, dep, kwargs, static=False)
        else:
            # dependency('foo') without specifying static kwarg should find this
            # override regardless of the static value here. But do not raise error
            # if it has already been overridden, which would happen when overriding
            # static and shared separately:
            # meson.override_dependency('foo', shared_dep, static: false)
            # meson.override_dependency('foo', static_dep, static: true)
            # In that case dependency('foo') would return the first override.
            self._override_dependency_impl(name, dep, kwargs, static=None, permissive=True)
            self._override_dependency_impl(name, dep, kwargs, static=static)

    def _override_dependency_impl(self, name: str, dep: dependencies.Dependency, kwargs: 'FuncOverrideDependency',
                                  static: T.Optional[bool], permissive: bool = False) -> None:
        # We need the cast here as get_dep_identifier works on such a dict,
        # which FuncOverrideDependency is, but mypy can't figure that out
        nkwargs = T.cast('T.Dict[str, T.Any]', kwargs.copy())
        if static is None:
            del nkwargs['static']
        else:
            nkwargs['static'] = static
        identifier = dependencies.get_dep_identifier(name, nkwargs)
        for_machine = kwargs['native']
        override = self.build.dependency_overrides[for_machine].get(identifier)
        if override:
            if permissive:
                return
            m = 'Tried to override dependency {!r} which has already been resolved or overridden at {}'
            location = mlog.get_error_location_string(override.node.filename, override.node.lineno)
            raise InterpreterException(m.format(name, location))
        self.build.dependency_overrides[for_machine][identifier] = \
            build.DependencyOverride(dep, self.interpreter.current_node)

    @noPosargs
    @noKwargs
    def project_version_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
        return self.build.dep_manifest[self.interpreter.active_projectname].version

    @FeatureNew('meson.project_license()', '0.45.0')
    @noPosargs
    @noKwargs
    def project_license_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> T.List[str]:
        return self.build.dep_manifest[self.interpreter.active_projectname].license

    @FeatureNew('meson.project_license_files()', '1.1.0')
    @noPosargs
    @noKwargs
    def project_license_files_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.List[mesonlib.File]:
        return [l[1] for l in self.build.dep_manifest[self.interpreter.active_projectname].license_files]

    @noPosargs
    @noKwargs
    def version_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> MesonVersionString:
        return MesonVersionString(self.interpreter.coredata.version)

    @noPosargs
    @noKwargs
    def project_name_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
        return self.interpreter.active_projectname

    def __get_external_property_impl(self, propname: str, fallback: T.Optional[object], machine: MachineChoice) -> object:
        """Shared implementation for get_cross_property and get_external_property."""
        try:
            return self.interpreter.environment.properties[machine][propname]
        except KeyError:
            if fallback is not None:
                return fallback
            raise InterpreterException(f'Unknown property for {machine.get_lower_case_name()} machine: {propname}')

    @noArgsFlattening
    @FeatureDeprecated('meson.get_cross_property', '0.58.0', 'Use meson.get_external_property() instead')
    @typed_pos_args('meson.get_cross_property', str, optargs=[object])
    @noKwargs
    def get_cross_property_method(self, args: T.Tuple[str, T.Optional[object]], kwargs: 'TYPE_kwargs') -> object:
        propname, fallback = args
        return self.__get_external_property_impl(propname, fallback, MachineChoice.HOST)

    @noArgsFlattening
    @FeatureNew('meson.get_external_property', '0.54.0')
    @typed_pos_args('meson.get_external_property', str, optargs=[object])
    @typed_kwargs('meson.get_external_property', NATIVE_KW)
    def get_external_property_method(self, args: T.Tuple[str, T.Optional[object]], kwargs: 'NativeKW') -> object:
        propname, fallback = args
        return self.__get_external_property_impl(propname, fallback, kwargs['native'])

    @FeatureNew('meson.has_external_property', '0.58.0')
    @typed_pos_args('meson.has_external_property', str)
    @typed_kwargs('meson.has_external_property', NATIVE_KW)
    def has_external_property_method(self, args: T.Tuple[str], kwargs: 'NativeKW') -> bool:
        prop_name = args[0]
        return prop_name in self.interpreter.environment.properties[kwargs['native']]

    @FeatureNew('add_devenv', '0.58.0')
    @typed_kwargs('environment', ENV_METHOD_KW, ENV_SEPARATOR_KW.evolve(since='0.62.0'))
    @typed_pos_args('add_devenv', (str, list, dict, mesonlib.EnvironmentVariables))
    def add_devenv_method(self, args: T.Tuple[T.Union[str, list, dict, mesonlib.EnvironmentVariables]],
                          kwargs: 'AddDevenvKW') -> None:
        env = args[0]
        msg = ENV_KW.validator(env)
        if msg:
            raise build.InvalidArguments(f'"add_devenv": {msg}')
        converted = env_convertor_with_method(env, kwargs['method'], kwargs['separator'])
        assert isinstance(converted, mesonlib.EnvironmentVariables)
        self.build.devenv.append(converted)

    @noPosargs
    @noKwargs
    @FeatureNew('meson.build_options', '1.1.0')
    def build_options_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
        options = self.interpreter.user_defined_options
        if options is None:
            return ''
        return coredata.format_cmd_line_options(options)
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.6946387
meson-1.3.2/mesonbuild/interpreter/primitives/0000755000175000017500000000000014562742414021740 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/interpreter/primitives/__init__.py0000644000175000017500000000134714562742363024061 0ustar00jpakkanejpakkane# Copyright 2021 The Meson development team
# SPDX-license-identifier: Apache-2.0

__all__ = [
    'ArrayHolder',
    'BooleanHolder',
    'DictHolder',
    'IntegerHolder',
    'RangeHolder',
    'StringHolder',
    'MesonVersionString',
    'MesonVersionStringHolder',
    'DependencyVariableString',
    'DependencyVariableStringHolder',
    'OptionString',
    'OptionStringHolder',
]

from .array import ArrayHolder
from .boolean import BooleanHolder
from .dict import DictHolder
from .integer import IntegerHolder
from .range import RangeHolder
from .string import (
    StringHolder,
    MesonVersionString, MesonVersionStringHolder,
    DependencyVariableString, DependencyVariableStringHolder,
    OptionString, OptionStringHolder,
)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/interpreter/primitives/array.py0000644000175000017500000000727114562742363023442 0ustar00jpakkanejpakkane# Copyright 2021 The Meson development team
# SPDX-license-identifier: Apache-2.0
from __future__ import annotations

import typing as T

from ...interpreterbase import (
    ObjectHolder,
    IterableObject,
    MesonOperator,
    typed_operator,
    noKwargs,
    noPosargs,
    noArgsFlattening,
    typed_pos_args,
    FeatureNew,

    TYPE_var,

    InvalidArguments,
)
from ...mparser import PlusAssignmentNode

if T.TYPE_CHECKING:
    # Object holders need the actual interpreter
    from ...interpreter import Interpreter
    from ...interpreterbase import TYPE_kwargs

class ArrayHolder(ObjectHolder[T.List[TYPE_var]], IterableObject):
    def __init__(self, obj: T.List[TYPE_var], interpreter: 'Interpreter') -> None:
        super().__init__(obj, interpreter)
        self.methods.update({
            'contains': self.contains_method,
            'length': self.length_method,
            'get': self.get_method,
        })

        self.trivial_operators.update({
            MesonOperator.EQUALS: (list, lambda x: self.held_object == x),
            MesonOperator.NOT_EQUALS: (list, lambda x: self.held_object != x),
            MesonOperator.IN: (object, lambda x: x in self.held_object),
            MesonOperator.NOT_IN: (object, lambda x: x not in self.held_object),
        })

        # Use actual methods for functions that require additional checks
        self.operators.update({
            MesonOperator.PLUS: self.op_plus,
            MesonOperator.INDEX: self.op_index,
        })

    def display_name(self) -> str:
        return 'array'

    def iter_tuple_size(self) -> None:
        return None

    def iter_self(self) -> T.Iterator[TYPE_var]:
        return iter(self.held_object)

    def size(self) -> int:
        return len(self.held_object)

    @noArgsFlattening
    @noKwargs
    @typed_pos_args('array.contains', object)
    def contains_method(self, args: T.Tuple[object], kwargs: TYPE_kwargs) -> bool:
        def check_contains(el: T.List[TYPE_var]) -> bool:
            for element in el:
                if isinstance(element, list):
                    found = check_contains(element)
                    if found:
                        return True
                if element == args[0]:
                    return True
            return False
        return check_contains(self.held_object)

    @noKwargs
    @noPosargs
    def length_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> int:
        return len(self.held_object)

    @noArgsFlattening
    @noKwargs
    @typed_pos_args('array.get', int, optargs=[object])
    def get_method(self, args: T.Tuple[int, T.Optional[TYPE_var]], kwargs: TYPE_kwargs) -> TYPE_var:
        index = args[0]
        if index < -len(self.held_object) or index >= len(self.held_object):
            if args[1] is None:
                raise InvalidArguments(f'Array index {index} is out of bounds for array of size {len(self.held_object)}.')
            return args[1]
        return self.held_object[index]

    @typed_operator(MesonOperator.PLUS, object)
    def op_plus(self, other: TYPE_var) -> T.List[TYPE_var]:
        if not isinstance(other, list):
            if not isinstance(self.current_node, PlusAssignmentNode):
                FeatureNew.single_use('list.', '0.60.0', self.subproject, 'The right hand operand was not a list.',
                                      location=self.current_node)
            other = [other]
        return self.held_object + other

    @typed_operator(MesonOperator.INDEX, int)
    def op_index(self, other: int) -> TYPE_var:
        try:
            return self.held_object[other]
        except IndexError:
            raise InvalidArguments(f'Index {other} out of bounds of array of size {len(self.held_object)}.')
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0
meson-1.3.2/mesonbuild/interpreter/primitives/boolean.py0000644000175000017500000000351714253672217023737 0ustar00jpakkanejpakkane# Copyright 2021 The Meson development team
# SPDX-license-identifier: Apache-2.0
from __future__ import annotations

from ...interpreterbase import (
    ObjectHolder,
    MesonOperator,
    typed_pos_args,
    noKwargs,
    noPosargs,

    InvalidArguments
)

import typing as T

if T.TYPE_CHECKING:
    # Object holders need the actual interpreter
    from ...interpreter import Interpreter
    from ...interpreterbase import TYPE_var, TYPE_kwargs

class BooleanHolder(ObjectHolder[bool]):
    def __init__(self, obj: bool, interpreter: 'Interpreter') -> None:
        super().__init__(obj, interpreter)
        self.methods.update({
            'to_int': self.to_int_method,
            'to_string': self.to_string_method,
        })

        self.trivial_operators.update({
            MesonOperator.BOOL: (None, lambda x: self.held_object),
            MesonOperator.NOT: (None, lambda x: not self.held_object),
            MesonOperator.EQUALS: (bool, lambda x: self.held_object == x),
            MesonOperator.NOT_EQUALS: (bool, lambda x: self.held_object != x),
        })

    def display_name(self) -> str:
        return 'bool'

    @noKwargs
    @noPosargs
    def to_int_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> int:
        return 1 if self.held_object else 0

    @noKwargs
    @typed_pos_args('bool.to_string', optargs=[str, str])
    def to_string_method(self, args: T.Tuple[T.Optional[str], T.Optional[str]], kwargs: TYPE_kwargs) -> str:
        true_str = args[0] or 'true'
        false_str = args[1] or 'false'
        if any(x is not None for x in args) and not all(x is not None for x in args):
            raise InvalidArguments('bool.to_string() must have either no arguments or exactly two string arguments that signify what values to return for true and false.')
        return true_str if self.held_object else false_str
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/interpreter/primitives/dict.py0000644000175000017500000000540414562742363023243 0ustar00jpakkanejpakkane# Copyright 2021 The Meson development team
# SPDX-license-identifier: Apache-2.0
from __future__ import annotations

import typing as T

from ...interpreterbase import (
    ObjectHolder,
    IterableObject,
    MesonOperator,
    typed_operator,
    noKwargs,
    noPosargs,
    noArgsFlattening,
    typed_pos_args,

    TYPE_var,

    InvalidArguments,
)

if T.TYPE_CHECKING:
    # Object holders need the actual interpreter
    from ...interpreter import Interpreter
    from ...interpreterbase import TYPE_kwargs

class DictHolder(ObjectHolder[T.Dict[str, TYPE_var]], IterableObject):
    def __init__(self, obj: T.Dict[str, TYPE_var], interpreter: 'Interpreter') -> None:
        super().__init__(obj, interpreter)
        self.methods.update({
            'has_key': self.has_key_method,
            'keys': self.keys_method,
            'get': self.get_method,
        })

        self.trivial_operators.update({
            # Arithmetic
            MesonOperator.PLUS: (dict, lambda x: {**self.held_object, **x}),

            # Comparison
            MesonOperator.EQUALS: (dict, lambda x: self.held_object == x),
            MesonOperator.NOT_EQUALS: (dict, lambda x: self.held_object != x),
            MesonOperator.IN: (str, lambda x: x in self.held_object),
            MesonOperator.NOT_IN: (str, lambda x: x not in self.held_object),
        })

        # Use actual methods for functions that require additional checks
        self.operators.update({
            MesonOperator.INDEX: self.op_index,
        })

    def display_name(self) -> str:
        return 'dict'

    def iter_tuple_size(self) -> int:
        return 2

    def iter_self(self) -> T.Iterator[T.Tuple[str, TYPE_var]]:
        return iter(self.held_object.items())

    def size(self) -> int:
        return len(self.held_object)

    @noKwargs
    @typed_pos_args('dict.has_key', str)
    def has_key_method(self, args: T.Tuple[str], kwargs: TYPE_kwargs) -> bool:
        return args[0] in self.held_object

    @noKwargs
    @noPosargs
    def keys_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.List[str]:
        return sorted(self.held_object)

    @noArgsFlattening
    @noKwargs
    @typed_pos_args('dict.get', str, optargs=[object])
    def get_method(self, args: T.Tuple[str, T.Optional[TYPE_var]], kwargs: TYPE_kwargs) -> TYPE_var:
        if args[0] in self.held_object:
            return self.held_object[args[0]]
        if args[1] is not None:
            return args[1]
        raise InvalidArguments(f'Key {args[0]!r} is not in the dictionary.')

    @typed_operator(MesonOperator.INDEX, str)
    def op_index(self, other: str) -> TYPE_var:
        if other not in self.held_object:
            raise InvalidArguments(f'Key {other} is not in the dictionary.')
        return self.held_object[other]
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/interpreter/primitives/integer.py0000644000175000017500000000643314562742363023760 0ustar00jpakkanejpakkane# Copyright 2021 The Meson development team
# SPDX-license-identifier: Apache-2.0
from __future__ import annotations

from ...interpreterbase import (
    FeatureBroken, InvalidArguments, MesonOperator, ObjectHolder, KwargInfo,
    noKwargs, noPosargs, typed_operator, typed_kwargs
)

import typing as T

if T.TYPE_CHECKING:
    # Object holders need the actual interpreter
    from ...interpreter import Interpreter
    from ...interpreterbase import TYPE_var, TYPE_kwargs

class IntegerHolder(ObjectHolder[int]):
    def __init__(self, obj: int, interpreter: 'Interpreter') -> None:
        super().__init__(obj, interpreter)
        self.methods.update({
            'is_even': self.is_even_method,
            'is_odd': self.is_odd_method,
            'to_string': self.to_string_method,
        })

        self.trivial_operators.update({
            # Arithmetic
            MesonOperator.UMINUS: (None, lambda x: -self.held_object),
            MesonOperator.PLUS: (int, lambda x: self.held_object + x),
            MesonOperator.MINUS: (int, lambda x: self.held_object - x),
            MesonOperator.TIMES: (int, lambda x: self.held_object * x),

            # Comparison
            MesonOperator.EQUALS: (int, lambda x: self.held_object == x),
            MesonOperator.NOT_EQUALS: (int, lambda x: self.held_object != x),
            MesonOperator.GREATER: (int, lambda x: self.held_object > x),
            MesonOperator.LESS: (int, lambda x: self.held_object < x),
            MesonOperator.GREATER_EQUALS: (int, lambda x: self.held_object >= x),
            MesonOperator.LESS_EQUALS: (int, lambda x: self.held_object <= x),
        })

        # Use actual methods for functions that require additional checks
        self.operators.update({
            MesonOperator.DIV: self.op_div,
            MesonOperator.MOD: self.op_mod,
        })

    def display_name(self) -> str:
        return 'int'

    def operator_call(self, operator: MesonOperator, other: TYPE_var) -> TYPE_var:
        if isinstance(other, bool):
            FeatureBroken.single_use('int operations with non-int', '1.2.0', self.subproject,
                                     'It is not commutative and only worked because of leaky Python abstractions.',
                                     location=self.current_node)
        return super().operator_call(operator, other)

    @noKwargs
    @noPosargs
    def is_even_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool:
        return self.held_object % 2 == 0

    @noKwargs
    @noPosargs
    def is_odd_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool:
        return self.held_object % 2 != 0

    @typed_kwargs(
        'to_string',
        KwargInfo('fill', int, default=0, since='1.3.0')
    )
    @noPosargs
    def to_string_method(self, args: T.List[TYPE_var], kwargs: T.Dict[str, T.Any]) -> str:
        return str(self.held_object).zfill(kwargs['fill'])

    @typed_operator(MesonOperator.DIV, int)
    def op_div(self, other: int) -> int:
        if other == 0:
            raise InvalidArguments('Tried to divide by 0')
        return self.held_object // other

    @typed_operator(MesonOperator.MOD, int)
    def op_mod(self, other: int) -> int:
        if other == 0:
            raise InvalidArguments('Tried to divide by 0')
        return self.held_object % other
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/interpreter/primitives/range.py0000644000175000017500000000204714562742363023414 0ustar00jpakkanejpakkane# Copyright 2021 The Meson development team
# SPDX-license-identifier: Apache-2.0
from __future__ import annotations

import typing as T

from ...interpreterbase import (
    MesonInterpreterObject,
    IterableObject,
    MesonOperator,
    InvalidArguments,
)

if T.TYPE_CHECKING:
    from ...interpreterbase import SubProject

class RangeHolder(MesonInterpreterObject, IterableObject):
    def __init__(self, start: int, stop: int, step: int, *, subproject: 'SubProject') -> None:
        super().__init__(subproject=subproject)
        self.range = range(start, stop, step)
        self.operators.update({
            MesonOperator.INDEX: self.op_index,
        })

    def op_index(self, other: int) -> int:
        try:
            return self.range[other]
        except IndexError:
            raise InvalidArguments(f'Index {other} out of bounds of range.')

    def iter_tuple_size(self) -> None:
        return None

    def iter_self(self) -> T.Iterator[int]:
        return iter(self.range)

    def size(self) -> int:
        return len(self.range)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/interpreter/primitives/string.py0000644000175000017500000002157514562742363023635 0ustar00jpakkanejpakkane# Copyright 2021 The Meson development team
# SPDX-license-identifier: Apache-2.0
from __future__ import annotations

import re
import os

import typing as T

from ...mesonlib import version_compare
from ...interpreterbase import (
    ObjectHolder,
    MesonOperator,
    FeatureNew,
    typed_operator,
    noArgsFlattening,
    noKwargs,
    noPosargs,
    typed_pos_args,
    InvalidArguments,
    FeatureBroken,
    stringifyUserArguments,
)


if T.TYPE_CHECKING:
    # Object holders need the actual interpreter
    from ...interpreter import Interpreter
    from ...interpreterbase import TYPE_var, TYPE_kwargs

class StringHolder(ObjectHolder[str]):
    def __init__(self, obj: str, interpreter: 'Interpreter') -> None:
        super().__init__(obj, interpreter)
        self.methods.update({
            'contains': self.contains_method,
            'startswith': self.startswith_method,
            'endswith': self.endswith_method,
            'format': self.format_method,
            'join': self.join_method,
            'replace': self.replace_method,
            'split': self.split_method,
            'splitlines': self.splitlines_method,
            'strip': self.strip_method,
            'substring': self.substring_method,
            'to_int': self.to_int_method,
            'to_lower': self.to_lower_method,
            'to_upper': self.to_upper_method,
            'underscorify': self.underscorify_method,
            'version_compare': self.version_compare_method,
        })

        self.trivial_operators.update({
            # Arithmetic
            MesonOperator.PLUS: (str, lambda x: self.held_object + x),

            # Comparison
            MesonOperator.EQUALS: (str, lambda x: self.held_object == x),
            MesonOperator.NOT_EQUALS: (str, lambda x: self.held_object != x),
            MesonOperator.GREATER: (str, lambda x: self.held_object > x),
            MesonOperator.LESS: (str, lambda x: self.held_object < x),
            MesonOperator.GREATER_EQUALS: (str, lambda x: self.held_object >= x),
            MesonOperator.LESS_EQUALS: (str, lambda x: self.held_object <= x),
        })

        # Use actual methods for functions that require additional checks
        self.operators.update({
            MesonOperator.DIV: self.op_div,
            MesonOperator.INDEX: self.op_index,
            MesonOperator.IN: self.op_in,
            MesonOperator.NOT_IN: self.op_notin,
        })

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

    @noKwargs
    @typed_pos_args('str.contains', str)
    def contains_method(self, args: T.Tuple[str], kwargs: TYPE_kwargs) -> bool:
        return self.held_object.find(args[0]) >= 0

    @noKwargs
    @typed_pos_args('str.startswith', str)
    def startswith_method(self, args: T.Tuple[str], kwargs: TYPE_kwargs) -> bool:
        return self.held_object.startswith(args[0])

    @noKwargs
    @typed_pos_args('str.endswith', str)
    def endswith_method(self, args: T.Tuple[str], kwargs: TYPE_kwargs) -> bool:
        return self.held_object.endswith(args[0])

    @noArgsFlattening
    @noKwargs
    @typed_pos_args('str.format', varargs=object)
    def format_method(self, args: T.Tuple[T.List[TYPE_var]], kwargs: TYPE_kwargs) -> str:
        arg_strings: T.List[str] = []
        for arg in args[0]:
            try:
                arg_strings.append(stringifyUserArguments(arg, self.subproject))
            except InvalidArguments as e:
                FeatureBroken.single_use(f'str.format: {str(e)}', '1.3.0', self.subproject, location=self.current_node)
                arg_strings.append(str(arg))

        def arg_replace(match: T.Match[str]) -> str:
            idx = int(match.group(1))
            if idx >= len(arg_strings):
                raise InvalidArguments(f'Format placeholder @{idx}@ out of range.')
            return arg_strings[idx]

        return re.sub(r'@(\d+)@', arg_replace, self.held_object)

    @noKwargs
    @noPosargs
    @FeatureNew('str.splitlines', '1.2.0')
    def splitlines_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.List[str]:
        return self.held_object.splitlines()

    @noKwargs
    @typed_pos_args('str.join', varargs=str)
    def join_method(self, args: T.Tuple[T.List[str]], kwargs: TYPE_kwargs) -> str:
        return self.held_object.join(args[0])

    @noKwargs
    @FeatureNew('str.replace', '0.58.0')
    @typed_pos_args('str.replace', str, str)
    def replace_method(self, args: T.Tuple[str, str], kwargs: TYPE_kwargs) -> str:
        return self.held_object.replace(args[0], args[1])

    @noKwargs
    @typed_pos_args('str.split', optargs=[str])
    def split_method(self, args: T.Tuple[T.Optional[str]], kwargs: TYPE_kwargs) -> T.List[str]:
        return self.held_object.split(args[0])

    @noKwargs
    @typed_pos_args('str.strip', optargs=[str])
    def strip_method(self, args: T.Tuple[T.Optional[str]], kwargs: TYPE_kwargs) -> str:
        if args[0]:
            FeatureNew.single_use('str.strip with a positional argument', '0.43.0', self.subproject, location=self.current_node)
        return self.held_object.strip(args[0])

    @noKwargs
    @FeatureNew('str.substring', '0.56.0')
    @typed_pos_args('str.substring', optargs=[int, int])
    def substring_method(self, args: T.Tuple[T.Optional[int], T.Optional[int]], kwargs: TYPE_kwargs) -> str:
        start = args[0] if args[0] is not None else 0
        end = args[1] if args[1] is not None else len(self.held_object)
        return self.held_object[start:end]

    @noKwargs
    @noPosargs
    def to_int_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> int:
        try:
            return int(self.held_object)
        except ValueError:
            raise InvalidArguments(f'String {self.held_object!r} cannot be converted to int')

    @noKwargs
    @noPosargs
    def to_lower_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return self.held_object.lower()

    @noKwargs
    @noPosargs
    def to_upper_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return self.held_object.upper()

    @noKwargs
    @noPosargs
    def underscorify_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
        return re.sub(r'[^a-zA-Z0-9]', '_', self.held_object)

    @noKwargs
    @typed_pos_args('str.version_compare', str)
    def version_compare_method(self, args: T.Tuple[str], kwargs: TYPE_kwargs) -> bool:
        return version_compare(self.held_object, args[0])

    @staticmethod
    def _op_div(this: str, other: str) -> str:
        return os.path.join(this, other).replace('\\', '/')

    @FeatureNew('/ with string arguments', '0.49.0')
    @typed_operator(MesonOperator.DIV, str)
    def op_div(self, other: str) -> str:
        return self._op_div(self.held_object, other)

    @typed_operator(MesonOperator.INDEX, int)
    def op_index(self, other: int) -> str:
        try:
            return self.held_object[other]
        except IndexError:
            raise InvalidArguments(f'Index {other} out of bounds of string of size {len(self.held_object)}.')

    @FeatureNew('"in" string operator', '1.0.0')
    @typed_operator(MesonOperator.IN, str)
    def op_in(self, other: str) -> bool:
        return other in self.held_object

    @FeatureNew('"not in" string operator', '1.0.0')
    @typed_operator(MesonOperator.NOT_IN, str)
    def op_notin(self, other: str) -> bool:
        return other not in self.held_object


class MesonVersionString(str):
    pass

class MesonVersionStringHolder(StringHolder):
    @noKwargs
    @typed_pos_args('str.version_compare', str)
    def version_compare_method(self, args: T.Tuple[str], kwargs: TYPE_kwargs) -> bool:
        self.interpreter.tmp_meson_version = args[0]
        return version_compare(self.held_object, args[0])

# These special subclasses of string exist to cover the case where a dependency
# exports a string variable interchangeable with a system dependency. This
# matters because a dependency can only have string-type get_variable() return
# values. If at any time dependencies start supporting additional variable
# types, this class could be deprecated.
class DependencyVariableString(str):
    pass

class DependencyVariableStringHolder(StringHolder):
    def op_div(self, other: str) -> T.Union[str, DependencyVariableString]:
        ret = super().op_div(other)
        if '..' in other:
            return ret
        return DependencyVariableString(ret)


class OptionString(str):
    optname: str

    def __new__(cls, value: str, name: str) -> 'OptionString':
        obj = str.__new__(cls, value)
        obj.optname = name
        return obj

    def __getnewargs__(self) -> T.Tuple[str, str]: # type: ignore # because the entire point of this is to diverge
        return (str(self), self.optname)


class OptionStringHolder(StringHolder):
    held_object: OptionString

    def op_div(self, other: str) -> T.Union[str, OptionString]:
        ret = super().op_div(other)
        name = self._op_div(self.held_object.optname, other)
        return OptionString(ret, name)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1700415808.0
meson-1.3.2/mesonbuild/interpreter/type_checking.py0000644000175000017500000007570414526444500022743 0ustar00jpakkanejpakkane# SPDX-License-Identifier: Apache-2.0
# Copyright Ā© 2021 Intel Corporation

"""Helpers for strict type checking."""

from __future__ import annotations
import itertools, os, re
import typing as T

from .. import compilers
from ..build import (CustomTarget, BuildTarget,
                     CustomTargetIndex, ExtractedObjects, GeneratedList, IncludeDirs,
                     BothLibraries, SharedLibrary, StaticLibrary, Jar, Executable, StructuredSources)
from ..coredata import UserFeatureOption
from ..dependencies import Dependency, InternalDependency
from ..interpreterbase.decorators import KwargInfo, ContainerTypeInfo
from ..mesonlib import (File, FileMode, MachineChoice, listify, has_path_sep,
                        OptionKey, EnvironmentVariables)
from ..programs import ExternalProgram

# Helper definition for type checks that are `Optional[T]`
NoneType: T.Type[None] = type(None)

if T.TYPE_CHECKING:
    from typing_extensions import Literal

    from ..build import ObjectTypes
    from ..interpreterbase import TYPE_var
    from ..mesonlib import EnvInitValueType

    _FullEnvInitValueType = T.Union[EnvironmentVariables, T.List[str], T.List[T.List[str]], EnvInitValueType, str, None]
    PkgConfigDefineType = T.Optional[T.Tuple[T.Tuple[str, str], ...]]
    SourcesVarargsType = T.List[T.Union[str, File, CustomTarget, CustomTargetIndex, GeneratedList, StructuredSources, ExtractedObjects, BuildTarget]]


def in_set_validator(choices: T.Set[str]) -> T.Callable[[str], T.Optional[str]]:
    """Check that the choice given was one of the given set."""

    def inner(check: str) -> T.Optional[str]:
        if check not in choices:
            return f"must be one of {', '.join(sorted(choices))}, not {check}"
        return None

    return inner


def _language_validator(l: T.List[str]) -> T.Optional[str]:
    """Validate language keyword argument.

    Particularly for functions like `add_compiler()`, and `add_*_args()`
    """
    diff = {a.lower() for a in l}.difference(compilers.all_languages)
    if diff:
        return f'unknown languages: {", ".join(diff)}'
    return None


def _install_mode_validator(mode: T.List[T.Union[str, bool, int]]) -> T.Optional[str]:
    """Validate the `install_mode` keyword argument.

    This is a rather odd thing, it's a scalar, or an array of 3 values in the form:
    [(str | False), (str | int | False) = False, (str | int | False) = False]
    where the second and third components are not required and default to False.
    """
    if not mode:
        return None
    if True in mode:
        return 'components can only be permission strings, numbers, or False'
    if len(mode) > 3:
        return 'may have at most 3 elements'

    perms = mode[0]
    if not isinstance(perms, (str, bool)):
        return 'first component must be a permissions string or False'

    if isinstance(perms, str):
        if not len(perms) == 9:
            return ('permissions string must be exactly 9 characters in the form rwxr-xr-x,'
                    f' got {len(perms)}')
        for i in [0, 3, 6]:
            if perms[i] not in {'-', 'r'}:
                return f'permissions character {i+1} must be "-" or "r", not {perms[i]}'
        for i in [1, 4, 7]:
            if perms[i] not in {'-', 'w'}:
                return f'permissions character {i+1} must be "-" or "w", not {perms[i]}'
        for i in [2, 5]:
            if perms[i] not in {'-', 'x', 's', 'S'}:
                return f'permissions character {i+1} must be "-", "s", "S", or "x", not {perms[i]}'
        if perms[8] not in {'-', 'x', 't', 'T'}:
            return f'permission character 9 must be "-", "t", "T", or "x", not {perms[8]}'

        if len(mode) >= 2 and not isinstance(mode[1], (int, str, bool)):
            return 'second component can only be a string, number, or False'
        if len(mode) >= 3 and not isinstance(mode[2], (int, str, bool)):
            return 'third component can only be a string, number, or False'

    return None


def _install_mode_convertor(mode: T.Optional[T.List[T.Union[str, bool, int]]]) -> FileMode:
    """Convert the DSL form of the `install_mode` keyword argument to `FileMode`"""

    if not mode:
        return FileMode()

    # This has already been validated by the validator. False denotes "use
    # default". mypy is totally incapable of understanding it, because
    # generators clobber types via homogeneous return. But also we *must*
    # convert the first element different from the rest
    m1 = mode[0] if isinstance(mode[0], str) else None
    rest = (m if isinstance(m, (str, int)) else None for m in mode[1:])

    return FileMode(m1, *rest)


def _lower_strlist(input: T.List[str]) -> T.List[str]:
    """Lower a list of strings.

    mypy (but not pyright) gets confused about using a lambda as the convertor function
    """
    return [i.lower() for i in input]


def _validate_shlib_version(val: T.Optional[str]) -> T.Optional[str]:
    if val is not None and not re.fullmatch(r'[0-9]+(\.[0-9]+){0,2}', val):
        return (f'Invalid Shared library version "{val}". '
                'Must be of the form X.Y.Z where all three are numbers. Y and Z are optional.')
    return None


def variables_validator(contents: T.Union[str, T.List[str], T.Dict[str, str]]) -> T.Optional[str]:
    if isinstance(contents, str):
        contents = [contents]
    if isinstance(contents, dict):
        variables = contents
    else:
        variables = {}
        for v in contents:
            try:
                key, val = v.split('=', 1)
            except ValueError:
                return f'variable {v!r} must have a value separated by equals sign.'
            variables[key.strip()] = val.strip()
    for k, v in variables.items():
        if not k:
            return 'empty variable name'
        if not v:
            return 'empty variable value'
        if any(c.isspace() for c in k):
            return f'invalid whitespace in variable name {k!r}'
    return None


def variables_convertor(contents: T.Union[str, T.List[str], T.Dict[str, str]]) -> T.Dict[str, str]:
    if isinstance(contents, str):
        contents = [contents]
    if isinstance(contents, dict):
        return contents
    variables = {}
    for v in contents:
        key, val = v.split('=', 1)
        variables[key.strip()] = val.strip()
    return variables


NATIVE_KW = KwargInfo(
    'native', bool,
    default=False,
    convertor=lambda n: MachineChoice.BUILD if n else MachineChoice.HOST)

LANGUAGE_KW = KwargInfo(
    'language', ContainerTypeInfo(list, str, allow_empty=False),
    listify=True,
    required=True,
    validator=_language_validator,
    convertor=_lower_strlist)

INSTALL_MODE_KW: KwargInfo[T.List[T.Union[str, bool, int]]] = KwargInfo(
    'install_mode',
    ContainerTypeInfo(list, (str, bool, int)),
    listify=True,
    default=[],
    validator=_install_mode_validator,
    convertor=_install_mode_convertor,
)

REQUIRED_KW: KwargInfo[T.Union[bool, UserFeatureOption]] = KwargInfo(
    'required',
    (bool, UserFeatureOption),
    default=True,
    # TODO: extract_required_kwarg could be converted to a convertor
)

DISABLER_KW: KwargInfo[bool] = KwargInfo('disabler', bool, default=False)

def _env_validator(value: T.Union[EnvironmentVariables, T.List['TYPE_var'], T.Dict[str, 'TYPE_var'], str, None],
                   only_dict_str: bool = True) -> T.Optional[str]:
    def _splitter(v: str) -> T.Optional[str]:
        split = v.split('=', 1)
        if len(split) == 1:
            return f'"{v}" is not two string values separated by an "="'
        return None

    if isinstance(value, str):
        v = _splitter(value)
        if v is not None:
            return v
    elif isinstance(value, list):
        for i in listify(value):
            if not isinstance(i, str):
                return f"All array elements must be a string, not {i!r}"
            v = _splitter(i)
            if v is not None:
                return v
    elif isinstance(value, dict):
        # We don't need to spilt here, just do the type checking
        for k, dv in value.items():
            if only_dict_str:
                if any(i for i in listify(dv) if not isinstance(i, str)):
                    return f"Dictionary element {k} must be a string or list of strings not {dv!r}"
            elif isinstance(dv, list):
                if any(not isinstance(i, str) for i in dv):
                    return f"Dictionary element {k} must be a string, bool, integer or list of strings, not {dv!r}"
            elif not isinstance(dv, (str, bool, int)):
                return f"Dictionary element {k} must be a string, bool, integer or list of strings, not {dv!r}"
    # We know that otherwise we have an EnvironmentVariables object or None, and
    # we're okay at this point
    return None

def _options_validator(value: T.Union[EnvironmentVariables, T.List['TYPE_var'], T.Dict[str, 'TYPE_var'], str, None]) -> T.Optional[str]:
    # Reusing the env validator is a little overkill, but nicer than duplicating the code
    return _env_validator(value, only_dict_str=False)

def split_equal_string(input: str) -> T.Tuple[str, str]:
    """Split a string in the form `x=y`

    This assumes that the string has already been validated to split properly.
    """
    a, b = input.split('=', 1)
    return (a, b)

# Split _env_convertor() and env_convertor_with_method() to make mypy happy.
# It does not want extra arguments in KwargInfo convertor callable.
def env_convertor_with_method(value: _FullEnvInitValueType,
                              init_method: Literal['set', 'prepend', 'append'] = 'set',
                              separator: str = os.pathsep) -> EnvironmentVariables:
    if isinstance(value, str):
        return EnvironmentVariables(dict([split_equal_string(value)]), init_method, separator)
    elif isinstance(value, list):
        return EnvironmentVariables(dict(split_equal_string(v) for v in listify(value)), init_method, separator)
    elif isinstance(value, dict):
        return EnvironmentVariables(value, init_method, separator)
    elif value is None:
        return EnvironmentVariables()
    return value

def _env_convertor(value: _FullEnvInitValueType) -> EnvironmentVariables:
    return env_convertor_with_method(value)

ENV_KW: KwargInfo[T.Union[EnvironmentVariables, T.List, T.Dict, str, None]] = KwargInfo(
    'env',
    (EnvironmentVariables, list, dict, str, NoneType),
    validator=_env_validator,
    convertor=_env_convertor,
)

DEPFILE_KW: KwargInfo[T.Optional[str]] = KwargInfo(
    'depfile',
    (str, type(None)),
    validator=lambda x: 'Depfile must be a plain filename with a subdirectory' if has_path_sep(x) else None
)

# TODO: CustomTargetIndex should be supported here as well
DEPENDS_KW: KwargInfo[T.List[T.Union[BuildTarget, CustomTarget]]] = KwargInfo(
    'depends',
    ContainerTypeInfo(list, (BuildTarget, CustomTarget)),
    listify=True,
    default=[],
)

DEPEND_FILES_KW: KwargInfo[T.List[T.Union[str, File]]] = KwargInfo(
    'depend_files',
    ContainerTypeInfo(list, (File, str)),
    listify=True,
    default=[],
)

COMMAND_KW: KwargInfo[T.List[T.Union[str, BuildTarget, CustomTarget, CustomTargetIndex, ExternalProgram, File]]] = KwargInfo(
    'command',
    # TODO: should accept CustomTargetIndex as well?
    ContainerTypeInfo(list, (str, BuildTarget, CustomTarget, CustomTargetIndex, ExternalProgram, File), allow_empty=False),
    required=True,
    listify=True,
    default=[],
)

def _override_options_convertor(raw: T.Union[str, T.List[str], T.Dict[str, T.Union[str, int, bool, T.List[str]]]]) -> T.Dict[OptionKey, T.Union[str, int, bool, T.List[str]]]:
    if isinstance(raw, str):
        raw = [raw]
    if isinstance(raw, list):
        output: T.Dict[OptionKey, T.Union[str, int, bool, T.List[str]]] = {}
        for each in raw:
            k, v = split_equal_string(each)
            output[OptionKey.from_string(k)] = v
        return output
    return {OptionKey.from_string(k): v for k, v in raw.items()}


OVERRIDE_OPTIONS_KW: KwargInfo[T.Union[str, T.Dict[str, T.Union[str, int, bool, T.List[str]]], T.List[str]]] = KwargInfo(
    'override_options',
    (str, ContainerTypeInfo(list, str), ContainerTypeInfo(dict, (str, int, bool, list))),
    default={},
    validator=_options_validator,
    convertor=_override_options_convertor,
    since_values={dict: '1.2.0'},
)


def _output_validator(outputs: T.List[str]) -> T.Optional[str]:
    output_set = set(outputs)
    if len(output_set) != len(outputs):
        seen = set()
        for el in outputs:
            if el in seen:
                return f"contains {el!r} multiple times, but no duplicates are allowed."
            seen.add(el)
    for i in outputs:
        if i == '':
            return 'Output must not be empty.'
        elif i.strip() == '':
            return 'Output must not consist only of whitespace.'
        elif has_path_sep(i):
            return f'Output {i!r} must not contain a path segment.'
        elif '@INPUT' in i:
            return f'output {i!r} contains "@INPUT", which is invalid. Did you mean "@PLAINNAME@" or "@BASENAME@?'

    return None

MULTI_OUTPUT_KW: KwargInfo[T.List[str]] = KwargInfo(
    'output',
    ContainerTypeInfo(list, str, allow_empty=False),
    listify=True,
    required=True,
    default=[],
    validator=_output_validator,
)

OUTPUT_KW: KwargInfo[str] = KwargInfo(
    'output',
    str,
    required=True,
    validator=lambda x: _output_validator([x])
)

CT_INPUT_KW: KwargInfo[T.List[T.Union[str, File, ExternalProgram, BuildTarget, CustomTarget, CustomTargetIndex, ExtractedObjects, GeneratedList]]] = KwargInfo(
    'input',
    ContainerTypeInfo(list, (str, File, ExternalProgram, BuildTarget, CustomTarget, CustomTargetIndex, ExtractedObjects, GeneratedList)),
    listify=True,
    default=[],
)

CT_INSTALL_TAG_KW: KwargInfo[T.List[T.Union[str, bool]]] = KwargInfo(
    'install_tag',
    ContainerTypeInfo(list, (str, bool)),
    listify=True,
    default=[],
    since='0.60.0',
    convertor=lambda x: [y if isinstance(y, str) else None for y in x],
)

INSTALL_TAG_KW: KwargInfo[T.Optional[str]] = KwargInfo('install_tag', (str, NoneType))

INSTALL_FOLLOW_SYMLINKS: KwargInfo[T.Optional[bool]] = KwargInfo(
    'follow_symlinks',
    (bool, NoneType),
    since='1.3.0',
)

INSTALL_KW = KwargInfo('install', bool, default=False)

CT_INSTALL_DIR_KW: KwargInfo[T.List[T.Union[str, Literal[False]]]] = KwargInfo(
    'install_dir',
    ContainerTypeInfo(list, (str, bool)),
    listify=True,
    default=[],
    validator=lambda x: 'must be `false` if boolean' if True in x else None,
)

CT_BUILD_BY_DEFAULT: KwargInfo[T.Optional[bool]] = KwargInfo('build_by_default', (bool, type(None)), since='0.40.0')

CT_BUILD_ALWAYS: KwargInfo[T.Optional[bool]] = KwargInfo(
    'build_always', (bool, NoneType),
    deprecated='0.47.0',
    deprecated_message='combine build_by_default and build_always_stale instead.',
)

CT_BUILD_ALWAYS_STALE: KwargInfo[T.Optional[bool]] = KwargInfo(
    'build_always_stale', (bool, NoneType),
    since='0.47.0',
)

INSTALL_DIR_KW: KwargInfo[T.Optional[str]] = KwargInfo('install_dir', (str, NoneType))

INCLUDE_DIRECTORIES: KwargInfo[T.List[T.Union[str, IncludeDirs]]] = KwargInfo(
    'include_directories',
    ContainerTypeInfo(list, (str, IncludeDirs)),
    listify=True,
    default=[],
)

DEFAULT_OPTIONS = OVERRIDE_OPTIONS_KW.evolve(name='default_options')

ENV_METHOD_KW = KwargInfo('method', str, default='set', since='0.62.0',
                          validator=in_set_validator({'set', 'prepend', 'append'}))

ENV_SEPARATOR_KW = KwargInfo('separator', str, default=os.pathsep)

DEPENDENCIES_KW: KwargInfo[T.List[Dependency]] = KwargInfo(
    'dependencies',
    # InternalDependency is a subclass of Dependency, but we want to
    # print it in error messages
    ContainerTypeInfo(list, (Dependency, InternalDependency)),
    listify=True,
    default=[],
)

D_MODULE_VERSIONS_KW: KwargInfo[T.List[T.Union[str, int]]] = KwargInfo(
    'd_module_versions',
    ContainerTypeInfo(list, (str, int)),
    listify=True,
    default=[],
)

_link_with_error = '''can only be self-built targets, external dependencies (including libraries) must go in "dependencies".'''

# Allow Dependency for the better error message? But then in other cases it will list this as one of the allowed types!
LINK_WITH_KW: KwargInfo[T.List[T.Union[BothLibraries, SharedLibrary, StaticLibrary, CustomTarget, CustomTargetIndex, Jar, Executable]]] = KwargInfo(
    'link_with',
    ContainerTypeInfo(list, (BothLibraries, SharedLibrary, StaticLibrary, CustomTarget, CustomTargetIndex, Jar, Executable, Dependency)),
    listify=True,
    default=[],
    validator=lambda x: _link_with_error if any(isinstance(i, Dependency) for i in x) else None,
)

def link_whole_validator(values: T.List[T.Union[StaticLibrary, CustomTarget, CustomTargetIndex, Dependency]]) -> T.Optional[str]:
    for l in values:
        if isinstance(l, (CustomTarget, CustomTargetIndex)) and l.links_dynamically():
            return f'{type(l).__name__} returning a shared library is not allowed'
        if isinstance(l, Dependency):
            return _link_with_error
    return None

LINK_WHOLE_KW: KwargInfo[T.List[T.Union[BothLibraries, StaticLibrary, CustomTarget, CustomTargetIndex]]] = KwargInfo(
    'link_whole',
    ContainerTypeInfo(list, (BothLibraries, StaticLibrary, CustomTarget, CustomTargetIndex, Dependency)),
    listify=True,
    default=[],
    validator=link_whole_validator,
)

DEPENDENCY_SOURCES_KW: KwargInfo[T.List[T.Union[str, File, CustomTarget, CustomTargetIndex, GeneratedList]]] = KwargInfo(
    'sources',
    ContainerTypeInfo(list, (str, File, CustomTarget, CustomTargetIndex, GeneratedList)),
    listify=True,
    default=[],
)

SOURCES_VARARGS = (str, File, CustomTarget, CustomTargetIndex, GeneratedList, StructuredSources, ExtractedObjects, BuildTarget)

BT_SOURCES_KW: KwargInfo[SourcesVarargsType] = KwargInfo(
    'sources',
    (NoneType, ContainerTypeInfo(list, SOURCES_VARARGS)),
    listify=True,
    default=[],
)

VARIABLES_KW: KwargInfo[T.Dict[str, str]] = KwargInfo(
    'variables',
    # str is listified by validator/convertor, cannot use listify=True here because
    # that would listify dict too.
    (str, ContainerTypeInfo(list, str), ContainerTypeInfo(dict, str)), # type: ignore
    validator=variables_validator,
    convertor=variables_convertor,
    default={},
)

PRESERVE_PATH_KW: KwargInfo[bool] = KwargInfo('preserve_path', bool, default=False, since='0.63.0')

TEST_KWS: T.List[KwargInfo] = [
    KwargInfo('args', ContainerTypeInfo(list, (str, File, BuildTarget, CustomTarget, CustomTargetIndex)),
              listify=True, default=[]),
    KwargInfo('should_fail', bool, default=False),
    KwargInfo('timeout', int, default=30),
    KwargInfo('workdir', (str, NoneType), default=None,
              validator=lambda x: 'must be an absolute path' if not os.path.isabs(x) else None),
    KwargInfo('protocol', str,
              default='exitcode',
              validator=in_set_validator({'exitcode', 'tap', 'gtest', 'rust'}),
              since_values={'gtest': '0.55.0', 'rust': '0.57.0'}),
    KwargInfo('priority', int, default=0, since='0.52.0'),
    # TODO: env needs reworks of the way the environment variable holder itself works probably
    ENV_KW,
    DEPENDS_KW.evolve(since='0.46.0'),
    KwargInfo('suite', ContainerTypeInfo(list, str), listify=True, default=['']),  # yes, a list of empty string
    KwargInfo('verbose', bool, default=False, since='0.62.0'),
]

# Cannot have a default value because we need to check that rust_crate_type and
# rust_abi are mutually exclusive.
RUST_CRATE_TYPE_KW: KwargInfo[T.Union[str, None]] = KwargInfo(
    'rust_crate_type', (str, NoneType),
    since='0.42.0',
    since_values={'proc-macro': '0.62.0'},
    deprecated='1.3.0',
    deprecated_message='Use rust_abi or rust.proc_macro() instead.',
    validator=in_set_validator({'bin', 'lib', 'rlib', 'dylib', 'cdylib', 'staticlib', 'proc-macro'}))

RUST_ABI_KW: KwargInfo[T.Union[str, None]] = KwargInfo(
    'rust_abi', (str, NoneType),
    since='1.3.0',
    validator=in_set_validator({'rust', 'c'}))

_VS_MODULE_DEFS_KW: KwargInfo[T.Optional[T.Union[str, File, CustomTarget, CustomTargetIndex]]] = KwargInfo(
    'vs_module_defs',
    (str, File, CustomTarget, CustomTargetIndex, NoneType),
    since_values={CustomTargetIndex: '1.3.0'}
)

_BASE_LANG_KW: KwargInfo[T.List[str]] = KwargInfo(
    'UNKNOWN',
    ContainerTypeInfo(list, (str)),
    listify=True,
    default=[],
)

_LANGUAGE_KWS: T.List[KwargInfo[T.List[str]]] = [
    _BASE_LANG_KW.evolve(name=f'{lang}_args')
    for lang in compilers.all_languages - {'rust', 'vala', 'java'}
]
# Cannot use _BASE_LANG_KW here because Vala is special for types
_LANGUAGE_KWS.append(KwargInfo(
    'vala_args', ContainerTypeInfo(list, (str, File)), listify=True, default=[]))
_LANGUAGE_KWS.append(_BASE_LANG_KW.evolve(name='rust_args', since='0.41.0'))

# We need this deprecated values more than the non-deprecated values. So we'll evolve them out elsewhere.
_JAVA_LANG_KW: KwargInfo[T.List[str]] = _BASE_LANG_KW.evolve(
    name='java_args',
    deprecated='1.3.0',
    deprecated_message='This does not, and never has, done anything. It should be removed'
)

def _objects_validator(vals: T.List[ObjectTypes]) -> T.Optional[str]:
    non_objects: T.List[str] = []

    for val in vals:
        if isinstance(val, (str, File, ExtractedObjects)):
            continue
        else:
            non_objects.extend(o for o in val.get_outputs() if not compilers.is_object(o))

    if non_objects:
        return f'{", ".join(non_objects)!r} are not objects'

    return None


# Applies to all build_target like classes
_ALL_TARGET_KWS: T.List[KwargInfo] = [
    OVERRIDE_OPTIONS_KW,
    KwargInfo('build_by_default', bool, default=True, since='0.38.0'),
    KwargInfo('extra_files', ContainerTypeInfo(list, (str, File)), default=[], listify=True),
    # Accursed. We allow this for backwards compat and warn in the interpreter.
    KwargInfo('install', object, default=False),
    INSTALL_MODE_KW,
    KwargInfo('implicit_include_directories', bool, default=True, since='0.42.0'),
    NATIVE_KW,
    KwargInfo('resources', ContainerTypeInfo(list, str), default=[], listify=True),
    KwargInfo(
        'objects',
        ContainerTypeInfo(list, (str, File, CustomTarget, CustomTargetIndex, GeneratedList, ExtractedObjects)),
        listify=True,
        default=[],
        validator=_objects_validator,
        since_values={
            ContainerTypeInfo(list, (GeneratedList, CustomTarget, CustomTargetIndex)):
                ('1.1.0', 'generated sources as positional "objects" arguments')
        },
    ),
]


def _name_validator(arg: T.Optional[T.Union[str, T.List]]) -> T.Optional[str]:
    if isinstance(arg, list) and arg:
        return 'must be empty when passed as an array to signify the default value.'
    return None


def _name_suffix_validator(arg: T.Optional[T.Union[str, T.List]]) -> T.Optional[str]:
    if arg == '':
        return 'must not be a empty string. An empty array may be passed if you want Meson to use the default behavior.'
    return _name_validator(arg)


_NAME_PREFIX_KW: KwargInfo[T.Optional[T.Union[str, T.List]]] = KwargInfo(
    'name_prefix',
    (str, NoneType, list),
    validator=_name_validator,
    convertor=lambda x: None if isinstance(x, list) else x,
)


# Applies to all build_target classes except jar
_BUILD_TARGET_KWS: T.List[KwargInfo] = [
    *_ALL_TARGET_KWS,
    *_LANGUAGE_KWS,
    BT_SOURCES_KW,
    INCLUDE_DIRECTORIES.evolve(name='d_import_dirs'),
    _NAME_PREFIX_KW,
    _NAME_PREFIX_KW.evolve(name='name_suffix', validator=_name_suffix_validator),
    RUST_CRATE_TYPE_KW,
    KwargInfo('d_debug', ContainerTypeInfo(list, (str, int)), default=[], listify=True),
    D_MODULE_VERSIONS_KW,
    KwargInfo('d_unittest', bool, default=False),
    KwargInfo(
        'rust_dependency_map',
        ContainerTypeInfo(dict, str),
        default={},
        since='1.2.0',
    ),
    KwargInfo('build_rpath', str, default='', since='0.42.0'),
    KwargInfo(
        'gnu_symbol_visibility',
        str,
        default='',
        validator=in_set_validator({'', 'default', 'internal', 'hidden', 'protected', 'inlineshidden'}),
        since='0.48.0',
    ),
    KwargInfo('install_rpath', str, default=''),
    KwargInfo(
        'link_depends',
        ContainerTypeInfo(list, (str, File, CustomTarget, CustomTargetIndex, BuildTarget)),
        default=[],
        listify=True,
    ),
    KwargInfo(
        'link_language',
        (str, NoneType),
        validator=in_set_validator(set(compilers.all_languages)),
        since='0.51.0',
    ),
]

def _validate_win_subsystem(value: T.Optional[str]) -> T.Optional[str]:
    if value is not None:
        if re.fullmatch(r'(boot_application|console|efi_application|efi_boot_service_driver|efi_rom|efi_runtime_driver|native|posix|windows)(,\d+(\.\d+)?)?', value) is None:
            return f'Invalid value for win_subsystem: {value}.'
    return None


def _validate_darwin_versions(darwin_versions: T.List[T.Union[str, int]]) -> T.Optional[str]:
    if len(darwin_versions) > 2:
        return f"Must contain between 0 and 2 elements, not {len(darwin_versions)}"
    if len(darwin_versions) == 1:
        darwin_versions = 2 * darwin_versions
    for v in darwin_versions:
        if isinstance(v, int):
            v = str(v)
        if not re.fullmatch(r'[0-9]+(\.[0-9]+){0,2}', v):
            return 'must be X.Y.Z where X, Y, Z are numbers, and Y and Z are optional'
        try:
            parts = v.split('.')
        except ValueError:
            return f'badly formed value: "{v}, not in X.Y.Z form'
        if len(parts) in {1, 2, 3} and int(parts[0]) > 65535:
            return '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:
            return 'must be X.Y.Z where Y is [0, 255] and Y, Z are optional'
        if len(parts) == 3 and int(parts[2]) > 255:
            return 'must be X.Y.Z where Z is [0, 255] and Y, Z are optional'
    return None


def _convert_darwin_versions(val: T.List[T.Union[str, int]]) -> T.Optional[T.Tuple[str, str]]:
    if not val:
        return None
    elif len(val) == 1:
        v = str(val[0])
        return (v, v)
    return (str(val[0]), str(val[1]))


_DARWIN_VERSIONS_KW: KwargInfo[T.List[T.Union[str, int]]] = KwargInfo(
    'darwin_versions',
    ContainerTypeInfo(list, (str, int)),
    default=[],
    listify=True,
    validator=_validate_darwin_versions,
    convertor=_convert_darwin_versions,
    since='0.48.0',
)

# Arguments exclusive to Executable. These are separated to make integrating
# them into build_target easier
_EXCLUSIVE_EXECUTABLE_KWS: T.List[KwargInfo] = [
    KwargInfo('export_dynamic', (bool, NoneType), since='0.45.0'),
    KwargInfo('gui_app', (bool, NoneType), deprecated='0.56.0', deprecated_message="Use 'win_subsystem' instead"),
    KwargInfo('implib', (bool, str, NoneType), since='0.42.0'),
    KwargInfo('pie', (bool, NoneType)),
    KwargInfo(
        'win_subsystem',
        (str, NoneType),
        convertor=lambda x: x.lower() if isinstance(x, str) else None,
        validator=_validate_win_subsystem,
    ),
]

# The total list of arguments used by Executable
EXECUTABLE_KWS = [
    *_BUILD_TARGET_KWS,
    *_EXCLUSIVE_EXECUTABLE_KWS,
    _VS_MODULE_DEFS_KW.evolve(since='1.3.0', since_values=None),
    _JAVA_LANG_KW,
]

# Arguments exclusive to library types
_EXCLUSIVE_LIB_KWS: T.List[KwargInfo] = [
    RUST_ABI_KW,
]

# Arguments exclusive to StaticLibrary. These are separated to make integrating
# them into build_target easier
_EXCLUSIVE_STATIC_LIB_KWS: T.List[KwargInfo] = [
    KwargInfo('prelink', bool, default=False, since='0.57.0'),
    KwargInfo('pic', (bool, NoneType), since='0.36.0'),
]

# The total list of arguments used by StaticLibrary
STATIC_LIB_KWS = [
    *_BUILD_TARGET_KWS,
    *_EXCLUSIVE_STATIC_LIB_KWS,
    *_EXCLUSIVE_LIB_KWS,
    _JAVA_LANG_KW,
]

# Arguments exclusive to SharedLibrary. These are separated to make integrating
# them into build_target easier
_EXCLUSIVE_SHARED_LIB_KWS: T.List[KwargInfo] = [
    _DARWIN_VERSIONS_KW,
    KwargInfo('soversion', (str, int, NoneType), convertor=lambda x: str(x) if x is not None else None),
    KwargInfo('version', (str, NoneType), validator=_validate_shlib_version),
]

# The total list of arguments used by SharedLibrary
SHARED_LIB_KWS = [
    *_BUILD_TARGET_KWS,
    *_EXCLUSIVE_SHARED_LIB_KWS,
    *_EXCLUSIVE_LIB_KWS,
    _VS_MODULE_DEFS_KW,
    _JAVA_LANG_KW,
]

# Arguments exclusive to SharedModule. These are separated to make integrating
# them into build_target easier
_EXCLUSIVE_SHARED_MOD_KWS: T.List[KwargInfo] = []

# The total list of arguments used by SharedModule
SHARED_MOD_KWS = [
    *_BUILD_TARGET_KWS,
    *_EXCLUSIVE_SHARED_MOD_KWS,
    *_EXCLUSIVE_LIB_KWS,
    _VS_MODULE_DEFS_KW,
    _JAVA_LANG_KW,
]

# Arguments exclusive to JAR. These are separated to make integrating
# them into build_target easier
_EXCLUSIVE_JAR_KWS: T.List[KwargInfo] = [
    KwargInfo('main_class', str, default=''),
    KwargInfo('java_resources', (StructuredSources, NoneType), since='0.62.0'),
    _JAVA_LANG_KW.evolve(deprecated=None, deprecated_message=None),
]

# The total list of arguments used by JAR
JAR_KWS = [
    *_ALL_TARGET_KWS,
    *_EXCLUSIVE_JAR_KWS,
    KwargInfo(
        'sources',
        ContainerTypeInfo(list, (str, File, CustomTarget, CustomTargetIndex, GeneratedList, ExtractedObjects, BuildTarget)),
        listify=True,
        default=[],
    ),
    *[a.evolve(deprecated='1.3.0', deprecated_message='This argument has never done anything in jar(), and should be removed')
      for a in _LANGUAGE_KWS],
]

_SHARED_STATIC_ARGS: T.List[KwargInfo[T.List[str]]] = [
    *[l.evolve(name=l.name.replace('_', '_static_'), since='1.3.0')
      for l in _LANGUAGE_KWS],
    *[l.evolve(name=l.name.replace('_', '_shared_'), since='1.3.0')
      for l in _LANGUAGE_KWS],
]

# Arguments used by both_library and library
LIBRARY_KWS = [
    *_BUILD_TARGET_KWS,
    *_EXCLUSIVE_LIB_KWS,
    *_EXCLUSIVE_SHARED_LIB_KWS,
    *_EXCLUSIVE_SHARED_MOD_KWS,
    *_EXCLUSIVE_STATIC_LIB_KWS,
    *_SHARED_STATIC_ARGS,
    _VS_MODULE_DEFS_KW,
    _JAVA_LANG_KW,
]

# Arguments used by build_Target
BUILD_TARGET_KWS = [
    *_BUILD_TARGET_KWS,
    *_EXCLUSIVE_SHARED_LIB_KWS,
    *_EXCLUSIVE_SHARED_MOD_KWS,
    *_EXCLUSIVE_STATIC_LIB_KWS,
    *_EXCLUSIVE_EXECUTABLE_KWS,
    *_SHARED_STATIC_ARGS,
    *[a.evolve(deprecated='1.3.0', deprecated_message='The use of "jar" in "build_target()" is deprecated, and this argument is only used by jar()')
      for a in _EXCLUSIVE_JAR_KWS],
    KwargInfo(
        'target_type',
        str,
        required=True,
        validator=in_set_validator({
            'executable', 'shared_library', 'static_library', 'shared_module',
            'both_libraries', 'library', 'jar'
        }),
        since_values={
            'shared_module': '0.51.0',
        },
        deprecated_values={
            'jar': ('1.3.0', 'use the "jar()" function directly'),
        }
    )
]

def _pkgconfig_define_convertor(x: T.List[str]) -> PkgConfigDefineType:
    if x:
        keys = itertools.islice(x, 0, None, 2)
        vals = itertools.islice(x, 1, None, 2)
        return tuple(zip(keys, vals))
    return None

PKGCONFIG_DEFINE_KW: KwargInfo = KwargInfo(
    'pkgconfig_define',
    ContainerTypeInfo(list, str, pairs=True),
    default=[],
    convertor=_pkgconfig_define_convertor,
)
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.7066388
meson-1.3.2/mesonbuild/interpreterbase/0000755000175000017500000000000014562742414020400 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/interpreterbase/__init__.py0000644000175000017500000000554714562742363022527 0ustar00jpakkanejpakkane# Copyright 2013-2021 The Meson development team

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

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

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

__all__ = [
    'InterpreterObject',
    'MesonInterpreterObject',
    'ObjectHolder',
    'IterableObject',
    'MutableInterpreterObject',
    'ContextManagerObject',

    'MesonOperator',

    'Disabler',
    'is_disabled',

    'InterpreterException',
    'InvalidCode',
    'InvalidArguments',
    'SubdirDoneRequest',
    'ContinueRequest',
    'BreakRequest',

    'default_resolve_key',
    'flatten',
    'resolve_second_level_holders',
    'stringifyUserArguments',

    'noPosargs',
    'noKwargs',
    'stringArgs',
    'noArgsFlattening',
    'noSecondLevelHolderResolving',
    'unholder_return',
    'disablerIfNotFound',
    'permittedKwargs',
    'typed_operator',
    'typed_pos_args',
    'ContainerTypeInfo',
    'KwargInfo',
    'typed_kwargs',
    'FeatureCheckBase',
    'FeatureNew',
    'FeatureDeprecated',
    'FeatureBroken',
    'FeatureNewKwargs',
    'FeatureDeprecatedKwargs',

    'InterpreterBase',

    'SubProject',

    'TV_func',
    'TYPE_elementary',
    'TYPE_var',
    'TYPE_nvar',
    'TYPE_kwargs',
    'TYPE_nkwargs',
    'TYPE_key_resolver',
    'TYPE_HoldableTypes',

    'HoldableTypes',
]

from .baseobjects import (
    InterpreterObject,
    MesonInterpreterObject,
    ObjectHolder,
    IterableObject,
    MutableInterpreterObject,
    ContextManagerObject,

    TV_func,
    TYPE_elementary,
    TYPE_var,
    TYPE_nvar,
    TYPE_kwargs,
    TYPE_nkwargs,
    TYPE_key_resolver,
    TYPE_HoldableTypes,

    SubProject,

    HoldableTypes,
)

from .decorators import (
    noPosargs,
    noKwargs,
    stringArgs,
    noArgsFlattening,
    noSecondLevelHolderResolving,
    unholder_return,
    disablerIfNotFound,
    permittedKwargs,
    typed_pos_args,
    ContainerTypeInfo,
    KwargInfo,
    typed_operator,
    typed_kwargs,
    FeatureCheckBase,
    FeatureNew,
    FeatureDeprecated,
    FeatureBroken,
    FeatureNewKwargs,
    FeatureDeprecatedKwargs,
)

from .exceptions import (
    InterpreterException,
    InvalidCode,
    InvalidArguments,
    SubdirDoneRequest,
    ContinueRequest,
    BreakRequest,
)

from .disabler import Disabler, is_disabled
from .helpers import (
    default_resolve_key,
    flatten,
    resolve_second_level_holders,
    stringifyUserArguments,
)
from .interpreterbase import InterpreterBase
from .operator import MesonOperator
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/interpreterbase/_unholder.py0000644000175000017500000000304114562742363022732 0ustar00jpakkanejpakkane# Copyright 2013-2021 The Meson development team

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

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

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

import typing as T

from .baseobjects import InterpreterObject, MesonInterpreterObject, ObjectHolder, HoldableTypes
from .exceptions import InvalidArguments
from ..mesonlib import HoldableObject, MesonBugException

if T.TYPE_CHECKING:
    from .baseobjects import TYPE_var

def _unholder(obj: InterpreterObject) -> TYPE_var:
    if isinstance(obj, ObjectHolder):
        assert isinstance(obj.held_object, HoldableTypes)
        return obj.held_object
    elif isinstance(obj, MesonInterpreterObject):
        return obj
    elif isinstance(obj, HoldableObject):
        raise MesonBugException(f'Argument {obj} of type {type(obj).__name__} is not held by an ObjectHolder.')
    elif isinstance(obj, InterpreterObject):
        raise InvalidArguments(f'Argument {obj} of type {type(obj).__name__} cannot be passed to a method or function')
    raise MesonBugException(f'Unknown object {obj} of type {type(obj).__name__} in the parameters.')
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/interpreterbase/baseobjects.py0000644000175000017500000002014514562742363023243 0ustar00jpakkanejpakkane# Copyright 2013-2021 The Meson development team

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

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

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

from .. import mparser
from .exceptions import InvalidCode, InvalidArguments
from .helpers import flatten, resolve_second_level_holders
from .operator import MesonOperator
from ..mesonlib import HoldableObject, MesonBugException
import textwrap

import typing as T
from abc import ABCMeta
from contextlib import AbstractContextManager

if T.TYPE_CHECKING:
    from typing_extensions import Protocol

    # Object holders need the actual interpreter
    from ..interpreter import Interpreter

    __T = T.TypeVar('__T', bound='TYPE_var', contravariant=True)

    class OperatorCall(Protocol[__T]):
        def __call__(self, other: __T) -> 'TYPE_var': ...


TV_func = T.TypeVar('TV_func', bound=T.Callable[..., T.Any])

TYPE_elementary = T.Union[str, int, bool, T.List[T.Any], T.Dict[str, T.Any]]
TYPE_var = T.Union[TYPE_elementary, HoldableObject, 'MesonInterpreterObject']
TYPE_nvar = T.Union[TYPE_var, mparser.BaseNode]
TYPE_kwargs = T.Dict[str, TYPE_var]
TYPE_nkwargs = T.Dict[str, TYPE_nvar]
TYPE_key_resolver = T.Callable[[mparser.BaseNode], str]

SubProject = T.NewType('SubProject', str)

class InterpreterObject:
    def __init__(self, *, subproject: T.Optional['SubProject'] = None) -> None:
        self.methods: T.Dict[
            str,
            T.Callable[[T.List[TYPE_var], TYPE_kwargs], TYPE_var]
        ] = {}
        self.operators: T.Dict[MesonOperator, 'OperatorCall'] = {}
        self.trivial_operators: T.Dict[
            MesonOperator,
            T.Tuple[
                T.Union[T.Type, T.Tuple[T.Type, ...]],
                'OperatorCall'
            ]
        ] = {}
        # 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:  mparser.BaseNode = None
        self.subproject = subproject or SubProject('')

        # Some default operators supported by all objects
        self.operators.update({
            MesonOperator.EQUALS: self.op_equals,
            MesonOperator.NOT_EQUALS: self.op_not_equals,
        })

    # The type of the object that can be printed to the user
    def display_name(self) -> str:
        return type(self).__name__

    def method_call(
                self,
                method_name: str,
                args: T.List[TYPE_var],
                kwargs: TYPE_kwargs
            ) -> TYPE_var:
        if method_name in self.methods:
            method = self.methods[method_name]
            if not getattr(method, 'no-args-flattening', False):
                args = flatten(args)
            if not getattr(method, 'no-second-level-holder-flattening', False):
                args, kwargs = resolve_second_level_holders(args, kwargs)
            return method(args, kwargs)
        raise InvalidCode(f'Unknown method "{method_name}" in object {self} of type {type(self).__name__}.')

    def operator_call(self, operator: MesonOperator, other: TYPE_var) -> TYPE_var:
        if operator in self.trivial_operators:
            op = self.trivial_operators[operator]
            if op[0] is None and other is not None:
                raise MesonBugException(f'The unary operator `{operator.value}` of {self.display_name()} was passed the object {other} of type {type(other).__name__}')
            if op[0] is not None and not isinstance(other, op[0]):
                raise InvalidArguments(f'The `{operator.value}` operator of {self.display_name()} does not accept objects of type {type(other).__name__} ({other})')
            return op[1](other)
        if operator in self.operators:
            return self.operators[operator](other)
        raise InvalidCode(f'Object {self} of type {self.display_name()} does not support the `{operator.value}` operator.')

    # Default comparison operator support
    def _throw_comp_exception(self, other: TYPE_var, opt_type: str) -> T.NoReturn:
        raise InvalidArguments(textwrap.dedent(
            f'''
                Trying to compare values of different types ({self.display_name()}, {type(other).__name__}) using {opt_type}.
                This was deprecated and undefined behavior previously and is as of 0.60.0 a hard error.
            '''
        ))

    def op_equals(self, other: TYPE_var) -> bool:
        # We use `type(...) == type(...)` here to enforce an *exact* match for comparison. We
        # don't want comparisons to be possible where `isinstance(derived_obj, type(base_obj))`
        # would pass because this comparison must never be true: `derived_obj == base_obj`
        if type(self) is not type(other):
            self._throw_comp_exception(other, '==')
        return self == other

    def op_not_equals(self, other: TYPE_var) -> bool:
        if type(self) is not type(other):
            self._throw_comp_exception(other, '!=')
        return self != other

class MesonInterpreterObject(InterpreterObject):
    ''' All non-elementary objects and non-object-holders should be derived from this '''

class MutableInterpreterObject:
    ''' Dummy class to mark the object type as mutable '''

HoldableTypes = (HoldableObject, int, bool, str, list, dict)
TYPE_HoldableTypes = T.Union[TYPE_elementary, HoldableObject]
InterpreterObjectTypeVar = T.TypeVar('InterpreterObjectTypeVar', bound=TYPE_HoldableTypes)

class ObjectHolder(InterpreterObject, T.Generic[InterpreterObjectTypeVar]):
    def __init__(self, obj: InterpreterObjectTypeVar, interpreter: 'Interpreter') -> None:
        super().__init__(subproject=interpreter.subproject)
        # This causes some type checkers to assume that obj is a base
        # HoldableObject, not the specialized type, so only do this assert in
        # non-type checking situations
        if not T.TYPE_CHECKING:
            assert isinstance(obj, HoldableTypes), f'This is a bug: Trying to hold object of type `{type(obj).__name__}` that is not in `{HoldableTypes}`'
        self.held_object = obj
        self.interpreter = interpreter
        self.env = self.interpreter.environment

    # Hide the object holder abstraction from the user
    def display_name(self) -> str:
        return type(self.held_object).__name__

    # Override default comparison operators for the held object
    def op_equals(self, other: TYPE_var) -> bool:
        # See the comment from InterpreterObject why we are using `type()` here.
        if type(self.held_object) is not type(other):
            self._throw_comp_exception(other, '==')
        return self.held_object == other

    def op_not_equals(self, other: TYPE_var) -> bool:
        if type(self.held_object) is not type(other):
            self._throw_comp_exception(other, '!=')
        return self.held_object != other

    def __repr__(self) -> str:
        return f'<[{type(self).__name__}] holds [{type(self.held_object).__name__}]: {self.held_object!r}>'

class IterableObject(metaclass=ABCMeta):
    '''Base class for all objects that can be iterated over in a foreach loop'''

    def iter_tuple_size(self) -> T.Optional[int]:
        '''Return the size of the tuple for each iteration. Returns None if only a single value is returned.'''
        raise MesonBugException(f'iter_tuple_size not implemented for {self.__class__.__name__}')

    def iter_self(self) -> T.Iterator[T.Union[TYPE_var, T.Tuple[TYPE_var, ...]]]:
        raise MesonBugException(f'iter not implemented for {self.__class__.__name__}')

    def size(self) -> int:
        raise MesonBugException(f'size not implemented for {self.__class__.__name__}')

class ContextManagerObject(MesonInterpreterObject, AbstractContextManager):
    def __init__(self, subproject: 'SubProject') -> None:
        super().__init__(subproject=subproject)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/interpreterbase/decorators.py0000644000175000017500000011121214562742363023120 0ustar00jpakkanejpakkane# Copyright 2013-2021 The Meson development team

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

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

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

from .. import mesonlib, mlog
from .disabler import Disabler
from .exceptions import InterpreterException, InvalidArguments
from ._unholder import _unholder

from dataclasses import dataclass
from functools import wraps
import abc
import itertools
import copy
import typing as T

if T.TYPE_CHECKING:
    from typing_extensions import Protocol

    from .. import mparser
    from .baseobjects import InterpreterObject, SubProject, TV_func, TYPE_var, TYPE_kwargs
    from .operator import MesonOperator

    _TV_IntegerObject = T.TypeVar('_TV_IntegerObject', bound=InterpreterObject, contravariant=True)
    _TV_ARG1 = T.TypeVar('_TV_ARG1', bound=TYPE_var, contravariant=True)

    class FN_Operator(Protocol[_TV_IntegerObject, _TV_ARG1]):
        def __call__(s, self: _TV_IntegerObject, other: _TV_ARG1) -> TYPE_var: ...
    _TV_FN_Operator = T.TypeVar('_TV_FN_Operator', bound=FN_Operator)

def get_callee_args(wrapped_args: T.Sequence[T.Any]) -> T.Tuple['mparser.BaseNode', T.List['TYPE_var'], 'TYPE_kwargs', 'SubProject']:
    # First argument could be InterpreterBase, InterpreterObject or ModuleObject.
    # In the case of a ModuleObject it is the 2nd argument (ModuleState) that
    # contains the needed information.
    s = wrapped_args[0]
    if not hasattr(s, 'current_node'):
        s = wrapped_args[1]
    node = s.current_node
    subproject = s.subproject
    args = kwargs = None
    if len(wrapped_args) >= 3:
        args = wrapped_args[-2]
        kwargs = wrapped_args[-1]
    return node, args, kwargs, subproject

def noPosargs(f: TV_func) -> TV_func:
    @wraps(f)
    def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
        args = get_callee_args(wrapped_args)[1]
        if args:
            raise InvalidArguments('Function does not take positional arguments.')
        return f(*wrapped_args, **wrapped_kwargs)
    return T.cast('TV_func', wrapped)

def noKwargs(f: TV_func) -> TV_func:
    @wraps(f)
    def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
        kwargs = get_callee_args(wrapped_args)[2]
        if kwargs:
            raise InvalidArguments('Function does not take keyword arguments.')
        return f(*wrapped_args, **wrapped_kwargs)
    return T.cast('TV_func', wrapped)

def stringArgs(f: TV_func) -> TV_func:
    @wraps(f)
    def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
        args = get_callee_args(wrapped_args)[1]
        if not isinstance(args, list):
            mlog.debug('Not a list:', str(args))
            raise InvalidArguments('Argument not a list.')
        if not all(isinstance(s, str) for s in args):
            mlog.debug('Element not a string:', str(args))
            raise InvalidArguments('Arguments must be strings.')
        return f(*wrapped_args, **wrapped_kwargs)
    return T.cast('TV_func', wrapped)

def noArgsFlattening(f: TV_func) -> TV_func:
    setattr(f, 'no-args-flattening', True)  # noqa: B010
    return f

def noSecondLevelHolderResolving(f: TV_func) -> TV_func:
    setattr(f, 'no-second-level-holder-flattening', True)  # noqa: B010
    return f

def unholder_return(f: TV_func) -> T.Callable[..., TYPE_var]:
    @wraps(f)
    def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
        res = f(*wrapped_args, **wrapped_kwargs)
        return _unholder(res)
    return T.cast('T.Callable[..., TYPE_var]', wrapped)

def disablerIfNotFound(f: TV_func) -> TV_func:
    @wraps(f)
    def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
        kwargs = get_callee_args(wrapped_args)[2]
        disabler = kwargs.pop('disabler', False)
        ret = f(*wrapped_args, **wrapped_kwargs)
        if disabler and not ret.found():
            return Disabler()
        return ret
    return T.cast('TV_func', wrapped)

@dataclass(repr=False, eq=False)
class permittedKwargs:
    permitted: T.Set[str]

    def __call__(self, f: TV_func) -> TV_func:
        @wraps(f)
        def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
            kwargs = get_callee_args(wrapped_args)[2]
            unknowns = set(kwargs).difference(self.permitted)
            if unknowns:
                ustr = ', '.join([f'"{u}"' for u in sorted(unknowns)])
                raise InvalidArguments(f'Got unknown keyword arguments {ustr}')
            return f(*wrapped_args, **wrapped_kwargs)
        return T.cast('TV_func', wrapped)

def typed_operator(operator: MesonOperator,
                   types: T.Union[T.Type, T.Tuple[T.Type, ...]]) -> T.Callable[['_TV_FN_Operator'], '_TV_FN_Operator']:
    """Decorator that does type checking for operator calls.

    The principle here is similar to typed_pos_args, however much simpler
    since only one other object ever is passed
    """
    def inner(f: '_TV_FN_Operator') -> '_TV_FN_Operator':
        @wraps(f)
        def wrapper(self: 'InterpreterObject', other: TYPE_var) -> TYPE_var:
            if not isinstance(other, types):
                raise InvalidArguments(f'The `{operator.value}` of {self.display_name()} does not accept objects of type {type(other).__name__} ({other})')
            return f(self, other)
        return T.cast('_TV_FN_Operator', wrapper)
    return inner


def typed_pos_args(name: str, *types: T.Union[T.Type, T.Tuple[T.Type, ...]],
                   varargs: T.Optional[T.Union[T.Type, T.Tuple[T.Type, ...]]] = None,
                   optargs: T.Optional[T.List[T.Union[T.Type, T.Tuple[T.Type, ...]]]] = None,
                   min_varargs: int = 0, max_varargs: int = 0) -> T.Callable[..., T.Any]:
    """Decorator that types type checking of positional arguments.

    This supports two different models of optional arguments, the first is the
    variadic argument model. Variadic arguments are a possibly bounded,
    possibly unbounded number of arguments of the same type (unions are
    supported). The second is the standard default value model, in this case
    a number of optional arguments may be provided, but they are still
    ordered, and they may have different types.

    This function does not support mixing variadic and default arguments.

    :name: The name of the decorated function (as displayed in error messages)
    :varargs: They type(s) of any variadic arguments the function takes. If
        None the function takes no variadic args
    :min_varargs: the minimum number of variadic arguments taken
    :max_varargs: the maximum number of variadic arguments taken. 0 means unlimited
    :optargs: The types of any optional arguments parameters taken. If None
        then no optional parameters are taken.

    Some examples of usage blow:
    >>> @typed_pos_args('mod.func', str, (str, int))
    ... def func(self, state: ModuleState, args: T.Tuple[str, T.Union[str, int]], kwargs: T.Dict[str, T.Any]) -> T.Any:
    ...     pass

    >>> @typed_pos_args('method', str, varargs=str)
    ... def method(self, node: BaseNode, args: T.Tuple[str, T.List[str]], kwargs: T.Dict[str, T.Any]) -> T.Any:
    ...     pass

    >>> @typed_pos_args('method', varargs=str, min_varargs=1)
    ... def method(self, node: BaseNode, args: T.Tuple[T.List[str]], kwargs: T.Dict[str, T.Any]) -> T.Any:
    ...     pass

    >>> @typed_pos_args('method', str, optargs=[(str, int), str])
    ... def method(self, node: BaseNode, args: T.Tuple[str, T.Optional[T.Union[str, int]], T.Optional[str]], kwargs: T.Dict[str, T.Any]) -> T.Any:
    ...     pass

    When should you chose `typed_pos_args('name', varargs=str,
    min_varargs=1)` vs `typed_pos_args('name', str, varargs=str)`?

    The answer has to do with the semantics of the function, if all of the
    inputs are the same type (such as with `files()`) then the former is
    correct, all of the arguments are string names of files. If the first
    argument is something else the it should be separated.
    """
    def inner(f: TV_func) -> TV_func:

        @wraps(f)
        def wrapper(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
            args = get_callee_args(wrapped_args)[1]

            # These are implementation programming errors, end users should never see them.
            assert isinstance(args, list), args
            assert max_varargs >= 0, 'max_varags cannot be negative'
            assert min_varargs >= 0, 'min_varags cannot be negative'
            assert optargs is None or varargs is None, \
                'varargs and optargs not supported together as this would be ambiguous'

            num_args = len(args)
            num_types = len(types)
            a_types = types

            if varargs:
                min_args = num_types + min_varargs
                max_args = num_types + max_varargs
                if max_varargs == 0 and num_args < min_args:
                    raise InvalidArguments(f'{name} takes at least {min_args} arguments, but got {num_args}.')
                elif max_varargs != 0 and (num_args < min_args or num_args > max_args):
                    raise InvalidArguments(f'{name} takes between {min_args} and {max_args} arguments, but got {num_args}.')
            elif optargs:
                if num_args < num_types:
                    raise InvalidArguments(f'{name} takes at least {num_types} arguments, but got {num_args}.')
                elif num_args > num_types + len(optargs):
                    raise InvalidArguments(f'{name} takes at most {num_types + len(optargs)} arguments, but got {num_args}.')
                # Add the number of positional arguments required
                if num_args > num_types:
                    diff = num_args - num_types
                    a_types = tuple(list(types) + list(optargs[:diff]))
            elif num_args != num_types:
                raise InvalidArguments(f'{name} takes exactly {num_types} arguments, but got {num_args}.')

            for i, (arg, type_) in enumerate(itertools.zip_longest(args, a_types, fillvalue=varargs), start=1):
                if not isinstance(arg, type_):
                    if isinstance(type_, tuple):
                        shouldbe = 'one of: {}'.format(", ".join(f'"{t.__name__}"' for t in type_))
                    else:
                        shouldbe = f'"{type_.__name__}"'
                    raise InvalidArguments(f'{name} argument {i} was of type "{type(arg).__name__}" but should have been {shouldbe}')

            # Ensure that we're actually passing a tuple.
            # Depending on what kind of function we're calling the length of
            # wrapped_args can vary.
            nargs = list(wrapped_args)
            i = nargs.index(args)
            if varargs:
                # if we have varargs we need to split them into a separate
                # tuple, as python's typing doesn't understand tuples with
                # fixed elements and variadic elements, only one or the other.
                # so in that case we need T.Tuple[int, str, float, T.Tuple[str, ...]]
                pos = args[:len(types)]
                var = list(args[len(types):])
                pos.append(var)
                nargs[i] = tuple(pos)
            elif optargs:
                if num_args < num_types + len(optargs):
                    diff = num_types + len(optargs) - num_args
                    nargs[i] = tuple(list(args) + [None] * diff)
                else:
                    nargs[i] = tuple(args)
            else:
                nargs[i] = tuple(args)
            return f(*nargs, **wrapped_kwargs)

        return T.cast('TV_func', wrapper)
    return inner


class ContainerTypeInfo:

    """Container information for keyword arguments.

    For keyword arguments that are containers (list or dict), this class encodes
    that information.

    :param container: the type of container
    :param contains: the types the container holds
    :param pairs: if the container is supposed to be of even length.
        This is mainly used for interfaces that predate the addition of dictionaries, and use
        `[key, value, key2, value2]` format.
    :param allow_empty: Whether this container is allowed to be empty
        There are some cases where containers not only must be passed, but must
        not be empty, and other cases where an empty container is allowed.
    """

    def __init__(self, container: T.Type, contains: T.Union[T.Type, T.Tuple[T.Type, ...]], *,
                 pairs: bool = False, allow_empty: bool = True):
        self.container = container
        self.contains = contains
        self.pairs = pairs
        self.allow_empty = allow_empty

    def check(self, value: T.Any) -> bool:
        """Check that a value is valid.

        :param value: A value to check
        :return: True if it is valid, False otherwise
        """
        if not isinstance(value, self.container):
            return False
        iter_ = iter(value.values()) if isinstance(value, dict) else iter(value)
        if any(not isinstance(i, self.contains) for i in iter_):
            return False
        if self.pairs and len(value) % 2 != 0:
            return False
        if not value and not self.allow_empty:
            return False
        return True

    def check_any(self, value: T.Any) -> bool:
        """Check a value should emit new/deprecated feature.

        :param value: A value to check
        :return: True if any of the items in value matches, False otherwise
        """
        if not isinstance(value, self.container):
            return False
        iter_ = iter(value.values()) if isinstance(value, dict) else iter(value)
        return any(isinstance(i, self.contains) for i in iter_)

    def description(self) -> str:
        """Human readable description of this container type.

        :return: string to be printed
        """
        container = 'dict' if self.container is dict else 'array'
        if isinstance(self.contains, tuple):
            contains = ' | '.join([t.__name__ for t in self.contains])
        else:
            contains = self.contains.__name__
        s = f'{container}[{contains}]'
        if self.pairs:
            s += ' that has even size'
        if not self.allow_empty:
            s += ' that cannot be empty'
        return s

_T = T.TypeVar('_T')

class _NULL_T:
    """Special null type for evolution, this is an implementation detail."""


_NULL = _NULL_T()

class KwargInfo(T.Generic[_T]):

    """A description of a keyword argument to a meson function

    This is used to describe a value to the :func:typed_kwargs function.

    :param name: the name of the parameter
    :param types: A type or tuple of types that are allowed, or a :class:ContainerType
    :param required: Whether this is a required keyword argument. defaults to False
    :param listify: If true, then the argument will be listified before being
        checked. This is useful for cases where the Meson DSL allows a scalar or
        a container, but internally we only want to work with containers
    :param default: A default value to use if this isn't set. defaults to None,
        this may be safely set to a mutable type, as long as that type does not
        itself contain mutable types, typed_kwargs will copy the default
    :param since: Meson version in which this argument has been added. defaults to None
    :param since_message: An extra message to pass to FeatureNew when since is triggered
    :param deprecated: Meson version in which this argument has been deprecated. defaults to None
    :param deprecated_message: An extra message to pass to FeatureDeprecated
        when since is triggered
    :param validator: A callable that does additional validation. This is mainly
        intended for cases where a string is expected, but only a few specific
        values are accepted. Must return None if the input is valid, or a
        message if the input is invalid
    :param convertor: A callable that converts the raw input value into a
        different type. This is intended for cases such as the meson DSL using a
        string, but the implementation using an Enum. This should not do
        validation, just conversion.
    :param deprecated_values: a dictionary mapping a value to the version of
        meson it was deprecated in. The Value may be any valid value for this
        argument.
    :param since_values: a dictionary mapping a value to the version of meson it was
        added in.
    :param not_set_warning: A warning message that is logged if the kwarg is not
        set by the user.
    """
    def __init__(self, name: str,
                 types: T.Union[T.Type[_T], T.Tuple[T.Union[T.Type[_T], ContainerTypeInfo], ...], ContainerTypeInfo],
                 *, required: bool = False, listify: bool = False,
                 default: T.Optional[_T] = None,
                 since: T.Optional[str] = None,
                 since_message: T.Optional[str] = None,
                 since_values: T.Optional[T.Dict[T.Union[_T, ContainerTypeInfo, type], T.Union[str, T.Tuple[str, str]]]] = None,
                 deprecated: T.Optional[str] = None,
                 deprecated_message: T.Optional[str] = None,
                 deprecated_values: T.Optional[T.Dict[T.Union[_T, ContainerTypeInfo, type], T.Union[str, T.Tuple[str, str]]]] = None,
                 validator: T.Optional[T.Callable[[T.Any], T.Optional[str]]] = None,
                 convertor: T.Optional[T.Callable[[_T], object]] = None,
                 not_set_warning: T.Optional[str] = None):
        self.name = name
        self.types = types
        self.required = required
        self.listify = listify
        self.default = default
        self.since = since
        self.since_message = since_message
        self.since_values = since_values
        self.deprecated = deprecated
        self.deprecated_message = deprecated_message
        self.deprecated_values = deprecated_values
        self.validator = validator
        self.convertor = convertor
        self.not_set_warning = not_set_warning

    def evolve(self, *,
               name: T.Union[str, _NULL_T] = _NULL,
               required: T.Union[bool, _NULL_T] = _NULL,
               listify: T.Union[bool, _NULL_T] = _NULL,
               default: T.Union[_T, None, _NULL_T] = _NULL,
               since: T.Union[str, None, _NULL_T] = _NULL,
               since_message: T.Union[str, None, _NULL_T] = _NULL,
               since_values: T.Union[T.Dict[T.Union[_T, ContainerTypeInfo, type], T.Union[str, T.Tuple[str, str]]], None, _NULL_T] = _NULL,
               deprecated: T.Union[str, None, _NULL_T] = _NULL,
               deprecated_message: T.Union[str, None, _NULL_T] = _NULL,
               deprecated_values: T.Union[T.Dict[T.Union[_T, ContainerTypeInfo, type], T.Union[str, T.Tuple[str, str]]], None, _NULL_T] = _NULL,
               validator: T.Union[T.Callable[[_T], T.Optional[str]], None, _NULL_T] = _NULL,
               convertor: T.Union[T.Callable[[_T], TYPE_var], None, _NULL_T] = _NULL) -> 'KwargInfo':
        """Create a shallow copy of this KwargInfo, with modifications.

        This allows us to create a new copy of a KwargInfo with modifications.
        This allows us to use a shared kwarg that implements complex logic, but
        has slight differences in usage, such as being added to different
        functions in different versions of Meson.

        The use the _NULL special value here allows us to pass None, which has
        meaning in many of these cases. _NULL itself is never stored, always
        being replaced by either the copy in self, or the provided new version.
        """
        return type(self)(
            name if not isinstance(name, _NULL_T) else self.name,
            self.types,
            listify=listify if not isinstance(listify, _NULL_T) else self.listify,
            required=required if not isinstance(required, _NULL_T) else self.required,
            default=default if not isinstance(default, _NULL_T) else self.default,
            since=since if not isinstance(since, _NULL_T) else self.since,
            since_message=since_message if not isinstance(since_message, _NULL_T) else self.since_message,
            since_values=since_values if not isinstance(since_values, _NULL_T) else self.since_values,
            deprecated=deprecated if not isinstance(deprecated, _NULL_T) else self.deprecated,
            deprecated_message=deprecated_message if not isinstance(deprecated_message, _NULL_T) else self.deprecated_message,
            deprecated_values=deprecated_values if not isinstance(deprecated_values, _NULL_T) else self.deprecated_values,
            validator=validator if not isinstance(validator, _NULL_T) else self.validator,
            convertor=convertor if not isinstance(convertor, _NULL_T) else self.convertor,
        )


def typed_kwargs(name: str, *types: KwargInfo, allow_unknown: bool = False) -> T.Callable[..., T.Any]:
    """Decorator for type checking keyword arguments.

    Used to wrap a meson DSL implementation function, where it checks various
    things about keyword arguments, including the type, and various other
    information. For non-required values it sets the value to a default, which
    means the value will always be provided.

    If type is a :class:ContainerTypeInfo, then the default value will be
    passed as an argument to the container initializer, making a shallow copy

    :param name: the name of the function, including the object it's attached to
        (if applicable)
    :param *types: KwargInfo entries for each keyword argument.
    """
    def inner(f: TV_func) -> TV_func:

        def types_description(types_tuple: T.Tuple[T.Union[T.Type, ContainerTypeInfo], ...]) -> str:
            candidates = []
            for t in types_tuple:
                if isinstance(t, ContainerTypeInfo):
                    candidates.append(t.description())
                else:
                    candidates.append(t.__name__)
            shouldbe = 'one of: ' if len(candidates) > 1 else ''
            shouldbe += ', '.join(candidates)
            return shouldbe

        def raw_description(t: object) -> str:
            """describe a raw type (ie, one that is not a ContainerTypeInfo)."""
            if isinstance(t, list):
                if t:
                    return f"array[{' | '.join(sorted(mesonlib.OrderedSet(type(v).__name__ for v in t)))}]"
                return 'array[]'
            elif isinstance(t, dict):
                if t:
                    return f"dict[{' | '.join(sorted(mesonlib.OrderedSet(type(v).__name__ for v in t.values())))}]"
                return 'dict[]'
            return type(t).__name__

        def check_value_type(types_tuple: T.Tuple[T.Union[T.Type, ContainerTypeInfo], ...],
                             value: T.Any) -> bool:
            for t in types_tuple:
                if isinstance(t, ContainerTypeInfo):
                    if t.check(value):
                        return True
                elif isinstance(value, t):
                    return True
            return False

        @wraps(f)
        def wrapper(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:

            def emit_feature_change(values: T.Dict[_T, T.Union[str, T.Tuple[str, str]]], feature: T.Union[T.Type['FeatureDeprecated'], T.Type['FeatureNew']]) -> None:
                for n, version in values.items():
                    if isinstance(version, tuple):
                        version, msg = version
                    else:
                        msg = None

                    warning: T.Optional[str] = None
                    if isinstance(n, ContainerTypeInfo):
                        if n.check_any(value):
                            warning = f'of type {n.description()}'
                    elif isinstance(n, type):
                        if isinstance(value, n):
                            warning = f'of type {n.__name__}'
                    elif isinstance(value, list):
                        if n in value:
                            warning = f'value "{n}" in list'
                    elif isinstance(value, dict):
                        if n in value.keys():
                            warning = f'value "{n}" in dict keys'
                    elif n == value:
                        warning = f'value "{n}"'
                    if warning:
                        feature.single_use(f'"{name}" keyword argument "{info.name}" {warning}', version, subproject, msg, location=node)

            node, _, _kwargs, subproject = get_callee_args(wrapped_args)
            # Cast here, as the convertor function may place something other than a TYPE_var in the kwargs
            kwargs = T.cast('T.Dict[str, object]', _kwargs)

            if not allow_unknown:
                all_names = {t.name for t in types}
                unknowns = set(kwargs).difference(all_names)
                if unknowns:
                    ustr = ', '.join([f'"{u}"' for u in sorted(unknowns)])
                    raise InvalidArguments(f'{name} got unknown keyword arguments {ustr}')

            for info in types:
                types_tuple = info.types if isinstance(info.types, tuple) else (info.types,)
                value = kwargs.get(info.name)
                if value is not None:
                    if info.since:
                        feature_name = info.name + ' arg in ' + name
                        FeatureNew.single_use(feature_name, info.since, subproject, info.since_message, location=node)
                    if info.deprecated:
                        feature_name = info.name + ' arg in ' + name
                        FeatureDeprecated.single_use(feature_name, info.deprecated, subproject, info.deprecated_message, location=node)
                    if info.listify:
                        kwargs[info.name] = value = mesonlib.listify(value)
                    if not check_value_type(types_tuple, value):
                        shouldbe = types_description(types_tuple)
                        raise InvalidArguments(f'{name} keyword argument {info.name!r} was of type {raw_description(value)} but should have been {shouldbe}')

                    if info.validator is not None:
                        msg = info.validator(value)
                        if msg is not None:
                            raise InvalidArguments(f'{name} keyword argument "{info.name}" {msg}')

                    if info.deprecated_values is not None:
                        emit_feature_change(info.deprecated_values, FeatureDeprecated)

                    if info.since_values is not None:
                        emit_feature_change(info.since_values, FeatureNew)

                elif info.required:
                    raise InvalidArguments(f'{name} is missing required keyword argument "{info.name}"')
                else:
                    # set the value to the default, this ensuring all kwargs are present
                    # This both simplifies the typing checking and the usage
                    assert check_value_type(types_tuple, info.default), f'In function {name} default value of {info.name} is not a valid type, got {type(info.default)} expected {types_description(types_tuple)}'
                    # Create a shallow copy of the container. This allows mutable
                    # types to be used safely as default values
                    kwargs[info.name] = copy.copy(info.default)
                    if info.not_set_warning:
                        mlog.warning(info.not_set_warning)

                if info.convertor:
                    kwargs[info.name] = info.convertor(kwargs[info.name])

            return f(*wrapped_args, **wrapped_kwargs)
        return T.cast('TV_func', wrapper)
    return inner


# This cannot be a dataclass due to https://github.com/python/mypy/issues/5374
class FeatureCheckBase(metaclass=abc.ABCMeta):
    "Base class for feature version checks"

    feature_registry: T.ClassVar[T.Dict[str, T.Dict[str, T.Set[T.Tuple[str, T.Optional['mparser.BaseNode']]]]]]
    emit_notice = False
    unconditional = False

    def __init__(self, feature_name: str, feature_version: str, extra_message: str = ''):
        self.feature_name = feature_name
        self.feature_version = feature_version
        self.extra_message = extra_message

    @staticmethod
    def get_target_version(subproject: str) -> str:
        # 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]

    @staticmethod
    @abc.abstractmethod
    def check_version(target_version: str, feature_version: str) -> bool:
        pass

    def use(self, subproject: 'SubProject', location: T.Optional['mparser.BaseNode'] = None) -> None:
        tv = self.get_target_version(subproject)
        # No target version
        if tv == '' and not self.unconditional:
            return
        # Target version is new enough, don't warn
        if self.check_version(tv, self.feature_version) and not self.emit_notice:
            return
        # Feature is too new for target version or we want to emit notices, 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()

        feature_key = (self.feature_name, location)
        if feature_key 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(feature_key)
        # Target version is new enough, don't warn even if it is registered for notice
        if self.check_version(tv, self.feature_version):
            return
        self.log_usage_warning(tv, location)

    @classmethod
    def report(cls, subproject: str) -> None:
        if subproject not in cls.feature_registry:
            return
        warning_str = cls.get_warning_str_prefix(cls.get_target_version(subproject))
        notice_str = cls.get_notice_str_prefix(cls.get_target_version(subproject))
        fv = cls.feature_registry[subproject]
        tv = cls.get_target_version(subproject)
        for version in sorted(fv.keys()):
            message = ', '.join(sorted({f"'{i[0]}'" for i in fv[version]}))
            if cls.check_version(tv, version):
                notice_str += '\n * {}: {{{}}}'.format(version, message)
            else:
                warning_str += '\n * {}: {{{}}}'.format(version, message)
        if '\n' in notice_str:
            mlog.notice(notice_str, fatal=False)
        if '\n' in warning_str:
            mlog.warning(warning_str)

    def log_usage_warning(self, tv: str, location: T.Optional['mparser.BaseNode']) -> None:
        raise InterpreterException('log_usage_warning not implemented')

    @staticmethod
    def get_warning_str_prefix(tv: str) -> str:
        raise InterpreterException('get_warning_str_prefix not implemented')

    @staticmethod
    def get_notice_str_prefix(tv: str) -> str:
        raise InterpreterException('get_notice_str_prefix not implemented')

    def __call__(self, f: TV_func) -> TV_func:
        @wraps(f)
        def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
            node, _, _, subproject = get_callee_args(wrapped_args)
            if subproject is None:
                raise AssertionError(f'{wrapped_args!r}')
            self.use(subproject, node)
            return f(*wrapped_args, **wrapped_kwargs)
        return T.cast('TV_func', wrapped)

    @classmethod
    def single_use(cls, feature_name: str, version: str, subproject: 'SubProject',
                   extra_message: str = '', location: T.Optional['mparser.BaseNode'] = None) -> None:
        """Oneline version that instantiates and calls use()."""
        cls(feature_name, version, extra_message).use(subproject, location)


class FeatureNew(FeatureCheckBase):
    """Checks for new features"""

    # Class variable, shared across all instances
    #
    # Format: {subproject: {feature_version: set(feature_names)}}
    feature_registry = {}

    @staticmethod
    def check_version(target_version: str, feature_version: str) -> bool:
        return mesonlib.version_compare_condition_with_min(target_version, feature_version)

    @staticmethod
    def get_warning_str_prefix(tv: str) -> str:
        return f'Project specifies a minimum meson_version \'{tv}\' but uses features which were added in newer versions:'

    @staticmethod
    def get_notice_str_prefix(tv: str) -> str:
        return ''

    def log_usage_warning(self, tv: str, location: T.Optional['mparser.BaseNode']) -> None:
        args = [
            'Project targets', f"'{tv}'",
            'but uses feature introduced in',
            f"'{self.feature_version}':",
            f'{self.feature_name}.',
        ]
        if self.extra_message:
            args.append(self.extra_message)
        mlog.warning(*args, location=location)

class FeatureDeprecated(FeatureCheckBase):
    """Checks for deprecated features"""

    # Class variable, shared across all instances
    #
    # Format: {subproject: {feature_version: set(feature_names)}}
    feature_registry = {}
    emit_notice = True

    @staticmethod
    def check_version(target_version: str, feature_version: str) -> bool:
        # For deprecation checks we need to return the inverse of FeatureNew checks
        return not mesonlib.version_compare_condition_with_min(target_version, feature_version)

    @staticmethod
    def get_warning_str_prefix(tv: str) -> str:
        return 'Deprecated features used:'

    @staticmethod
    def get_notice_str_prefix(tv: str) -> str:
        return 'Future-deprecated features used:'

    def log_usage_warning(self, tv: str, location: T.Optional['mparser.BaseNode']) -> None:
        args = [
            'Project targets', f"'{tv}'",
            'but uses feature deprecated since',
            f"'{self.feature_version}':",
            f'{self.feature_name}.',
        ]
        if self.extra_message:
            args.append(self.extra_message)
        mlog.warning(*args, location=location)


class FeatureBroken(FeatureCheckBase):
    """Checks for broken features"""

    # Class variable, shared across all instances
    #
    # Format: {subproject: {feature_version: set(feature_names)}}
    feature_registry = {}
    unconditional = True

    @staticmethod
    def check_version(target_version: str, feature_version: str) -> bool:
        # always warn for broken stuff
        return False

    @staticmethod
    def get_warning_str_prefix(tv: str) -> str:
        return 'Broken features used:'

    @staticmethod
    def get_notice_str_prefix(tv: str) -> str:
        return ''

    def log_usage_warning(self, tv: str, location: T.Optional['mparser.BaseNode']) -> None:
        args = [
            'Project uses feature that was always broken,',
            'and is now deprecated since',
            f"'{self.feature_version}':",
            f'{self.feature_name}.',
        ]
        if self.extra_message:
            args.append(self.extra_message)
        mlog.deprecation(*args, location=location)


# This cannot be a dataclass due to https://github.com/python/mypy/issues/5374
class FeatureCheckKwargsBase(metaclass=abc.ABCMeta):

    @property
    @abc.abstractmethod
    def feature_check_class(self) -> T.Type[FeatureCheckBase]:
        pass

    def __init__(self, feature_name: str, feature_version: str,
                 kwargs: T.List[str], extra_message: T.Optional[str] = None):
        self.feature_name = feature_name
        self.feature_version = feature_version
        self.kwargs = kwargs
        self.extra_message = extra_message

    def __call__(self, f: TV_func) -> TV_func:
        @wraps(f)
        def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
            node, _, kwargs, subproject = get_callee_args(wrapped_args)
            if subproject is None:
                raise AssertionError(f'{wrapped_args!r}')
            for arg in self.kwargs:
                if arg not in kwargs:
                    continue
                name = arg + ' arg in ' + self.feature_name
                self.feature_check_class.single_use(
                        name, self.feature_version, subproject, self.extra_message, node)
            return f(*wrapped_args, **wrapped_kwargs)
        return T.cast('TV_func', wrapped)

class FeatureNewKwargs(FeatureCheckKwargsBase):
    feature_check_class = FeatureNew

class FeatureDeprecatedKwargs(FeatureCheckKwargsBase):
    feature_check_class = FeatureDeprecated
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/interpreterbase/disabler.py0000644000175000017500000000271414562742363022546 0ustar00jpakkanejpakkane# Copyright 2013-2021 The Meson development team

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

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

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

import typing as T

from .baseobjects import MesonInterpreterObject

if T.TYPE_CHECKING:
    from .baseobjects import TYPE_var, TYPE_kwargs

class Disabler(MesonInterpreterObject):
    def method_call(self, method_name: str, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> TYPE_var:
        if method_name == 'found':
            return False
        return Disabler()

def _is_arg_disabled(arg: T.Any) -> bool:
    if isinstance(arg, Disabler):
        return True
    if isinstance(arg, list):
        for i in arg:
            if _is_arg_disabled(i):
                return True
    return False

def is_disabled(args: T.Sequence[T.Any], kwargs: T.Dict[str, T.Any]) -> 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
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/interpreterbase/exceptions.py0000644000175000017500000000164714562742363023146 0ustar00jpakkanejpakkane# Copyright 2013-2021 The Meson development team

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

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

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

from ..mesonlib import MesonException

class InterpreterException(MesonException):
    pass

class InvalidCode(InterpreterException):
    pass

class InvalidArguments(InterpreterException):
    pass

class SubdirDoneRequest(BaseException):
    pass

class ContinueRequest(BaseException):
    pass

class BreakRequest(BaseException):
    pass
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/interpreterbase/helpers.py0000644000175000017500000000624514562742363022426 0ustar00jpakkanejpakkane# Copyright 2013-2021 The Meson development team

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

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

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

from .. import mesonlib, mparser
from .exceptions import InterpreterException, InvalidArguments
from ..coredata import UserOption


import collections.abc
import typing as T

if T.TYPE_CHECKING:
    from .baseobjects import TYPE_var, TYPE_kwargs, SubProject

def flatten(args: T.Union['TYPE_var', T.List['TYPE_var']]) -> T.List['TYPE_var']:
    if isinstance(args, mparser.BaseStringNode):
        assert isinstance(args.value, str)
        return [args.value]
    if not isinstance(args, collections.abc.Sequence):
        return [args]
    result: T.List['TYPE_var'] = []
    for a in args:
        if isinstance(a, list):
            rest = flatten(a)
            result = result + rest
        elif isinstance(a, mparser.BaseStringNode):
            result.append(a.value)
        else:
            result.append(a)
    return result

def resolve_second_level_holders(args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> T.Tuple[T.List['TYPE_var'], 'TYPE_kwargs']:
    def resolver(arg: 'TYPE_var') -> 'TYPE_var':
        if isinstance(arg, list):
            return [resolver(x) for x in arg]
        if isinstance(arg, dict):
            return {k: resolver(v) for k, v in arg.items()}
        if isinstance(arg, mesonlib.SecondLevelHolder):
            return arg.get_default_object()
        return arg
    return [resolver(x) for x in args], {k: resolver(v) for k, v in kwargs.items()}

def default_resolve_key(key: mparser.BaseNode) -> str:
    if not isinstance(key, mparser.IdNode):
        raise InterpreterException('Invalid kwargs format.')
    return key.value

def stringifyUserArguments(args: TYPE_var, subproject: SubProject, quote: bool = False) -> str:
    if isinstance(args, str):
        return f"'{args}'" if quote else args
    elif isinstance(args, bool):
        return 'true' if args else 'false'
    elif isinstance(args, int):
        return str(args)
    elif isinstance(args, list):
        return '[%s]' % ', '.join([stringifyUserArguments(x, subproject, True) for x in args])
    elif isinstance(args, dict):
        l = ['{} : {}'.format(stringifyUserArguments(k, subproject, True),
                              stringifyUserArguments(v, subproject, True)) for k, v in args.items()]
        return '{%s}' % ', '.join(l)
    elif isinstance(args, UserOption):
        from .decorators import FeatureNew
        FeatureNew.single_use('User option in string format', '1.3.0', subproject)
        return stringifyUserArguments(args.printable_value(), subproject)
    raise InvalidArguments('Value other than strings, integers, bools, options, dictionaries and lists thereof.')
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/interpreterbase/interpreterbase.py0000644000175000017500000007546614562742363024175 0ustar00jpakkanejpakkane# 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 __future__ import annotations

from .. import environment, mparser, mesonlib

from .baseobjects import (
    InterpreterObject,
    MesonInterpreterObject,
    MutableInterpreterObject,
    ObjectHolder,
    IterableObject,
    ContextManagerObject,

    HoldableTypes,
)

from .exceptions import (
    BreakRequest,
    ContinueRequest,
    InterpreterException,
    InvalidArguments,
    InvalidCode,
    SubdirDoneRequest,
)

from .decorators import FeatureNew
from .disabler import Disabler, is_disabled
from .helpers import default_resolve_key, flatten, resolve_second_level_holders, stringifyUserArguments
from .operator import MesonOperator
from ._unholder import _unholder

import os, copy, re, pathlib
import typing as T
import textwrap

if T.TYPE_CHECKING:
    from .baseobjects import InterpreterObjectTypeVar, SubProject, TYPE_kwargs, TYPE_var
    from ..interpreter import Interpreter

    HolderMapType = T.Dict[
        T.Union[
            T.Type[mesonlib.HoldableObject],
            T.Type[int],
            T.Type[bool],
            T.Type[str],
            T.Type[list],
            T.Type[dict],
        ],
        # For some reason, this has to be a callable and can't just be ObjectHolder[InterpreterObjectTypeVar]
        T.Callable[[InterpreterObjectTypeVar, 'Interpreter'], ObjectHolder[InterpreterObjectTypeVar]]
    ]

    FunctionType = T.Dict[
        str,
        T.Callable[[mparser.BaseNode, T.List[TYPE_var], T.Dict[str, TYPE_var]], TYPE_var]
    ]


class InvalidCodeOnVoid(InvalidCode):

    def __init__(self, op_type: str) -> None:
        super().__init__(f'Cannot perform {op_type!r} operation on void statement.')


class InterpreterBase:
    def __init__(self, source_root: str, subdir: str, subproject: 'SubProject'):
        self.source_root = source_root
        self.funcs: FunctionType = {}
        self.builtin: T.Dict[str, InterpreterObject] = {}
        # Holder maps store a mapping from an HoldableObject to a class ObjectHolder
        self.holder_map: HolderMapType = {}
        self.bound_holder_map: HolderMapType = {}
        self.subdir = subdir
        self.root_subdir = subdir
        self.subproject = subproject
        self.variables: T.Dict[str, InterpreterObject] = {}
        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: mparser.BaseNode = None
        # This is set to `version_string` when this statement is evaluated:
        # meson.version().compare_version(version_string)
        # If it was part of a if-clause, it is used to temporally override the
        # current meson version target within that if-block.
        self.tmp_meson_version: T.Optional[str] = None

    def handle_meson_version_from_ast(self, strict: bool = True) -> None:
        # do nothing in an AST interpreter
        return

    def load_root_meson_file(self) -> None:
        mesonfile = os.path.join(self.source_root, self.subdir, environment.build_filename)
        if not os.path.isfile(mesonfile):
            raise InvalidArguments(f'Missing Meson file in {mesonfile}')
        with open(mesonfile, encoding='utf-8') as mf:
            code = mf.read()
        if code.isspace():
            raise InvalidCode('Builder file is empty.')
        assert isinstance(code, str)
        try:
            self.ast = mparser.Parser(code, mesonfile).parse()
            self.handle_meson_version_from_ast()
        except mparser.ParseException as me:
            me.file = mesonfile
            # try to detect parser errors from new syntax added by future
            # meson versions, and just tell the user to update meson
            self.ast = me.ast
            self.handle_meson_version_from_ast()
            raise me

    def parse_project(self) -> None:
        """
        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) -> None:
        def _is_project(ast: mparser.CodeBlockNode) -> object:
            if not isinstance(ast, mparser.CodeBlockNode):
                raise InvalidCode('AST is of invalid type. Possibly a bug in the parser.')
            if not ast.lines:
                raise InvalidCode('No statements in code.')
            first = ast.lines[0]
            return isinstance(first, mparser.FunctionNode) and first.func_name.value == 'project'

        if not _is_project(self.ast):
            p = pathlib.Path(self.source_root).resolve()
            found = p
            for parent in p.parents:
                if (parent / 'meson.build').is_file():
                    with open(parent / 'meson.build', encoding='utf-8') as f:
                        code = f.read()

                    try:
                        ast = mparser.Parser(code, 'empty').parse()
                    except mparser.ParseException:
                        continue

                    if _is_project(ast):
                        found = parent
                        break
                else:
                    break

            error = 'first statement must be a call to project()'
            if found != p:
                raise InvalidCode(f'Not the project root: {error}\n\nDid you mean to run meson from the directory: "{found}"?')
            else:
                raise InvalidCode(f'Invalid source tree: {error}')

    def run(self) -> None:
        # 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: mparser.CodeBlockNode, start: int = 0, end: T.Optional[int] = None) -> 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 getattr(e, 'lineno', None) is None:
                    # We are doing the equivalent to setattr here and mypy does not like it
                    # NOTE: self.current_node is continually updated during processing
                    e.lineno = self.current_node.lineno                                               # type: ignore
                    e.colno = self.current_node.colno                                                 # type: ignore
                    e.file = os.path.join(self.source_root, self.subdir, environment.build_filename)  # type: ignore
                raise e
            i += 1 # In THE FUTURE jump over blocks and stuff.

    def evaluate_statement(self, cur: mparser.BaseNode) -> T.Optional[InterpreterObject]:
        self.current_node = cur
        if isinstance(cur, mparser.FunctionNode):
            return self.function_call(cur)
        elif isinstance(cur, mparser.PlusAssignmentNode):
            self.evaluate_plusassign(cur)
        elif isinstance(cur, mparser.AssignmentNode):
            self.assignment(cur)
        elif isinstance(cur, mparser.MethodNode):
            return self.method_call(cur)
        elif isinstance(cur, mparser.BaseStringNode):
            if isinstance(cur, mparser.MultilineFormatStringNode):
                return self.evaluate_multiline_fstring(cur)
            elif isinstance(cur, mparser.FormatStringNode):
                return self.evaluate_fstring(cur)
            else:
                return self._holderify(cur.value)
        elif isinstance(cur, mparser.BooleanNode):
            return self._holderify(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 self._holderify(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):
            self.evaluate_foreach(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 isinstance(cur, mparser.ParenthesizedNode):
            return self.evaluate_statement(cur.inner)
        elif isinstance(cur, mparser.TestCaseClauseNode):
            return self.evaluate_testcase(cur)
        else:
            raise InvalidCode("Unknown statement.")
        return None

    def evaluate_arraystatement(self, cur: mparser.ArrayNode) -> InterpreterObject:
        (arguments, kwargs) = self.reduce_arguments(cur.args)
        if len(kwargs) > 0:
            raise InvalidCode('Keyword arguments are invalid in array construction.')
        return self._holderify([_unholder(x) for x in arguments])

    @FeatureNew('dict', '0.47.0')
    def evaluate_dictstatement(self, cur: mparser.DictNode) -> InterpreterObject:
        def resolve_key(key: mparser.BaseNode) -> str:
            if not isinstance(key, mparser.BaseStringNode):
                FeatureNew.single_use('Dictionary entry using non literal key', '0.53.0', self.subproject)
            key_holder = self.evaluate_statement(key)
            if key_holder is None:
                raise InvalidArguments('Key cannot be void.')
            str_key = _unholder(key_holder)
            if not isinstance(str_key, str):
                raise InvalidArguments('Key must be a string')
            return str_key
        arguments, kwargs = self.reduce_arguments(cur.args, key_resolver=resolve_key, duplicate_key_error='Duplicate dictionary key: {}')
        assert not arguments
        return self._holderify({k: _unholder(v) for k, v in kwargs.items()})

    def evaluate_notstatement(self, cur: mparser.NotNode) -> InterpreterObject:
        v = self.evaluate_statement(cur.value)
        if v is None:
            raise InvalidCodeOnVoid('not')
        if isinstance(v, Disabler):
            return v
        return self._holderify(v.operator_call(MesonOperator.NOT, None))

    def evaluate_if(self, node: mparser.IfClauseNode) -> T.Optional[Disabler]:
        assert isinstance(node, mparser.IfClauseNode)
        for i in node.ifs:
            # Reset self.tmp_meson_version to know if it gets set during this
            # statement evaluation.
            self.tmp_meson_version = None
            result = self.evaluate_statement(i.condition)
            if result is None:
                raise InvalidCodeOnVoid('if')
            if isinstance(result, Disabler):
                return result
            if not isinstance(result, InterpreterObject):
                raise mesonlib.MesonBugException(f'Argument to if ({result}) is not an InterpreterObject but {type(result).__name__}.')
            res = result.operator_call(MesonOperator.BOOL, None)
            if not isinstance(res, bool):
                raise InvalidCode(f'If clause {result!r} does not evaluate to true or false.')
            if res:
                prev_meson_version = mesonlib.project_meson_versions[self.subproject]
                if self.tmp_meson_version:
                    mesonlib.project_meson_versions[self.subproject] = self.tmp_meson_version
                try:
                    self.evaluate_codeblock(i.block)
                finally:
                    mesonlib.project_meson_versions[self.subproject] = prev_meson_version
                return None
        if not isinstance(node.elseblock, mparser.EmptyNode):
            self.evaluate_codeblock(node.elseblock.block)
        return None

    def evaluate_testcase(self, node: mparser.TestCaseClauseNode) -> T.Optional[Disabler]:
        result = self.evaluate_statement(node.condition)
        if isinstance(result, Disabler):
            return result
        if not isinstance(result, ContextManagerObject):
            raise InvalidCode(f'testcase clause {result!r} does not evaluate to a context manager.')
        with result:
            self.evaluate_codeblock(node.block)
        return None

    def evaluate_comparison(self, node: mparser.ComparisonNode) -> InterpreterObject:
        val1 = self.evaluate_statement(node.left)
        if val1 is None:
            raise mesonlib.MesonException('Cannot compare a void statement on the left-hand side')
        if isinstance(val1, Disabler):
            return val1
        val2 = self.evaluate_statement(node.right)
        if val2 is None:
            raise mesonlib.MesonException('Cannot compare a void statement on the right-hand side')
        if isinstance(val2, Disabler):
            return val2

        # New code based on InterpreterObjects
        operator = {
            'in': MesonOperator.IN,
            'notin': MesonOperator.NOT_IN,
            '==': MesonOperator.EQUALS,
            '!=': MesonOperator.NOT_EQUALS,
            '>': MesonOperator.GREATER,
            '<': MesonOperator.LESS,
            '>=': MesonOperator.GREATER_EQUALS,
            '<=': MesonOperator.LESS_EQUALS,
        }[node.ctype]

        # Check if the arguments should be reversed for simplicity (this essentially converts `in` to `contains`)
        if operator in (MesonOperator.IN, MesonOperator.NOT_IN):
            val1, val2 = val2, val1

        val1.current_node = node
        return self._holderify(val1.operator_call(operator, _unholder(val2)))

    def evaluate_andstatement(self, cur: mparser.AndNode) -> InterpreterObject:
        l = self.evaluate_statement(cur.left)
        if l is None:
            raise mesonlib.MesonException('Cannot compare a void statement on the left-hand side')
        if isinstance(l, Disabler):
            return l
        l_bool = l.operator_call(MesonOperator.BOOL, None)
        if not l_bool:
            return self._holderify(l_bool)
        r = self.evaluate_statement(cur.right)
        if r is None:
            raise mesonlib.MesonException('Cannot compare a void statement on the right-hand side')
        if isinstance(r, Disabler):
            return r
        return self._holderify(r.operator_call(MesonOperator.BOOL, None))

    def evaluate_orstatement(self, cur: mparser.OrNode) -> InterpreterObject:
        l = self.evaluate_statement(cur.left)
        if l is None:
            raise mesonlib.MesonException('Cannot compare a void statement on the left-hand side')
        if isinstance(l, Disabler):
            return l
        l_bool = l.operator_call(MesonOperator.BOOL, None)
        if l_bool:
            return self._holderify(l_bool)
        r = self.evaluate_statement(cur.right)
        if r is None:
            raise mesonlib.MesonException('Cannot compare a void statement on the right-hand side')
        if isinstance(r, Disabler):
            return r
        return self._holderify(r.operator_call(MesonOperator.BOOL, None))

    def evaluate_uminusstatement(self, cur: mparser.UMinusNode) -> InterpreterObject:
        v = self.evaluate_statement(cur.value)
        if v is None:
            raise InvalidCodeOnVoid('unary minus')
        if isinstance(v, Disabler):
            return v
        v.current_node = cur
        return self._holderify(v.operator_call(MesonOperator.UMINUS, None))

    def evaluate_arithmeticstatement(self, cur: mparser.ArithmeticNode) -> InterpreterObject:
        l = self.evaluate_statement(cur.left)
        if isinstance(l, Disabler):
            return l
        r = self.evaluate_statement(cur.right)
        if isinstance(r, Disabler):
            return r
        if l is None or r is None:
            raise InvalidCodeOnVoid(cur.operation)

        mapping: T.Dict[str, MesonOperator] = {
            'add': MesonOperator.PLUS,
            'sub': MesonOperator.MINUS,
            'mul': MesonOperator.TIMES,
            'div': MesonOperator.DIV,
            'mod': MesonOperator.MOD,
        }
        l.current_node = cur
        res = l.operator_call(mapping[cur.operation], _unholder(r))
        return self._holderify(res)

    def evaluate_ternary(self, node: mparser.TernaryNode) -> T.Optional[InterpreterObject]:
        assert isinstance(node, mparser.TernaryNode)
        result = self.evaluate_statement(node.condition)
        if result is None:
            raise mesonlib.MesonException('Cannot use a void statement as condition for ternary operator.')
        if isinstance(result, Disabler):
            return result
        result.current_node = node
        result_bool = result.operator_call(MesonOperator.BOOL, None)
        if result_bool:
            return self.evaluate_statement(node.trueblock)
        else:
            return self.evaluate_statement(node.falseblock)

    @FeatureNew('multiline format strings', '0.63.0')
    def evaluate_multiline_fstring(self, node: mparser.MultilineFormatStringNode) -> InterpreterObject:
        return self.evaluate_fstring(node)

    @FeatureNew('format strings', '0.58.0')
    def evaluate_fstring(self, node: T.Union[mparser.FormatStringNode, mparser.MultilineFormatStringNode]) -> InterpreterObject:
        def replace(match: T.Match[str]) -> str:
            var = str(match.group(1))
            try:
                val = _unholder(self.variables[var])
                if isinstance(val, (list, dict)):
                    FeatureNew.single_use('List or dictionary in f-string', '1.3.0', self.subproject, location=self.current_node)
                try:
                    return stringifyUserArguments(val, self.subproject)
                except InvalidArguments as e:
                    raise InvalidArguments(f'f-string: {str(e)}')
            except KeyError:
                raise InvalidCode(f'Identifier "{var}" does not name a variable.')

        res = re.sub(r'@([_a-zA-Z][_0-9a-zA-Z]*)@', replace, node.value)
        return self._holderify(res)

    def evaluate_foreach(self, node: mparser.ForeachClauseNode) -> None:
        assert isinstance(node, mparser.ForeachClauseNode)
        items = self.evaluate_statement(node.items)
        if not isinstance(items, IterableObject):
            raise InvalidArguments('Items of foreach loop do not support iterating')

        tsize = items.iter_tuple_size()
        if len(node.varnames) != (tsize or 1):
            raise InvalidArguments(f'Foreach expects exactly {tsize or 1} variables for iterating over objects of type {items.display_name()}')

        for i in items.iter_self():
            if tsize is None:
                if isinstance(i, tuple):
                    raise mesonlib.MesonBugException(f'Iteration of {items} returned a tuple even though iter_tuple_size() is None')
                self.set_variable(node.varnames[0].value, self._holderify(i))
            else:
                if not isinstance(i, tuple):
                    raise mesonlib.MesonBugException(f'Iteration of {items} did not return a tuple even though iter_tuple_size() is {tsize}')
                if len(i) != tsize:
                    raise mesonlib.MesonBugException(f'Iteration of {items} did not return a tuple even though iter_tuple_size() is {tsize}')
                for j in range(tsize):
                    self.set_variable(node.varnames[j].value, self._holderify(i[j]))
            try:
                self.evaluate_codeblock(node.block)
            except ContinueRequest:
                continue
            except BreakRequest:
                break

    def evaluate_plusassign(self, node: mparser.PlusAssignmentNode) -> None:
        assert isinstance(node, mparser.PlusAssignmentNode)
        varname = node.var_name.value
        addition = self.evaluate_statement(node.value)
        if addition is None:
            raise InvalidCodeOnVoid('plus assign')

        # Remember that all variables are immutable. We must always create a
        # full new variable and then assign it.
        old_variable = self.get_variable(varname)
        old_variable.current_node = node
        new_value = self._holderify(old_variable.operator_call(MesonOperator.PLUS, _unholder(addition)))
        self.set_variable(varname, new_value)

    def evaluate_indexing(self, node: mparser.IndexNode) -> InterpreterObject:
        assert isinstance(node, mparser.IndexNode)
        iobject = self.evaluate_statement(node.iobject)
        if iobject is None:
            raise InterpreterException('Tried to evaluate indexing on void.')
        if isinstance(iobject, Disabler):
            return iobject
        index_holder = self.evaluate_statement(node.index)
        if index_holder is None:
            raise InvalidArguments('Cannot use void statement as index.')
        index = _unholder(index_holder)

        iobject.current_node = node
        return self._holderify(iobject.operator_call(MesonOperator.INDEX, index))

    def function_call(self, node: mparser.FunctionNode) -> T.Optional[InterpreterObject]:
        func_name = node.func_name.value
        (h_posargs, h_kwargs) = self.reduce_arguments(node.args)
        (posargs, kwargs) = self._unholder_args(h_posargs, h_kwargs)
        if is_disabled(posargs, kwargs) and func_name not in {'get_variable', 'set_variable', 'unset_variable', 'is_disabler'}:
            return Disabler()
        if func_name in self.funcs:
            func = self.funcs[func_name]
            func_args = posargs
            if not getattr(func, 'no-args-flattening', False):
                func_args = flatten(posargs)
            if not getattr(func, 'no-second-level-holder-flattening', False):
                func_args, kwargs = resolve_second_level_holders(func_args, kwargs)
            self.current_node = node
            res = func(node, func_args, kwargs)
            return self._holderify(res) if res is not None else None
        else:
            self.unknown_function_called(func_name)
            return None

    def method_call(self, node: mparser.MethodNode) -> T.Optional[InterpreterObject]:
        invocable = node.source_object
        obj: T.Optional[InterpreterObject]
        if isinstance(invocable, mparser.IdNode):
            object_display_name = f'variable "{invocable.value}"'
            obj = self.get_variable(invocable.value)
        else:
            object_display_name = invocable.__class__.__name__
            obj = self.evaluate_statement(invocable)
        method_name = node.name.value
        (h_args, h_kwargs) = self.reduce_arguments(node.args)
        (args, kwargs) = self._unholder_args(h_args, h_kwargs)
        if is_disabled(args, kwargs):
            return Disabler()
        if not isinstance(obj, InterpreterObject):
            raise InvalidArguments(f'{object_display_name} is not callable.')
        # TODO: InterpreterBase **really** shouldn't be in charge of checking this
        if method_name == 'extract_objects':
            if isinstance(obj, ObjectHolder):
                self.validate_extraction(obj.held_object)
            elif not isinstance(obj, Disabler):
                raise InvalidArguments(f'Invalid operation "extract_objects" on {object_display_name} of type {type(obj).__name__}')
        obj.current_node = self.current_node = node
        res = obj.method_call(method_name, args, kwargs)
        return self._holderify(res) if res is not None else None

    def _holderify(self, res: T.Union[TYPE_var, InterpreterObject]) -> InterpreterObject:
        if isinstance(res, HoldableTypes):
            # Always check for an exact match first.
            cls = self.holder_map.get(type(res), None)
            if cls is not None:
                # Casts to Interpreter are required here since an assertion would
                # not work for the `ast` module.
                return cls(res, T.cast('Interpreter', self))
            # Try the boundary types next.
            for typ, cls in self.bound_holder_map.items():
                if isinstance(res, typ):
                    return cls(res, T.cast('Interpreter', self))
            raise mesonlib.MesonBugException(f'Object {res} of type {type(res).__name__} is neither in self.holder_map nor self.bound_holder_map.')
        elif isinstance(res, ObjectHolder):
            raise mesonlib.MesonBugException(f'Returned object {res} of type {type(res).__name__} is an object holder.')
        elif isinstance(res, MesonInterpreterObject):
            return res
        raise mesonlib.MesonBugException(f'Unknown returned object {res} of type {type(res).__name__} in the parameters.')

    def _unholder_args(self,
                       args: T.List[InterpreterObject],
                       kwargs: T.Dict[str, InterpreterObject]) -> T.Tuple[T.List[TYPE_var], TYPE_kwargs]:
        return [_unholder(x) for x in args], {k: _unholder(v) for k, v in kwargs.items()}

    def unknown_function_called(self, func_name: str) -> None:
        raise InvalidCode(f'Unknown function "{func_name}".')

    def reduce_arguments(
                self,
                args: mparser.ArgumentNode,
                key_resolver: T.Callable[[mparser.BaseNode], str] = default_resolve_key,
                duplicate_key_error: T.Optional[str] = None,
            ) -> T.Tuple[
                T.List[InterpreterObject],
                T.Dict[str, InterpreterObject]
            ]:
        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]
        if any(x is None for x in reduced_pos):
            raise InvalidArguments('At least one value in the arguments is void.')
        reduced_kw: T.Dict[str, InterpreterObject] = {}
        for key, val in args.kwargs.items():
            reduced_key = key_resolver(key)
            assert isinstance(val, mparser.BaseNode)
            reduced_val = self.evaluate_statement(val)
            if reduced_val is None:
                raise InvalidArguments(f'Value of key {reduced_key} is void.')
            self.current_node = key
            if duplicate_key_error and reduced_key in reduced_kw:
                raise InvalidArguments(duplicate_key_error.format(reduced_key))
            reduced_kw[reduced_key] = reduced_val
        self.argument_depth -= 1
        final_kw = self.expand_default_kwargs(reduced_kw)
        return reduced_pos, final_kw

    def expand_default_kwargs(self, kwargs: T.Dict[str, T.Optional[InterpreterObject]]) -> T.Dict[str, T.Optional[InterpreterObject]]:
        if 'kwargs' not in kwargs:
            return kwargs
        to_expand = _unholder(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(f'Entry "{k}" defined both as a keyword argument and in a "kwarg" entry.')
            kwargs[k] = self._holderify(v)
        return kwargs

    def assignment(self, node: mparser.AssignmentNode) -> None:
        assert isinstance(node, mparser.AssignmentNode)
        if self.argument_depth != 0:
            raise InvalidArguments(textwrap.dedent('''\
                Tried to assign values inside an argument list.
                To specify a keyword argument, use : instead of =.
            '''))
        var_name = node.var_name.value
        if not isinstance(var_name, str):
            raise InvalidArguments('Tried to assign value to a non-variable.')
        value = self.evaluate_statement(node.value)
        # 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)

    def set_variable(self, varname: str, variable: T.Union[TYPE_var, InterpreterObject], *, holderify: bool = False) -> None:
        if variable is None:
            raise InvalidCode('Can not assign void to variable.')
        if holderify:
            variable = self._holderify(variable)
        else:
            # Ensure that we are always storing ObjectHolders
            if not isinstance(variable, InterpreterObject):
                raise mesonlib.MesonBugException(f'set_variable in InterpreterBase called with a non InterpreterObject {variable} of type {type(variable).__name__}')
        if not isinstance(varname, str):
            raise InvalidCode('First argument to set_variable must be a string.')
        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(f'Tried to overwrite internal variable "{varname}"')
        self.variables[varname] = variable

    def get_variable(self, varname: str) -> InterpreterObject:
        if varname in self.builtin:
            return self.builtin[varname]
        if varname in self.variables:
            return self.variables[varname]
        raise InvalidCode(f'Unknown variable "{varname}".')

    def validate_extraction(self, buildtarget: mesonlib.HoldableObject) -> None:
        raise InterpreterException('validate_extraction is not implemented in this context (please file a bug)')
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/interpreterbase/operator.py0000644000175000017500000000105214562742363022606 0ustar00jpakkanejpakkane# SPDX-license-identifier: Apache-2.0

from enum import Enum

class MesonOperator(Enum):
    # Arithmetic
    PLUS = '+'
    MINUS = '-'
    TIMES = '*'
    DIV = '/'
    MOD = '%'

    UMINUS = 'uminus'

    # Logic
    NOT = 'not'

    # Should return the boolsche interpretation of the value (`'' == false` for instance)
    BOOL = 'bool()'

    # Comparison
    EQUALS = '=='
    NOT_EQUALS = '!='
    GREATER = '>'
    LESS = '<'
    GREATER_EQUALS = '>='
    LESS_EQUALS = '<='

    # Container
    IN = 'in'
    NOT_IN = 'not in'
    INDEX = '[]'
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.7066388
meson-1.3.2/mesonbuild/linkers/0000755000175000017500000000000014562742414016651 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/linkers/__init__.py0000644000175000017500000000155114562742363020767 0ustar00jpakkanejpakkane# Copyright 2012-2021 The Meson development team

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

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

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


from .base import ArLikeLinker, RSPFileSyntax
from .detect import (
    defaults,
    guess_win_linker,
    guess_nix_linker,
)

__all__ = [
    # base.py
    'ArLikeLinker',
    'RSPFileSyntax',

    # detect.py
    'defaults',
    'guess_win_linker',
    'guess_nix_linker',
]
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/linkers/base.py0000644000175000017500000000270114562742363020140 0ustar00jpakkanejpakkane# Copyright 2012-2023 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

#     https://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.

# Core public classes for linkers.
from __future__ import annotations

import enum
import typing as T

if T.TYPE_CHECKING:
    from ..environment import Environment


@enum.unique
class RSPFileSyntax(enum.Enum):

    """Which RSP file syntax the compiler supports."""

    MSVC = enum.auto()
    GCC = enum.auto()


class ArLikeLinker:
    # POSIX requires supporting the dash, GNU permits omitting it
    std_args = ['-csr']

    def can_linker_accept_rsp(self) -> bool:
        # armar / AIX can't accept arguments using the @rsp syntax
        # in fact, only the 'ar' id can
        return False

    def get_std_link_args(self, env: 'Environment', is_thin: bool) -> T.List[str]:
        return self.std_args

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

    def rsp_file_syntax(self) -> RSPFileSyntax:
        return RSPFileSyntax.GCC
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0
meson-1.3.2/mesonbuild/linkers/detect.py0000644000175000017500000002541014562742373020501 0ustar00jpakkanejpakkane# Copyright 2012-2022 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 __future__ import annotations

from .. import mlog
from ..mesonlib import (
    EnvironmentException,
    Popen_safe, Popen_safe_logged, join_args, search_version
)

import re
import shlex
import typing as T

if T.TYPE_CHECKING:
    from .linkers import DynamicLinker, GnuDynamicLinker
    from ..environment import Environment
    from ..compilers import Compiler
    from ..mesonlib import MachineChoice

defaults: T.Dict[str, T.List[str]] = {}
defaults['static_linker'] = ['ar', 'gar']
defaults['vs_static_linker'] = ['lib']
defaults['clang_cl_static_linker'] = ['llvm-lib']
defaults['cuda_static_linker'] = ['nvlink']
defaults['gcc_static_linker'] = ['gcc-ar']
defaults['clang_static_linker'] = ['llvm-ar']

def __failed_to_detect_linker(compiler: T.List[str], args: T.List[str], stdout: str, stderr: str) -> 'T.NoReturn':
    msg = 'Unable to detect linker for compiler `{}`\nstdout: {}\nstderr: {}'.format(
        join_args(compiler + args), stdout, stderr)
    raise EnvironmentException(msg)


def guess_win_linker(env: 'Environment', compiler: T.List[str], comp_class: T.Type['Compiler'],
                     comp_version: str, for_machine: MachineChoice, *,
                     use_linker_prefix: bool = True, invoked_directly: bool = True,
                     extra_args: T.Optional[T.List[str]] = None) -> 'DynamicLinker':
    from . import linkers
    env.coredata.add_lang_args(comp_class.language, comp_class, for_machine, env)

    # 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 += env.coredata.get_external_link_args(for_machine, comp_class.language)

    override: T.List[str] = []
    value = env.lookup_binary_entry(for_machine, comp_class.language + '_ld')
    if value is not None:
        override = comp_class.use_linker_args(value[0], comp_version)
        check_args += override

    if extra_args is not None:
        check_args.extend(extra_args)

    p, o, _ = Popen_safe(compiler + check_args)
    if 'LLD' in o.split('\n', maxsplit=1)[0]:
        if '(compatible with GNU linkers)' in o:
            return linkers.LLVMDynamicLinker(
                compiler, for_machine, comp_class.LINKER_PREFIX,
                override, version=search_version(o))
        elif not invoked_directly:
            return linkers.ClangClDynamicLinker(
                for_machine, override, exelist=compiler, prefix=comp_class.LINKER_PREFIX,
                version=search_version(o), direct=False, machine=None)

    if value is not None and invoked_directly:
        compiler = value
        # We've already handled the non-direct case above

    p, o, e = Popen_safe(compiler + check_args)
    if 'LLD' in o.split('\n', maxsplit=1)[0]:
        return linkers.ClangClDynamicLinker(
            for_machine, [],
            prefix=comp_class.LINKER_PREFIX if use_linker_prefix else [],
            exelist=compiler, version=search_version(o), direct=invoked_directly)
    elif 'OPTLINK' in o:
        # Optlink's stdout *may* begin with a \r character.
        return linkers.OptlinkDynamicLinker(compiler, 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 linkers.MSVCDynamicLinker(
            for_machine, [], machine=target, exelist=compiler,
            prefix=comp_class.LINKER_PREFIX if use_linker_prefix else [],
            version=search_version(out), direct=invoked_directly)
    elif 'GNU coreutils' in o:
        import shutil
        fullpath = shutil.which(compiler[0])
        raise EnvironmentException(
            f"Found GNU link.exe instead of MSVC link.exe in {fullpath}.\n"
            "This link.exe is not a linker.\n"
            "You may need to reorder entries to your %PATH% variable to resolve this.")
    __failed_to_detect_linker(compiler, check_args, o, e)

def guess_nix_linker(env: 'Environment', compiler: T.List[str], comp_class: T.Type['Compiler'],
                     comp_version: str, 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)
    :comp_version: The compiler version string
    :for_machine: which machine this linker targets
    :extra_args: Any additional arguments required (such as a source file)
    """
    from . import linkers
    env.coredata.add_lang_args(comp_class.language, comp_class, for_machine, env)
    extra_args = extra_args or []

    ldflags = env.coredata.get_external_link_args(for_machine, comp_class.language)
    extra_args += comp_class._unix_args_to_native(ldflags, env.machines[for_machine])

    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: T.List[str] = []
    value = env.lookup_binary_entry(for_machine, comp_class.language + '_ld')
    if value is not None:
        override = comp_class.use_linker_args(value[0], comp_version)
        check_args += override

    mlog.debug('-----')
    p, o, e = Popen_safe_logged(compiler + check_args, msg='Detecting linker via')

    v = search_version(o + e)
    linker: DynamicLinker
    if 'LLD' in o.split('\n', maxsplit=1)[0]:
        if isinstance(comp_class.LINKER_PREFIX, str):
            cmd = compiler + override + [comp_class.LINKER_PREFIX + '-v'] + extra_args
        else:
            cmd = compiler + override + comp_class.LINKER_PREFIX + ['-v'] + extra_args
        _, newo, newerr = Popen_safe_logged(cmd, msg='Detecting LLD linker via')

        lld_cls: T.Type[DynamicLinker]
        if 'ld64.lld' in newerr:
            lld_cls = linkers.LLVMLD64DynamicLinker
        else:
            lld_cls = linkers.LLVMDynamicLinker

        linker = lld_cls(
            compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v)
    elif 'Snapdragon' in e and 'LLVM' in e:
        linker = linkers.QualcommLLVMDynamicLinker(
            compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v)
    elif e.startswith('lld-link: '):
        # The LLD MinGW frontend didn't respond to --version before version 9.0.0,
        # and produced an error message about failing to link (when no object
        # files were specified), instead of printing the version number.
        # 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 = linkers.LLVMDynamicLinker(compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v)
    # detect xtools first, bug #10805
    elif 'xtools-' in o.split('\n', maxsplit=1)[0]:
        xtools = o.split(' ', maxsplit=1)[0]
        v = xtools.split('-', maxsplit=2)[1]
        linker = linkers.AppleDynamicLinker(compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v)
    # First might be apple clang, second is for real gcc, the third is icc.
    # Note that "ld: unknown option: " sometimes instead is "ld: unknown options:".
    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):
            cmd = compiler + [comp_class.LINKER_PREFIX + '-v'] + extra_args
        else:
            cmd = compiler + comp_class.LINKER_PREFIX + ['-v'] + extra_args
        _, newo, newerr = Popen_safe_logged(cmd, msg='Detecting Apple linker via')

        for line in newerr.split('\n'):
            if 'PROJECT:ld' in line or 'PROJECT:dyld' in line:
                v = line.split('-')[1]
                break
        else:
            __failed_to_detect_linker(compiler, check_args, o, e)
        linker = linkers.AppleDynamicLinker(compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v)
    elif 'GNU' in o or 'GNU' in e:
        gnu_cls: T.Type[GnuDynamicLinker]
        # this is always the only thing on stdout, except for swift
        # which may or may not redirect the linker stdout to stderr
        if o.startswith('GNU gold') or e.startswith('GNU gold'):
            gnu_cls = linkers.GnuGoldDynamicLinker
        elif o.startswith('mold') or e.startswith('mold'):
            gnu_cls = linkers.MoldDynamicLinker
        else:
            gnu_cls = linkers.GnuBFDDynamicLinker
        linker = gnu_cls(compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v)
    elif 'Solaris' in e or 'Solaris' in o:
        for line in (o+e).split('\n'):
            if 'ld: Software Generation Utilities' in line:
                v = line.split(':')[2].lstrip()
                break
        else:
            v = 'unknown version'
        linker = linkers.SolarisDynamicLinker(
            compiler, for_machine, comp_class.LINKER_PREFIX, override,
            version=v)
    elif 'ld: 0706-012 The -- flag is not recognized' 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)
        linker = linkers.AIXDynamicLinker(
            compiler, for_machine, comp_class.LINKER_PREFIX, override,
            version=search_version(e))
    else:
        __failed_to_detect_linker(compiler, check_args, o, e)
    return linker
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/linkers/linkers.py0000644000175000017500000016123614562742363020706 0ustar00jpakkanejpakkane# Copyright 2012-2022 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 __future__ import annotations

import abc
import os
import typing as T
import re

from .base import ArLikeLinker, RSPFileSyntax
from .. import mesonlib
from ..mesonlib import EnvironmentException, MesonException
from ..arglist import CompilerArgs

if T.TYPE_CHECKING:
    from ..coredata import KeyedOptionDictType
    from ..environment import Environment
    from ..mesonlib import MachineChoice


class StaticLinker:

    id: str

    def __init__(self, exelist: T.List[str]):
        self.exelist = exelist

    def compiler_args(self, args: T.Optional[T.Iterable[str]] = None) -> CompilerArgs:
        return CompilerArgs(self, args)

    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: 'KeyedOptionDictType') -> 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, env: 'Environment', is_thin: bool) -> 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: T.Tuple[str, ...], build_rpath: str,
                         install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
        return ([], set())

    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: 'KeyedOptionDictType') -> 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_name(self, targetfile: str) -> T.Optional[str]:
        return None

    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 []

    def rsp_file_syntax(self) -> RSPFileSyntax:
        """The format of the RSP file that this compiler supports.

        If `self.can_linker_accept_rsp()` returns True, then this needs to
        be implemented
        """
        assert not self.can_linker_accept_rsp(), f'{self.id} linker accepts RSP, but doesn\' provide a supported format, this is a bug'
        raise EnvironmentException(f'{self.id} does not implement rsp format, this shouldn\'t be called')


class DynamicLinker(metaclass=abc.ABCMeta):

    """Base class for dynamic linkers."""

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

    @abc.abstractproperty
    def id(self) -> str:
        pass

    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: T.List[str] = []
        for arg in args:
            ret += self.prefix_arg + [arg]
        return ret

    def __init__(self, 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.prefix_arg = prefix_arg
        self.always_args = always_args
        self.machine: T.Optional[str] = None

    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 f'({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 rsp_file_syntax(self) -> RSPFileSyntax:
        """The format of the RSP file that this compiler supports.

        If `self.can_linker_accept_rsp()` returns True, then this needs to
        be implemented
        """
        return RSPFileSyntax.GCC

    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_option_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
        return []

    def has_multi_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]:
        raise EnvironmentException(f'Language {self.id} does not support has_multi_link_arguments.')

    def get_debugfile_name(self, targetfile: str) -> T.Optional[str]:
        '''Name of debug file written out (see below)'''
        return None

    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: 'KeyedOptionDictType') -> 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.
        raise EnvironmentException(f'Linker {self.id} does not support position-independent executable')

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

    def get_thinlto_cache_args(self, path: str) -> 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 EnvironmentException(
            f'Linker {self.id} does not support link_whole')

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

    @abc.abstractmethod
    def get_output_args(self, outputname: str) -> T.List[str]:
        pass

    def get_coverage_args(self) -> T.List[str]:
        raise EnvironmentException(f"Linker {self.id} doesn't implement coverage data generation.")

    @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 headerpad_args(self) -> T.List[str]:
        # Only used by the Apple linker
        return []

    def get_win_subsystem_args(self, value: str) -> T.List[str]:
        # Only used if supported by the dynamic linker and
        # only when targeting Windows
        return []

    def bitcode_args(self) -> T.List[str]:
        raise MesonException('This linker does not support bitcode bundles')

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

    def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
                        suffix: str, soversion: str, darwin_versions: T.Tuple[str, str]) -> T.List[str]:
        return []

    def get_archive_name(self, filename: str) -> str:
        #Only used by AIX.
        return str()

    def get_command_to_archive_shlib(self) -> T.List[str]:
        #Only used by AIX.
        return []


if T.TYPE_CHECKING:
    StaticLinkerBase = StaticLinker
    DynamicLinkerBase = DynamicLinker
else:
    StaticLinkerBase = DynamicLinkerBase = object


class VisualStudioLikeLinker(StaticLinkerBase):
    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: 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.c 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.c import VisualStudioCCompiler
        return VisualStudioCCompiler.native_args_to_unix(args)

    def rsp_file_syntax(self) -> RSPFileSyntax:
        return RSPFileSyntax.MSVC


class VisualStudioLinker(VisualStudioLikeLinker, StaticLinker):

    """Microsoft's lib static linker."""

    id = 'lib'

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

    id = 'xilib'

    def __init__(self, exelist: T.List[str], machine: str):
        StaticLinker.__init__(self, exelist)
        VisualStudioLikeLinker.__init__(self, machine)


class ArLinker(ArLikeLinker, StaticLinker):
    id = 'ar'

    def __init__(self, for_machine: mesonlib.MachineChoice, exelist: T.List[str]):
        super().__init__(exelist)
        stdo = mesonlib.Popen_safe(self.exelist + ['-h'])[1]
        # Enable deterministic builds if they are available.
        stdargs = 'csr'
        thinargs = ''
        if '[D]' in stdo:
            stdargs += 'D'
        if '[T]' in stdo:
            thinargs = 'T'
        self.std_args = [stdargs]
        self.std_thin_args = [stdargs + thinargs]
        self.can_rsp = '@<' in stdo
        self.for_machine = for_machine

    def can_linker_accept_rsp(self) -> bool:
        return self.can_rsp

    def get_std_link_args(self, env: 'Environment', is_thin: bool) -> T.List[str]:
        # Thin archives are a GNU extension not supported by the system linkers
        # on Mac OS X, Solaris, or illumos, so don't build them on those OSes.
        # OS X ld rejects with: "file built for unknown-unsupported file format"
        # illumos/Solaris ld rejects with: "unknown file type"
        if is_thin and not env.machines[self.for_machine].is_darwin() \
          and not env.machines[self.for_machine].is_sunos():
            return self.std_thin_args
        else:
            return self.std_args


class AppleArLinker(ArLinker):

    # mostly this is used to determine that we need to call ranlib

    id = 'applear'


class ArmarLinker(ArLikeLinker, StaticLinker):
    id = 'armar'


class DLinker(StaticLinker):
    def __init__(self, exelist: T.List[str], arch: str, *, rsp_syntax: RSPFileSyntax = RSPFileSyntax.GCC):
        super().__init__(exelist)
        self.id = exelist[0]
        self.arch = arch
        self.__rsp_syntax = rsp_syntax

    def get_std_link_args(self, env: 'Environment', is_thin: bool) -> 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 []

    def rsp_file_syntax(self) -> RSPFileSyntax:
        return self.__rsp_syntax


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 [f'-output={target}']

    def get_linker_always_args(self) -> T.List[str]:
        return ['-nologo', '-form=library']


class Xc16Linker(StaticLinker):

    def __init__(self, exelist: T.List[str]):
        super().__init__(exelist)
        self.id = 'xc16-ar'

    def can_linker_accept_rsp(self) -> bool:
        return False

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

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

class CompCertLinker(StaticLinker):

    def __init__(self, exelist: T.List[str]):
        super().__init__(exelist)
        self.id = 'ccomp'

    def can_linker_accept_rsp(self) -> bool:
        return False

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


class TILinker(StaticLinker):

    def __init__(self, exelist: T.List[str]):
        super().__init__(exelist)
        self.id = 'ti-ar'

    def can_linker_accept_rsp(self) -> bool:
        return False

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

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


class C2000Linker(TILinker):
    # Required for backwards compat with projects created before ti-cgt support existed
    id = 'ar2000'


class AIXArLinker(ArLikeLinker, StaticLinker):
    id = 'aixar'
    std_args = ['-csr', '-Xany']


class MetrowerksStaticLinker(StaticLinker):

    def can_linker_accept_rsp(self) -> bool:
        return True

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

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

    def rsp_file_syntax(self) -> RSPFileSyntax:
        return RSPFileSyntax.GCC


class MetrowerksStaticLinkerARM(MetrowerksStaticLinker):
    id = 'mwldarm'


class MetrowerksStaticLinkerEmbeddedPowerPC(MetrowerksStaticLinker):
    id = 'mwldeppc'

def prepare_rpaths(raw_rpaths: T.Tuple[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 PosixDynamicLinkerMixin(DynamicLinkerBase):

    """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, outputname: str) -> T.List[str]:
        return ['-o', outputname]

    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(DynamicLinkerBase):

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

    if T.TYPE_CHECKING:
        for_machine = MachineChoice.HOST
        def _apply_prefix(self, arg: T.Union[str, T.List[str]]) -> T.List[str]: ...

    _BUILDTYPE_ARGS: T.Dict[str, T.List[str]] = {
        'plain': [],
        'debug': [],
        'debugoptimized': [],
        'release': ['-O1'],
        'minsize': [],
        'custom': [],
    }

    _SUBSYSTEMS: T.Dict[str, str] = {
        "native": "1",
        "windows": "windows",
        "console": "console",
        "posix": "7",
        "efi_application": "10",
        "efi_boot_service_driver": "11",
        "efi_runtime_driver": "12",
        "efi_rom": "13",
        "boot_application": "16",
    }

    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]) -> 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(f'-soname,{prefix}{shlib_name}.{suffix}{sostr}')

    def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
                         rpath_paths: T.Tuple[str, ...], build_rpath: str,
                         install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
        m = env.machines[self.for_machine]
        if m.is_windows() or m.is_cygwin():
            return ([], set())
        if not rpath_paths and not install_rpath and not build_rpath:
            return ([], set())
        args: T.List[str] = []
        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])
        rpath_dirs_to_remove: T.Set[bytes] = set()
        for p in all_paths:
            rpath_dirs_to_remove.add(p.encode('utf8'))
        # Build_rpath is used as-is (it is usually absolute).
        if build_rpath != '':
            all_paths.add(build_rpath)
            for p in build_rpath.split(':'):
                rpath_dirs_to_remove.add(p.encode('utf8'))

        # 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, rpath_dirs_to_remove)

        # 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, rpath_dirs_to_remove)

    def get_win_subsystem_args(self, value: str) -> T.List[str]:
        # MinGW only directly supports a couple of the possible
        # PE application types. The raw integer works as an argument
        # as well, and is always accepted, so we manually map the
        # other types here. List of all types:
        # https://github.com/wine-mirror/wine/blob/3ded60bd1654dc689d24a23305f4a93acce3a6f2/include/winnt.h#L2492-L2507
        versionsuffix = None
        if ',' in value:
            value, versionsuffix = value.split(',', 1)
        newvalue = self._SUBSYSTEMS.get(value)
        if newvalue is not None:
            if versionsuffix is not None:
                newvalue += f':{versionsuffix}'
            args = [f'--subsystem,{newvalue}']
        else:
            raise mesonlib.MesonBugException(f'win_subsystem: {value!r} not handled in MinGW linker. This should not be possible.')

        return self._apply_prefix(args)


class AppleDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):

    """Apple's ld implementation."""

    id = 'ld64'

    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: 'KeyedOptionDictType') -> T.List[str]:
        return ['-bundle'] + self._apply_prefix('-undefined,dynamic_lookup')

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

    def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
        result: 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]:
        # We used to emit -undefined,error, but starting with Xcode 15 /
        # Sonoma, doing so triggers "ld: warning: -undefined error is
        # deprecated". Given that "-undefined error" is documented to be the
        # linker's default behaviour, this warning seems ill advised. However,
        # it does create a lot of noise.  As "-undefined error" is the default
        # behaviour, the least bad way to deal with this seems to be to just
        # not emit anything here. Of course that only works as long as nothing
        # else injects -undefined dynamic_lookup, or such. Complain to Apple.
        return []

    def headerpad_args(self) -> T.List[str]:
        return self._apply_prefix('-headerpad_max_install_names')

    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]) -> T.List[str]:
        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: T.Tuple[str, ...], build_rpath: str,
                         install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
        if not rpath_paths and not install_rpath and not build_rpath:
            return ([], set())
        args: T.List[str] = []
        # @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, set())

    def get_thinlto_cache_args(self, path: str) -> T.List[str]:
        return ["-Wl,-cache_path_lto," + path]


class LLVMLD64DynamicLinker(AppleDynamicLinker):

    id = 'ld64.lld'


class GnuDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, DynamicLinker):

    """Representation of GNU ld.bfd and ld.gold."""

    def get_accepts_rsp(self) -> bool:
        return True


class GnuGoldDynamicLinker(GnuDynamicLinker):

    id = 'ld.gold'

    def get_thinlto_cache_args(self, path: str) -> T.List[str]:
        return ['-Wl,-plugin-opt,cache-dir=' + path]


class GnuBFDDynamicLinker(GnuDynamicLinker):

    id = 'ld.bfd'


class MoldDynamicLinker(GnuDynamicLinker):

    id = 'ld.mold'

    def get_thinlto_cache_args(self, path: str) -> T.List[str]:
        return ['-Wl,--thinlto-cache-dir=' + path]


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

    id = 'ld.lld'

    def __init__(self, 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'):
        super().__init__(exelist, for_machine, prefix_arg, always_args, version=version)

        # Some targets don't seem to support this argument (windows, wasm, ...)
        _, _, e = mesonlib.Popen_safe(self.exelist + always_args + self._apply_prefix('--allow-shlib-undefined'))
        # Versions < 9 do not have a quoted argument
        self.has_allow_shlib_undefined = ('unknown argument: --allow-shlib-undefined' not in e) and ("unknown argument: '--allow-shlib-undefined'" not in e)

    def get_allow_undefined_args(self) -> T.List[str]:
        if self.has_allow_shlib_undefined:
            return self._apply_prefix('--allow-shlib-undefined')
        return []

    def get_thinlto_cache_args(self, path: str) -> T.List[str]:
        return ['-Wl,--thinlto-cache-dir=' + path]

    def get_win_subsystem_args(self, value: str) -> T.List[str]:
        # lld does not support a numeric subsystem value
        version = None
        if ',' in value:
            value, version = value.split(',', 1)
        if value in self._SUBSYSTEMS:
            if version is not None:
                value += f':{version}'
            return self._apply_prefix([f'--subsystem,{value}'])
        else:
            raise mesonlib.MesonBugException(f'win_subsystem: {value} not handled in lld linker. This should not be possible.')


class WASMDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, DynamicLinker):

    """Emscripten's wasm-ld."""

    id = 'ld.wasm'

    def get_allow_undefined_args(self) -> T.List[str]:
        return ['-sERROR_ON_UNDEFINED_SYMBOLS=0']

    def no_undefined_args(self) -> T.List[str]:
        return ['-sERROR_ON_UNDEFINED_SYMBOLS=1']

    def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
                        suffix: str, soversion: str, darwin_versions: T.Tuple[str, str]) -> T.List[str]:
        raise MesonException(f'{self.id} does not support shared libraries.')

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

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


class CcrxDynamicLinker(DynamicLinker):

    """Linker for Renesas CCrx compiler."""

    id = 'rlink'

    def __init__(self, for_machine: mesonlib.MachineChoice,
                 *, version: str = 'unknown version'):
        super().__init__(['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 [f'-output={outputname}']

    def get_search_args(self, dirname: str) -> 'T.NoReturn':
        raise OSError('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]) -> T.List[str]:
        return []


class Xc16DynamicLinker(DynamicLinker):

    """Linker for Microchip XC16 compiler."""

    id = 'xc16-gcc'

    def __init__(self, for_machine: mesonlib.MachineChoice,
                 *, version: str = 'unknown version'):
        super().__init__(['xc16-gcc'], for_machine, '', [],
                         version=version)

    def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
        if not args:
            return args
        return self._apply_prefix('--start-group') + args + self._apply_prefix('--end-group')

    def get_accepts_rsp(self) -> bool:
        return False

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

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

    def get_output_args(self, outputname: str) -> T.List[str]:
        return [f'-o{outputname}']

    def get_search_args(self, dirname: str) -> 'T.NoReturn':
        raise OSError('xc16-gcc 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]) -> T.List[str]:
        return []

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

class CompCertDynamicLinker(DynamicLinker):

    """Linker for CompCert C compiler."""

    id = 'ccomp'

    def __init__(self, for_machine: mesonlib.MachineChoice,
                 *, version: str = 'unknown version'):
        super().__init__(['ccomp'], for_machine, '', [],
                         version=version)

    def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
        if not args:
            return args
        return self._apply_prefix('-Wl,--whole-archive') + args + self._apply_prefix('-Wl,--no-whole-archive')

    def get_accepts_rsp(self) -> bool:
        return False

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

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

    def get_output_args(self, outputname: str) -> T.List[str]:
        return [f'-o{outputname}']

    def get_search_args(self, dirname: str) -> T.List[str]:
        return [f'-L{dirname}']

    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]) -> T.List[str]:
        raise MesonException(f'{self.id} does not support shared libraries.')

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

class TIDynamicLinker(DynamicLinker):

    """Linker for Texas Instruments compiler family."""

    id = 'ti'

    def __init__(self, exelist: T.List[str], for_machine: mesonlib.MachineChoice,
                 *, version: str = 'unknown version'):
        super().__init__(exelist, for_machine, '', [],
                         version=version)

    def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
        if not args:
            return args
        return self._apply_prefix('--start-group') + args + self._apply_prefix('--end-group')

    def get_accepts_rsp(self) -> bool:
        return False

    def get_lib_prefix(self) -> str:
        return '-l='

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

    def get_output_args(self, outputname: str) -> T.List[str]:
        return ['-z', f'--output_file={outputname}']

    def get_search_args(self, dirname: str) -> 'T.NoReturn':
        raise OSError('TI compilers do not have a search dir argument')

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

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


class C2000DynamicLinker(TIDynamicLinker):
    # Required for backwards compat with projects created before ti-cgt support existed
    id = 'cl2000'


class ArmDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):

    """Linker for the ARM compiler."""

    id = 'armlink'

    def __init__(self, for_machine: mesonlib.MachineChoice,
                 *, version: str = 'unknown version'):
        super().__init__(['armlink'], for_machine, '', [],
                         version=version)

    def get_accepts_rsp(self) -> bool:
        return False

    def get_std_shared_lib_args(self) -> 'T.NoReturn':
        raise 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 QualcommLLVMDynamicLinker(LLVMDynamicLinker):

    """ARM Linker from Snapdragon LLVM ARM Compiler."""

    id = 'ld.qcld'


class NAGDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):

    """NAG Fortran linker, ld via gcc indirection.

    Using nagfor -Wl,foo passes option foo to a backend gcc invocation.
    (This linking gathers the correct objects needed from the nagfor runtime
    system.)
    To pass gcc -Wl,foo options (i.e., to ld) one must apply indirection
    again: nagfor -Wl,-Wl,,foo
    """

    id = 'nag'

    def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
                         rpath_paths: T.Tuple[str, ...], build_rpath: str,
                         install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
        if not rpath_paths and not install_rpath and not build_rpath:
            return ([], set())
        args: T.List[str] = []
        origin_placeholder = '$ORIGIN'
        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('-Wl,-Wl,,-rpath,,' + rp))

        return (args, set())

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

    def get_std_shared_lib_args(self) -> T.List[str]:
        from ..compilers.fortran import NAGFortranCompiler
        return NAGFortranCompiler.get_nagfor_quiet(self.version) + ['-Wl,-shared']


class PGIDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):

    """PGI linker."""

    id = 'pgi'

    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]) -> 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: T.Tuple[str, ...], build_rpath: str,
                         install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
        if not env.machines[self.for_machine].is_windows():
            return (['-R' + os.path.join(build_dir, p) for p in rpath_paths], set())
        return ([], set())

NvidiaHPC_DynamicLinker = PGIDynamicLinker


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, env: 'Environment', is_thin: bool) -> T.List[str]:
        return self.std_args

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

NvidiaHPC_StaticLinker = PGIStaticLinker


class VisualStudioLikeLinkerMixin(DynamicLinkerBase):

    """Mixin class for dynamic linkers that act like Microsoft's link.exe."""

    if T.TYPE_CHECKING:
        for_machine = MachineChoice.HOST
        def _apply_prefix(self, arg: T.Union[str, T.List[str]]) -> T.List[str]: ...

    _BUILDTYPE_ARGS: T.Dict[str, T.List[str]] = {
        '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': [],
    }

    def __init__(self, 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', direct: bool = True, machine: str = 'x86'):
        # There's no way I can find to make mypy understand what's going on here
        super().__init__(exelist, for_machine, prefix_arg, always_args, version=version)
        self.machine = machine
        self.direct = direct

    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_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]:
        parent = super().get_always_args()
        return self._apply_prefix('/nologo') + parent

    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_name(self, targetfile: str) -> str:
        return targetfile

    def get_debugfile_args(self, targetfile: str) -> T.List[str]:
        return self._apply_prefix(['/DEBUG', '/PDB:' + self.get_debugfile_name(targetfile)])

    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]) -> T.List[str]:
        return []

    def import_library_args(self, implibname: str) -> T.List[str]:
        """The command to generate the import library."""
        return self._apply_prefix(['/IMPLIB:' + implibname])

    def rsp_file_syntax(self) -> RSPFileSyntax:
        return RSPFileSyntax.MSVC


class MSVCDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker):

    """Microsoft's Link.exe."""

    id = 'link'

    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__(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(['/release']) + super().get_always_args()

    def get_win_subsystem_args(self, value: str) -> T.List[str]:
        return self._apply_prefix([f'/SUBSYSTEM:{value.upper()}'])


class ClangClDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker):

    """Clang's lld-link.exe."""

    id = 'lld-link'

    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__(exelist or ['lld-link.exe'], for_machine,
                         prefix, always_args, machine=machine, version=version, direct=direct)

    def get_output_args(self, outputname: str) -> T.List[str]:
        # If we're being driven indirectly by clang just skip /MACHINE
        # as clang's target triple will handle the machine selection
        if self.machine is None:
            return self._apply_prefix([f"/OUT:{outputname}"])

        return super().get_output_args(outputname)

    def get_win_subsystem_args(self, value: str) -> T.List[str]:
        return self._apply_prefix([f'/SUBSYSTEM:{value.upper()}'])

    def get_thinlto_cache_args(self, path: str) -> T.List[str]:
        return ["/lldltocache:" + path]


class XilinkDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker):

    """Intel's Xilink.exe."""

    id = 'xilink'

    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__(['xilink.exe'], for_machine, '', always_args, version=version)

    def get_win_subsystem_args(self, value: str) -> T.List[str]:
        return self._apply_prefix([f'/SUBSYSTEM:{value.upper()}'])


class SolarisDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):

    """Sys-V derived linker used on Solaris and OpenSolaris."""

    id = 'ld.solaris'

    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_pie_args(self) -> T.List[str]:
        # Available in Solaris 11.2 and later
        pc, stdo, stde = mesonlib.Popen_safe(self.exelist + self._apply_prefix('-zhelp'))
        for line in (stdo + stde).split('\n'):
            if '-z type' in line:
                if 'pie' in line:
                    return ['-z', 'type=pie']
                break
        return []

    def get_asneeded_args(self) -> T.List[str]:
        return self._apply_prefix(['-z', 'ignore'])

    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: T.Tuple[str, ...], build_rpath: str,
                         install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
        if not rpath_paths and not install_rpath and not build_rpath:
            return ([], set())
        processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir)
        all_paths = mesonlib.OrderedSet([os.path.join('$ORIGIN', p) for p in processed_rpaths])
        rpath_dirs_to_remove: T.Set[bytes] = set()
        for p in all_paths:
            rpath_dirs_to_remove.add(p.encode('utf8'))
        if build_rpath != '':
            all_paths.add(build_rpath)
            for p in build_rpath.split(':'):
                rpath_dirs_to_remove.add(p.encode('utf8'))

        # 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(f'-rpath,{paths}'), rpath_dirs_to_remove)

    def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
                        suffix: str, soversion: str, darwin_versions: T.Tuple[str, str]) -> T.List[str]:
        sostr = '' if soversion is None else '.' + soversion
        return self._apply_prefix(f'-soname,{prefix}{shlib_name}.{suffix}{sostr}')


class AIXDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):

    """Sys-V derived linker used on AIX"""

    id = 'ld.aix'

    def get_always_args(self) -> T.List[str]:
        return self._apply_prefix(['-bnoipath', '-bbigtoc']) + super().get_always_args()

    def no_undefined_args(self) -> T.List[str]:
        return self._apply_prefix(['-bernotok'])

    def get_allow_undefined_args(self) -> T.List[str]:
        return self._apply_prefix(['-berok'])

    def get_archive_name(self, filename: str) -> str:
        # In AIX we allow the shared library name to have the lt_version and so_version.
        # But the archive name must just be .a .
        # For Example shared object can have the name libgio.so.0.7200.1 but the archive
        # must have the name libgio.a having libgio.a (libgio.so.0.7200.1) in the
        # archive. This regular expression is to do the same.
        filename = re.sub('[.][a]([.]?([0-9]+))*([.]?([a-z]+))*', '.a', filename.replace('.so', '.a'))
        return filename

    def get_command_to_archive_shlib(self) -> T.List[str]:
        # Archive shared library object and remove the shared library object,
        # since it already exists in the archive.
        command = ['ar', '-q', '-v', '$out', '$in', '&&', 'rm', '-f', '$in']
        return command

    def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
        # AIX's linker always links the whole archive: "The ld command
        # processes all input files in the same manner, whether they are
        # archives or not."
        return args

    def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
                         rpath_paths: T.Tuple[str, ...], build_rpath: str,
                         install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
        all_paths: mesonlib.OrderedSet[str] = mesonlib.OrderedSet()
        # install_rpath first, followed by other paths, and the system path last
        if install_rpath != '':
            all_paths.add(install_rpath)
        if build_rpath != '':
            all_paths.add(build_rpath)
        for p in rpath_paths:
            all_paths.add(os.path.join(build_dir, p))
        # We should consider allowing the $LIBPATH environment variable
        # to override sys_path.
        sys_path = env.get_compiler_system_lib_dirs(self.for_machine)
        if len(sys_path) == 0:
            # get_compiler_system_lib_dirs doesn't support our compiler.
            # Use the default system library path
            all_paths.update(['/usr/lib', '/lib'])
        else:
            # Include the compiler's default library paths, but filter out paths that don't exist
            for p in sys_path:
                if os.path.isdir(p):
                    all_paths.add(p)
        return (self._apply_prefix('-blibpath:' + ':'.join(all_paths)), set())

    def thread_flags(self, env: 'Environment') -> T.List[str]:
        return ['-pthread']


class OptlinkDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker):

    """Digital Mars dynamic linker for windows."""

    id = 'optlink'

    def __init__(self, exelist: T.List[str], for_machine: mesonlib.MachineChoice,
                 *, version: str = 'unknown version'):
        # Use optlink instead of link so we don't interfere with other link.exe
        # implementations.
        super().__init__(exelist, for_machine, '', [], version=version)

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

    def get_debugfile_args(self, targetfile: str) -> T.List[str]:
        # Optlink does not generate pdb files.
        return []

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


class CudaLinker(PosixDynamicLinkerMixin, DynamicLinker):
    """Cuda linker (nvlink)"""

    id = 'nvlink'

    @staticmethod
    def parse_version() -> str:
        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().rsplit('V', maxsplit=1)[-1]

    def get_accepts_rsp(self) -> bool:
        # nvcc does not support response files
        return False

    def get_lib_prefix(self) -> str:
        # 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.
        #
        # On Linux, we have to use rely on -Xlinker= too, since nvcc/nvlink chokes on
        # versioned shared libraries:
        #
        #   nvcc fatal : Don't know what to do with 'subprojects/foo/libbar.so.0.1.2'
        #
        from ..compilers.cuda 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]) -> T.List[str]:
        return []


class MetrowerksLinker(DynamicLinker):

    def __init__(self, exelist: T.List[str], for_machine: mesonlib.MachineChoice,
                 *, version: str = 'unknown version'):
        super().__init__(exelist, for_machine, '', [],
                         version=version)

    def fatal_warnings(self) -> T.List[str]:
        return ['-w', 'error']

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

    def get_accepts_rsp(self) -> bool:
        return True

    def get_lib_prefix(self) -> str:
        return ""

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

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

    def get_search_args(self, dirname: str) -> T.List[str]:
        return self._apply_prefix('-L' + dirname)

    def invoked_by_compiler(self) -> bool:
        return False

    def rsp_file_syntax(self) -> RSPFileSyntax:
        return RSPFileSyntax.GCC


class MetrowerksLinkerARM(MetrowerksLinker):
    id = 'mwldarm'


class MetrowerksLinkerEmbeddedPowerPC(MetrowerksLinker):
    id = 'mwldeppc'
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/mcompile.py0000644000175000017500000003456314562742363017377 0ustar00jpakkanejpakkane# Copyright 2020 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 __future__ import annotations

"""Entrypoint script for backend agnostic compile."""

import os
import json
import re
import sys
import shutil
import typing as T
from collections import defaultdict
from pathlib import Path

from . import mlog
from . import mesonlib
from .mesonlib import MesonException, RealPathAction, join_args, setup_vsenv
from mesonbuild.environment import detect_ninja
from mesonbuild.coredata import UserArrayOption
from mesonbuild import build

if T.TYPE_CHECKING:
    import argparse

def array_arg(value: str) -> T.List[str]:
    return UserArrayOption.listify_value(value)

def validate_builddir(builddir: Path) -> None:
    if not (builddir / 'meson-private' / 'coredata.dat').is_file():
        raise MesonException(f'Current directory is not a meson build directory: `{builddir}`.\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.')

def parse_introspect_data(builddir: Path) -> T.Dict[str, T.List[dict]]:
    """
    Converts a List of name-to-dict to a dict of name-to-dicts (since names are not unique)
    """
    path_to_intro = builddir / 'meson-info' / 'intro-targets.json'
    if not path_to_intro.exists():
        raise MesonException(f'`{path_to_intro.name}` is missing! Directory is not configured yet?')
    with path_to_intro.open(encoding='utf-8') as f:
        schema = json.load(f)

    parsed_data: T.Dict[str, T.List[dict]] = defaultdict(list)
    for target in schema:
        parsed_data[target['name']] += [target]
    return parsed_data

class ParsedTargetName:
    full_name = ''
    base_name = ''
    name = ''
    type = ''
    path = ''
    suffix = ''

    def __init__(self, target: str):
        self.full_name = target
        split = target.rsplit(':', 1)
        if len(split) > 1:
            self.type = split[1]
            if not self._is_valid_type(self.type):
                raise MesonException(f'Can\'t invoke target `{target}`: unknown target type: `{self.type}`')

        split = split[0].rsplit('/', 1)
        if len(split) > 1:
            self.path = split[0]
            self.name = split[1]
        else:
            self.name = split[0]

        split = self.name.rsplit('.', 1)
        if len(split) > 1:
            self.base_name = split[0]
            self.suffix = split[1]
        else:
            self.base_name = split[0]

    @staticmethod
    def _is_valid_type(type: str) -> bool:
        # Amend docs in Commands.md when editing this list
        allowed_types = {
            'executable',
            'static_library',
            'shared_library',
            'shared_module',
            'custom',
            'alias',
            'run',
            'jar',
        }
        return type in allowed_types

def get_target_from_intro_data(target: ParsedTargetName, builddir: Path, introspect_data: T.Dict[str, T.Any]) -> T.Dict[str, T.Any]:
    if target.name not in introspect_data and target.base_name not in introspect_data:
        raise MesonException(f'Can\'t invoke target `{target.full_name}`: target not found')

    intro_targets = introspect_data[target.name]
    # if target.name doesn't find anything, try just the base name
    if not intro_targets:
        intro_targets = introspect_data[target.base_name]
    found_targets: T.List[T.Dict[str, T.Any]] = []

    resolved_bdir = builddir.resolve()

    if not target.type and not target.path and not target.suffix:
        found_targets = intro_targets
    else:
        for intro_target in intro_targets:
            # Parse out the name from the id if needed
            intro_target_name = intro_target['name']
            split = intro_target['id'].rsplit('@', 1)
            if len(split) > 1:
                split = split[0].split('@@', 1)
                if len(split) > 1:
                    intro_target_name = split[1]
                else:
                    intro_target_name = split[0]
            if ((target.type and target.type != intro_target['type'].replace(' ', '_')) or
                (target.name != intro_target_name) or
                (target.path and intro_target['filename'] != 'no_name' and
                 Path(target.path) != Path(intro_target['filename'][0]).relative_to(resolved_bdir).parent)):
                continue
            found_targets += [intro_target]

    if not found_targets:
        raise MesonException(f'Can\'t invoke target `{target.full_name}`: target not found')
    elif len(found_targets) > 1:
        suggestions: T.List[str] = []
        for i in found_targets:
            i_name = i['name']
            split = i['id'].rsplit('@', 1)
            if len(split) > 1:
                split = split[0].split('@@', 1)
                if len(split) > 1:
                    i_name = split[1]
                else:
                    i_name = split[0]
            p = Path(i['filename'][0]).relative_to(resolved_bdir).parent / i_name
            t = i['type'].replace(' ', '_')
            suggestions.append(f'- ./{p}:{t}')
        suggestions_str = '\n'.join(suggestions)
        raise MesonException(f'Can\'t invoke target `{target.full_name}`: ambiguous name.'
                             f' Add target type and/or path:\n{suggestions_str}')

    return found_targets[0]

def generate_target_names_ninja(target: ParsedTargetName, builddir: Path, introspect_data: dict) -> T.List[str]:
    intro_target = get_target_from_intro_data(target, builddir, introspect_data)

    if intro_target['type'] in {'alias', 'run'}:
        return [target.name]
    else:
        return [str(Path(out_file).relative_to(builddir.resolve())) for out_file in intro_target['filename']]

def get_parsed_args_ninja(options: 'argparse.Namespace', builddir: Path) -> T.Tuple[T.List[str], T.Optional[T.Dict[str, str]]]:
    runner = detect_ninja()
    if runner is None:
        raise MesonException('Cannot find ninja.')

    cmd = runner
    if not builddir.samefile('.'):
        cmd.extend(['-C', builddir.as_posix()])

    # If the value is set to < 1 then don't set anything, which let's
    # ninja/samu decide what to do.
    if options.jobs > 0:
        cmd.extend(['-j', str(options.jobs)])
    if options.load_average > 0:
        cmd.extend(['-l', str(options.load_average)])

    if options.verbose:
        cmd.append('-v')

    cmd += options.ninja_args

    # operands must be processed after options/option-arguments
    if options.targets:
        intro_data = parse_introspect_data(builddir)
        for t in options.targets:
            cmd.extend(generate_target_names_ninja(ParsedTargetName(t), builddir, intro_data))
    if options.clean:
        cmd.append('clean')

    return cmd, None

def generate_target_name_vs(target: ParsedTargetName, builddir: Path, introspect_data: dict) -> str:
    intro_target = get_target_from_intro_data(target, builddir, introspect_data)

    assert intro_target['type'] not in {'alias', 'run'}, 'Should not reach here: `run` targets must be handle above'

    # Normalize project name
    # Source: https://docs.microsoft.com/en-us/visualstudio/msbuild/how-to-build-specific-targets-in-solutions-by-using-msbuild-exe
    target_name = re.sub(r"[\%\$\@\;\.\(\)']", '_', intro_target['id'])
    rel_path = Path(intro_target['filename'][0]).relative_to(builddir.resolve()).parent
    if rel_path != Path('.'):
        target_name = str(rel_path / target_name)
    return target_name

def get_parsed_args_vs(options: 'argparse.Namespace', builddir: Path) -> T.Tuple[T.List[str], T.Optional[T.Dict[str, str]]]:
    slns = list(builddir.glob('*.sln'))
    assert len(slns) == 1, 'More than one solution in a project?'
    sln = slns[0]

    cmd = ['msbuild']

    if options.targets:
        intro_data = parse_introspect_data(builddir)
        has_run_target = any(
            get_target_from_intro_data(ParsedTargetName(t), builddir, intro_data)['type'] in {'alias', 'run'}
            for t in options.targets)

        if has_run_target:
            # `run` target can't be used the same way as other targets on `vs` backend.
            # They are defined as disabled projects, which can't be invoked as `.sln`
            # target and have to be invoked directly as project instead.
            # Issue: https://github.com/microsoft/msbuild/issues/4772

            if len(options.targets) > 1:
                raise MesonException('Only one target may be specified when `run` target type is used on this backend.')
            intro_target = get_target_from_intro_data(ParsedTargetName(options.targets[0]), builddir, intro_data)
            proj_dir = Path(intro_target['filename'][0]).parent
            proj = proj_dir/'{}.vcxproj'.format(intro_target['id'])
            cmd += [str(proj.resolve())]
        else:
            cmd += [str(sln.resolve())]
            cmd.extend(['-target:{}'.format(generate_target_name_vs(ParsedTargetName(t), builddir, intro_data)) for t in options.targets])
    else:
        cmd += [str(sln.resolve())]

    if options.clean:
        cmd.extend(['-target:Clean'])

    # In msbuild `-maxCpuCount` with no number means "detect cpus", the default is `-maxCpuCount:1`
    if options.jobs > 0:
        cmd.append(f'-maxCpuCount:{options.jobs}')
    else:
        cmd.append('-maxCpuCount')

    if options.load_average:
        mlog.warning('Msbuild does not have a load-average switch, ignoring.')

    if not options.verbose:
        cmd.append('-verbosity:minimal')

    cmd += options.vs_args

    # Remove platform from env if set so that msbuild does not
    # pick x86 platform when solution platform is Win32
    env = os.environ.copy()
    env.pop('PLATFORM', None)

    return cmd, env

def get_parsed_args_xcode(options: 'argparse.Namespace', builddir: Path) -> T.Tuple[T.List[str], T.Optional[T.Dict[str, str]]]:
    runner = 'xcodebuild'
    if not shutil.which(runner):
        raise MesonException('Cannot find xcodebuild, did you install XCode?')

    # No argument to switch directory
    os.chdir(str(builddir))

    cmd = [runner, '-parallelizeTargets']

    if options.targets:
        for t in options.targets:
            cmd += ['-target', t]

    if options.clean:
        if options.targets:
            cmd += ['clean']
        else:
            cmd += ['-alltargets', 'clean']
        # Otherwise xcodebuild tries to delete the builddir and fails
        cmd += ['-UseNewBuildSystem=FALSE']

    if options.jobs > 0:
        cmd.extend(['-jobs', str(options.jobs)])

    if options.load_average > 0:
        mlog.warning('xcodebuild does not have a load-average switch, ignoring')

    if options.verbose:
        # xcodebuild is already quite verbose, and -quiet doesn't print any
        # status messages
        pass

    cmd += options.xcode_args
    return cmd, None

# Note: when adding arguments, please also add them to the completion
# scripts in $MESONSRC/data/shell-completions/
def add_arguments(parser: 'argparse.ArgumentParser') -> None:
    """Add compile specific arguments."""
    parser.add_argument(
        'targets',
        metavar='TARGET',
        nargs='*',
        default=None,
        help='Targets to build. Target has the following format: [PATH_TO_TARGET/]TARGET_NAME.TARGET_SUFFIX[:TARGET_TYPE].')
    parser.add_argument(
        '--clean',
        action='store_true',
        help='Clean the build directory.'
    )
    parser.add_argument('-C', dest='wd', action=RealPathAction,
                        help='directory to cd into before running')

    parser.add_argument(
        '-j', '--jobs',
        action='store',
        default=0,
        type=int,
        help='The number of worker jobs to run (if supported). If the value is less than 1 the build program will guess.'
    )
    parser.add_argument(
        '-l', '--load-average',
        action='store',
        default=0,
        type=float,
        help='The system load average to try to maintain (if supported).'
    )
    parser.add_argument(
        '-v', '--verbose',
        action='store_true',
        help='Show more verbose output.'
    )
    parser.add_argument(
        '--ninja-args',
        type=array_arg,
        default=[],
        help='Arguments to pass to `ninja` (applied only on `ninja` backend).'
    )
    parser.add_argument(
        '--vs-args',
        type=array_arg,
        default=[],
        help='Arguments to pass to `msbuild` (applied only on `vs` backend).'
    )
    parser.add_argument(
        '--xcode-args',
        type=array_arg,
        default=[],
        help='Arguments to pass to `xcodebuild` (applied only on `xcode` backend).'
    )

def run(options: 'argparse.Namespace') -> int:
    bdir = Path(options.wd)
    validate_builddir(bdir)
    if options.targets and options.clean:
        raise MesonException('`TARGET` and `--clean` can\'t be used simultaneously')

    b = build.load(options.wd)
    cdata = b.environment.coredata
    need_vsenv = T.cast('bool', cdata.get_option(mesonlib.OptionKey('vsenv')))
    if setup_vsenv(need_vsenv):
        mlog.log(mlog.green('INFO:'), 'automatically activated MSVC compiler environment')

    cmd: T.List[str] = []
    env: T.Optional[T.Dict[str, str]] = None

    backend = cdata.get_option(mesonlib.OptionKey('backend'))
    assert isinstance(backend, str)
    mlog.log(mlog.green('INFO:'), 'autodetecting backend as', backend)
    if backend == 'ninja':
        cmd, env = get_parsed_args_ninja(options, bdir)
    elif backend.startswith('vs'):
        cmd, env = get_parsed_args_vs(options, bdir)
    elif backend == 'xcode':
        cmd, env = get_parsed_args_xcode(options, bdir)
    else:
        raise MesonException(
            f'Backend `{backend}` is not yet supported by `compile`. Use generated project files directly instead.')

    mlog.log(mlog.green('INFO:'), 'calculating backend command to run:', join_args(cmd))
    p, *_ = mesonlib.Popen_safe(cmd, stdout=sys.stdout.buffer, stderr=sys.stderr.buffer, env=env)

    return p.returncode
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/mconf.py0000644000175000017500000003665414562742363016677 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import itertools
import shutil
import os
import textwrap
import typing as T
import collections

from . import build
from . import coredata
from . import environment
from . import mesonlib
from . import mintro
from . import mlog
from .ast import AstIDGenerator, IntrospectionInterpreter
from .mesonlib import MachineChoice, OptionKey

if T.TYPE_CHECKING:
    import argparse

    # cannot be TV_Loggable, because non-ansidecorators do direct string concat
    LOGLINE = T.Union[str, mlog.AnsiDecorator]

# Note: when adding arguments, please also add them to the completion
# scripts in $MESONSRC/data/shell-completions/
def add_arguments(parser: 'argparse.ArgumentParser') -> None:
    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)')
    parser.add_argument('--no-pager', action='store_false', dest='pager',
                        help='Do not redirect output to a pager')

def stringify(val: T.Any) -> str:
    if isinstance(val, bool):
        return str(val).lower()
    elif isinstance(val, list):
        s = ', '.join(stringify(i) for i in val)
        return f'[{s}]'
    elif val is None:
        return ''
    else:
        return str(val)


class ConfException(mesonlib.MesonException):
    pass


class Conf:
    def __init__(self, build_dir: str):
        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: T.List[LOGLINE] = []
        self.value_col: T.List[LOGLINE] = []
        self.choices_col: T.List[LOGLINE] = []
        self.descr_col: T.List[LOGLINE] = []
        self.all_subprojects: T.Set[str] = 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 = self.build.environment.coredata
            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
            with mlog.no_logging():
                self.source_dir = os.path.abspath(os.path.realpath(self.build_dir))
                intr = IntrospectionInterpreter(self.source_dir, '', 'ninja', visitors = [AstIDGenerator()])
                intr.analyze()
            self.coredata = intr.coredata
            self.default_values_only = True
        else:
            raise ConfException(f'Directory {build_dir} is neither a Meson build directory nor a project source directory.')

    def clear_cache(self) -> None:
        self.coredata.clear_cache()

    def set_options(self, options: T.Dict[OptionKey, str]) -> bool:
        return self.coredata.set_options(options)

    def save(self) -> None:
        # Do nothing when using introspection
        if self.default_values_only:
            return
        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) -> None:
        """Do the actual printing.

        This prints the generated output in an aligned, pretty form. it aims
        for a total width of 160 characters, but will use whatever the tty
        reports it's value to be. Though this is much wider than the standard
        80 characters of terminals, and even than the newer 120, compressing
        it to those lengths makes the output hard to read.

        Each column will have a specific width, and will be line wrapped.
        """
        total_width = shutil.get_terminal_size(fallback=(160, 0))[0]
        _col = max(total_width // 5, 20)
        last_column = total_width - (3 * _col) - 3
        four_column = (_col, _col, _col, last_column if last_column > 1 else _col)

        for line in zip(self.name_col, self.value_col, self.choices_col, self.descr_col):
            if not any(line):
                mlog.log('')
                continue

            # This is a header, like `Subproject foo:`,
            # We just want to print that and get on with it
            if line[0] and not any(line[1:]):
                mlog.log(line[0])
                continue

            def wrap_text(text: LOGLINE, width: int) -> mlog.TV_LoggableList:
                raw = text.text if isinstance(text, mlog.AnsiDecorator) else text
                indent = ' ' if raw.startswith('[') else ''
                wrapped_ = textwrap.wrap(raw, width, subsequent_indent=indent)
                # We cast this because https://github.com/python/mypy/issues/1965
                # mlog.TV_LoggableList does not provide __len__ for stringprotocol
                if isinstance(text, mlog.AnsiDecorator):
                    wrapped = T.cast('T.List[LOGLINE]', [mlog.AnsiDecorator(i, text.code) for i in wrapped_])
                else:
                    wrapped = T.cast('T.List[LOGLINE]', wrapped_)
                # Add padding here to get even rows, as `textwrap.wrap()` will
                # only shorten, not lengthen each item
                return [str(i) + ' ' * (width - len(i)) for i in wrapped]

            # wrap will take a long string, and create a list of strings no
            # longer than the size given. Then that list can be zipped into, to
            # print each line of the output, such the that columns are printed
            # to the right width, row by row.
            name = wrap_text(line[0], four_column[0])
            val = wrap_text(line[1], four_column[1])
            choice = wrap_text(line[2], four_column[2])
            desc = wrap_text(line[3], four_column[3])
            for l in itertools.zip_longest(name, val, choice, desc, fillvalue=''):
                items = [l[i] if l[i] else ' ' * four_column[i] for i in range(4)]
                mlog.log(*items)

    def split_options_per_subproject(self, options: 'coredata.KeyedOptionDictType') -> T.Dict[str, 'coredata.MutableKeyedOptionDictType']:
        result: T.Dict[str, 'coredata.MutableKeyedOptionDictType'] = {}
        for k, o in options.items():
            if k.subproject:
                self.all_subprojects.add(k.subproject)
            result.setdefault(k.subproject, {})[k] = o
        return result

    def _add_line(self, name: LOGLINE, value: LOGLINE, choices: LOGLINE, descr: LOGLINE) -> None:
        if isinstance(name, mlog.AnsiDecorator):
            name.text = ' ' * self.print_margin + name.text
        else:
            name = ' ' * self.print_margin + name
        self.name_col.append(name)
        self.value_col.append(value)
        self.choices_col.append(choices)
        self.descr_col.append(descr)

    def add_option(self, name: str, descr: str, value: T.Any, choices: T.Any) -> None:
        value = stringify(value)
        choices = stringify(choices)
        self._add_line(mlog.green(name), mlog.yellow(value), mlog.blue(choices), descr)

    def add_title(self, title: str) -> None:
        newtitle = mlog.cyan(title)
        descr = mlog.cyan('Description')
        value = mlog.cyan('Default Value' if self.default_values_only else 'Current Value')
        choices = mlog.cyan('Possible Values')
        self._add_line('', '', '', '')
        self._add_line(newtitle, value, choices, descr)
        self._add_line('-' * len(newtitle), '-' * len(value), '-' * len(choices), '-' * len(descr))

    def add_section(self, section: str) -> None:
        self.print_margin = 0
        self._add_line('', '', '', '')
        self._add_line(mlog.normal_yellow(section + ':'), '', '', '')
        self.print_margin = 2

    def print_options(self, title: str, options: 'coredata.KeyedOptionDictType') -> None:
        if not options:
            return
        if title:
            self.add_title(title)
        auto = T.cast('coredata.UserFeatureOption', self.coredata.options[OptionKey('auto_features')])
        for k, o in sorted(options.items()):
            printable_value = o.printable_value()
            root = k.as_root()
            if o.yielding and k.subproject and root in self.coredata.options:
                printable_value = ''
            if isinstance(o, coredata.UserFeatureOption) and o.is_auto():
                printable_value = auto.printable_value()
            self.add_option(str(root), o.description, printable_value, o.choices)

    def print_conf(self, pager: bool) -> None:
        if pager:
            mlog.start_pager()

        def print_default_values_warning() -> None:
            mlog.warning('The source directory instead of the build directory was specified.')
            mlog.warning('Only the default values for the project are printed.')

        if self.default_values_only:
            print_default_values_warning()
            mlog.log('')

        mlog.log('Core properties:')
        mlog.log('  Source dir', self.source_dir)
        if not self.default_values_only:
            mlog.log('  Build dir ', self.build_dir)

        dir_option_names = set(coredata.BUILTIN_DIR_OPTIONS)
        test_option_names = {OptionKey('errorlogs'),
                             OptionKey('stdsplit')}

        dir_options: 'coredata.MutableKeyedOptionDictType' = {}
        test_options: 'coredata.MutableKeyedOptionDictType' = {}
        core_options: 'coredata.MutableKeyedOptionDictType' = {}
        module_options: T.Dict[str, 'coredata.MutableKeyedOptionDictType'] = collections.defaultdict(dict)
        for k, v in self.coredata.options.items():
            if k in dir_option_names:
                dir_options[k] = v
            elif k in test_option_names:
                test_options[k] = v
            elif k.module:
                # Ignore module options if we did not use that module during
                # configuration.
                if self.build and k.module not in self.build.modules:
                    continue
                module_options[k.module][k] = v
            elif k.is_builtin():
                core_options[k] = v

        host_core_options = self.split_options_per_subproject({k: v for k, v in core_options.items() if k.machine is MachineChoice.HOST})
        build_core_options = self.split_options_per_subproject({k: v for k, v in core_options.items() if k.machine is MachineChoice.BUILD})
        host_compiler_options = self.split_options_per_subproject({k: v for k, v in self.coredata.options.items() if k.is_compiler() and k.machine is MachineChoice.HOST})
        build_compiler_options = self.split_options_per_subproject({k: v for k, v in self.coredata.options.items() if k.is_compiler() and k.machine is MachineChoice.BUILD})
        project_options = self.split_options_per_subproject({k: v for k, v in self.coredata.options.items() if k.is_project()})
        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', host_core_options[''])
        if show_build_options:
            self.print_options('', build_core_options[''])
        self.print_options('Backend options', {k: v for k, v in self.coredata.options.items() if k.is_backend()})
        self.print_options('Base options', {k: v for k, v in self.coredata.options.items() if k.is_base()})
        self.print_options('Compiler options', host_compiler_options.get('', {}))
        if show_build_options:
            self.print_options('', build_compiler_options.get('', {}))
        for mod, mod_options in module_options.items():
            self.print_options(f'{mod} module options', mod_options)
        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 host_core_options:
                self.print_options('Core options', host_core_options[subproject])
            if subproject in build_core_options and show_build_options:
                self.print_options('', build_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:
            mlog.log('')
            print_default_values_warning()

        self.print_nondefault_buildtype_options()

    def print_nondefault_buildtype_options(self) -> None:
        mismatching = self.coredata.get_nondefault_buildtype_args()
        if not mismatching:
            return
        mlog.log("\nThe following option(s) have a different value than the build type default\n")
        mlog.log('               current   default')
        for m in mismatching:
            mlog.log(f'{m[0]:21}{m[1]:10}{m[2]:10}')

def run_impl(options: argparse.Namespace, builddir: str) -> int:
    print_only = not options.cmd_line_options and not options.clearcache
    c = None
    try:
        c = Conf(builddir)
        if c.default_values_only and not print_only:
            raise mesonlib.MesonException('No valid build directory found, cannot modify options.')
        if c.default_values_only or print_only:
            c.print_conf(options.pager)
            return 0

        save = False
        if options.cmd_line_options:
            save = c.set_options(options.cmd_line_options)
            coredata.update_cmd_line_file(builddir, options)
        if options.clearcache:
            c.clear_cache()
            save = True
        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:
        mlog.log('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
    except BrokenPipeError:
        # Pager quit before we wrote everything.
        pass
    return 0

def run(options: argparse.Namespace) -> int:
    coredata.parse_cmd_line_options(options)
    builddir = os.path.abspath(os.path.realpath(options.builddir))
    return run_impl(options, builddir)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/mdevenv.py0000644000175000017500000002420514562742363017226 0ustar00jpakkanejpakkanefrom __future__ import annotations

import os, subprocess
import argparse
import tempfile
import shutil
import itertools

from pathlib import Path
from . import build, minstall
from .mesonlib import (EnvironmentVariables, MesonException, is_windows, setup_vsenv, OptionKey,
                       get_wine_shortpath, MachineChoice)
from . import mlog

import typing as T
if T.TYPE_CHECKING:
    from .backends import InstallData

POWERSHELL_EXES = {'pwsh.exe', 'powershell.exe'}

# Note: when adding arguments, please also add them to the completion
# scripts in $MESONSRC/data/shell-completions/
def add_arguments(parser: argparse.ArgumentParser) -> None:
    parser.add_argument('-C', dest='builddir', type=Path, default='.',
                        help='Path to build directory')
    parser.add_argument('--workdir', '-w', type=Path, default=None,
                        help='Directory to cd into before running (default: builddir, Since 1.0.0)')
    parser.add_argument('--dump', nargs='?', const=True,
                        help='Only print required environment (Since 0.62.0) ' +
                             'Takes an optional file path (Since 1.1.0)')
    parser.add_argument('--dump-format', default='export',
                        choices=['sh', 'export', 'vscode'],
                        help='Format used with --dump (Since 1.1.0)')
    parser.add_argument('devcmd', nargs=argparse.REMAINDER, metavar='command',
                        help='Command to run in developer environment (default: interactive shell)')

def get_windows_shell() -> T.Optional[str]:
    mesonbuild = Path(__file__).parent
    script = mesonbuild / 'scripts' / 'cmd_or_ps.ps1'
    for shell in POWERSHELL_EXES:
        try:
            command = [shell, '-noprofile', '-executionpolicy', 'bypass', '-file', str(script)]
            result = subprocess.check_output(command)
            return result.decode().strip()
        except (subprocess.CalledProcessError, OSError):
            pass
    return None

def reduce_winepath(env: T.Dict[str, str]) -> None:
    winepath = env.get('WINEPATH')
    if not winepath:
        return
    winecmd = shutil.which('wine64') or shutil.which('wine')
    if not winecmd:
        return
    env['WINEPATH'] = get_wine_shortpath([winecmd], winepath.split(';'))
    mlog.log('Meson detected wine and has set WINEPATH accordingly')

def get_env(b: build.Build, dump_fmt: T.Optional[str]) -> T.Tuple[T.Dict[str, str], T.Set[str]]:
    extra_env = EnvironmentVariables()
    extra_env.set('MESON_DEVENV', ['1'])
    extra_env.set('MESON_PROJECT_NAME', [b.project_name])

    sysroot = b.environment.properties[MachineChoice.HOST].get_sys_root()
    if sysroot:
        extra_env.set('QEMU_LD_PREFIX', [sysroot])

    env = {} if dump_fmt else os.environ.copy()
    default_fmt = '${0}' if dump_fmt in {'sh', 'export'} else None
    varnames = set()
    for i in itertools.chain(b.devenv, {extra_env}):
        env = i.get_env(env, default_fmt)
        varnames |= i.get_names()

    reduce_winepath(env)

    return env, varnames

def bash_completion_files(b: build.Build, install_data: 'InstallData') -> T.List[str]:
    from .dependencies.pkgconfig import PkgConfigDependency
    result = []
    dep = PkgConfigDependency('bash-completion', b.environment,
                              {'required': False, 'silent': True, 'version': '>=2.10'})
    if dep.found():
        prefix = b.environment.coredata.get_option(OptionKey('prefix'))
        assert isinstance(prefix, str), 'for mypy'
        datadir = b.environment.coredata.get_option(OptionKey('datadir'))
        assert isinstance(datadir, str), 'for mypy'
        datadir_abs = os.path.join(prefix, datadir)
        completionsdir = dep.get_variable(pkgconfig='completionsdir', pkgconfig_define=(('datadir', datadir_abs),))
        assert isinstance(completionsdir, str), 'for mypy'
        completionsdir_path = Path(completionsdir)
        for f in install_data.data:
            if completionsdir_path in Path(f.install_path).parents:
                result.append(f.path)
    return result

def add_gdb_auto_load(autoload_path: Path, gdb_helper: str, fname: Path) -> None:
    # Copy or symlink the GDB helper into our private directory tree
    destdir = autoload_path / fname.parent
    destdir.mkdir(parents=True, exist_ok=True)
    try:
        if is_windows():
            shutil.copy(gdb_helper, str(destdir / os.path.basename(gdb_helper)))
        else:
            os.symlink(gdb_helper, str(destdir / os.path.basename(gdb_helper)))
    except (FileExistsError, shutil.SameFileError):
        pass

def write_gdb_script(privatedir: Path, install_data: 'InstallData', workdir: Path) -> None:
    if not shutil.which('gdb'):
        return
    bdir = privatedir.parent
    autoload_basedir = privatedir / 'gdb-auto-load'
    autoload_path = Path(autoload_basedir, *bdir.parts[1:])
    have_gdb_helpers = False
    for d in install_data.data:
        if d.path.endswith('-gdb.py') or d.path.endswith('-gdb.gdb') or d.path.endswith('-gdb.scm'):
            # This GDB helper is made for a specific shared library, search if
            # we have it in our builddir.
            libname = Path(d.path).name.rsplit('-', 1)[0]
            for t in install_data.targets:
                path = Path(t.fname)
                if path.name == libname:
                    add_gdb_auto_load(autoload_path, d.path, path)
                    have_gdb_helpers = True
    if have_gdb_helpers:
        gdbinit_line = f'add-auto-load-scripts-directory {autoload_basedir}\n'
        gdbinit_path = bdir / '.gdbinit'
        first_time = False
        try:
            with gdbinit_path.open('r+', encoding='utf-8') as f:
                if gdbinit_line not in f.readlines():
                    f.write(gdbinit_line)
                    first_time = True
        except FileNotFoundError:
            gdbinit_path.write_text(gdbinit_line, encoding='utf-8')
            first_time = True
        if first_time:
            gdbinit_path = gdbinit_path.resolve()
            workdir_path = workdir.resolve()
            rel_path = gdbinit_path.relative_to(workdir_path)
            mlog.log('Meson detected GDB helpers and added config in', mlog.bold(str(rel_path)))
            mlog.log('To load it automatically you might need to:')
            mlog.log(' - Add', mlog.bold(f'add-auto-load-safe-path {gdbinit_path.parent}'),
                     'in', mlog.bold('~/.gdbinit'))
            if gdbinit_path.parent != workdir_path:
                mlog.log(' - Change current workdir to', mlog.bold(str(rel_path.parent)),
                         'or use', mlog.bold(f'--init-command {rel_path}'))

def dump(devenv: T.Dict[str, str], varnames: T.Set[str], dump_format: T.Optional[str], output: T.Optional[T.TextIO] = None) -> None:
    for name in varnames:
        print(f'{name}="{devenv[name]}"', file=output)
        if dump_format == 'export':
            print(f'export {name}', file=output)

def run(options: argparse.Namespace) -> int:
    privatedir = Path(options.builddir) / 'meson-private'
    buildfile = privatedir / 'build.dat'
    if not buildfile.is_file():
        raise MesonException(f'Directory {options.builddir!r} does not seem to be a Meson build directory.')
    b = build.load(options.builddir)
    workdir = options.workdir or options.builddir

    need_vsenv = T.cast('bool', b.environment.coredata.get_option(OptionKey('vsenv')))
    setup_vsenv(need_vsenv) # Call it before get_env to get vsenv vars as well
    dump_fmt = options.dump_format if options.dump else None
    devenv, varnames = get_env(b, dump_fmt)
    if options.dump:
        if options.devcmd:
            raise MesonException('--dump option does not allow running other command.')
        if options.dump is True:
            dump(devenv, varnames, dump_fmt)
        else:
            with open(options.dump, "w", encoding='utf-8') as output:
                dump(devenv, varnames, dump_fmt, output)
        return 0

    if b.environment.need_exe_wrapper():
        m = 'An executable wrapper could be required'
        exe_wrapper = b.environment.get_exe_wrapper()
        if exe_wrapper:
            cmd = ' '.join(exe_wrapper.get_command())
            m += f': {cmd}'
        mlog.log(m)

    install_data = minstall.load_install_data(str(privatedir / 'install.dat'))
    write_gdb_script(privatedir, install_data, workdir)

    args = options.devcmd
    if not args:
        prompt_prefix = f'[{b.project_name}]'
        shell_env = os.environ.get("SHELL")
        # Prefer $SHELL in a MSYS2 bash despite it being Windows
        if shell_env and os.path.exists(shell_env):
            args = [shell_env]
        elif is_windows():
            shell = get_windows_shell()
            if not shell:
                mlog.warning('Failed to determine Windows shell, fallback to cmd.exe')
            if shell in POWERSHELL_EXES:
                args = [shell, '-NoLogo', '-NoExit']
                prompt = f'function global:prompt {{  "{prompt_prefix} PS " + $PWD + "> "}}'
                args += ['-Command', prompt]
            else:
                args = [os.environ.get("COMSPEC", r"C:\WINDOWS\system32\cmd.exe")]
                args += ['/k', f'prompt {prompt_prefix} $P$G']
        else:
            args = [os.environ.get("SHELL", os.path.realpath("/bin/sh"))]
        if "bash" in args[0]:
            # Let the GC remove the tmp file
            tmprc = tempfile.NamedTemporaryFile(mode='w')
            tmprc.write('[ -e ~/.bashrc ] && . ~/.bashrc\n')
            if not os.environ.get("MESON_DISABLE_PS1_OVERRIDE"):
                tmprc.write(f'export PS1="{prompt_prefix} $PS1"\n')
            for f in bash_completion_files(b, install_data):
                tmprc.write(f'. "{f}"\n')
            tmprc.flush()
            args.append("--rcfile")
            args.append(tmprc.name)
    else:
        # Try to resolve executable using devenv's PATH
        abs_path = shutil.which(args[0], path=devenv.get('PATH', None))
        args[0] = abs_path or args[0]

    try:
        return subprocess.call(args, close_fds=False,
                               env=devenv,
                               cwd=workdir)
    except subprocess.CalledProcessError as e:
        return e.returncode
    except FileNotFoundError:
        raise MesonException(f'Command not found: {args[0]}')
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/mdist.py0000644000175000017500000003732214562742363016706 0ustar00jpakkanejpakkane# 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 __future__ import annotations


import abc
import argparse
import gzip
import os
import sys
import shlex
import shutil
import subprocess
import tarfile
import tempfile
import hashlib
import typing as T

from dataclasses import dataclass
from glob import glob
from pathlib import Path
from mesonbuild.environment import detect_ninja
from mesonbuild.mesonlib import (MesonException, RealPathAction, quiet_git,
                                 windows_proof_rmtree, setup_vsenv, OptionKey)
from mesonbuild.msetup import add_arguments as msetup_argparse
from mesonbuild.wrap import wrap
from mesonbuild import mlog, build, coredata
from .scripts.meson_exe import run_exe

if T.TYPE_CHECKING:
    from ._typing import ImmutableListProtocol
    from .mesonlib import ExecutableSerialisation

archive_choices = ['gztar', 'xztar', 'zip']

archive_extension = {'gztar': '.tar.gz',
                     'xztar': '.tar.xz',
                     'zip': '.zip'}

# Note: when adding arguments, please also add them to the completion
# scripts in $MESONSRC/data/shell-completions/
def add_arguments(parser: argparse.ArgumentParser) -> None:
    parser.add_argument('-C', dest='wd', action=RealPathAction,
                        help='directory to cd into before running')
    parser.add_argument('--allow-dirty', action='store_true',
                        help='Allow even when repository contains uncommitted changes.')
    parser.add_argument('--formats', default='xztar',
                        help='Comma separated list of archive types to create. Supports xztar (default), gztar, and zip.')
    parser.add_argument('--include-subprojects', action='store_true',
                        help='Include source code of subprojects that have been used for the build.')
    parser.add_argument('--no-tests', action='store_true',
                        help='Do not build and test generated packages.')


def create_hash(fname: str) -> None:
    hashname = fname + '.sha256sum'
    m = hashlib.sha256()
    m.update(open(fname, 'rb').read())
    with open(hashname, 'w', encoding='utf-8') as f:
        # A space and an asterisk because that is the format defined by GNU coreutils
        # and accepted by busybox and the Perl shasum tool.
        f.write('{} *{}\n'.format(m.hexdigest(), os.path.basename(fname)))


msg_uncommitted_changes = 'Repository has uncommitted changes that will not be included in the dist tarball'

def handle_dirty_opt(msg: str, allow_dirty: bool) -> None:
    if allow_dirty:
        mlog.warning(msg)
    else:
        mlog.error(msg + '\n' + 'Use --allow-dirty to ignore the warning and proceed anyway')
        sys.exit(1)

def is_git(src_root: str) -> bool:
    '''
    Checks if meson.build file at the root source directory is tracked by git.
    It could be a subproject part of the parent project git repository.
    '''
    return quiet_git(['ls-files', '--error-unmatch', 'meson.build'], src_root)[0]

def is_hg(src_root: str) -> bool:
    return os.path.isdir(os.path.join(src_root, '.hg'))


@dataclass
class Dist(metaclass=abc.ABCMeta):
    dist_name: str
    src_root: str
    bld_root: str
    dist_scripts: T.List[ExecutableSerialisation]
    subprojects: T.Dict[str, str]
    options: argparse.Namespace

    def __post_init__(self) -> None:
        self.dist_sub = os.path.join(self.bld_root, 'meson-dist')
        self.distdir = os.path.join(self.dist_sub, self.dist_name)

    @abc.abstractmethod
    def create_dist(self, archives: T.List[str]) -> T.List[str]:
        pass

    def run_dist_scripts(self) -> None:
        assert os.path.isabs(self.distdir)
        env = {}
        env['MESON_DIST_ROOT'] = self.distdir
        env['MESON_SOURCE_ROOT'] = self.src_root
        env['MESON_BUILD_ROOT'] = self.bld_root
        for d in self.dist_scripts:
            if d.subproject and d.subproject not in self.subprojects:
                continue
            subdir = self.subprojects.get(d.subproject, '')
            env['MESON_PROJECT_DIST_ROOT'] = os.path.join(self.distdir, subdir)
            env['MESON_PROJECT_SOURCE_ROOT'] = os.path.join(self.src_root, subdir)
            env['MESON_PROJECT_BUILD_ROOT'] = os.path.join(self.bld_root, subdir)
            name = ' '.join(d.cmd_args)
            print(f'Running custom dist script {name!r}')
            try:
                rc = run_exe(d, env)
                if rc != 0:
                    sys.exit('Dist script errored out')
            except OSError:
                print(f'Failed to run dist script {name!r}')
                sys.exit(1)


class GitDist(Dist):
    def git_root(self, dir_: str) -> Path:
        # Cannot use --show-toplevel here because git in our CI prints cygwin paths
        # that python cannot resolve. Workaround this by taking parent of src_root.
        prefix = quiet_git(['rev-parse', '--show-prefix'], dir_, check=True)[1].strip()
        if not prefix:
            return Path(dir_)
        prefix_level = len(Path(prefix).parents)
        return Path(dir_).parents[prefix_level - 1]

    def have_dirty_index(self) -> bool:
        '''Check whether there are uncommitted changes in git'''
        ret = subprocess.call(['git', '-C', self.src_root, 'diff-index', '--quiet', 'HEAD'])
        return ret == 1

    def copy_git(self, src: T.Union[str, os.PathLike], distdir: str, revision: str = 'HEAD',
                 prefix: T.Optional[str] = None, subdir: T.Optional[str] = None) -> None:
        cmd = ['git', 'archive', '--format', 'tar', revision]
        if prefix is not None:
            cmd.insert(2, f'--prefix={prefix}/')
        if subdir is not None:
            cmd.extend(['--', subdir])
        with tempfile.TemporaryFile() as f:
            subprocess.check_call(cmd, cwd=src, stdout=f)
            f.seek(0)
            t = tarfile.open(fileobj=f) # [ignore encoding]
            t.extractall(path=distdir)

    def process_git_project(self, src_root: str, distdir: str) -> None:
        if self.have_dirty_index():
            handle_dirty_opt(msg_uncommitted_changes, self.options.allow_dirty)
        if os.path.exists(distdir):
            windows_proof_rmtree(distdir)
        repo_root = self.git_root(src_root)
        if repo_root.samefile(src_root):
            os.makedirs(distdir)
            self.copy_git(src_root, distdir)
        else:
            subdir = Path(src_root).relative_to(repo_root)
            tmp_distdir = distdir + '-tmp'
            if os.path.exists(tmp_distdir):
                windows_proof_rmtree(tmp_distdir)
            os.makedirs(tmp_distdir)
            self.copy_git(repo_root, tmp_distdir, subdir=str(subdir))
            Path(tmp_distdir, subdir).rename(distdir)
            windows_proof_rmtree(tmp_distdir)
        self.process_submodules(src_root, distdir)

    def process_submodules(self, src: str, distdir: str) -> None:
        module_file = os.path.join(src, '.gitmodules')
        if not os.path.exists(module_file):
            return
        cmd = ['git', 'submodule', 'status', '--cached', '--recursive']
        modlist = subprocess.check_output(cmd, cwd=src, universal_newlines=True).splitlines()
        for submodule in modlist:
            status = submodule[:1]
            sha1, rest = submodule[1:].split(' ', 1)
            subpath = rest.rsplit(' ', 1)[0]

            if status == '-':
                mlog.warning(f'Submodule {subpath!r} is not checked out and cannot be added to the dist')
                continue
            elif status in {'+', 'U'}:
                handle_dirty_opt(f'Submodule {subpath!r} has uncommitted changes that will not be included in the dist tarball', self.options.allow_dirty)

            self.copy_git(os.path.join(src, subpath), distdir, revision=sha1, prefix=subpath)

    def create_dist(self, archives: T.List[str]) -> T.List[str]:
        self.process_git_project(self.src_root, self.distdir)
        for path in self.subprojects.values():
            sub_src_root = os.path.join(self.src_root, path)
            sub_distdir = os.path.join(self.distdir, path)
            if os.path.exists(sub_distdir):
                continue
            if is_git(sub_src_root):
                self.process_git_project(sub_src_root, sub_distdir)
            else:
                shutil.copytree(sub_src_root, sub_distdir)
        self.run_dist_scripts()
        output_names = []
        for a in archives:
            compressed_name = self.distdir + archive_extension[a]
            shutil.make_archive(self.distdir, a, root_dir=self.dist_sub, base_dir=self.dist_name)
            output_names.append(compressed_name)
        windows_proof_rmtree(self.distdir)
        return output_names


class HgDist(Dist):
    def have_dirty_index(self) -> bool:
        '''Check whether there are uncommitted changes in hg'''
        out = subprocess.check_output(['hg', '-R', self.src_root, 'summary'])
        return b'commit: (clean)' not in out

    def create_dist(self, archives: T.List[str]) -> T.List[str]:
        if self.have_dirty_index():
            handle_dirty_opt(msg_uncommitted_changes, self.options.allow_dirty)
        if self.dist_scripts:
            mlog.warning('dist scripts are not supported in Mercurial projects')

        os.makedirs(self.dist_sub, exist_ok=True)
        tarname = os.path.join(self.dist_sub, self.dist_name + '.tar')
        xzname = tarname + '.xz'
        gzname = tarname + '.gz'
        zipname = os.path.join(self.dist_sub, self.dist_name + '.zip')
        # Note that -X interprets relative paths using the current working
        # directory, not the repository root, so this must be an absolute path:
        # https://bz.mercurial-scm.org/show_bug.cgi?id=6267
        #
        # .hg[a-z]* is used instead of .hg* to keep .hg_archival.txt, which may
        # be useful to link the tarball to the Mercurial revision for either
        # manual inspection or in case any code interprets it for a --version or
        # similar.
        subprocess.check_call(['hg', 'archive', '-R', self.src_root, '-S', '-t', 'tar',
                               '-X', self.src_root + '/.hg[a-z]*', tarname])
        output_names = []
        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', self.src_root, '-S', '-t', 'zip', zipname])
            output_names.append(zipname)
        return output_names


def run_dist_steps(meson_command: T.List[str], unpacked_src_dir: str, builddir: str, installdir: str, ninja_args: T.List[str]) -> int:
    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_args, cwd=builddir) != 0:
        print('Compiling the distribution package failed')
        return 1
    if subprocess.call(ninja_args + ['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_args + ['install'], cwd=builddir, env=myenv) != 0:
        print('Installing the distribution package failed')
        return 1
    return 0

def check_dist(packagename: str, meson_command: ImmutableListProtocol[str], extra_meson_args: T.List[str], bld_root: str, privdir: str) -> int:
    print(f'Testing distribution package {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):
            windows_proof_rmtree(p)
        os.mkdir(p)
    ninja_args = detect_ninja()
    shutil.unpack_archive(packagename, unpackdir)
    unpacked_files = glob(os.path.join(unpackdir, '*'))
    assert len(unpacked_files) == 1
    unpacked_src_dir = unpacked_files[0]
    meson_command += ['setup']
    meson_command += create_cmdline_args(bld_root)
    meson_command += extra_meson_args

    ret = run_dist_steps(meson_command, unpacked_src_dir, builddir, installdir, ninja_args)
    if ret > 0:
        print(f'Dist check build directory was {builddir}')
    else:
        windows_proof_rmtree(unpackdir)
        windows_proof_rmtree(builddir)
        windows_proof_rmtree(installdir)
        print(f'Distribution package {packagename} tested')
    return ret

def create_cmdline_args(bld_root: str) -> T.List[str]:
    parser = argparse.ArgumentParser()
    msetup_argparse(parser)
    args = parser.parse_args([])
    coredata.parse_cmd_line_options(args)
    coredata.read_cmd_line_file(bld_root, args)
    args.cmd_line_options.pop(OptionKey('backend'), '')
    return shlex.split(coredata.format_cmd_line_options(args))

def determine_archives_to_generate(options: argparse.Namespace) -> T.List[str]:
    result = []
    for i in options.formats.split(','):
        if i not in archive_choices:
            sys.exit(f'Value "{i}" not one of permitted values {archive_choices}.')
        result.append(i)
    if len(i) == 0:
        sys.exit('No archive types specified.')
    return result

def run(options: argparse.Namespace) -> int:
    buildfile = Path(options.wd) / 'meson-private' / 'build.dat'
    if not buildfile.is_file():
        raise MesonException(f'Directory {options.wd!r} does not seem to be a Meson build directory.')
    b = build.load(options.wd)
    need_vsenv = T.cast('bool', b.environment.coredata.get_option(OptionKey('vsenv')))
    setup_vsenv(need_vsenv)
    # This import must be load delayed, otherwise it will get the default
    # value of None.
    from mesonbuild.mesonlib import get_meson_command
    src_root = b.environment.source_dir
    bld_root = b.environment.build_dir
    priv_dir = os.path.join(bld_root, 'meson-private')

    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[sub] = os.path.join(b.subproject_dir, directory)
        extra_meson_args.append('-Dwrap_mode=nodownload')

    cls: T.Type[Dist]
    if is_git(src_root):
        cls = GitDist
    elif is_hg(src_root):
        if subprojects:
            print('--include-subprojects option currently not supported with Mercurial')
            return 1
        cls = HgDist
    else:
        print('Dist currently only works with Git or Mercurial repos')
        return 1

    project = cls(dist_name, src_root, bld_root, b.dist_scripts, subprojects, options)
    names = project.create_dist(archives)

    if names is None:
        return 1
    rc = 0
    if not options.no_tests:
        # Check only one.
        rc = check_dist(names[0], get_meson_command(), extra_meson_args, bld_root, priv_dir)
    if rc == 0:
        for name in names:
            create_hash(name)
            print('Created', name)
    return rc
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/mesondata.py0000644000175000017500000000334214562742363017534 0ustar00jpakkanejpakkane# Copyright 2021 The Meson development team

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

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

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


import importlib.resources
from pathlib import PurePosixPath, Path
import typing as T

if T.TYPE_CHECKING:
    from .environment import Environment

class DataFile:
    def __init__(self, path: str) -> None:
        self.path = PurePosixPath(path)

    def write_once(self, path: Path) -> None:
        if not path.exists():
            data = importlib.resources.read_text( # [ignore encoding] it's on the next lines, Mr. Lint
                    ('mesonbuild' / self.path.parent).as_posix().replace('/', '.'),
                    self.path.name,
                    encoding='utf-8')
            path.write_text(data, encoding='utf-8')

    def write_to_private(self, env: 'Environment') -> Path:
        try:
            resource = importlib.resources.files('mesonbuild') / self.path
            if isinstance(resource, Path):
                return resource
        except AttributeError:
            # fall through to python 3.7 compatible code
            pass

        out_file = Path(env.scratch_dir) / 'data' / self.path.name
        out_file.parent.mkdir(exist_ok=True)
        self.write_once(out_file)
        return out_file
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/mesonlib.py0000644000175000017500000000207714562742363017375 0ustar00jpakkanejpakkane# SPDX-license-identifier: Apache-2.0
# Copyright 2012-2021 The Meson development team
# Copyright Ā© 2021 Intel Corporation

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

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

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

# pylint: skip-file

"""Helper functions and classes."""

import os

from .utils.core import *
from .utils.vsenv import *

from .utils.universal import *

# Here we import either the posix implementations, the windows implementations,
# or a generic no-op implementation
if os.name == 'posix':
    from .utils.posix import *
elif os.name == 'nt':
    from .utils.win32 import *
else:
    from .utils.platform import *
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/mesonmain.py0000644000175000017500000003214114562742363017546 0ustar00jpakkanejpakkane# Copyright 2012-2021 The Meson development team

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

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

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

# Work around some pathlib bugs...

from . import _pathlib
import sys
sys.modules['pathlib'] = _pathlib

# This file is an entry point for all commands, including scripts. Include the
# strict minimum python modules for performance reasons.
import os.path
import platform
import importlib
import argparse

from .utils.core import MesonException, MesonBugException
from . import mlog

def errorhandler(e, command):
    import traceback
    if isinstance(e, MesonException):
        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 e
        return 1
    else:
        # We assume many types of traceback are Meson logic bugs, but most
        # particularly anything coming from the interpreter during `setup`.
        # Some things definitely aren't:
        # - PermissionError is always a problem in the user environment
        # - runpython doesn't run Meson's own code, even though it is
        #   dispatched by our run()
        if os.environ.get('MESON_FORCE_BACKTRACE'):
            raise e
        traceback.print_exc()

        if command == 'runpython':
            return 2
        elif isinstance(e, OSError):
            mlog.exception("Unhandled python OSError. This is probably not a Meson bug, "
                           "but an issue with your build environment.")
            return e.errno
        else: # Exception
            msg = 'Unhandled python exception'
            if all(getattr(e, a, None) is not None for a in ['file', 'lineno', 'colno']):
                e = MesonBugException(msg, e.file, e.lineno, e.colno) # type: ignore
            else:
                e = MesonBugException(msg)
            mlog.exception(e)
        return 2

# Note: when adding arguments, please also add them to the completion
# scripts in $MESONSRC/data/shell-completions/
class CommandLineParser:
    def __init__(self):
        # only import these once we do full argparse processing
        from . import mconf, mdist, minit, minstall, mintro, msetup, mtest, rewriter, msubprojects, munstable_coredata, mcompile, mdevenv
        from .scripts import env2mfile
        from .wrap import wraptool
        import shutil

        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', dest='command',
                                                     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('rewrite', lambda parser: rewriter.add_arguments(parser, self.formatter), rewriter.run,
                         help_msg='Modify the project definition')
        self.add_command('compile', mcompile.add_arguments, mcompile.run,
                         help_msg='Build the project')
        self.add_command('devenv', mdevenv.add_arguments, mdevenv.run,
                         help_msg='Run commands in developer environment')
        self.add_command('env2mfile', env2mfile.add_arguments, env2mfile.run,
                         help_msg='Convert current environment to a cross or native file')
        # Add new commands above this line to list them in help command
        self.add_command('help', self.add_help_arguments, self.run_help_command,
                         help_msg='Print help of a subcommand')

        # 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: argparse.ArgumentParser):
        parser.add_argument('-c', action='store_true', dest='eval_arg', default=False)
        parser.add_argument('--version', action='version', version=platform.python_version())
        parser.add_argument('script_file')
        parser.add_argument('script_args', nargs=argparse.REMAINDER)

    def run_runpython_command(self, options):
        sys.argv[1:] = options.script_args
        if options.eval_arg:
            exec(options.script_file)
        else:
            import runpy
            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='?', choices=list(self.commands.keys()))

    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):
        implicit_setup_command_notice = False
        # 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:
            implicit_setup_command_notice = True
            args = ['setup'] + args

        # Hidden commands have their own parser instead of using the global one
        if args[0] in self.hidden_commands:
            command = args[0]
            parser = self.commands[command]
            args = args[1:]
        else:
            parser = self.parser
            command = None

        from . import mesonlib
        args = mesonlib.expand_arguments(args)
        options = parser.parse_args(args)

        if command is None:
            command = options.command

        # Bump the version here in order to add a pre-exit warning that we are phasing out
        # support for old python. If this is already the oldest supported version, then
        # this can never be true and does nothing.
        pending_python_deprecation_notice = \
            command in {'setup', 'compile', 'test', 'install'} and sys.version_info < (3, 7)

        try:
            return options.run_func(options)
        except Exception as e:
            return errorhandler(e, command)
        finally:
            if implicit_setup_command_notice:
                mlog.warning('Running the setup command as `meson [options]` instead of '
                             '`meson setup [options]` is ambiguous and deprecated.', fatal=False)
            if pending_python_deprecation_notice:
                mlog.notice('You are using Python 3.6 which is EOL. Starting with v0.62.0, '
                            'Meson will require Python 3.7 or newer', fatal=False)
            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(f'Error in {script_name} helper script:')
        mlog.exception(e)
        return 1

def ensure_stdout_accepts_unicode():
    if sys.stdout.encoding and not sys.stdout.encoding.upper().startswith('UTF-'):
        sys.stdout.reconfigure(errors='surrogateescape')

def set_meson_command(mainfile):
    # Set the meson command that will be used to run scripts and so on
    from . import mesonlib
    mesonlib.set_meson_command(mainfile)

def run(original_args, mainfile):
    if os.environ.get('MESON_SHOW_DEPRECATIONS'):
        # workaround for https://bugs.python.org/issue34624
        import warnings
        for typ in [DeprecationWarning, SyntaxWarning, FutureWarning, PendingDeprecationWarning]:
            warnings.filterwarnings('error', category=typ, module='mesonbuild')
        warnings.filterwarnings('ignore', message=".*importlib-resources.*")

    if sys.version_info >= (3, 10) and os.environ.get('MESON_RUNNING_IN_PROJECT_TESTS'):
        # workaround for https://bugs.python.org/issue34624
        import warnings
        warnings.filterwarnings('error', category=EncodingWarning, module='mesonbuild')
        # python 3.11 adds a warning that in 3.15, UTF-8 mode will be default.
        # This is fantastic news, we'd love that. Less fantastic: this warning is silly,
        # we *want* these checks to be affected. Plus, the recommended alternative API
        # would (in addition to warning people when UTF-8 mode removed the problem) also
        # require using a minimum python version of 3.11 (in which the warning was added)
        # or add verbose if/else soup.
        warnings.filterwarnings('ignore', message="UTF-8 Mode affects .*getpreferredencoding", category=EncodingWarning)

    # 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 == 'cygwin' and os.environ.get('MSYSTEM', '') not in ['MSYS', '']:
        mlog.error('This python3 seems to be msys/python on MSYS2 Windows, but you are in a MinGW environment')
        mlog.error('Please install and use mingw-w64-x86_64-python3 and/or mingw-w64-x86_64-meson with Pacman')
        return 2

    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':
            set_meson_command(mainfile)
            from . import msetup
            try:
                return msetup.run(['--reconfigure'] + args[2:])
            except Exception as e:
                return errorhandler(e, 'setup')
        else:
            return run_script_command(args[1], args[2:])

    set_meson_command(mainfile)
    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.abspath(sys.argv[0])
    return run(sys.argv[1:], launcher)

if __name__ == '__main__':
    sys.exit(main())
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/minit.py0000644000175000017500000002110114562742363016672 0ustar00jpakkanejpakkane# 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 __future__ import annotations

from pathlib import Path
from enum import Enum
import subprocess
import shutil
import sys
import os
import re
from glob import glob
import typing as T

from mesonbuild import build, mesonlib, mlog
from mesonbuild.coredata import FORBIDDEN_TARGET_NAMES
from mesonbuild.environment import detect_ninja
from mesonbuild.templates.mesontemplates import create_meson_build
from mesonbuild.templates.samplefactory import sample_generator

if T.TYPE_CHECKING:
    import argparse

    from typing_extensions import Protocol, Literal

    class Arguments(Protocol):

        srcfiles: T.List[Path]
        wd: str
        name: str
        executable: str
        deps: str
        language: Literal['c', 'cpp', 'cs', 'cuda', 'd', 'fortran', 'java', 'rust', 'objc', 'objcpp', 'vala']
        build: bool
        builddir: str
        force: bool
        type: Literal['executable', 'library']
        version: str


FORTRAN_SUFFIXES = {'.f', '.for', '.F', '.f90', '.F90'}
LANG_SUFFIXES = {'.c', '.cc', '.cpp', '.cs', '.cu', '.d', '.m', '.mm', '.rs', '.java', '.vala'} | FORTRAN_SUFFIXES
LANG_SUPPORTED = {'c', 'cpp', 'cs', 'cuda', 'd', 'fortran', 'java', 'rust', 'objc', 'objcpp', 'vala'}

DEFAULT_PROJECT = 'executable'
DEFAULT_VERSION = '0.1'
class DEFAULT_TYPES(Enum):
    EXE = 'executable'
    LIB = 'library'

INFO_MESSAGE = '''Sample project created. To build it run the
following commands:

meson setup builddir
meson compile -C builddir
'''


def create_sample(options: Arguments) -> None:
    '''
    Based on what arguments are passed we check for a match in language
    then check for project type and create new Meson samples project.
    '''
    sample_gen = sample_generator(options)
    if options.type == DEFAULT_TYPES['EXE'].value:
        sample_gen.create_executable()
    elif options.type == DEFAULT_TYPES['LIB'].value:
        sample_gen.create_library()
    else:
        raise RuntimeError('Unreachable code')
    print(INFO_MESSAGE)

def autodetect_options(options: Arguments, sample: bool = False) -> None:
    '''
    Here we autodetect options for args not passed in so don't have to
    think about it.
    '''
    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(f'Name of current directory "{options.name}" is not usable as a sample project name.\n'
                             'Specify a project name with --name.')
        print(f'Using "{options.name}" (name of current directory) as project name.')
    if not options.executable:
        options.executable = options.name
        print(f'Using "{options.executable}" (project name) as name of executable to build.')
    if options.executable in FORBIDDEN_TARGET_NAMES:
        raise mesonlib.MesonException(f'Executable name {options.executable!r} is reserved for Meson internal use. '
                                      'Refusing to init an invalid project.')
    if sample:
        # The rest of the autodetection is not applicable to generating sample projects.
        return
    if not options.srcfiles:
        srcfiles: T.List[Path] = []
        for f in (f for f in Path().iterdir() if f.is_file()):
            if f.suffix in LANG_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(str(s) for s in srcfiles))
    if not options.language:
        for f in options.srcfiles:
            if f.suffix == '.c':
                options.language = 'c'
                break
            if f.suffix in {'.cc', '.cpp'}:
                options.language = 'cpp'
                break
            if f.suffix == '.cs':
                options.language = 'cs'
                break
            if f.suffix == '.cu':
                options.language = 'cuda'
                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 f.suffix == '.mm':
                options.language = 'objcpp'
                break
            if f.suffix == '.java':
                options.language = 'java'
                break
            if f.suffix == '.vala':
                options.language = 'vala'
                break
        if not options.language:
            raise SystemExit("Can't autodetect language, please specify it with -l.")
        print("Detected language: " + options.language)

# Note: when adding arguments, please also add them to the completion
# scripts in $MESONSRC/data/shell-completions/
def add_arguments(parser: 'argparse.ArgumentParser') -> None:
    '''
    Here we add args for that the user can passed when making a new
    Meson project.
    '''
    parser.add_argument("srcfiles", metavar="sourcefile", nargs="*", type=Path, help="source files. default: all recognized files in current directory")
    parser.add_argument('-C', dest='wd', action=mesonlib.RealPathAction,
                        help='directory to cd into before running')
    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=sorted(LANG_SUPPORTED), help="project language. default: autodetected based on source files")
    parser.add_argument("-b", "--build", action='store_true', help="build after generation")
    parser.add_argument("--builddir", default='build', help="directory for build")
    parser.add_argument("-f", "--force", action="store_true", help="force overwrite of existing files and directories.")
    parser.add_argument('--type', default=DEFAULT_PROJECT, choices=('executable', 'library'), help=f"project type. default: {DEFAULT_PROJECT} based project")
    parser.add_argument('--version', default=DEFAULT_VERSION, help=f"project version. default: {DEFAULT_VERSION}")

def run(options: Arguments) -> int:
    '''
    Here we generate the new Meson sample project.
    '''
    if not Path(options.wd).exists():
        sys.exit('Project source root directory not found. Run this command in source directory root.')
    os.chdir(options.wd)

    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.get_meson_command() + ['setup', options.builddir]
        ret = subprocess.run(cmd)
        if ret.returncode:
            raise SystemExit

        b = build.load(options.builddir)
        need_vsenv = T.cast('bool', b.environment.coredata.get_option(mesonlib.OptionKey('vsenv')))
        vsenv_active = mesonlib.setup_vsenv(need_vsenv)
        if vsenv_active:
            mlog.log(mlog.green('INFO:'), 'automatically activated MSVC compiler environment')

        cmd = detect_ninja() + ['-C', options.builddir]
        ret = subprocess.run(cmd)
        if ret.returncode:
            raise SystemExit
    return 0
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/minstall.py0000644000175000017500000011475414562742363017416 0ustar00jpakkanejpakkane# 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.
from __future__ import annotations

from glob import glob
import argparse
import errno
import os
import selectors
import shlex
import shutil
import subprocess
import sys
import typing as T
import re

from . import build, environment
from .backend.backends import InstallData
from .mesonlib import (MesonException, Popen_safe, RealPathAction, is_windows,
                       is_aix, setup_vsenv, pickle_load, is_osx, OptionKey)
from .scripts import depfixer, destdir_join
from .scripts.meson_exe import run_exe
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

if T.TYPE_CHECKING:
    from .backend.backends import (
            InstallDataBase, InstallEmptyDir,
            InstallSymlinkData, TargetInstallData
    )
    from .mesonlib import FileMode, EnvironOrDict, ExecutableSerialisation

    try:
        from typing import Protocol
    except AttributeError:
        from typing_extensions import Protocol  # type: ignore

    class ArgumentType(Protocol):
        """Typing information for the object returned by argparse."""
        no_rebuild: bool
        only_changed: bool
        profile: bool
        quiet: bool
        wd: str
        destdir: str
        dry_run: bool
        skip_subprojects: str
        tags: str
        strip: bool


symlink_warning = '''\
Warning: trying to copy a symlink that points to a file. This currently copies
the file by default, but will be changed in a future version of Meson to copy
the link instead.  Set follow_symlinks to true to preserve current behavior, or
false to copy the link.'''

selinux_updates: T.List[str] = []

# Note: when adding arguments, please also add them to the completion
# scripts in $MESONSRC/data/shell-completions/
def add_arguments(parser: argparse.ArgumentParser) -> None:
    parser.add_argument('-C', dest='wd', action=RealPathAction,
                        help='directory to cd into before running')
    parser.add_argument('--profile-self', action='store_true', dest='profile',
                        help=argparse.SUPPRESS)
    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.')
    parser.add_argument('--quiet', default=False, action='store_true',
                        help='Do not print every file that was installed.')
    parser.add_argument('--destdir', default=None,
                        help='Sets or overrides DESTDIR environment. (Since 0.57.0)')
    parser.add_argument('--dry-run', '-n', action='store_true',
                        help='Doesn\'t actually install, but print logs. (Since 0.57.0)')
    parser.add_argument('--skip-subprojects', nargs='?', const='*', default='',
                        help='Do not install files from given subprojects. (Since 0.58.0)')
    parser.add_argument('--tags', default=None,
                        help='Install only targets having one of the given tags. (Since 0.60.0)')
    parser.add_argument('--strip', action='store_true',
                        help='Strip targets even if strip option was not set during configure. (Since 0.62.0)')

class DirMaker:
    def __init__(self, lf: T.TextIO, makedirs: T.Callable[..., None]):
        self.lf = lf
        self.dirs: T.List[str] = []
        self.all_dirs: T.Set[str] = set()
        self.makedirs_impl = makedirs

    def makedirs(self, path: str, exist_ok: bool = False) -> None:
        dirname = os.path.normpath(path)
        self.all_dirs.add(dirname)
        dirs = []
        while dirname != os.path.dirname(dirname):
            if dirname in self.dirs:
                # In dry-run mode the directory does not exist but we would have
                # created it with all its parents otherwise.
                break
            if not os.path.exists(dirname):
                dirs.append(dirname)
            dirname = os.path.dirname(dirname)
        self.makedirs_impl(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) -> 'DirMaker':
        return self

    def __exit__(self, exception_type: T.Type[Exception], value: T.Any, traceback: T.Any) -> None:
        self.dirs.reverse()
        for d in self.dirs:
            append_to_log(self.lf, d)


def load_install_data(fname: str) -> InstallData:
    return pickle_load(fname, 'InstallData', InstallData)

def is_executable(path: str, follow_symlinks: bool = False) -> bool:
    '''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: T.TextIO, line: str) -> None:
    lf.write(line)
    if not line.endswith('\n'):
        lf.write('\n')
    lf.flush()


def set_chown(path: str, user: T.Union[str, int, None] = None,
              group: T.Union[str, int, None] = None,
              dir_fd: T.Optional[int] = None, follow_symlinks: bool = True) -> None:
    # 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

    def chown(path: T.Union[int, str, 'os.PathLike[str]', bytes, 'os.PathLike[bytes]'],
              uid: int, gid: int, *, dir_fd: T.Optional[int] = dir_fd,
              follow_symlinks: bool = follow_symlinks) -> None:
        """Override the default behavior of os.chown

        Use a real function rather than a lambda to help mypy out. Also real
        functions are faster.
        """
        real_os_chown(path, uid, gid, dir_fd=dir_fd, follow_symlinks=follow_symlinks)

    try:
        os.chown = chown
        shutil.chown(path, user, group)
    finally:
        os.chown = real_os_chown


def set_chmod(path: str, mode: int, dir_fd: T.Optional[int] = None,
              follow_symlinks: bool = True) -> None:
    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: str, umask: T.Union[str, int]) -> None:
    # TODO: with python 3.8 or typing_extensions we could replace this with
    # `umask: T.Union[T.Literal['preserve'], int]`, which would be more correct
    if umask == 'preserve':
        return
    assert isinstance(umask, int), 'umask should only be "preserver" or an integer'
    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:
        print(f'{path!r}: Unable to set permissions {new_perms!r}: {e.strerror}, ignoring...')


def set_mode(path: str, mode: T.Optional['FileMode'], default_umask: T.Union[str, int]) -> None:
    if mode is None or all(m is None for m in [mode.perms_s, mode.owner, mode.group]):
        # 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 is not None or mode.group is not None):
        try:
            set_chown(path, mode.owner, mode.group, follow_symlinks=False)
        except PermissionError as e:
            print(f'{path!r}: Unable to set owner {mode.owner!r} and group {mode.group!r}: {e.strerror}, ignoring...')
        except LookupError:
            print(f'{path!r}: Nonexistent owner {mode.owner!r} or group {mode.group!r}: ignoring...')
        except OSError as e:
            if e.errno == errno.EINVAL:
                print(f'{path!r}: Nonexistent numeric owner {mode.owner!r} or group {mode.group!r}: ignoring...')
            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:
            print(f'{path!r}: Unable to set permissions {mode.perms_s!r}: {e.strerror}, ignoring...')
    else:
        sanitize_permissions(path, default_umask)


def restore_selinux_contexts() -> None:
    '''
    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, OSError, 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

    if not selinux_updates:
        # If the list of files is empty, do not try to call restorecon.
        return

    proc, out, err = Popen_safe(['restorecon', '-F', '-f-', '-0'], ('\0'.join(f for f in selinux_updates) + '\0'))
    if proc.returncode != 0:
        print('Failed to restore SELinux context of installed files...',
              'Standard output:', out,
              'Standard error:', err, sep='\n')

def get_destdir_path(destdir: str, fullprefix: str, path: str) -> str:
    if os.path.isabs(path):
        output = destdir_join(destdir, path)
    else:
        output = os.path.join(fullprefix, path)
    return output


def check_for_stampfile(fname: str) -> str:
    '''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: 'ArgumentType', lf: T.TextIO):
        self.did_install_something = False
        self.printed_symlink_error = False
        self.options = options
        self.lf = lf
        self.preserved_file_count = 0
        self.dry_run = options.dry_run
        # [''] means skip none,
        # ['*'] means skip all,
        # ['sub1', ...] means skip only those.
        self.skip_subprojects = [i.strip() for i in options.skip_subprojects.split(',')]
        self.tags = [i.strip() for i in options.tags.split(',')] if options.tags else None

    def remove(self, *args: T.Any, **kwargs: T.Any) -> None:
        if not self.dry_run:
            os.remove(*args, **kwargs)

    def symlink(self, *args: T.Any, **kwargs: T.Any) -> None:
        if not self.dry_run:
            os.symlink(*args, **kwargs)

    def makedirs(self, *args: T.Any, **kwargs: T.Any) -> None:
        if not self.dry_run:
            os.makedirs(*args, **kwargs)

    def copy(self, *args: T.Any, **kwargs: T.Any) -> None:
        if not self.dry_run:
            shutil.copy(*args, **kwargs)

    def copy2(self, *args: T.Any, **kwargs: T.Any) -> None:
        if not self.dry_run:
            shutil.copy2(*args, **kwargs)

    def copyfile(self, *args: T.Any, **kwargs: T.Any) -> None:
        if not self.dry_run:
            shutil.copyfile(*args, **kwargs)

    def copystat(self, *args: T.Any, **kwargs: T.Any) -> None:
        if not self.dry_run:
            shutil.copystat(*args, **kwargs)

    def fix_rpath(self, *args: T.Any, **kwargs: T.Any) -> None:
        if not self.dry_run:
            depfixer.fix_rpath(*args, **kwargs)

    def set_chown(self, *args: T.Any, **kwargs: T.Any) -> None:
        if not self.dry_run:
            set_chown(*args, **kwargs)

    def set_chmod(self, *args: T.Any, **kwargs: T.Any) -> None:
        if not self.dry_run:
            set_chmod(*args, **kwargs)

    def sanitize_permissions(self, *args: T.Any, **kwargs: T.Any) -> None:
        if not self.dry_run:
            sanitize_permissions(*args, **kwargs)

    def set_mode(self, *args: T.Any, **kwargs: T.Any) -> None:
        if not self.dry_run:
            set_mode(*args, **kwargs)

    def restore_selinux_contexts(self, destdir: str) -> None:
        if not self.dry_run and not destdir:
            restore_selinux_contexts()

    def Popen_safe(self, *args: T.Any, **kwargs: T.Any) -> T.Tuple[int, str, str]:
        if not self.dry_run:
            p, o, e = Popen_safe(*args, **kwargs)
            return p.returncode, o, e
        return 0, '', ''

    def run_exe(self, exe: ExecutableSerialisation, extra_env: T.Optional[T.Dict[str, str]] = None) -> int:
        if (not self.dry_run) or exe.dry_run:
            return run_exe(exe, extra_env)
        return 0

    def should_install(self, d: T.Union[TargetInstallData, InstallEmptyDir,
                                        InstallDataBase, InstallSymlinkData,
                                        ExecutableSerialisation]) -> bool:
        if d.subproject and (d.subproject in self.skip_subprojects or '*' in self.skip_subprojects):
            return False
        if self.tags and d.tag not in self.tags:
            return False
        return True

    def log(self, msg: str) -> None:
        if not self.options.quiet:
            print(msg)

    def should_preserve_existing_file(self, from_file: str, to_file: str) -> bool:
        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: str, to_file: str,
                    makedirs: T.Optional[T.Tuple[T.Any, str]] = None,
                    follow_symlinks: T.Optional[bool] = None) -> bool:
        outdir = os.path.split(to_file)[0]
        if not os.path.isfile(from_file) and not os.path.islink(from_file):
            raise MesonException(f'Tried to install something that isn\'t a file: {from_file!r}')
        # 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 MesonException(f'Destination {to_file!r} already exists and is not a file')
            if self.should_preserve_existing_file(from_file, to_file):
                append_to_log(self.lf, f'# Preserving old file {to_file}\n')
                self.preserved_file_count += 1
                return False
            self.log(f'Installing {from_file} to {outdir}')
            self.remove(to_file)
        else:
            self.log(f'Installing {from_file} to {outdir}')
            if makedirs:
                # Unpack tuple
                dirmaker, outdir = makedirs
                # Create dirs if needed
                dirmaker.makedirs(outdir, exist_ok=True)
        if os.path.islink(from_file):
            if not os.path.exists(from_file):
                # Dangling symlink. Replicate as is.
                self.copy(from_file, outdir, follow_symlinks=False)
            else:
                if follow_symlinks is None:
                    follow_symlinks = True  # TODO: change to False when removing the warning
                    print(symlink_warning)
                self.copy2(from_file, to_file, follow_symlinks=follow_symlinks)
        else:
            self.copy2(from_file, to_file)
        selinux_updates.append(to_file)
        append_to_log(self.lf, to_file)
        return True

    def do_symlink(self, target: str, link: str, destdir: str, full_dst_dir: str, allow_missing: bool) -> bool:
        abs_target = target
        if not os.path.isabs(target):
            abs_target = os.path.join(full_dst_dir, target)
        elif not os.path.exists(abs_target) and not allow_missing:
            abs_target = destdir_join(destdir, abs_target)
        if not os.path.exists(abs_target) and not allow_missing:
            raise MesonException(f'Tried to install symlink to missing file {abs_target}')
        if os.path.exists(link):
            if not os.path.islink(link):
                raise MesonException(f'Destination {link!r} already exists and is not a symlink')
            self.remove(link)
        if not self.printed_symlink_error:
            self.log(f'Installing symlink pointing to {target} to {link}')
        try:
            self.symlink(target, link, target_is_directory=os.path.isdir(abs_target))
        except (NotImplementedError, OSError):
            if not self.printed_symlink_error:
                print("Symlink creation does not work on this platform. "
                      "Skipping all symlinking.")
                self.printed_symlink_error = True
            return False
        append_to_log(self.lf, link)
        return True

    def do_copydir(self, data: InstallData, src_dir: str, dst_dir: str,
                   exclude: T.Optional[T.Tuple[T.Set[str], T.Set[str]]],
                   install_mode: 'FileMode', dm: DirMaker, follow_symlinks: T.Optional[bool] = None) -> None:
        '''
        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(f'src_dir must be absolute, got {src_dir}')
        if not os.path.isabs(dst_dir):
            raise ValueError(f'dst_dir must be absolute, got {dst_dir}')
        if exclude is not None:
            exclude_files, exclude_dirs = exclude
            exclude_files = {os.path.normpath(x) for x in exclude_files}
            exclude_dirs = {os.path.normpath(x) for x in exclude_dirs}
        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(f'Tried to copy directory {abs_dst} but a file of that name already exists.')
                    sys.exit(1)
                dm.makedirs(abs_dst)
                self.copystat(abs_src, abs_dst)
                self.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(f'Tried to copy file {abs_dst} but a directory of that name already exists.')
                    sys.exit(1)
                parent_dir = os.path.dirname(abs_dst)
                if not os.path.isdir(parent_dir):
                    dm.makedirs(parent_dir)
                    self.copystat(os.path.dirname(abs_src), parent_dir)
                # FIXME: what about symlinks?
                self.do_copyfile(abs_src, abs_dst, follow_symlinks=follow_symlinks)
                self.set_mode(abs_dst, install_mode, data.install_umask)

    def do_install(self, datafilename: str) -> None:
        d = load_install_data(datafilename)

        destdir = self.options.destdir
        if destdir is None:
            destdir = os.environ.get('DESTDIR')
        if destdir and not os.path.isabs(destdir):
            destdir = os.path.join(d.build_dir, destdir)
        # Override in the env because some scripts could use it and require an
        # absolute path.
        if destdir is not None:
            os.environ['DESTDIR'] = destdir
        destdir = destdir or ''
        fullprefix = destdir_join(destdir, d.prefix)

        if d.install_umask != 'preserve':
            assert isinstance(d.install_umask, int)
            os.umask(d.install_umask)

        self.did_install_something = False
        try:
            with DirMaker(self.lf, self.makedirs) as dm:
                self.install_subdirs(d, dm, destdir, fullprefix) # Must be first, because it needs to delete the old subtree.
                self.install_targets(d, dm, destdir, fullprefix)
                self.install_headers(d, dm, destdir, fullprefix)
                self.install_man(d, dm, destdir, fullprefix)
                self.install_emptydir(d, dm, destdir, fullprefix)
                self.install_data(d, dm, destdir, fullprefix)
                self.install_symlinks(d, dm, destdir, fullprefix)
                self.restore_selinux_contexts(destdir)
                self.run_install_script(d, destdir, fullprefix)
                if not self.did_install_something:
                    self.log('Nothing to install.')
                if not self.options.quiet and self.preserved_file_count > 0:
                    self.log('Preserved {} unchanged files, see {} for the full list'
                             .format(self.preserved_file_count, os.path.normpath(self.lf.name)))
        except PermissionError:
            if is_windows() or destdir != '' or not os.isatty(sys.stdout.fileno()) or not os.isatty(sys.stderr.fileno()):
                # can't elevate to root except in an interactive unix environment *and* when not doing a destdir install
                raise
            rootcmd = os.environ.get('MESON_ROOT_CMD') or shutil.which('sudo') or shutil.which('doas')
            pkexec = shutil.which('pkexec')
            if rootcmd is None and pkexec is not None and 'PKEXEC_UID' not in os.environ:
                rootcmd = pkexec

            if rootcmd is not None:
                print('Installation failed due to insufficient permissions.')
                s = selectors.DefaultSelector()
                s.register(sys.stdin, selectors.EVENT_READ)
                ans = None
                for attempt in range(5):
                    print(f'Attempt to use {rootcmd} to gain elevated privileges? [y/n] ', end='', flush=True)
                    if s.select(30):
                        # we waited on sys.stdin *only*
                        ans = sys.stdin.readline().rstrip('\n')
                    else:
                        print()
                        break
                    if ans in {'y', 'n'}:
                        break
                else:
                    if ans is not None:
                        raise MesonException('Answer not one of [y/n]')
                if ans == 'y':
                    os.execlp(rootcmd, rootcmd, sys.executable, main_file, *sys.argv[1:],
                              '-C', os.getcwd(), '--no-rebuild')
            raise

    def do_strip(self, strip_bin: T.List[str], fname: str, outname: str) -> None:
        self.log(f'Stripping target {fname!r}.')
        if is_osx():
            # macOS expects dynamic objects to be stripped with -x maximum.
            # To also strip the debug info, -S must be added.
            # See: https://www.unix.com/man-page/osx/1/strip/
            returncode, stdo, stde = self.Popen_safe(strip_bin + ['-S', '-x', outname])
        else:
            returncode, stdo, stde = self.Popen_safe(strip_bin + [outname])
        if returncode != 0:
            print('Could not strip file.\n')
            print(f'Stdout:\n{stdo}\n')
            print(f'Stderr:\n{stde}\n')
            sys.exit(1)

    def install_subdirs(self, d: InstallData, dm: DirMaker, destdir: str, fullprefix: str) -> None:
        for i in d.install_subdirs:
            if not self.should_install(i):
                continue
            self.did_install_something = True
            full_dst_dir = get_destdir_path(destdir, fullprefix, i.install_path)
            self.log(f'Installing subdir {i.path} to {full_dst_dir}')
            dm.makedirs(full_dst_dir, exist_ok=True)
            self.do_copydir(d, i.path, full_dst_dir, i.exclude, i.install_mode, dm,
                            follow_symlinks=i.follow_symlinks)

    def install_data(self, d: InstallData, dm: DirMaker, destdir: str, fullprefix: str) -> None:
        for i in d.data:
            if not self.should_install(i):
                continue
            fullfilename = i.path
            outfilename = get_destdir_path(destdir, fullprefix, i.install_path)
            outdir = os.path.dirname(outfilename)
            if self.do_copyfile(fullfilename, outfilename, makedirs=(dm, outdir), follow_symlinks=i.follow_symlinks):
                self.did_install_something = True
            self.set_mode(outfilename, i.install_mode, d.install_umask)

    def install_symlinks(self, d: InstallData, dm: DirMaker, destdir: str, fullprefix: str) -> None:
        for s in d.symlinks:
            if not self.should_install(s):
                continue
            full_dst_dir = get_destdir_path(destdir, fullprefix, s.install_path)
            full_link_name = get_destdir_path(destdir, fullprefix, s.name)
            dm.makedirs(full_dst_dir, exist_ok=True)
            if self.do_symlink(s.target, full_link_name, destdir, full_dst_dir, s.allow_missing):
                self.did_install_something = True

    def install_man(self, d: InstallData, dm: DirMaker, destdir: str, fullprefix: str) -> None:
        for m in d.man:
            if not self.should_install(m):
                continue
            full_source_filename = m.path
            outfilename = get_destdir_path(destdir, fullprefix, m.install_path)
            outdir = os.path.dirname(outfilename)
            if self.do_copyfile(full_source_filename, outfilename, makedirs=(dm, outdir)):
                self.did_install_something = True
            self.set_mode(outfilename, m.install_mode, d.install_umask)

    def install_emptydir(self, d: InstallData, dm: DirMaker, destdir: str, fullprefix: str) -> None:
        for e in d.emptydir:
            if not self.should_install(e):
                continue
            self.did_install_something = True
            full_dst_dir = get_destdir_path(destdir, fullprefix, e.path)
            self.log(f'Installing new directory {full_dst_dir}')
            if os.path.isfile(full_dst_dir):
                print(f'Tried to create directory {full_dst_dir} but a file of that name already exists.')
                sys.exit(1)
            dm.makedirs(full_dst_dir, exist_ok=True)
            self.set_mode(full_dst_dir, e.install_mode, d.install_umask)

    def install_headers(self, d: InstallData, dm: DirMaker, destdir: str, fullprefix: str) -> None:
        for t in d.headers:
            if not self.should_install(t):
                continue
            fullfilename = t.path
            fname = os.path.basename(fullfilename)
            outdir = get_destdir_path(destdir, fullprefix, t.install_path)
            outfilename = os.path.join(outdir, fname)
            if self.do_copyfile(fullfilename, outfilename, makedirs=(dm, outdir),
                                follow_symlinks=t.follow_symlinks):
                self.did_install_something = True
            self.set_mode(outfilename, t.install_mode, d.install_umask)

    def run_install_script(self, d: InstallData, destdir: str, fullprefix: str) -> None:
        env = {'MESON_SOURCE_ROOT': d.source_dir,
               'MESON_BUILD_ROOT': d.build_dir,
               'MESONINTROSPECT': ' '.join([shlex.quote(x) for x in d.mesonintrospect]),
               }
        if self.options.quiet:
            env['MESON_INSTALL_QUIET'] = '1'
        if self.dry_run:
            env['MESON_INSTALL_DRY_RUN'] = '1'

        for i in d.install_scripts:
            if not self.should_install(i):
                continue

            if i.installdir_map is not None:
                mapp = i.installdir_map
            else:
                mapp = {'prefix': d.prefix}
            localenv = env.copy()
            localenv.update({'MESON_INSTALL_'+k.upper(): os.path.join(d.prefix, v) for k, v in mapp.items()})
            localenv.update({'MESON_INSTALL_DESTDIR_'+k.upper(): get_destdir_path(destdir, fullprefix, v) for k, v in mapp.items()})

            name = ' '.join(i.cmd_args)
            if i.skip_if_destdir and destdir:
                self.log(f'Skipping custom install script because DESTDIR is set {name!r}')
                continue
            self.did_install_something = True  # Custom script must report itself if it does nothing.
            self.log(f'Running custom install script {name!r}')
            try:
                rc = self.run_exe(i, localenv)
            except OSError:
                print(f'FAILED: install script \'{name}\' could not be run, stopped')
                # POSIX shells return 127 when a command could not be found
                sys.exit(127)
            if rc != 0:
                print(f'FAILED: install script \'{name}\' exit code {rc}, stopped')
                sys.exit(rc)

    def install_targets(self, d: InstallData, dm: DirMaker, destdir: str, fullprefix: str) -> None:
        for t in d.targets:
            # In AIX, we archive our shared libraries.  When we install any package in AIX we need to
            # install the archive in which the shared library exists. The below code does the same.
            # We change the .so files having lt_version or so_version to archive file install.
            # If .so does not exist then it means it is in the archive. Otherwise it is a .so that exists.
            if is_aix():
                if not os.path.exists(t.fname) and '.so' in t.fname:
                    t.fname = re.sub('[.][a]([.]?([0-9]+))*([.]?([a-z]+))*', '.a', t.fname.replace('.so', '.a'))
            if not self.should_install(t):
                continue
            if not os.path.exists(t.fname):
                # For example, import libraries of shared modules are optional
                if t.optional:
                    self.log(f'File {t.fname!r} not found, skipping')
                    continue
                else:
                    raise MesonException(f'File {t.fname!r} could not be found')
            file_copied = False # not set when a directory is copied
            fname = check_for_stampfile(t.fname)
            outdir = get_destdir_path(destdir, fullprefix, t.outdir)
            outname = os.path.join(outdir, os.path.basename(fname))
            final_path = os.path.join(d.prefix, t.outdir, os.path.basename(fname))
            should_strip = t.strip or (t.can_strip and self.options.strip)
            install_rpath = t.install_rpath
            install_name_mappings = t.install_name_mappings
            install_mode = t.install_mode
            if not os.path.exists(fname):
                raise MesonException(f'File {fname!r} could not be found')
            elif os.path.isfile(fname):
                file_copied = self.do_copyfile(fname, outname, makedirs=(dm, outdir))
                if should_strip and d.strip_bin is not None:
                    if fname.endswith('.jar'):
                        self.log('Not stripping jar target: {}'.format(os.path.basename(fname)))
                        continue
                    self.do_strip(d.strip_bin, fname, outname)
                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'
                        file_copied = 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))
                dm.makedirs(outdir, exist_ok=True)
                self.do_copydir(d, fname, outname, None, install_mode, dm)
            else:
                raise RuntimeError(f'Unknown file type for {fname!r}')
            if file_copied:
                self.did_install_something = True
                try:
                    self.fix_rpath(outname, t.rpath_dirs_to_remove, 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
                # file mode needs to be set last, after strip/depfixer editing
                self.set_mode(outname, install_mode, d.install_umask)

def rebuild_all(wd: str, backend: str) -> bool:
    if backend == 'none':
        # nothing to build...
        return True
    if backend != 'ninja':
        print('Only ninja backend is supported to rebuild the project before installation.')
        return True

    ninja = environment.detect_ninja()
    if not ninja:
        print("Can't find ninja, can't rebuild test.")
        return False

    def drop_privileges() -> T.Tuple[T.Optional[EnvironOrDict], T.Optional[T.Callable[[], None]]]:
        if not is_windows() and os.geteuid() == 0:
            import pwd
            env = os.environ.copy()

            if os.environ.get('SUDO_USER') is not None:
                orig_user = env.pop('SUDO_USER')
                orig_uid = env.pop('SUDO_UID', 0)
                orig_gid = env.pop('SUDO_GID', 0)
                try:
                    homedir = pwd.getpwuid(int(orig_uid)).pw_dir
                except KeyError:
                    # `sudo chroot` leaves behind stale variable and builds as root without a user
                    return None, None
            elif os.environ.get('DOAS_USER') is not None:
                orig_user = env.pop('DOAS_USER')
                try:
                    pwdata = pwd.getpwnam(orig_user)
                except KeyError:
                    # `doas chroot` leaves behind stale variable and builds as root without a user
                    return None, None
                orig_uid = pwdata.pw_uid
                orig_gid = pwdata.pw_gid
                homedir = pwdata.pw_dir
            else:
                return None, None

            if os.stat(os.path.join(wd, 'build.ninja')).st_uid != int(orig_uid):
                # the entire build process is running with sudo, we can't drop privileges
                return None, None

            env['USER'] = orig_user
            env['HOME'] = homedir

            def wrapped() -> None:
                print(f'Dropping privileges to {orig_user!r} before running ninja...')
                if orig_gid is not None:
                    os.setgid(int(orig_gid))
                if orig_uid is not None:
                    os.setuid(int(orig_uid))

            return env, wrapped
        else:
            return None, None

    env, preexec_fn = drop_privileges()
    ret = subprocess.run(ninja + ['-C', wd], env=env, preexec_fn=preexec_fn).returncode
    if ret != 0:
        print(f'Could not rebuild {wd}')
        return False

    return True


def run(opts: 'ArgumentType') -> int:
    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:
        b = build.load(opts.wd)
        need_vsenv = T.cast('bool', b.environment.coredata.get_option(OptionKey('vsenv')))
        setup_vsenv(need_vsenv)
        backend = T.cast('str', b.environment.coredata.get_option(OptionKey('backend')))
        if not rebuild_all(opts.wd, backend):
            sys.exit(-1)
    os.chdir(opts.wd)
    with open(os.path.join(log_dir, 'install-log.txt'), 'w', encoding='utf-8') 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.')
        if opts.profile:
            import cProfile as profile
            fname = os.path.join(private_dir, 'profile-installer.log')
            profile.runctx('installer.do_install(datafilename)', globals(), locals(), filename=fname)
        else:
            installer.do_install(datafilename)
    return 0
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/mintro.py0000644000175000017500000007431314562742363017077 0ustar00jpakkanejpakkane# 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 __future__ import annotations

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

from contextlib import redirect_stdout
import collections
import dataclasses
import json
import os
from pathlib import Path, PurePath
import sys
import typing as T

from . import build, mesonlib, coredata as cdata
from .ast import IntrospectionInterpreter, BUILD_TARGET_FUNCTIONS, AstConditionLevel, AstIDGenerator, AstIndentationGenerator, AstJSONPrinter
from .backend import backends
from .dependencies import Dependency
from . import environment
from .interpreterbase import ObjectHolder
from .mesonlib import OptionKey
from .mparser import FunctionNode, ArrayNode, ArgumentNode, BaseStringNode

if T.TYPE_CHECKING:
    import argparse

    from .interpreter import Interpreter
    from .mparser import BaseNode

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) -> 'T.Mapping[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()
        interpreter = backend.interpreter
    else:
        benchmarkdata = testdata = installdata = None

    # Enforce key order for argparse
    return collections.OrderedDict([
        ('ast', IntroCommand('Dump the AST of the meson file', no_bd=dump_ast)),
        ('benchmarks', IntroCommand('List all benchmarks', func=lambda: list_benchmarks(benchmarkdata))),
        ('buildoptions', IntroCommand('List all build options', func=lambda: list_buildoptions(coredata), no_bd=list_buildoptions_from_source)),
        ('buildsystem_files', IntroCommand('List files that make up the build system', func=lambda: list_buildsystem_files(builddata, interpreter))),
        ('compilers', IntroCommand('List used compilers', func=lambda: list_compilers(coredata))),
        ('dependencies', IntroCommand('List external dependencies', func=lambda: list_deps(coredata, backend), 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('List all installed files and directories', func=lambda: list_installed(installdata))),
        ('install_plan', IntroCommand('List all installed files and directories with their details', func=lambda: list_install_plan(installdata))),
        ('machines', IntroCommand('Information about host, build, and target machines', func=lambda: list_machines(builddata))),
        ('projectinfo', IntroCommand('Information about projects', func=lambda: list_projinfo(builddata), no_bd=list_projinfo_from_source)),
        ('targets', IntroCommand('List top level targets', func=lambda: list_targets(builddata, installdata, backend), no_bd=list_targets_from_source)),
        ('tests', IntroCommand('List all unit tests', func=lambda: list_tests(testdata))),
    ])

# Note: when adding arguments, please also add them to the completion
# scripts in $MESONSRC/data/shell-completions/
def add_arguments(parser: argparse.ArgumentParser) -> None:
    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=sorted(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 dump_ast(intr: IntrospectionInterpreter) -> T.Dict[str, T.Any]:
    printer = AstJSONPrinter()
    intr.ast.accept(printer)
    return printer.result

def list_installed(installdata: backends.InstallData) -> T.Dict[str, str]:
    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 i in installdata.data:
            res[i.path] = os.path.join(installdata.prefix, i.install_path)
        for i in installdata.headers:
            res[i.path] = os.path.join(installdata.prefix, i.install_path, os.path.basename(i.path))
        for i in installdata.man:
            res[i.path] = os.path.join(installdata.prefix, i.install_path)
        for i in installdata.install_subdirs:
            res[i.path] = os.path.join(installdata.prefix, i.install_path)
        for s in installdata.symlinks:
            basename = os.path.basename(s.name)
            res[basename] = os.path.join(installdata.prefix, s.install_path, basename)
    return res

def list_install_plan(installdata: backends.InstallData) -> T.Dict[str, T.Dict[str, T.Dict[str, T.Optional[str]]]]:
    plan: T.Dict[str, T.Dict[str, T.Dict[str, T.Optional[str]]]] = {
        'targets': {
            os.path.join(installdata.build_dir, target.fname): {
                'destination': target.out_name,
                'tag': target.tag or None,
                'subproject': target.subproject or None,
            }
            for target in installdata.targets
        },
    }
    for key, data_list in {
        'data': installdata.data,
        'man': installdata.man,
        'headers': installdata.headers,
        'install_subdirs': installdata.install_subdirs
    }.items():
        # Mypy doesn't recognize SubdirInstallData as a subclass of InstallDataBase
        for data in data_list: # type: ignore[attr-defined]
            data_type = data.data_type or key
            install_path_name = data.install_path_name
            if key == 'headers':  # in the headers, install_path_name is the directory
                install_path_name = os.path.join(install_path_name, os.path.basename(data.path))

            entry = {
                'destination': install_path_name,
                'tag': data.tag or None,
                'subproject': data.subproject or None,
            }

            if key == 'install_subdirs':
                exclude_files, exclude_dirs = data.exclude or ([], [])
                entry['exclude_dirs'] = list(exclude_dirs)
                entry['exclude_files'] = list(exclude_files)

            plan[data_type] = plan.get(data_type, {})
            plan[data_type][data.path] = entry

    return plan

def get_target_dir(coredata: cdata.CoreData, subdir: str) -> str:
    if coredata.get_option(OptionKey('layout')) == 'flat':
        return 'meson-out'
    else:
        return subdir

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: T.List[T.Dict[str, T.Union[bool, str, T.List[T.Union[str, T.Dict[str, T.Union[str, T.List[str], bool]]]]]]] = []
    root_dir = Path(intr.source_root)

    def nodes_to_paths(node_list: T.List[BaseNode]) -> T.List[Path]:
        res: T.List[Path] = []
        for n in node_list:
            args: T.List[BaseNode] = []
            if isinstance(n, FunctionNode):
                args = list(n.args.arguments)
                if n.func_name.value 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, BaseStringNode):
                    assert isinstance(j.value, str)
                    res += [Path(j.value)]
                elif isinstance(j, str):
                    res += [Path(j)]
        res = [root_dir / i['subdir'] / x for x in res]
        res = [x.resolve() for x in res]
        return res

    for i in intr.targets:
        sources = nodes_to_paths(i['sources'])
        extra_f = nodes_to_paths(i['extra_files'])
        outdir = get_target_dir(intr.coredata, i['subdir'])

        tlist += [{
            'name': i['name'],
            'id': i['id'],
            'type': i['type'],
            'defined_in': i['defined_in'],
            'filename': [os.path.join(outdir, x) for x in i['outputs']],
            'build_by_default': i['build_by_default'],
            'target_sources': [{
                'language': 'unknown',
                'compiler': [],
                'parameters': [],
                'sources': [str(x) for x in sources],
                'generated_sources': []
            }],
            'depends': [],
            'extra_files': [str(x) for x in extra_f],
            'subproject': None, # Subprojects are not supported
            'installed': i['installed']
        }]

    return tlist

def list_targets(builddata: build.Build, installdata: backends.InstallData, backend: backends.Backend) -> T.List[T.Any]:
    tlist: T.List[T.Any] = []
    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:
        basename = os.path.basename(i.fname)
        install_lookuptable[basename] = [str(PurePath(installdata.prefix, i.outdir, basename))]
    for s in installdata.symlinks:
        # Symlink's target must already be in the table. They share the same list
        # to support symlinks to symlinks recursively, such as .so -> .so.0 -> .so.1.2.3
        basename = os.path.basename(s.name)
        try:
            install_lookuptable[basename] = install_lookuptable[os.path.basename(s.target)]
            install_lookuptable[basename].append(str(PurePath(installdata.prefix, s.install_path, basename)))
        except KeyError:
            pass

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

        outdir = get_target_dir(builddata.environment.coredata, target.subdir)
        t = {
            'name': target.get_basename(),
            'id': idname,
            'type': target.get_typename(),
            'defined_in': os.path.normpath(os.path.join(src_dir, target.subdir, environment.build_filename)),
            'filename': [os.path.join(build_dir, outdir, x) for x in target.get_outputs()],
            'build_by_default': target.build_by_default,
            'target_sources': backend.get_introspection_data(idname, target),
            'extra_files': [os.path.normpath(os.path.join(src_dir, x.subdir, x.fname)) for x in target.extra_files],
            'subproject': target.subproject or None,
            'dependencies': [d.name for d in getattr(target, 'external_deps', [])],
            'depends': [lib.get_id() for lib in getattr(target, 'dependencies', [])]
        }

        vs_module_defs = getattr(target, 'vs_module_defs', None)
        if vs_module_defs is not None:
            t['vs_module_defs'] = vs_module_defs.relative_name()
        win_subsystem = getattr(target, 'win_subsystem', None)
        if win_subsystem is not None:
            t['win_subsystem'] = win_subsystem

        if installdata and target.should_install():
            t['installed'] = True
            ifn = [install_lookuptable.get(x, [None]) for x in target.get_outputs()]
            t['install_filename'] = [x for sublist in ifn for x in sublist]  # flatten the list
        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]]]]:
    subprojects = [i['name'] for i in intr.project_data['subprojects']]
    return list_buildoptions(intr.coredata, subprojects)

def list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[str]] = None) -> T.List[T.Dict[str, T.Union[str, bool, int, T.List[str]]]]:
    optlist: T.List[T.Dict[str, T.Union[str, bool, int, T.List[str]]]] = []
    subprojects = subprojects or []

    dir_option_names = set(cdata.BUILTIN_DIR_OPTIONS)
    test_option_names = {OptionKey('errorlogs'),
                         OptionKey('stdsplit')}

    dir_options: 'cdata.MutableKeyedOptionDictType' = {}
    test_options: 'cdata.MutableKeyedOptionDictType' = {}
    core_options: 'cdata.MutableKeyedOptionDictType' = {}
    for k, v in coredata.options.items():
        if k in dir_option_names:
            dir_options[k] = v
        elif k in test_option_names:
            test_options[k] = v
        elif k.is_builtin():
            core_options[k] = v
            if not v.yielding:
                for s in subprojects:
                    core_options[k.evolve(subproject=s)] = v

    def add_keys(options: 'cdata.KeyedOptionDictType', section: str) -> None:
        for key, opt in sorted(options.items()):
            optdict = {'name': str(key), 'value': opt.value, 'section': section,
                       'machine': key.machine.get_lower_case_name() if coredata.is_per_machine_option(key) else 'any'}
            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'
                if opt.choices:
                    optdict['choices'] = opt.choices
            else:
                raise RuntimeError("Unknown option type")
            optdict['type'] = typestr
            optdict['description'] = opt.description
            optlist.append(optdict)

    add_keys(core_options, 'core')
    add_keys({k: v for k, v in coredata.options.items() if k.is_backend()}, 'backend')
    add_keys({k: v for k, v in coredata.options.items() if k.is_base()}, 'base')
    add_keys(
        {k: v for k, v in sorted(coredata.options.items(), key=lambda i: i[0].machine) if k.is_compiler()},
        'compiler',
    )
    add_keys(dir_options, 'directory')
    add_keys({k: v for k, v in coredata.options.items() if k.is_project()}, 'user')
    add_keys(test_options, 'test')
    return optlist

def find_buildsystem_files_list(src_dir: str) -> T.List[str]:
    build_files = frozenset({'meson.build', 'meson.options', 'meson_options.txt'})
    # I feel dirty about this. But only slightly.
    filelist: T.List[str] = []
    for root, _, files in os.walk(src_dir):
        filelist.extend(os.path.relpath(os.path.join(root, f), src_dir)
                        for f in build_files.intersection(files))
    return filelist

def list_buildsystem_files(builddata: build.Build, interpreter: Interpreter) -> T.List[str]:
    src_dir = builddata.environment.get_source_dir()
    filelist = list(interpreter.get_build_def_files())
    filelist = [PurePath(src_dir, x).as_posix() for x in filelist]
    return filelist

def list_compilers(coredata: cdata.CoreData) -> T.Dict[str, T.Dict[str, T.Dict[str, str]]]:
    compilers: T.Dict[str, T.Dict[str, T.Dict[str, str]]] = {}
    for machine in ('host', 'build'):
        compilers[machine] = {}
        for language, compiler in getattr(coredata.compilers, machine).items():
            compilers[machine][language] = {
                'id': compiler.get_id(),
                'exelist': compiler.get_exelist(),
                'linker_exelist': compiler.get_linker_exelist(),
                'file_suffixes': compiler.file_suffixes,
                'default_suffix': compiler.get_default_suffix(),
                'version': compiler.version,
                'full_version': compiler.full_version,
                'linker_id': compiler.get_linker_id(),
            }
    return compilers

def list_deps_from_source(intr: IntrospectionInterpreter) -> T.List[T.Dict[str, T.Union[str, bool]]]:
    result: 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, backend: backends.Backend) -> T.List[T.Dict[str, T.Union[str, T.List[str]]]]:
    result: T.Dict[str, T.Dict[str, T.Union[str, T.List[str]]]] = {}

    def _src_to_str(src_file: T.Union[mesonlib.FileOrString, build.CustomTarget, build.StructuredSources, build.CustomTargetIndex, build.GeneratedList]) -> T.List[str]:
        if isinstance(src_file, str):
            return [src_file]
        if isinstance(src_file, mesonlib.File):
            return [src_file.absolute_path(backend.source_dir, backend.build_dir)]
        if isinstance(src_file, (build.CustomTarget, build.CustomTargetIndex, build.GeneratedList)):
            return src_file.get_outputs()
        if isinstance(src_file, build.StructuredSources):
            return [f for s in src_file.as_list() for f in _src_to_str(s)]
        raise mesonlib.MesonBugException(f'Invalid file type {type(src_file)}.')

    def _create_result(d: Dependency, varname: T.Optional[str] = None) -> T.Dict[str, T.Any]:
        return {
            'name': d.name,
            'type': d.type_name,
            'version': d.get_version(),
            'compile_args': d.get_compile_args(),
            'link_args': d.get_link_args(),
            'include_directories': [i for idirs in d.get_include_dirs() for i in idirs.to_string_list(backend.source_dir, backend.build_dir)],
            'sources': [f for s in d.get_sources() for f in _src_to_str(s)],
            'extra_files': [f for s in d.get_extra_files() for f in _src_to_str(s)],
            'dependencies': [e.name for e in d.ext_deps],
            'depends': [lib.get_id() for lib in getattr(d, 'libraries', [])],
            'meson_variables': [varname] if varname else [],
        }

    for d in coredata.deps.host.values():
        if d.found():
            result[d.name] = _create_result(d)

    for varname, holder in backend.interpreter.variables.items():
        if isinstance(holder, ObjectHolder):
            d = holder.held_object
            if isinstance(d, Dependency) and d.found():
                if d.name in result:
                    T.cast('T.List[str]', result[d.name]['meson_variables']).append(varname)
                else:
                    result[d.name] = _create_result(d, varname)

    return list(result.values())

def get_test_list(testdata: T.List[backends.TestSerialisation]) -> T.List[T.Dict[str, T.Union[str, int, T.List[str], T.Dict[str, str]]]]:
    result: T.List[T.Dict[str, T.Union[str, int, T.List[str], T.Dict[str, str]]]] = []
    for t in testdata:
        to: T.Dict[str, T.Union[str, int, T.List[str], T.Dict[str, str]]] = {}
        if isinstance(t.fname, str):
            fname = [t.fname]
        else:
            fname = t.fname
        to['cmd'] = fname + t.cmd_args
        if isinstance(t.env, mesonlib.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'] = str(t.protocol)
        to['depends'] = t.depends
        to['extra_paths'] = t.extra_paths
        result.append(to)
    return result

def list_tests(testdata: T.List[backends.TestSerialisation]) -> 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[backends.TestSerialisation]) -> T.List[T.Dict[str, T.Union[str, int, T.List[str], T.Dict[str, str]]]]:
    return get_test_list(benchdata)

def list_machines(builddata: build.Build) -> T.Dict[str, T.Dict[str, T.Union[str, bool]]]:
    machines: T.Dict[str, T.Dict[str, T.Union[str, bool]]] = {}
    for m in ('host', 'build', 'target'):
        machine = getattr(builddata.environment.machines, m)
        machines[m] = dataclasses.asdict(machine)
        machines[m]['is_64_bit'] = machine.is_64_bit
        machines[m]['exe_suffix'] = machine.get_exe_suffix()
        machines[m]['object_suffix'] = machine.get_object_suffix()
    return machines

def list_projinfo(builddata: build.Build) -> T.Dict[str, T.Union[str, T.List[T.Dict[str, str]]]]:
    result: T.Dict[str, T.Union[str, T.List[T.Dict[str, str]]]] = {
        'version': builddata.project_version,
        'descriptive_name': builddata.project_name,
        'subproject_dir': builddata.subproject_dir,
    }
    subprojects = []
    for k, v in builddata.subprojects.items():
        c: T.Dict[str, str] = {
            '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: argparse.Namespace, results: T.Sequence[T.Tuple[str, T.Union[dict, T.List[T.Any]]]], indent: T.Optional[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 get_infodir(builddir: T.Optional[str] = None) -> str:
    infodir = 'meson-info'
    if builddir is not None:
        infodir = os.path.join(builddir, infodir)
    return infodir

def get_info_file(infodir: str, kind: T.Optional[str] = None) -> str:
    return os.path.join(infodir,
                        'meson-info.json' if not kind else f'intro-{kind}.json')

def load_info_file(infodir: str, kind: T.Optional[str] = None) -> T.Any:
    with open(get_info_file(infodir, kind), encoding='utf-8') as fp:
        return json.load(fp)

def run(options: argparse.Namespace) -> int:
    datadir = 'meson-private'
    infodir = get_infodir(options.builddir)
    if options.builddir is not None:
        datadir = os.path.join(options.builddir, datadir)
    indent = 4 if options.indent else None
    results: 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()

    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
        with redirect_stdout(sys.stderr):
            backend = backends.get_backend_from_name(options.backend)
            assert backend is not None
            intr = IntrospectionInterpreter(sourcedir, '', backend.name, visitors = [AstIDGenerator(), AstIndentationGenerator(), AstConditionLevel()])
            intr.analyze()

        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)

    try:
        raw = load_info_file(infodir)
        intro_vers = raw.get('introspection', {}).get('version', {}).get('full', '0.0.0')
    except FileNotFoundError:
        if not os.path.isdir(datadir) or not os.path.isdir(infodir):
            print('Current directory is not a meson build directory.\n'
                  'Please specify a valid build dir or change the working directory to it.')
        else:
            print('Introspection file {} does not exist.\n'
                  'It is also possible that the build directory was generated with an old\n'
                  'meson version. Please regenerate it in this case.'.format(get_info_file(infodir)))
        return 1

    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, v in intro_types.items():
        if not v.func:
            continue
        if not options.all and not getattr(options, i, False):
            continue
        try:
            results += [(i, load_info_file(infodir, i))]
        except FileNotFoundError:
            print('Introspection file {} does not exist.'.format(get_info_file(infodir, i)))
            return 1

    return print_results(options, results, indent)

updated_introspection_files: 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:
    for kind, data in intro_info:
        out_file = os.path.join(info_dir, f'intro-{kind}.json')
        tmp_file = os.path.join(info_dir, 'tmp_dump.json')
        with open(tmp_file, 'w', encoding='utf-8') as fp:
            json.dump(data, fp)
            fp.flush() # Not sure if this is needed
        os.replace(tmp_file, out_file)
        updated_introspection_files.append(kind)

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: 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: str) -> 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:
    info_dir = builddata.environment.info_dir
    info_file = get_meson_info_file(info_dir)
    intro_types = get_meson_introspection_types()
    intro_info = {}

    for i, v in intro_types.items():
        if not v.func:
            continue
        intro_info[i] = {
            'file': f'intro-{i}.json',
            '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', encoding='utf-8') as fp:
        json.dump(info_data, fp)
        fp.flush()
    os.replace(tmp_file, info_file)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/mlog.py0000644000175000017500000004736714562742363016536 0ustar00jpakkanejpakkane# 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.

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

from __future__ import annotations

import enum
import os
import io
import sys
import time
import platform
import shlex
import subprocess
import shutil
import typing as T
from contextlib import contextmanager
from dataclasses import dataclass, field
from pathlib import Path

if T.TYPE_CHECKING:
    from ._typing import StringProtocol, SizedStringProtocol

    from .mparser import BaseNode

    TV_Loggable = T.Union[str, 'AnsiDecorator', StringProtocol]
    TV_LoggableList = T.List[TV_Loggable]

def is_windows() -> bool:
    platname = platform.system().lower()
    return platname == 'windows'

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 colorize_console() -> bool:
    _colorize_console: bool = getattr(sys.stdout, 'colorize_console', None)
    if _colorize_console is not None:
        return _colorize_console

    try:
        if is_windows():
            _colorize_console = os.isatty(sys.stdout.fileno()) and _windows_ansi()
        else:
            _colorize_console = os.isatty(sys.stdout.fileno()) and os.environ.get('TERM', 'dumb') != 'dumb'
    except Exception:
        _colorize_console = False

    sys.stdout.colorize_console = _colorize_console  # type: ignore[attr-defined]
    return _colorize_console

def setup_console() -> None:
    # on Windows, a subprocess might call SetConsoleMode() on the console
    # connected to stdout and turn off ANSI escape processing. Call this after
    # running a subprocess to ensure we turn it on again.
    if is_windows():
        try:
            delattr(sys.stdout, 'colorize_console')
        except AttributeError:
            pass

_in_ci = 'CI' in os.environ


class _Severity(enum.Enum):

    NOTICE = enum.auto()
    WARNING = enum.auto()
    ERROR = enum.auto()
    DEPRECATION = enum.auto()

@dataclass
class _Logger:

    log_dir: T.Optional[str] = None
    log_depth: T.List[str] = field(default_factory=list)
    log_file: T.Optional[T.TextIO] = None
    log_timestamp_start: T.Optional[float] = None
    log_fatal_warnings = False
    log_disable_stdout = False
    log_errors_only = False
    logged_once: T.Set[T.Tuple[str, ...]] = field(default_factory=set)
    log_warnings_counter = 0
    log_pager: T.Optional['subprocess.Popen'] = None

    _LOG_FNAME: T.ClassVar[str] = 'meson-log.txt'

    @contextmanager
    def no_logging(self) -> T.Iterator[None]:
        self.log_disable_stdout = True
        try:
            yield
        finally:
            self.log_disable_stdout = False

    @contextmanager
    def force_logging(self) -> T.Iterator[None]:
        restore = self.log_disable_stdout
        self.log_disable_stdout = False
        try:
            yield
        finally:
            self.log_disable_stdout = restore

    def set_quiet(self) -> None:
        self.log_errors_only = True

    def set_verbose(self) -> None:
        self.log_errors_only = False

    def set_timestamp_start(self, start: float) -> None:
        self.log_timestamp_start = start

    def shutdown(self) -> T.Optional[str]:
        if self.log_file is not None:
            path = self.log_file.name
            exception_around_goer = self.log_file
            self.log_file = None
            exception_around_goer.close()
            return path
        self.stop_pager()
        return None

    def start_pager(self) -> None:
        if not colorize_console():
            return
        pager_cmd = []
        if 'PAGER' in os.environ:
            pager_cmd = shlex.split(os.environ['PAGER'])
        else:
            less = shutil.which('less')
            if not less and is_windows():
                git = shutil.which('git')
                if git:
                    path = Path(git).parents[1] / 'usr' / 'bin'
                    less = shutil.which('less', path=str(path))
            if less:
                pager_cmd = [less]
        if not pager_cmd:
            return
        try:
            # Set 'LESS' environment variable, rather than arguments in
            # pager_cmd, to also support the case where the user has 'PAGER'
            # set to 'less'. Arguments set are:
            # "R" : support color
            # "X" : do not clear the screen when leaving the pager
            # "F" : skip the pager if content fits into the screen
            env = os.environ.copy()
            if 'LESS' not in env:
                env['LESS'] = 'RXF'
            # Set "-c" for lv to support color
            if 'LV' not in env:
                env['LV'] = '-c'
            self.log_pager = subprocess.Popen(pager_cmd, stdin=subprocess.PIPE,
                                              text=True, encoding='utf-8', env=env)
        except Exception as e:
            # Ignore errors, unless it is a user defined pager.
            if 'PAGER' in os.environ:
                from .mesonlib import MesonException
                raise MesonException(f'Failed to start pager: {str(e)}')

    def stop_pager(self) -> None:
        if self.log_pager:
            try:
                self.log_pager.stdin.flush()
                self.log_pager.stdin.close()
            except OSError:
                pass
            self.log_pager.wait()
            self.log_pager = None

    def initialize(self, logdir: str, fatal_warnings: bool = False) -> None:
        self.log_dir = logdir
        self.log_file = open(os.path.join(logdir, self._LOG_FNAME), 'w', encoding='utf-8')
        self.log_fatal_warnings = fatal_warnings

    def process_markup(self, args: T.Sequence[TV_Loggable], keep: bool, display_timestamp: bool = True) -> T.List[str]:
        arr: T.List[str] = []
        if self.log_timestamp_start is not None and display_timestamp:
            arr = ['[{:.3f}]'.format(time.monotonic() - self.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(self, *args: str, nested: bool, sep: T.Optional[str] = None,
                    end: T.Optional[str] = None) -> None:
        if self.log_disable_stdout:
            return
        iostr = io.StringIO()
        print(*args, sep=sep, end=end, file=iostr)

        raw = iostr.getvalue()
        if self.log_depth:
            prepend = self.log_depth[-1] + '| ' if nested else ''
            lines = []
            for l in raw.split('\n'):
                l = l.strip()
                lines.append(prepend + l if l else '')
            raw = '\n'.join(lines)

        # _Something_ is going to get printed.
        try:
            output = self.log_pager.stdin if self.log_pager else None
            print(raw, end='', file=output)
        except UnicodeEncodeError:
            cleaned = raw.encode('ascii', 'replace').decode('ascii')
            print(cleaned, end='')

    def debug(self, *args: TV_Loggable, sep: T.Optional[str] = None,
              end: T.Optional[str] = None, display_timestamp: bool = True) -> None:
        arr = process_markup(args, False, display_timestamp)
        if self.log_file is not None:
            print(*arr, file=self.log_file, sep=sep, end=end)
            self.log_file.flush()

    def _log(self, *args: TV_Loggable, is_error: bool = False,
             nested: bool = True, sep: T.Optional[str] = None,
             end: T.Optional[str] = None, display_timestamp: bool = True) -> None:
        arr = process_markup(args, False, display_timestamp)
        if self.log_file is not None:
            print(*arr, file=self.log_file, sep=sep, end=end)
            self.log_file.flush()
        if colorize_console():
            arr = process_markup(args, True, display_timestamp)
        if not self.log_errors_only or is_error:
            force_print(*arr, nested=nested, sep=sep, end=end)

    def _debug_log_cmd(self, cmd: str, args: T.List[str]) -> None:
        if not _in_ci:
            return
        args = [f'"{x}"' for x in args]  # Quote all args, just in case
        self.debug('!meson_ci!/{} {}'.format(cmd, ' '.join(args)))

    def cmd_ci_include(self, file: str) -> None:
        self._debug_log_cmd('ci_include', [file])

    def log(self, *args: TV_Loggable, is_error: bool = False,
            once: bool = False, nested: bool = True,
            sep: T.Optional[str] = None,
            end: T.Optional[str] = None,
            display_timestamp: bool = True) -> None:
        if once:
            self._log_once(*args, is_error=is_error, nested=nested, sep=sep, end=end, display_timestamp=display_timestamp)
        else:
            self._log(*args, is_error=is_error, nested=nested, sep=sep, end=end, display_timestamp=display_timestamp)

    def log_timestamp(self, *args: TV_Loggable) -> None:
        if self.log_timestamp_start:
            self.log(*args)

    def _log_once(self, *args: TV_Loggable, is_error: bool = False,
                  nested: bool = True, sep: T.Optional[str] = None,
                  end: T.Optional[str] = None, display_timestamp: bool = True) -> None:
        """Log variant that only prints a given message one time per meson invocation.

        This considers ansi decorated values by the values they wrap without
        regard for the AnsiDecorator itself.
        """
        def to_str(x: TV_Loggable) -> str:
            if isinstance(x, str):
                return x
            if isinstance(x, AnsiDecorator):
                return x.text
            return str(x)
        t = tuple(to_str(a) for a in args)
        if t in self.logged_once:
            return
        self.logged_once.add(t)
        self._log(*args, is_error=is_error, nested=nested, sep=sep, end=end, display_timestamp=display_timestamp)

    def _log_error(self, severity: _Severity, *rargs: TV_Loggable,
                   once: bool = False, fatal: bool = True,
                   location: T.Optional[BaseNode] = None,
                   nested: bool = True, sep: T.Optional[str] = None,
                   end: T.Optional[str] = None,
                   is_error: bool = True) -> None:
        from .mesonlib import MesonException, relpath

        # The typing 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 is _Severity.NOTICE:
            label: TV_LoggableList = [bold('NOTICE:')]
        elif severity is _Severity.WARNING:
            label = [yellow('WARNING:')]
        elif severity is _Severity.ERROR:
            label = [red('ERROR:')]
        elif severity is _Severity.DEPRECATION:
            label = [red('DEPRECATION:')]
        # rargs is a tuple, not a list
        args = label + list(rargs)

        if location is not None:
            location_file = relpath(location.filename, os.getcwd())
            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('TV_LoggableList', [location_str])
            args = location_list + args

        log(*args, once=once, nested=nested, sep=sep, end=end, is_error=is_error)

        self.log_warnings_counter += 1

        if self.log_fatal_warnings and fatal:
            raise MesonException("Fatal warnings enabled, aborting")

    def error(self, *args: TV_Loggable,
              once: bool = False, fatal: bool = True,
              location: T.Optional[BaseNode] = None,
              nested: bool = True, sep: T.Optional[str] = None,
              end: T.Optional[str] = None) -> None:
        return self._log_error(_Severity.ERROR, *args, once=once, fatal=fatal, location=location,
                               nested=nested, sep=sep, end=end, is_error=True)

    def warning(self, *args: TV_Loggable,
                once: bool = False, fatal: bool = True,
                location: T.Optional[BaseNode] = None,
                nested: bool = True, sep: T.Optional[str] = None,
                end: T.Optional[str] = None) -> None:
        return self._log_error(_Severity.WARNING, *args, once=once, fatal=fatal, location=location,
                               nested=nested, sep=sep, end=end, is_error=True)

    def deprecation(self, *args: TV_Loggable,
                    once: bool = False, fatal: bool = True,
                    location: T.Optional[BaseNode] = None,
                    nested: bool = True, sep: T.Optional[str] = None,
                    end: T.Optional[str] = None) -> None:
        return self._log_error(_Severity.DEPRECATION, *args, once=once, fatal=fatal, location=location,
                               nested=nested, sep=sep, end=end, is_error=True)

    def notice(self, *args: TV_Loggable,
               once: bool = False, fatal: bool = True,
               location: T.Optional[BaseNode] = None,
               nested: bool = True, sep: T.Optional[str] = None,
               end: T.Optional[str] = None) -> None:
        return self._log_error(_Severity.NOTICE, *args, once=once, fatal=fatal, location=location,
                               nested=nested, sep=sep, end=end, is_error=False)

    def exception(self, e: Exception, prefix: T.Optional[AnsiDecorator] = None) -> None:
        if prefix is None:
            prefix = red('ERROR:')
        self.log()
        args: T.List[T.Union[AnsiDecorator, str]] = []
        if all(getattr(e, a, None) is not None for a in ['file', 'lineno', 'colno']):
            # Mypy doesn't follow hasattr, and it's pretty easy to visually inspect
            # that this is correct, so we'll just ignore it.
            path = get_relative_path(Path(e.file), Path(os.getcwd()))  # type: ignore
            args.append(f'{path}:{e.lineno}:{e.colno}:')  # type: ignore
        if prefix:
            args.append(prefix)
        args.append(str(e))

        with self.force_logging():
            self.log(*args, is_error=True)

    @contextmanager
    def nested(self, name: str = '') -> T.Generator[None, None, None]:
        self.log_depth.append(name)
        try:
            yield
        finally:
            self.log_depth.pop()

    def get_log_dir(self) -> str:
        return self.log_dir

    def get_log_depth(self) -> int:
        return len(self.log_depth)

    @contextmanager
    def nested_warnings(self) -> T.Iterator[None]:
        old = self.log_warnings_counter
        self.log_warnings_counter = 0
        try:
            yield
        finally:
            self.log_warnings_counter = old

    def get_warning_count(self) -> int:
        return self.log_warnings_counter

_logger = _Logger()
cmd_ci_include = _logger.cmd_ci_include
debug = _logger.debug
deprecation = _logger.deprecation
error = _logger.error
exception = _logger.exception
force_print = _logger.force_print
get_log_depth = _logger.get_log_depth
get_log_dir = _logger.get_log_dir
get_warning_count = _logger.get_warning_count
initialize = _logger.initialize
log = _logger.log
log_timestamp = _logger.log_timestamp
nested = _logger.nested
nested_warnings = _logger.nested_warnings
no_logging = _logger.no_logging
notice = _logger.notice
process_markup = _logger.process_markup
set_quiet = _logger.set_quiet
set_timestamp_start = _logger.set_timestamp_start
set_verbose = _logger.set_verbose
shutdown = _logger.shutdown
start_pager = _logger.start_pager
stop_pager = _logger.stop_pager
warning = _logger.warning

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 and self.code:
            text = self.code + self.text + AnsiDecorator.plain_code
        if self.quoted:
            text = f'"{text}"'
        return text

    def __len__(self) -> int:
        return len(self.text)

    def __str__(self) -> str:
        return self.get_text(colorize_console())

class AnsiText:
    def __init__(self, *args: 'SizedStringProtocol'):
        self.args = args

    def __len__(self) -> int:
        return sum(len(x) for x in self.args)

    def __str__(self) -> str:
        return ''.join(str(x) for x in self.args)


def bold(text: str, quoted: bool = False) -> AnsiDecorator:
    return AnsiDecorator(text, "\033[1m", quoted=quoted)

def italic(text: str, quoted: bool = False) -> AnsiDecorator:
    return AnsiDecorator(text, "\033[3m", quoted=quoted)

def plain(text: str) -> AnsiDecorator:
    return AnsiDecorator(text, "")

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")

def get_error_location_string(fname: StringProtocol, lineno: int) -> str:
    return f'{fname}:{lineno}:'

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

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


def code_line(text: str, line: str, colno: int) -> str:
    """Print a line with a caret pointing to the colno

    :param text: A message to display before the line
    :param line: The line of code to be pointed to
    :param colno: The column number to point at
    :return: A formatted string of the text, line, and a caret
    """
    return f'{text}\n{line}\n{" " * colno}^'
././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.722639
meson-1.3.2/mesonbuild/modules/0000755000175000017500000000000014562742414016652 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0
meson-1.3.2/mesonbuild/modules/__init__.py0000644000175000017500000002644614562742373021003 0ustar00jpakkanejpakkane# 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 base representation for import('modname')

from __future__ import annotations
import dataclasses
import typing as T

from .. import build, mesonlib
from ..build import IncludeDirs
from ..interpreterbase.decorators import noKwargs, noPosargs
from ..mesonlib import relpath, HoldableObject, MachineChoice
from ..programs import ExternalProgram

if T.TYPE_CHECKING:
    from ..interpreter import Interpreter
    from ..interpreter.interpreter import ProgramVersionFunc
    from ..interpreter.interpreterobjects import MachineHolder
    from ..interpreterbase import TYPE_var, TYPE_kwargs
    from ..programs import OverrideProgram
    from ..wrap import WrapMode
    from ..dependencies import Dependency

class ModuleState:
    """Object passed to all module methods.

    This is a WIP API provided to modules, it should be extended to have everything
    needed so modules does not touch any other part of Meson internal APIs.
    """

    def __init__(self, interpreter: 'Interpreter') -> None:
        # Keep it private, it should be accessed only through methods.
        self._interpreter = interpreter

        self.source_root = interpreter.environment.get_source_dir()
        self.build_to_src = relpath(interpreter.environment.get_source_dir(),
                                    interpreter.environment.get_build_dir())
        self.subproject = interpreter.subproject
        self.subdir = interpreter.subdir
        self.root_subdir = interpreter.root_subdir
        self.current_lineno = interpreter.current_lineno
        self.environment = interpreter.environment
        self.project_name = interpreter.build.project_name
        self.project_version = interpreter.build.dep_manifest[interpreter.active_projectname].version
        # The backend object is under-used right now, but we will need it:
        # https://github.com/mesonbuild/meson/issues/1419
        self.backend = interpreter.backend
        self.targets = interpreter.build.targets
        self.data = interpreter.build.data
        self.headers = interpreter.build.get_headers()
        self.man = interpreter.build.get_man()
        self.global_args = interpreter.build.global_args.host
        self.project_args = interpreter.build.projects_args.host.get(interpreter.subproject, {})
        self.build_machine = T.cast('MachineHolder', interpreter.builtin['build_machine']).held_object
        self.host_machine = T.cast('MachineHolder', interpreter.builtin['host_machine']).held_object
        self.target_machine = T.cast('MachineHolder', interpreter.builtin['target_machine']).held_object
        self.current_node = interpreter.current_node

    def get_include_args(self, include_dirs: T.Iterable[T.Union[str, build.IncludeDirs]], prefix: str = '-I') -> T.List[str]:
        if not include_dirs:
            return []

        srcdir = self.environment.get_source_dir()
        builddir = self.environment.get_build_dir()

        dirs_str: T.List[str] = []
        for dirs in include_dirs:
            if isinstance(dirs, str):
                dirs_str += [f'{prefix}{dirs}']
            else:
                dirs_str.extend([f'{prefix}{i}' for i in dirs.to_string_list(srcdir, builddir)])
                dirs_str.extend([f'{prefix}{i}' for i in dirs.get_extra_build_dirs()])

        return dirs_str

    def find_program(self, prog: T.Union[mesonlib.FileOrString, T.List[mesonlib.FileOrString]],
                     required: bool = True,
                     version_func: T.Optional[ProgramVersionFunc] = None,
                     wanted: T.Optional[str] = None, silent: bool = False,
                     for_machine: MachineChoice = MachineChoice.HOST) -> T.Union[ExternalProgram, build.Executable, OverrideProgram]:
        if not isinstance(prog, list):
            prog = [prog]
        return self._interpreter.find_program_impl(prog, required=required, version_func=version_func,
                                                   wanted=wanted, silent=silent, for_machine=for_machine)

    def find_tool(self, name: str, depname: str, varname: str, required: bool = True,
                  wanted: T.Optional[str] = None) -> T.Union['build.Executable', ExternalProgram, 'OverrideProgram']:
        # Look in overrides in case it's built as subproject
        progobj = self._interpreter.program_from_overrides([name], [])
        if progobj is not None:
            return progobj

        # Look in machine file
        prog_list = self.environment.lookup_binary_entry(MachineChoice.HOST, name)
        if prog_list is not None:
            return ExternalProgram.from_entry(name, prog_list)

        # Check if pkgconfig has a variable
        dep = self.dependency(depname, native=True, required=False, wanted=wanted)
        if dep.found() and dep.type_name == 'pkgconfig':
            value = dep.get_variable(pkgconfig=varname)
            if value:
                progobj = ExternalProgram(value)
                if not progobj.found():
                    msg = (f'Dependency {depname!r} tool variable {varname!r} contains erroneous value: {value!r}\n\n'
                           f'This is a distributor issue -- please report it to your {depname} provider.')
                    raise mesonlib.MesonException(msg)
                return progobj

        # Normal program lookup
        return self.find_program(name, required=required, wanted=wanted)

    def dependency(self, depname: str, native: bool = False, required: bool = True,
                   wanted: T.Optional[str] = None) -> 'Dependency':
        kwargs: T.Dict[str, object] = {'native': native, 'required': required}
        if wanted:
            kwargs['version'] = wanted
        # FIXME: Even if we fix the function, mypy still can't figure out what's
        # going on here. And we really dont want to call interpreter
        # implementations of meson functions anyway.
        return self._interpreter.func_dependency(self.current_node, [depname], kwargs) # type: ignore

    def test(self, args: T.Tuple[str, T.Union[build.Executable, build.Jar, 'ExternalProgram', mesonlib.File]],
             workdir: T.Optional[str] = None,
             env: T.Union[T.List[str], T.Dict[str, str], str] = None,
             depends: T.List[T.Union[build.CustomTarget, build.BuildTarget]] = None) -> None:
        kwargs = {'workdir': workdir,
                  'env': env,
                  'depends': depends,
                  }
        # typed_* takes a list, and gives a tuple to func_test. Violating that constraint
        # makes the universe (or at least use of this function) implode
        real_args = list(args)
        # TODO: Use interpreter internal API, but we need to go through @typed_kwargs
        self._interpreter.func_test(self.current_node, real_args, kwargs)

    def get_option(self, name: str, subproject: str = '',
                   machine: MachineChoice = MachineChoice.HOST,
                   lang: T.Optional[str] = None,
                   module: T.Optional[str] = None) -> T.Union[T.List[str], str, int, bool, 'WrapMode']:
        return self.environment.coredata.get_option(mesonlib.OptionKey(name, subproject, machine, lang, module))

    def is_user_defined_option(self, name: str, subproject: str = '',
                               machine: MachineChoice = MachineChoice.HOST,
                               lang: T.Optional[str] = None,
                               module: T.Optional[str] = None) -> bool:
        key = mesonlib.OptionKey(name, subproject, machine, lang, module)
        return key in self._interpreter.user_defined_options.cmd_line_options

    def process_include_dirs(self, dirs: T.Iterable[T.Union[str, IncludeDirs]]) -> T.Iterable[IncludeDirs]:
        """Convert raw include directory arguments to only IncludeDirs

        :param dirs: An iterable of strings and IncludeDirs
        :return: None
        :yield: IncludeDirs objects
        """
        for d in dirs:
            if isinstance(d, IncludeDirs):
                yield d
            else:
                yield self._interpreter.build_incdir_object([d])

    def add_language(self, lang: str, for_machine: MachineChoice) -> None:
        self._interpreter.add_languages([lang], True, for_machine)

class ModuleObject(HoldableObject):
    """Base class for all objects returned by modules
    """
    def __init__(self) -> None:
        self.methods: T.Dict[
            str,
            T.Callable[[ModuleState, T.List['TYPE_var'], 'TYPE_kwargs'], T.Union[ModuleReturnValue, 'TYPE_var']]
        ] = {}


class MutableModuleObject(ModuleObject):
    pass


@dataclasses.dataclass
class ModuleInfo:

    """Metadata about a Module."""

    name: str
    added: T.Optional[str] = None
    deprecated: T.Optional[str] = None
    unstable: bool = False
    stabilized: T.Optional[str] = None


class NewExtensionModule(ModuleObject):

    """Class for modern modules

    provides the found method.
    """

    INFO: ModuleInfo

    def __init__(self) -> None:
        super().__init__()
        self.methods.update({
            'found': self.found_method,
        })

    @noPosargs
    @noKwargs
    def found_method(self, state: 'ModuleState', args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool:
        return self.found()

    @staticmethod
    def found() -> bool:
        return True

    def postconf_hook(self, b: build.Build) -> None:
        pass

# FIXME: Port all modules to stop using self.interpreter and use API on
# ModuleState instead. Modules should stop using this class and instead use
# ModuleObject base class.
class ExtensionModule(NewExtensionModule):
    def __init__(self, interpreter: 'Interpreter') -> None:
        super().__init__()
        self.interpreter = interpreter

class NotFoundExtensionModule(NewExtensionModule):

    """Class for modern modules

    provides the found method.
    """

    def __init__(self, name: str) -> None:
        super().__init__()
        self.INFO = ModuleInfo(name)

    @staticmethod
    def found() -> bool:
        return False


def is_module_library(fname: mesonlib.FileOrString) -> bool:
    '''
    Check if the file is a library-like file generated by a module-specific
    target, such as GirTarget or TypelibTarget
    '''
    suffix = fname.split('.')[-1]
    return suffix in {'gir', 'typelib'}


class ModuleReturnValue:
    def __init__(self, return_value: T.Optional['TYPE_var'],
                 new_objects: T.Sequence[T.Union['TYPE_var', 'mesonlib.ExecutableSerialisation']]) -> None:
        self.return_value = return_value
        assert isinstance(new_objects, list)
        self.new_objects: T.List[T.Union['TYPE_var', 'mesonlib.ExecutableSerialisation']] = new_objects

class GResourceTarget(build.CustomTarget):
    pass

class GResourceHeaderTarget(build.CustomTarget):
    pass

class GirTarget(build.CustomTarget):
    pass

class TypelibTarget(build.CustomTarget):
    pass

class VapiTarget(build.CustomTarget):
    pass
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/cmake.py0000644000175000017500000004444314562742363020320 0ustar00jpakkanejpakkane# 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.

from __future__ import annotations
import re
import os, os.path, pathlib
import shutil
import typing as T

from . import ExtensionModule, ModuleReturnValue, ModuleObject, ModuleInfo

from .. import build, mesonlib, mlog, dependencies
from ..cmake import TargetOptions, cmake_defines_to_args
from ..interpreter import SubprojectHolder
from ..interpreter.type_checking import REQUIRED_KW, INSTALL_DIR_KW, NoneType, in_set_validator
from ..interpreterbase import (
    FeatureNew,
    FeatureNewKwargs,

    stringArgs,
    permittedKwargs,
    noPosargs,
    noKwargs,

    InvalidArguments,
    InterpreterException,

    typed_pos_args,
    typed_kwargs,
    KwargInfo,
    ContainerTypeInfo,
)

if T.TYPE_CHECKING:
    from typing_extensions import TypedDict

    from . import ModuleState
    from ..cmake import SingleTargetOptions
    from ..environment import Environment
    from ..interpreter import Interpreter, kwargs
    from ..interpreterbase import TYPE_kwargs, TYPE_var

    class WriteBasicPackageVersionFile(TypedDict):

        arch_independent: bool
        compatibility: str
        install_dir: T.Optional[str]
        name: str
        version: str

    class ConfigurePackageConfigFile(TypedDict):

        configuration: T.Union[build.ConfigurationData, dict]
        input: T.Union[str, mesonlib.File]
        install_dir: T.Optional[str]
        name: str

    class Subproject(kwargs.ExtractRequired):

        options: T.Optional[CMakeSubprojectOptions]
        cmake_options: T.List[str]


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 CMakeSubproject(ModuleObject):
    def __init__(self, subp: SubprojectHolder):
        assert isinstance(subp, SubprojectHolder)
        assert subp.cm_interpreter is not None
        super().__init__()
        self.subp = subp
        self.cm_interpreter = subp.cm_interpreter
        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: T.List[str]) -> T.Dict[str, str]:
        if len(args) != 1:
            raise InterpreterException('Exactly one argument is required.')

        tgt = args[0]
        res = self.cm_interpreter.target_info(tgt)
        if res is None:
            raise InterpreterException(f'The CMake target {tgt} does not exist\n' +
                                       '  Use the following command in your meson.build to list all available targets:\n\n' +
                                       '    message(\'CMake targets:\\n - \' + \'\\n - \'.join(.target_list()))')

        # 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

    @noKwargs
    @stringArgs
    def get_variable(self, state: ModuleState, args: T.List[str], kwargs: TYPE_kwargs) -> TYPE_var:
        return self.subp.get_variable_method(args, kwargs)

    @FeatureNewKwargs('dependency', '0.56.0', ['include_type'])
    @permittedKwargs({'include_type'})
    @stringArgs
    def dependency(self, state: ModuleState, args: T.List[str], kwargs: T.Dict[str, str]) -> dependencies.Dependency:
        info = self._args_to_info(args)
        if info['func'] == 'executable':
            raise InvalidArguments(f'{args[0]} is an executable and does not support the dependency() method. Use target() instead.')
        orig = self.get_variable(state, [info['dep']], {})
        assert isinstance(orig, dependencies.Dependency)
        actual = orig.include_type
        if 'include_type' in kwargs and kwargs['include_type'] != actual:
            mlog.debug('Current include type is {}. Converting to requested {}'.format(actual, kwargs['include_type']))
            return orig.generate_system_dependency(kwargs['include_type'])
        return orig

    @noKwargs
    @stringArgs
    def include_directories(self, state: ModuleState, args: T.List[str], kwargs: TYPE_kwargs) -> build.IncludeDirs:
        info = self._args_to_info(args)
        return self.get_variable(state, [info['inc']], kwargs)

    @noKwargs
    @stringArgs
    def target(self, state: ModuleState, args: T.List[str], kwargs: TYPE_kwargs) -> build.Target:
        info = self._args_to_info(args)
        return self.get_variable(state, [info['tgt']], kwargs)

    @noKwargs
    @stringArgs
    def target_type(self, state: ModuleState, args: T.List[str], kwargs: TYPE_kwargs) -> str:
        info = self._args_to_info(args)
        return info['func']

    @noPosargs
    @noKwargs
    def target_list(self, state: ModuleState, args: TYPE_var, kwargs: TYPE_kwargs) -> T.List[str]:
        return self.cm_interpreter.target_list()

    @noPosargs
    @noKwargs
    @FeatureNew('CMakeSubproject.found()', '0.53.2')
    def found_method(self, state: ModuleState, args: TYPE_var, kwargs: TYPE_kwargs) -> bool:
        return self.subp is not None


class CMakeSubprojectOptions(ModuleObject):
    def __init__(self) -> None:
        super().__init__()
        self.cmake_options: T.List[str] = []
        self.target_options = TargetOptions()

        self.methods.update(
            {
                'add_cmake_defines': self.add_cmake_defines,
                'set_override_option': self.set_override_option,
                'set_install': self.set_install,
                'append_compile_args': self.append_compile_args,
                'append_link_args': self.append_link_args,
                'clear': self.clear,
            }
        )

    def _get_opts(self, kwargs: dict) -> SingleTargetOptions:
        if 'target' in kwargs:
            return self.target_options[kwargs['target']]
        return self.target_options.global_options

    @typed_pos_args('subproject_options.add_cmake_defines', varargs=dict)
    @noKwargs
    def add_cmake_defines(self, state: ModuleState, args: T.Tuple[T.List[T.Dict[str, TYPE_var]]], kwargs: TYPE_kwargs) -> None:
        self.cmake_options += cmake_defines_to_args(args[0])

    @typed_pos_args('subproject_options.set_override_option', str, str)
    @permittedKwargs({'target'})
    def set_override_option(self, state: ModuleState, args: T.Tuple[str, str], kwargs: TYPE_kwargs) -> None:
        self._get_opts(kwargs).set_opt(args[0], args[1])

    @typed_pos_args('subproject_options.set_install', bool)
    @permittedKwargs({'target'})
    def set_install(self, state: ModuleState, args: T.Tuple[bool], kwargs: TYPE_kwargs) -> None:
        self._get_opts(kwargs).set_install(args[0])

    @typed_pos_args('subproject_options.append_compile_args', str, varargs=str, min_varargs=1)
    @permittedKwargs({'target'})
    def append_compile_args(self, state: ModuleState, args: T.Tuple[str, T.List[str]], kwargs: TYPE_kwargs) -> None:
        self._get_opts(kwargs).append_args(args[0], args[1])

    @typed_pos_args('subproject_options.append_compile_args', varargs=str, min_varargs=1)
    @permittedKwargs({'target'})
    def append_link_args(self, state: ModuleState, args: T.Tuple[T.List[str]], kwargs: TYPE_kwargs) -> None:
        self._get_opts(kwargs).append_link_args(args[0])

    @noPosargs
    @noKwargs
    def clear(self, state: ModuleState, args: TYPE_var, kwargs: TYPE_kwargs) -> None:
        self.cmake_options.clear()
        self.target_options = TargetOptions()


class CmakeModule(ExtensionModule):
    cmake_detected = False
    cmake_root = None

    INFO = ModuleInfo('cmake', '0.50.0')

    def __init__(self, interpreter: Interpreter) -> None:
        super().__init__(interpreter)
        self.methods.update({
            'write_basic_package_version_file': self.write_basic_package_version_file,
            'configure_package_config_file': self.configure_package_config_file,
            'subproject': self.subproject,
            'subproject_options': self.subproject_options,
        })

    def detect_voidp_size(self, env: Environment) -> int:
        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)[0]

    def detect_cmake(self, state: ModuleState) -> bool:
        if self.cmake_detected:
            return True

        cmakebin = state.find_program('cmake', silent=False)
        if not cmakebin.found():
            return False

        p, stdout, stderr = mesonlib.Popen_safe(cmakebin.get_command() + ['--system-information', '-G', 'Ninja'])[0:3]
        if p.returncode != 0:
            mlog.log(f'error retrieving cmake information: returnCode={p.returncode} stdout={stdout} stderr={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

    @noPosargs
    @typed_kwargs(
        'cmake.write_basic_package_version_file',
        KwargInfo('arch_independent', bool, default=False, since='0.62.0'),
        KwargInfo('compatibility', str, default='AnyNewerVersion', validator=in_set_validator(set(COMPATIBILITIES))),
        KwargInfo('name', str, required=True),
        KwargInfo('version', str, required=True),
        INSTALL_DIR_KW,
    )
    def write_basic_package_version_file(self, state: ModuleState, args: TYPE_var, kwargs: 'WriteBasicPackageVersionFile') -> ModuleReturnValue:
        arch_independent = kwargs['arch_independent']
        compatibility = kwargs['compatibility']
        name = kwargs['name']
        version = kwargs['version']

        if not self.detect_cmake(state):
            raise mesonlib.MesonException('Unable to find cmake')

        pkgroot = pkgroot_name = kwargs['install_dir']
        if pkgroot is None:
            pkgroot = os.path.join(state.environment.coredata.get_option(mesonlib.OptionKey('libdir')), 'cmake', name)
            pkgroot_name = os.path.join('{libdir}', 'cmake', name)

        template_file = os.path.join(self.cmake_root, 'Modules', f'BasicConfigVersion-{compatibility}.cmake.in')
        if not os.path.exists(template_file):
            raise mesonlib.MesonException(f'your cmake installation doesn\'t support the {compatibility} compatibility')

        version_file = os.path.join(state.environment.scratch_dir, f'{name}ConfigVersion.cmake')

        conf: T.Dict[str, T.Union[str, bool, int]] = {
            'CVF_VERSION': version,
            'CMAKE_SIZEOF_VOID_P': str(self.detect_voidp_size(state.environment)),
            'CVF_ARCH_INDEPENDENT': arch_independent,
        }
        mesonlib.do_conf_file(template_file, version_file, build.ConfigurationData(conf), 'meson')

        res = build.Data([mesonlib.File(True, state.environment.get_scratch_dir(), version_file)], pkgroot, pkgroot_name, None, state.subproject)
        return ModuleReturnValue(res, [res])

    def create_package_file(self, infile: str, outfile: str, PACKAGE_RELATIVE_PATH: str, extra: str, confdata: build.ConfigurationData) -> None:
        package_init = PACKAGE_INIT_BASE.replace('@PACKAGE_RELATIVE_PATH@', PACKAGE_RELATIVE_PATH)
        package_init = package_init.replace('@inputFileName@', os.path.basename(infile))
        package_init += extra
        package_init += PACKAGE_INIT_SET_AND_CHECK

        try:
            with open(infile, encoding='utf-8') as fin:
                data = fin.readlines()
        except Exception as e:
            raise mesonlib.MesonException(f'Could not read input file {infile}: {e!s}')

        result = []
        regex = mesonlib.get_variable_regex('cmake@')
        for line in data:
            line = line.replace('@PACKAGE_INIT@', package_init)
            line, _missing = mesonlib.do_replacement(regex, line, 'cmake@', 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)

    @noPosargs
    @typed_kwargs(
        'cmake.configure_package_config_file',
        KwargInfo('configuration', (build.ConfigurationData, dict), required=True),
        KwargInfo('input',
                  (str, mesonlib.File, ContainerTypeInfo(list, mesonlib.File)), required=True,
                  validator=lambda x: 'requires exactly one file' if isinstance(x, list) and len(x) != 1 else None,
                  convertor=lambda x: x[0] if isinstance(x, list) else x),
        KwargInfo('name', str, required=True),
        INSTALL_DIR_KW,
    )
    def configure_package_config_file(self, state: ModuleState, args: TYPE_var, kwargs: 'ConfigurePackageConfigFile') -> build.Data:
        inputfile = kwargs['input']
        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)

        name = kwargs['name']

        (ofile_path, ofile_fname) = os.path.split(os.path.join(state.subdir, f'{name}Config.cmake'))
        ofile_abs = os.path.join(state.environment.build_dir, ofile_path, ofile_fname)

        install_dir = kwargs['install_dir']
        if install_dir is None:
            install_dir = os.path.join(state.environment.coredata.get_option(mesonlib.OptionKey('libdir')), 'cmake', name)

        conf = kwargs['configuration']
        if isinstance(conf, dict):
            FeatureNew.single_use('cmake.configure_package_config_file dict as configuration', '0.62.0', state.subproject, location=state.current_node)
            conf = build.ConfigurationData(conf)

        prefix = state.environment.coredata.get_option(mesonlib.OptionKey('prefix'))
        abs_install_dir = install_dir
        if not os.path.isabs(abs_install_dir):
            abs_install_dir = os.path.join(prefix, install_dir)

        # path used in cmake scripts are POSIX even on Windows
        PACKAGE_RELATIVE_PATH = pathlib.PurePath(os.path.relpath(prefix, abs_install_dir)).as_posix()
        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)
        conf.used = True

        conffile = os.path.normpath(inputfile.relative_name())
        self.interpreter.build_def_files.add(conffile)

        res = build.Data([mesonlib.File(True, ofile_path, ofile_fname)], install_dir, install_dir, None, state.subproject)
        self.interpreter.build.data.append(res)

        return res

    @FeatureNew('subproject', '0.51.0')
    @typed_pos_args('cmake.subproject', str)
    @typed_kwargs(
        'cmake.subproject',
        REQUIRED_KW,
        KwargInfo('options', (CMakeSubprojectOptions, NoneType), since='0.55.0'),
        KwargInfo(
            'cmake_options',
            ContainerTypeInfo(list, str),
            default=[],
            listify=True,
            deprecated='0.55.0',
            deprecated_message='Use options instead',
        ),
    )
    def subproject(self, state: ModuleState, args: T.Tuple[str], kwargs_: Subproject) -> T.Union[SubprojectHolder, CMakeSubproject]:
        if kwargs_['cmake_options'] and kwargs_['options'] is not None:
            raise InterpreterException('"options" cannot be used together with "cmake_options"')
        dirname = args[0]
        kw: kwargs.DoSubproject = {
            'required': kwargs_['required'],
            'options': kwargs_['options'],
            'cmake_options': kwargs_['cmake_options'],
            'default_options': {},
            'version': [],
        }
        subp = self.interpreter.do_subproject(dirname, kw, force_method='cmake')
        if not subp.found():
            return subp
        return CMakeSubproject(subp)

    @FeatureNew('subproject_options', '0.55.0')
    @noKwargs
    @noPosargs
    def subproject_options(self, state: ModuleState, args: TYPE_var, kwargs: TYPE_kwargs) -> CMakeSubprojectOptions:
        return CMakeSubprojectOptions()

def initialize(*args: T.Any, **kwargs: T.Any) -> CmakeModule:
    return CmakeModule(*args, **kwargs)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/cuda.py0000644000175000017500000004450714562742363020155 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import typing as T
import re

from ..mesonlib import version_compare
from ..compilers.cuda import CudaCompiler

from . import NewExtensionModule, ModuleInfo

from ..interpreterbase import (
    flatten, permittedKwargs, noKwargs,
    InvalidArguments
)

if T.TYPE_CHECKING:
    from . import ModuleState
    from ..compilers import Compiler

class CudaModule(NewExtensionModule):

    INFO = ModuleInfo('CUDA', '0.50.0', unstable=True)

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.methods.update({
            "min_driver_version": self.min_driver_version,
            "nvcc_arch_flags":    self.nvcc_arch_flags,
            "nvcc_arch_readable": self.nvcc_arch_readable,
        })

    @noKwargs
    def min_driver_version(self, state: 'ModuleState',
                           args: T.Tuple[str],
                           kwargs: T.Dict[str, T.Any]) -> str:
        argerror = InvalidArguments('min_driver_version must have exactly one positional argument: ' +
                                    'a CUDA Toolkit version string. Beware that, since CUDA 11.0, ' +
                                    'the CUDA Toolkit\'s components (including NVCC) are versioned ' +
                                    'independently from each other (and the CUDA Toolkit as a whole).')

        if len(args) != 1 or not isinstance(args[0], str):
            raise argerror

        cuda_version = args[0]
        driver_version_table = [
            {'cuda_version': '>=12.0.0',   'windows': '527.41', 'linux': '525.60.13'},
            {'cuda_version': '>=11.8.0',   'windows': '522.06', 'linux': '520.61.05'},
            {'cuda_version': '>=11.7.1',   'windows': '516.31', 'linux': '515.48.07'},
            {'cuda_version': '>=11.7.0',   'windows': '516.01', 'linux': '515.43.04'},
            {'cuda_version': '>=11.6.1',   'windows': '511.65', 'linux': '510.47.03'},
            {'cuda_version': '>=11.6.0',   'windows': '511.23', 'linux': '510.39.01'},
            {'cuda_version': '>=11.5.1',   'windows': '496.13', 'linux': '495.29.05'},
            {'cuda_version': '>=11.5.0',   'windows': '496.04', 'linux': '495.29.05'},
            {'cuda_version': '>=11.4.3',   'windows': '472.50', 'linux': '470.82.01'},
            {'cuda_version': '>=11.4.1',   'windows': '471.41', 'linux': '470.57.02'},
            {'cuda_version': '>=11.4.0',   'windows': '471.11', 'linux': '470.42.01'},
            {'cuda_version': '>=11.3.0',   'windows': '465.89', 'linux': '465.19.01'},
            {'cuda_version': '>=11.2.2',   'windows': '461.33', 'linux': '460.32.03'},
            {'cuda_version': '>=11.2.1',   'windows': '461.09', 'linux': '460.32.03'},
            {'cuda_version': '>=11.2.0',   'windows': '460.82', 'linux': '460.27.03'},
            {'cuda_version': '>=11.1.1',   'windows': '456.81', 'linux': '455.32'},
            {'cuda_version': '>=11.1.0',   'windows': '456.38', 'linux': '455.23'},
            {'cuda_version': '>=11.0.3',   'windows': '451.82', 'linux': '450.51.06'},
            {'cuda_version': '>=11.0.2',   'windows': '451.48', 'linux': '450.51.05'},
            {'cuda_version': '>=11.0.1',   'windows': '451.22', 'linux': '450.36.06'},
            {'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 driver_version

    @permittedKwargs(['detected'])
    def nvcc_arch_flags(self, state: 'ModuleState',
                        args: T.Tuple[T.Union[Compiler, CudaCompiler, str]],
                        kwargs: T.Dict[str, T.Any]) -> T.List[str]:
        nvcc_arch_args = self._validate_nvcc_arch_args(args, kwargs)
        ret = self._nvcc_arch_flags(*nvcc_arch_args)[0]
        return ret

    @permittedKwargs(['detected'])
    def nvcc_arch_readable(self, state: 'ModuleState',
                           args: T.Tuple[T.Union[Compiler, CudaCompiler, str]],
                           kwargs: T.Dict[str, T.Any]) -> T.List[str]:
        nvcc_arch_args = self._validate_nvcc_arch_args(args, kwargs)
        ret = self._nvcc_arch_flags(*nvcc_arch_args)[1]
        return 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, CudaCompiler):
            return c.detected_cc
        return ''

    @staticmethod
    def _version_from_compiler(c):
        if isinstance(c, CudaCompiler):
            return c.version
        if isinstance(c, str):
            return c
        return 'unknown'

    def _validate_nvcc_arch_args(self, 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 _filter_cuda_arch_list(self, cuda_arch_list, lo=None, hi=None, saturate=None):
        """
        Filter CUDA arch list (no codenames) for >= low and < hi architecture
        bounds, and deduplicate.
        If saturate is provided, architectures >= hi are replaced with saturate.
        """

        filtered_cuda_arch_list = []
        for arch in cuda_arch_list:
            if arch:
                if lo and version_compare(arch, '<' + lo):
                    continue
                if hi and version_compare(arch, '>=' + hi):
                    if not saturate:
                        continue
                    arch = saturate
                if arch not in filtered_cuda_arch_list:
                    filtered_cuda_arch_list.append(arch)
        return filtered_cuda_arch_list

    def _nvcc_arch_flags(self, cuda_version, cuda_arch_list='Auto', detected=''):
        """
        Using the CUDA Toolkit version and the target architectures, compute
        the NVCC architecture flags.
        """

        # Replicates much of the logic of
        #     https://github.com/Kitware/CMake/blob/master/Modules/FindCUDA/select_compute_arch.cmake
        # except that a bug with cuda_arch_list="All" is worked around by
        # tracking both lower and upper limits on GPU architectures.

        cuda_known_gpu_architectures   = ['Fermi', 'Kepler', 'Maxwell']  # noqa: E221
        cuda_common_gpu_architectures  = ['3.0', '3.5', '5.0']           # noqa: E221
        cuda_hi_limit_gpu_architecture = None                            # noqa: E221
        cuda_lo_limit_gpu_architecture = '2.0'                           # noqa: E221
        cuda_all_gpu_architectures     = ['3.0', '3.2', '3.5', '5.0']    # noqa: E221

        if version_compare(cuda_version, '<7.0'):
            cuda_hi_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_hi_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_hi_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']             # noqa: E221
            cuda_all_gpu_architectures    += ['7.0', '7.2']      # noqa: E221
            # https://docs.nvidia.com/cuda/archive/9.0/cuda-toolkit-release-notes/index.html#unsupported-features
            cuda_lo_limit_gpu_architecture = '3.0'               # noqa: E221

            if version_compare(cuda_version, '<10.0'):
                cuda_common_gpu_architectures += ['7.2+PTX']  # noqa: E221
                cuda_hi_limit_gpu_architecture = '8.0'        # noqa: E221

        if version_compare(cuda_version, '>=10.0'):
            cuda_known_gpu_architectures  += ['Turing'] # noqa: E221
            cuda_common_gpu_architectures += ['7.5']    # noqa: E221
            cuda_all_gpu_architectures    += ['7.5']    # noqa: E221

            if version_compare(cuda_version, '<11.0'):
                cuda_common_gpu_architectures += ['7.5+PTX']  # noqa: E221
                cuda_hi_limit_gpu_architecture = '8.0'        # noqa: E221

        # need to account for the fact that Ampere is commonly assumed to include
        # SM8.0 and SM8.6 even though CUDA 11.0 doesn't support SM8.6
        cuda_ampere_bin = ['8.0']
        cuda_ampere_ptx = ['8.0']
        if version_compare(cuda_version, '>=11.0'):
            cuda_known_gpu_architectures  += ['Ampere'] # noqa: E221
            cuda_common_gpu_architectures += ['8.0']    # noqa: E221
            cuda_all_gpu_architectures    += ['8.0']    # noqa: E221
            # https://docs.nvidia.com/cuda/archive/11.0/cuda-toolkit-release-notes/index.html#deprecated-features
            cuda_lo_limit_gpu_architecture = '3.5'      # noqa: E221

            if version_compare(cuda_version, '<11.1'):
                cuda_common_gpu_architectures += ['8.0+PTX']  # noqa: E221
                cuda_hi_limit_gpu_architecture = '8.6'        # noqa: E221

        if version_compare(cuda_version, '>=11.1'):
            cuda_ampere_bin += ['8.6'] # noqa: E221
            cuda_ampere_ptx  = ['8.6'] # noqa: E221

            cuda_common_gpu_architectures += ['8.6']             # noqa: E221
            cuda_all_gpu_architectures    += ['8.6']             # noqa: E221

            if version_compare(cuda_version, '<11.8'):
                cuda_common_gpu_architectures += ['8.6+PTX']  # noqa: E221
                cuda_hi_limit_gpu_architecture = '8.7'        # noqa: E221

        if version_compare(cuda_version, '>=11.8'):
            cuda_known_gpu_architectures  += ['Orin', 'Lovelace', 'Hopper']  # noqa: E221
            cuda_common_gpu_architectures += ['8.9', '9.0', '9.0+PTX']       # noqa: E221
            cuda_all_gpu_architectures    += ['8.7', '8.9', '9.0']           # noqa: E221

            if version_compare(cuda_version, '<12'):
                cuda_hi_limit_gpu_architecture = '9.1'        # noqa: E221

        if version_compare(cuda_version, '>=12.0'):
            # https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html#deprecated-features (Current)
            # https://docs.nvidia.com/cuda/archive/12.0/cuda-toolkit-release-notes/index.html#deprecated-features (Eventual?)
            cuda_lo_limit_gpu_architecture = '5.0'            # noqa: E221

            if version_compare(cuda_version, '<13'):
                cuda_hi_limit_gpu_architecture = '10.0'       # noqa: E221

        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)
                cuda_arch_list = self._filter_cuda_arch_list(cuda_arch_list,
                                                             cuda_lo_limit_gpu_architecture,
                                                             cuda_hi_limit_gpu_architecture,
                                                             cuda_common_gpu_architectures[-1])
            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']),
                    'Ampere':        (cuda_ampere_bin,     cuda_ampere_ptx),
                    'Orin':          (['8.7'],             []),
                    'Lovelace':      (['8.9'],             ['8.9']),
                    'Hopper':        (['9.0'],             ['9.0']),
                }.get(arch_name, (None, None))

            if arch_bin is None:
                raise InvalidArguments(f'Unknown CUDA Architecture Name {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 = sorted(set(cuda_arch_bin))
        cuda_arch_ptx = sorted(set(cuda_arch_ptx))

        nvcc_flags = []
        nvcc_archs_readable = []

        for arch in cuda_arch_bin:
            arch, codev = re.fullmatch(
                '([0-9]+\\.[0-9])(?:\\(([0-9]+\\.[0-9])\\))?', arch).groups()

            if version_compare(arch, '<' + cuda_lo_limit_gpu_architecture):
                continue
            if cuda_hi_limit_gpu_architecture and version_compare(arch, '>=' + cuda_hi_limit_gpu_architecture):
                continue

            if codev:
                arch = arch.replace('.', '')
                codev = codev.replace('.', '')
                nvcc_flags += ['-gencode', 'arch=compute_' + codev + ',code=sm_' + arch]
                nvcc_archs_readable += ['sm_' + arch]
            else:
                arch = arch.replace('.', '')
                nvcc_flags += ['-gencode', 'arch=compute_' + arch + ',code=sm_' + arch]
                nvcc_archs_readable += ['sm_' + arch]

        for arch in cuda_arch_ptx:
            arch, codev = re.fullmatch(
                '([0-9]+\\.[0-9])(?:\\(([0-9]+\\.[0-9])\\))?', arch).groups()

            if codev:
                arch = codev

            if version_compare(arch, '<' + cuda_lo_limit_gpu_architecture):
                continue
            if cuda_hi_limit_gpu_architecture and version_compare(arch, '>=' + cuda_hi_limit_gpu_architecture):
                continue

            arch = arch.replace('.', '')
            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)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/dlang.py0000644000175000017500000001203314562742363020313 0ustar00jpakkanejpakkane# 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.
from __future__ import annotations

import json
import os

from . import ExtensionModule, ModuleInfo
from .. import mlog
from ..dependencies import Dependency
from ..dependencies.dub import DubDependency
from ..interpreterbase import typed_pos_args
from ..mesonlib import Popen_safe, MesonException

class DlangModule(ExtensionModule):
    class_dubbin = None
    init_dub = False

    INFO = ModuleInfo('dlang', '0.48.0')

    def __init__(self, interpreter):
        super().__init__(interpreter)
        self.methods.update({
            'generate_dub_file': self.generate_dub_file,
        })

    def _init_dub(self, state):
        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(state)
            DlangModule.class_dubbin = self.dubbin
        else:
            self.dubbin = DlangModule.class_dubbin

        if not self.dubbin:
            if not self.dubbin:
                raise MesonException('DUB not found.')

    @typed_pos_args('dlang.generate_dub_file', str, str)
    def generate_dub_file(self, state, args, kwargs):
        if not DlangModule.init_dub:
            self._init_dub(state)

        config = {
            'name': args[0]
        }

        config_path = os.path.join(args[1], 'dub.json')
        if os.path.exists(config_path):
            with open(config_path, encoding='utf-8') 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, Dependency):
                            name = dep.get_name()
                            ret, res = self._call_dubbin(['describe', name])
                            if ret == 0:
                                version = dep.get_version()
                                if version is None:
                                    config[key][name] = ''
                                else:
                                    config[key][name] = version
                elif isinstance(value, Dependency):
                    name = value.get_name()
                    ret, res = self._call_dubbin(['describe', name])
                    if ret == 0:
                        version = value.get_version()
                        if version is None:
                            config[key][name] = ''
                        else:
                            config[key][name] = version
            else:
                config[key] = value

        with open(config_path, 'w', encoding='utf-8') 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, state):
        dubbin = state.find_program('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)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/external_project.py0000644000175000017500000003305714562742363022607 0ustar00jpakkanejpakkane# Copyright 2020 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 __future__ import annotations

from pathlib import Path
import os
import shlex
import subprocess
import typing as T

from . import ExtensionModule, ModuleReturnValue, NewExtensionModule, ModuleInfo
from .. import mlog, build
from ..compilers.compilers import CFLAGS_MAPPING
from ..envconfig import ENV_VAR_PROG_MAP
from ..dependencies import InternalDependency
from ..dependencies.pkgconfig import PkgConfigInterface
from ..interpreterbase import FeatureNew
from ..interpreter.type_checking import ENV_KW, DEPENDS_KW
from ..interpreterbase.decorators import ContainerTypeInfo, KwargInfo, typed_kwargs, typed_pos_args
from ..mesonlib import (EnvironmentException, MesonException, Popen_safe, MachineChoice,
                        get_variable_regex, do_replacement, join_args, OptionKey)

if T.TYPE_CHECKING:
    from typing_extensions import TypedDict

    from . import ModuleState
    from .._typing import ImmutableListProtocol
    from ..build import BuildTarget, CustomTarget
    from ..interpreter import Interpreter
    from ..interpreterbase import TYPE_var
    from ..mesonlib import EnvironmentVariables
    from ..utils.core import EnvironOrDict

    class Dependency(TypedDict):

        subdir: str

    class AddProject(TypedDict):

        configure_options: T.List[str]
        cross_configure_options: T.List[str]
        verbose: bool
        env: EnvironmentVariables
        depends: T.List[T.Union[BuildTarget, CustomTarget]]


class ExternalProject(NewExtensionModule):

    make: ImmutableListProtocol[str]

    def __init__(self,
                 state: 'ModuleState',
                 configure_command: str,
                 configure_options: T.List[str],
                 cross_configure_options: T.List[str],
                 env: EnvironmentVariables,
                 verbose: bool,
                 extra_depends: T.List[T.Union['BuildTarget', 'CustomTarget']]):
        super().__init__()
        self.methods.update({'dependency': self.dependency_method,
                             })

        self.subdir = Path(state.subdir)
        self.project_version = state.project_version
        self.subproject = state.subproject
        self.env = state.environment
        self.build_machine = state.build_machine
        self.host_machine = state.host_machine
        self.configure_command = configure_command
        self.configure_options = configure_options
        self.cross_configure_options = cross_configure_options
        self.verbose = verbose
        self.user_env = env

        self.src_dir = Path(self.env.get_source_dir(), self.subdir)
        self.build_dir = Path(self.env.get_build_dir(), self.subdir, 'build')
        self.install_dir = Path(self.env.get_build_dir(), self.subdir, 'dist')
        _p = self.env.coredata.get_option(OptionKey('prefix'))
        assert isinstance(_p, str), 'for mypy'
        self.prefix = Path(_p)
        _l = self.env.coredata.get_option(OptionKey('libdir'))
        assert isinstance(_l, str), 'for mypy'
        self.libdir = Path(_l)
        _i = self.env.coredata.get_option(OptionKey('includedir'))
        assert isinstance(_i, str), 'for mypy'
        self.includedir = Path(_i)
        self.name = self.src_dir.name

        # On Windows if the prefix is "c:/foo" and DESTDIR is "c:/bar", `make`
        # will install files into "c:/bar/c:/foo" which is an invalid path.
        # Work around that issue by removing the drive from prefix.
        if self.prefix.drive:
            self.prefix = self.prefix.relative_to(self.prefix.drive)

        # self.prefix is an absolute path, so we cannot append it to another path.
        self.rel_prefix = self.prefix.relative_to(self.prefix.root)

        self._configure(state)

        self.targets = self._create_targets(extra_depends)

    def _configure(self, state: 'ModuleState') -> None:
        if self.configure_command == 'waf':
            FeatureNew('Waf external project', '0.60.0').use(self.subproject, state.current_node)
            waf = state.find_program('waf')
            configure_cmd = waf.get_command()
            configure_cmd += ['configure', '-o', str(self.build_dir)]
            workdir = self.src_dir
            self.make = waf.get_command() + ['build']
        else:
            # Assume it's the name of a script in source dir, like 'configure',
            # 'autogen.sh', etc).
            configure_path = Path(self.src_dir, self.configure_command)
            configure_prog = state.find_program(configure_path.as_posix())
            configure_cmd = configure_prog.get_command()
            workdir = self.build_dir
            self.make = state.find_program('make').get_command()

        d = [('PREFIX', '--prefix=@PREFIX@', self.prefix.as_posix()),
             ('LIBDIR', '--libdir=@PREFIX@/@LIBDIR@', self.libdir.as_posix()),
             ('INCLUDEDIR', None, self.includedir.as_posix()),
             ]
        self._validate_configure_options(d, state)

        configure_cmd += self._format_options(self.configure_options, d)

        if self.env.is_cross_build():
            host = '{}-{}-{}'.format(self.host_machine.cpu_family,
                                     self.build_machine.system,
                                     self.host_machine.system)
            d = [('HOST', None, host)]
            configure_cmd += self._format_options(self.cross_configure_options, d)

        # Set common env variables like CFLAGS, CC, etc.
        link_exelist: T.List[str] = []
        link_args: T.List[str] = []
        self.run_env: EnvironOrDict = os.environ.copy()
        for lang, compiler in self.env.coredata.compilers[MachineChoice.HOST].items():
            if any(lang not in i for i in (ENV_VAR_PROG_MAP, CFLAGS_MAPPING)):
                continue
            cargs = self.env.coredata.get_external_args(MachineChoice.HOST, lang)
            assert isinstance(cargs, list), 'for mypy'
            self.run_env[ENV_VAR_PROG_MAP[lang]] = self._quote_and_join(compiler.get_exelist())
            self.run_env[CFLAGS_MAPPING[lang]] = self._quote_and_join(cargs)
            if not link_exelist:
                link_exelist = compiler.get_linker_exelist()
                _l = self.env.coredata.get_external_link_args(MachineChoice.HOST, lang)
                assert isinstance(_l, list), 'for mypy'
                link_args = _l
        if link_exelist:
            # FIXME: Do not pass linker because Meson uses CC as linker wrapper,
            # but autotools often expects the real linker (e.h. GNU ld).
            # self.run_env['LD'] = self._quote_and_join(link_exelist)
            pass
        self.run_env['LDFLAGS'] = self._quote_and_join(link_args)

        self.run_env = self.user_env.get_env(self.run_env)
        self.run_env = PkgConfigInterface.setup_env(self.run_env, self.env, MachineChoice.HOST,
                                                    uninstalled=True)

        self.build_dir.mkdir(parents=True, exist_ok=True)
        self._run('configure', configure_cmd, workdir)

    def _quote_and_join(self, array: T.List[str]) -> str:
        return ' '.join([shlex.quote(i) for i in array])

    def _validate_configure_options(self, variables: T.List[T.Tuple[str, str, str]], state: 'ModuleState') -> None:
        # Ensure the user at least try to pass basic info to the build system,
        # like the prefix, libdir, etc.
        for key, default, val in variables:
            if default is None:
                continue
            key_format = f'@{key}@'
            for option in self.configure_options:
                if key_format in option:
                    break
            else:
                FeatureNew('Default configure_option', '0.57.0').use(self.subproject, state.current_node)
                self.configure_options.append(default)

    def _format_options(self, options: T.List[str], variables: T.List[T.Tuple[str, str, str]]) -> T.List[str]:
        out: T.List[str] = []
        missing = set()
        regex = get_variable_regex('meson')
        confdata: T.Dict[str, T.Tuple[str, T.Optional[str]]] = {k: (v, None) for k, _, v in variables}
        for o in options:
            arg, missing_vars = do_replacement(regex, o, 'meson', confdata)
            missing.update(missing_vars)
            out.append(arg)
        if missing:
            var_list = ", ".join(repr(m) for m in sorted(missing))
            raise EnvironmentException(
                f"Variables {var_list} in configure options are missing.")
        return out

    def _run(self, step: str, command: T.List[str], workdir: Path) -> None:
        mlog.log(f'External project {self.name}:', mlog.bold(step))
        m = 'Running command ' + str(command) + ' in directory ' + str(workdir) + '\n'
        log_filename = Path(mlog.get_log_dir(), f'{self.name}-{step}.log')
        output = None
        if not self.verbose:
            output = open(log_filename, 'w', encoding='utf-8')
            output.write(m + '\n')
            output.flush()
        else:
            mlog.log(m)
        p, *_ = Popen_safe(command, cwd=workdir, env=self.run_env,
                           stderr=subprocess.STDOUT,
                           stdout=output)
        if p.returncode != 0:
            m = f'{step} step returned error code {p.returncode}.'
            if not self.verbose:
                m += '\nSee logs: ' + str(log_filename)
            raise MesonException(m)

    def _create_targets(self, extra_depends: T.List[T.Union['BuildTarget', 'CustomTarget']]) -> T.List['TYPE_var']:
        cmd = self.env.get_build_command()
        cmd += ['--internal', 'externalproject',
                '--name', self.name,
                '--srcdir', self.src_dir.as_posix(),
                '--builddir', self.build_dir.as_posix(),
                '--installdir', self.install_dir.as_posix(),
                '--logdir', mlog.get_log_dir(),
                '--make', join_args(self.make),
                ]
        if self.verbose:
            cmd.append('--verbose')

        self.target = build.CustomTarget(
            self.name,
            self.subdir.as_posix(),
            self.subproject,
            self.env,
            cmd + ['@OUTPUT@', '@DEPFILE@'],
            [],
            [f'{self.name}.stamp'],
            depfile=f'{self.name}.d',
            console=True,
            extra_depends=extra_depends,
            description='Generating external project {}',
        )

        idir = build.InstallDir(self.subdir.as_posix(),
                                Path('dist', self.rel_prefix).as_posix(),
                                install_dir='.',
                                install_dir_name='.',
                                install_mode=None,
                                exclude=None,
                                strip_directory=True,
                                from_source_dir=False,
                                subproject=self.subproject)

        return [self.target, idir]

    @typed_pos_args('external_project.dependency', str)
    @typed_kwargs('external_project.dependency', KwargInfo('subdir', str, default=''))
    def dependency_method(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'Dependency') -> InternalDependency:
        libname = args[0]

        abs_includedir = Path(self.install_dir, self.rel_prefix, self.includedir)
        if kwargs['subdir']:
            abs_includedir = Path(abs_includedir, kwargs['subdir'])
        abs_libdir = Path(self.install_dir, self.rel_prefix, self.libdir)

        version = self.project_version
        compile_args = [f'-I{abs_includedir}']
        link_args = [f'-L{abs_libdir}', f'-l{libname}']
        sources = self.target
        dep = InternalDependency(version, [], compile_args, link_args, [],
                                 [], [sources], [], [], {}, [], [], [])
        return dep


class ExternalProjectModule(ExtensionModule):

    INFO = ModuleInfo('External build system', '0.56.0', unstable=True)

    def __init__(self, interpreter: 'Interpreter'):
        super().__init__(interpreter)
        self.methods.update({'add_project': self.add_project,
                             })

    @typed_pos_args('external_project_mod.add_project', str)
    @typed_kwargs(
        'external_project.add_project',
        KwargInfo('configure_options', ContainerTypeInfo(list, str), default=[], listify=True),
        KwargInfo('cross_configure_options', ContainerTypeInfo(list, str), default=['--host=@HOST@'], listify=True),
        KwargInfo('verbose', bool, default=False),
        ENV_KW,
        DEPENDS_KW.evolve(since='0.63.0'),
    )
    def add_project(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'AddProject') -> ModuleReturnValue:
        configure_command = args[0]
        project = ExternalProject(state,
                                  configure_command,
                                  kwargs['configure_options'],
                                  kwargs['cross_configure_options'],
                                  kwargs['env'],
                                  kwargs['verbose'],
                                  kwargs['depends'])
        return ModuleReturnValue(project, project.targets)


def initialize(interp: 'Interpreter') -> ExternalProjectModule:
    return ExternalProjectModule(interp)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/fs.py0000644000175000017500000003311414562742363017641 0ustar00jpakkanejpakkane# 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 __future__ import annotations
from pathlib import Path, PurePath, PureWindowsPath
import hashlib
import os
import typing as T

from . import ExtensionModule, ModuleReturnValue, ModuleInfo
from .. import mlog
from ..build import BuildTarget, CustomTarget, CustomTargetIndex, InvalidArguments
from ..interpreter.type_checking import INSTALL_KW, INSTALL_MODE_KW, INSTALL_TAG_KW, NoneType
from ..interpreterbase import FeatureNew, KwargInfo, typed_kwargs, typed_pos_args, noKwargs
from ..mesonlib import File, MesonException, has_path_sep, path_is_in_root, relpath

if T.TYPE_CHECKING:
    from . import ModuleState
    from ..build import BuildTargetTypes
    from ..interpreter import Interpreter
    from ..interpreterbase import TYPE_kwargs
    from ..mesonlib import FileOrString, FileMode

    from typing_extensions import TypedDict

    class ReadKwArgs(TypedDict):
        """Keyword Arguments for fs.read."""

        encoding: str

    class CopyKw(TypedDict):

        """Kwargs for fs.copy"""

        install: bool
        install_dir: T.Optional[str]
        install_mode: FileMode
        install_tag: T.Optional[str]


class FSModule(ExtensionModule):

    INFO = ModuleInfo('fs', '0.53.0')

    def __init__(self, interpreter: 'Interpreter') -> None:
        super().__init__(interpreter)
        self.methods.update({
            'expanduser': self.expanduser,
            'is_absolute': self.is_absolute,
            'as_posix': self.as_posix,
            'exists': self.exists,
            'is_symlink': self.is_symlink,
            'is_file': self.is_file,
            'is_dir': self.is_dir,
            'hash': self.hash,
            'size': self.size,
            'is_samepath': self.is_samepath,
            'replace_suffix': self.replace_suffix,
            'parent': self.parent,
            'name': self.name,
            'stem': self.stem,
            'read': self.read,
            'copyfile': self.copyfile,
            'relative_to': self.relative_to,
        })

    def _absolute_dir(self, state: 'ModuleState', arg: 'FileOrString') -> Path:
        """
        make an absolute path from a relative path, WITHOUT resolving symlinks
        """
        if isinstance(arg, File):
            return Path(arg.absolute_path(state.source_root, self.interpreter.environment.get_build_dir()))
        return Path(state.source_root) / Path(state.subdir) / Path(arg).expanduser()

    def _resolve_dir(self, state: 'ModuleState', arg: 'FileOrString') -> Path:
        """
        resolves symlinks and makes absolute a directory relative to calling meson.build,
        if not already absolute
        """
        path = self._absolute_dir(state, arg)
        try:
            # accommodate unresolvable paths e.g. symlink loops
            path = path.resolve()
        except Exception:
            # return the best we could do
            pass
        return path

    @noKwargs
    @FeatureNew('fs.expanduser', '0.54.0')
    @typed_pos_args('fs.expanduser', str)
    def expanduser(self, state: 'ModuleState', args: T.Tuple[str], kwargs: T.Dict[str, T.Any]) -> str:
        return str(Path(args[0]).expanduser())

    @noKwargs
    @FeatureNew('fs.is_absolute', '0.54.0')
    @typed_pos_args('fs.is_absolute', (str, File))
    def is_absolute(self, state: 'ModuleState', args: T.Tuple['FileOrString'], kwargs: T.Dict[str, T.Any]) -> bool:
        if isinstance(args[0], File):
            FeatureNew('fs.is_absolute_file', '0.59.0').use(state.subproject)
        return PurePath(str(args[0])).is_absolute()

    @noKwargs
    @FeatureNew('fs.as_posix', '0.54.0')
    @typed_pos_args('fs.as_posix', str)
    def as_posix(self, state: 'ModuleState', args: T.Tuple[str], kwargs: T.Dict[str, T.Any]) -> str:
        """
        this function assumes you are passing a Windows path, even if on a Unix-like system
        and so ALL '\' are turned to '/', even if you meant to escape a character
        """
        return PureWindowsPath(args[0]).as_posix()

    @noKwargs
    @typed_pos_args('fs.exists', str)
    def exists(self, state: 'ModuleState', args: T.Tuple[str], kwargs: T.Dict[str, T.Any]) -> bool:
        return self._resolve_dir(state, args[0]).exists()

    @noKwargs
    @typed_pos_args('fs.is_symlink', (str, File))
    def is_symlink(self, state: 'ModuleState', args: T.Tuple['FileOrString'], kwargs: T.Dict[str, T.Any]) -> bool:
        if isinstance(args[0], File):
            FeatureNew('fs.is_symlink_file', '0.59.0').use(state.subproject)
        return self._absolute_dir(state, args[0]).is_symlink()

    @noKwargs
    @typed_pos_args('fs.is_file', str)
    def is_file(self, state: 'ModuleState', args: T.Tuple[str], kwargs: T.Dict[str, T.Any]) -> bool:
        return self._resolve_dir(state, args[0]).is_file()

    @noKwargs
    @typed_pos_args('fs.is_dir', str)
    def is_dir(self, state: 'ModuleState', args: T.Tuple[str], kwargs: T.Dict[str, T.Any]) -> bool:
        return self._resolve_dir(state, args[0]).is_dir()

    @noKwargs
    @typed_pos_args('fs.hash', (str, File), str)
    def hash(self, state: 'ModuleState', args: T.Tuple['FileOrString', str], kwargs: T.Dict[str, T.Any]) -> str:
        if isinstance(args[0], File):
            FeatureNew('fs.hash_file', '0.59.0').use(state.subproject)
        file = self._resolve_dir(state, args[0])
        if not file.is_file():
            raise MesonException(f'{file} is not a file and therefore cannot be hashed')
        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 h.hexdigest()

    @noKwargs
    @typed_pos_args('fs.size', (str, File))
    def size(self, state: 'ModuleState', args: T.Tuple['FileOrString'], kwargs: T.Dict[str, T.Any]) -> int:
        if isinstance(args[0], File):
            FeatureNew('fs.size_file', '0.59.0').use(state.subproject)
        file = self._resolve_dir(state, args[0])
        if not file.is_file():
            raise MesonException(f'{file} is not a file and therefore cannot be sized')
        try:
            return file.stat().st_size
        except ValueError:
            raise MesonException('{} size could not be determined'.format(args[0]))

    @noKwargs
    @typed_pos_args('fs.is_samepath', (str, File), (str, File))
    def is_samepath(self, state: 'ModuleState', args: T.Tuple['FileOrString', 'FileOrString'], kwargs: T.Dict[str, T.Any]) -> bool:
        if isinstance(args[0], File) or isinstance(args[1], File):
            FeatureNew('fs.is_samepath_file', '0.59.0').use(state.subproject)
        file1 = self._resolve_dir(state, args[0])
        file2 = self._resolve_dir(state, args[1])
        if not file1.exists():
            return False
        if not file2.exists():
            return False
        try:
            return file1.samefile(file2)
        except OSError:
            return False

    @noKwargs
    @typed_pos_args('fs.replace_suffix', (str, File), str)
    def replace_suffix(self, state: 'ModuleState', args: T.Tuple['FileOrString', str], kwargs: T.Dict[str, T.Any]) -> str:
        if isinstance(args[0], File):
            FeatureNew('fs.replace_suffix_file', '0.59.0').use(state.subproject)
        original = PurePath(str(args[0]))
        new = original.with_suffix(args[1])
        return str(new)

    @noKwargs
    @typed_pos_args('fs.parent', (str, File))
    def parent(self, state: 'ModuleState', args: T.Tuple['FileOrString'], kwargs: T.Dict[str, T.Any]) -> str:
        if isinstance(args[0], File):
            FeatureNew('fs.parent_file', '0.59.0').use(state.subproject)
        original = PurePath(str(args[0]))
        new = original.parent
        return str(new)

    @noKwargs
    @typed_pos_args('fs.name', (str, File))
    def name(self, state: 'ModuleState', args: T.Tuple['FileOrString'], kwargs: T.Dict[str, T.Any]) -> str:
        if isinstance(args[0], File):
            FeatureNew('fs.name_file', '0.59.0').use(state.subproject)
        original = PurePath(str(args[0]))
        new = original.name
        return str(new)

    @noKwargs
    @typed_pos_args('fs.stem', (str, File))
    @FeatureNew('fs.stem', '0.54.0')
    def stem(self, state: 'ModuleState', args: T.Tuple['FileOrString'], kwargs: T.Dict[str, T.Any]) -> str:
        if isinstance(args[0], File):
            FeatureNew('fs.stem_file', '0.59.0').use(state.subproject)
        original = PurePath(str(args[0]))
        new = original.stem
        return str(new)

    @FeatureNew('fs.read', '0.57.0')
    @typed_pos_args('fs.read', (str, File))
    @typed_kwargs('fs.read', KwargInfo('encoding', str, default='utf-8'))
    def read(self, state: 'ModuleState', args: T.Tuple['FileOrString'], kwargs: 'ReadKwArgs') -> str:
        """Read a file from the source tree and return its value as a decoded
        string.

        If the encoding is not specified, the file is assumed to be utf-8
        encoded. Paths must be relative by default (to prevent accidents) and
        are forbidden to be read from the build directory (to prevent build
        loops)
        """
        path = args[0]
        encoding = kwargs['encoding']
        src_dir = self.interpreter.environment.source_dir
        sub_dir = self.interpreter.subdir
        build_dir = self.interpreter.environment.get_build_dir()

        if isinstance(path, File):
            if path.is_built:
                raise MesonException(
                    'fs.read_file does not accept built files() objects')
            path = os.path.join(src_dir, path.relative_name())
        else:
            if sub_dir:
                src_dir = os.path.join(src_dir, sub_dir)
            path = os.path.join(src_dir, path)

        path = os.path.abspath(path)
        if path_is_in_root(Path(path), Path(build_dir), resolve=True):
            raise MesonException('path must not be in the build tree')
        try:
            with open(path, encoding=encoding) as f:
                data = f.read()
        except FileNotFoundError:
            raise MesonException(f'File {args[0]} does not exist.')
        except UnicodeDecodeError:
            raise MesonException(f'decoding failed for {args[0]}')
        # Reconfigure when this file changes as it can contain data used by any
        # part of the build configuration (e.g. `project(..., version:
        # fs.read_file('VERSION')` or `configure_file(...)`
        self.interpreter.add_build_def_file(path)
        return data

    @FeatureNew('fs.copyfile', '0.64.0')
    @typed_pos_args('fs.copyfile', (File, str), optargs=[str])
    @typed_kwargs(
        'fs.copyfile',
        INSTALL_KW,
        INSTALL_MODE_KW,
        INSTALL_TAG_KW,
        KwargInfo('install_dir', (str, NoneType)),
    )
    def copyfile(self, state: ModuleState, args: T.Tuple[FileOrString, T.Optional[str]],
                 kwargs: CopyKw) -> ModuleReturnValue:
        """Copy a file into the build directory at build time."""
        if kwargs['install'] and not kwargs['install_dir']:
            raise InvalidArguments('"install_dir" must be specified when "install" is true')

        src = self.interpreter.source_strings_to_files([args[0]])[0]

        # The input is allowed to have path separators, but the output may not,
        # so use the basename for the default case
        dest = args[1] if args[1] else os.path.basename(src.fname)
        if has_path_sep(dest):
            raise InvalidArguments('Destination path may not have path separators')

        ct = CustomTarget(
            dest,
            state.subdir,
            state.subproject,
            state.environment,
            state.environment.get_build_command() + ['--internal', 'copy', '@INPUT@', '@OUTPUT@'],
            [src],
            [dest],
            build_by_default=True,
            install=kwargs['install'],
            install_dir=[kwargs['install_dir']],
            install_mode=kwargs['install_mode'],
            install_tag=[kwargs['install_tag']],
            backend=state.backend,
            description='Copying file {}',
        )

        return ModuleReturnValue(ct, [ct])

    @FeatureNew('fs.relative_to', '1.3.0')
    @typed_pos_args('fs.relative_to', (str, File, CustomTarget, CustomTargetIndex, BuildTarget), (str, File, CustomTarget, CustomTargetIndex, BuildTarget))
    @noKwargs
    def relative_to(self, state: ModuleState, args: T.Tuple[T.Union[FileOrString, BuildTargetTypes], T.Union[FileOrString, BuildTargetTypes]], kwargs: TYPE_kwargs) -> str:
        def to_path(arg: T.Union[FileOrString, CustomTarget, CustomTargetIndex, BuildTarget]) -> str:
            if isinstance(arg, File):
                return arg.absolute_path(state.environment.source_dir, state.environment.build_dir)
            elif isinstance(arg, (CustomTarget, CustomTargetIndex, BuildTarget)):
                return state.backend.get_target_filename_abs(arg)
            else:
                return os.path.join(state.environment.source_dir, state.subdir, arg)

        t = to_path(args[0])
        f = to_path(args[1])

        return relpath(t, f)


def initialize(*args: T.Any, **kwargs: T.Any) -> FSModule:
    return FSModule(*args, **kwargs)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/gnome.py0000644000175000017500000031473614562742363020352 0ustar00jpakkanejpakkane# 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'''
from __future__ import annotations

import copy
import itertools
import functools
import os
import subprocess
import textwrap
import typing as T

from . import (
    ExtensionModule, GirTarget, GResourceHeaderTarget, GResourceTarget, ModuleInfo,
    ModuleReturnValue, TypelibTarget, VapiTarget,
)
from .. import build
from .. import interpreter
from .. import mesonlib
from .. import mlog
from ..build import CustomTarget, CustomTargetIndex, Executable, GeneratedList, InvalidArguments
from ..dependencies import Dependency, InternalDependency
from ..dependencies.pkgconfig import PkgConfigDependency, PkgConfigInterface
from ..interpreter.type_checking import DEPENDS_KW, DEPEND_FILES_KW, ENV_KW, INSTALL_DIR_KW, INSTALL_KW, NoneType, DEPENDENCY_SOURCES_KW, in_set_validator
from ..interpreterbase import noPosargs, noKwargs, FeatureNew, FeatureDeprecated
from ..interpreterbase import typed_kwargs, KwargInfo, ContainerTypeInfo
from ..interpreterbase.decorators import typed_pos_args
from ..mesonlib import (
    MachineChoice, MesonException, OrderedSet, Popen_safe, join_args, quote_arg
)
from ..programs import OverrideProgram
from ..scripts.gettext import read_linguas

if T.TYPE_CHECKING:
    from typing_extensions import Literal, TypedDict

    from . import ModuleState
    from ..build import BuildTarget
    from ..compilers import Compiler
    from ..interpreter import Interpreter
    from ..interpreterbase import TYPE_var, TYPE_kwargs
    from ..mesonlib import FileOrString
    from ..programs import ExternalProgram

    class PostInstall(TypedDict):
        glib_compile_schemas: bool
        gio_querymodules: T.List[str]
        gtk_update_icon_cache: bool
        update_desktop_database: bool
        update_mime_database: bool

    class CompileSchemas(TypedDict):

        build_by_default: bool
        depend_files: T.List[FileOrString]

    class Yelp(TypedDict):

        languages: T.List[str]
        media: T.List[str]
        sources: T.List[str]
        symlink_media: bool

    class CompileResources(TypedDict):

        build_by_default: bool
        c_name: T.Optional[str]
        dependencies: T.List[T.Union[mesonlib.File, CustomTarget, CustomTargetIndex]]
        export: bool
        extra_args: T.List[str]
        gresource_bundle: bool
        install: bool
        install_dir: T.Optional[str]
        install_header: bool
        source_dir: T.List[str]

    class GenerateGir(TypedDict):

        build_by_default: bool
        dependencies: T.List[Dependency]
        export_packages: T.List[str]
        extra_args: T.List[str]
        fatal_warnings: bool
        header: T.List[str]
        identifier_prefix: T.List[str]
        include_directories: T.List[T.Union[build.IncludeDirs, str]]
        includes: T.List[T.Union[str, GirTarget]]
        install: bool
        install_dir_gir: T.Optional[str]
        install_dir_typelib: T.Optional[str]
        link_with: T.List[T.Union[build.SharedLibrary, build.StaticLibrary]]
        namespace: str
        nsversion: str
        sources: T.List[T.Union[FileOrString, build.GeneratedTypes]]
        symbol_prefix: T.List[str]

    class GtkDoc(TypedDict):

        src_dir: T.List[T.Union[str, build.IncludeDirs]]
        main_sgml: str
        main_xml: str
        module_version: str
        namespace: str
        mode: Literal['xml', 'smgl', 'auto', 'none']
        html_args: T.List[str]
        scan_args: T.List[str]
        scanobjs_args: T.List[str]
        fixxref_args: T.List[str]
        mkdb_args: T.List[str]
        content_files: T.List[T.Union[build.GeneratedTypes, FileOrString]]
        ignore_headers: T.List[str]
        install_dir: T.List[str]
        check: bool
        install: bool
        gobject_typesfile: T.List[FileOrString]
        html_assets: T.List[FileOrString]
        expand_content_files: T.List[FileOrString]
        c_args: T.List[str]
        include_directories: T.List[T.Union[str, build.IncludeDirs]]
        dependencies: T.List[T.Union[Dependency, build.SharedLibrary, build.StaticLibrary]]

    class GdbusCodegen(TypedDict):

        sources: T.List[FileOrString]
        extra_args: T.List[str]
        interface_prefix: T.Optional[str]
        namespace: T.Optional[str]
        object_manager: bool
        build_by_default: bool
        annotations: T.List[T.List[str]]
        install_header: bool
        install_dir: T.Optional[str]
        docbook: T.Optional[str]
        autocleanup: Literal['all', 'none', 'objects', 'default']

    class GenMarshal(TypedDict):

        build_always: T.Optional[str]
        build_always_stale: T.Optional[bool]
        build_by_default: T.Optional[bool]
        depend_files: T.List[mesonlib.File]
        extra_args: T.List[str]
        install_dir: T.Optional[str]
        install_header: bool
        internal: bool
        nostdinc: bool
        prefix: T.Optional[str]
        skip_source: bool
        sources: T.List[FileOrString]
        stdinc: bool
        valist_marshallers: bool

    class GenerateVapi(TypedDict):

        sources: T.List[T.Union[str, GirTarget]]
        install_dir: T.Optional[str]
        install: bool
        vapi_dirs: T.List[str]
        metadata_dirs: T.List[str]
        gir_dirs: T.List[str]
        packages: T.List[T.Union[str, InternalDependency]]

    class _MkEnumsCommon(TypedDict):

        install_header: bool
        install_dir: T.Optional[str]
        identifier_prefix: T.Optional[str]
        symbol_prefix: T.Optional[str]

    class MkEnumsSimple(_MkEnumsCommon):

        sources: T.List[FileOrString]
        header_prefix: str
        decorator: str
        function_prefix: str
        body_prefix: str

    class MkEnums(_MkEnumsCommon):

        sources: T.List[T.Union[FileOrString, build.GeneratedTypes]]
        c_template: T.Optional[FileOrString]
        h_template: T.Optional[FileOrString]
        comments: T.Optional[str]
        eprod: T.Optional[str]
        fhead: T.Optional[str]
        fprod: T.Optional[str]
        ftail: T.Optional[str]
        vhead: T.Optional[str]
        vprod: T.Optional[str]
        vtail: T.Optional[str]
        depends: T.List[T.Union[BuildTarget, CustomTarget, CustomTargetIndex]]

    ToolType = T.Union[Executable, ExternalProgram, OverrideProgram]


# Differs from the CustomTarget version in that it straight defaults to True
_BUILD_BY_DEFAULT: KwargInfo[bool] = KwargInfo(
    'build_by_default', bool, default=True,
)

_EXTRA_ARGS_KW: KwargInfo[T.List[str]] = KwargInfo(
    'extra_args',
    ContainerTypeInfo(list, str),
    default=[],
    listify=True,
)

_MK_ENUMS_COMMON_KWS: T.List[KwargInfo] = [
    INSTALL_KW.evolve(name='install_header'),
    INSTALL_DIR_KW,
    KwargInfo('identifier_prefix', (str, NoneType)),
    KwargInfo('symbol_prefix', (str, NoneType)),
]

def annotations_validator(annotations: T.List[T.Union[str, T.List[str]]]) -> T.Optional[str]:
    """Validate gdbus-codegen annotations argument"""

    badlist = 'must be made up of 3 strings for ELEMENT, KEY, and VALUE'

    if not annotations:
        return None
    elif all(isinstance(annot, str) for annot in annotations):
        if len(annotations) == 3:
            return None
        else:
            return badlist
    elif not all(isinstance(annot, list) for annot in annotations):
        for c, annot in enumerate(annotations):
            if not isinstance(annot, list):
                return f'element {c+1} must be a list'
    else:
        for c, annot in enumerate(annotations):
            if len(annot) != 3 or not all(isinstance(i, str) for i in annot):
                return f'element {c+1} {badlist}'
    return None

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

class GnomeModule(ExtensionModule):

    INFO = ModuleInfo('gnome')

    def __init__(self, interpreter: 'Interpreter') -> None:
        super().__init__(interpreter)
        self.gir_dep: T.Optional[Dependency] = None
        self.giscanner: T.Optional[T.Union[ExternalProgram, Executable, OverrideProgram]] = None
        self.gicompiler: T.Optional[T.Union[ExternalProgram, Executable, OverrideProgram]] = None
        self.install_glib_compile_schemas = False
        self.install_gio_querymodules: T.List[str] = []
        self.install_gtk_update_icon_cache = False
        self.install_update_desktop_database = False
        self.install_update_mime_database = False
        self.devenv: T.Optional[mesonlib.EnvironmentVariables] = None
        self.native_glib_version: T.Optional[str] = None
        self.methods.update({
            'post_install': self.post_install,
            'compile_resources': self.compile_resources,
            'generate_gir': self.generate_gir,
            'compile_schemas': self.compile_schemas,
            'yelp': self.yelp,
            'gtkdoc': self.gtkdoc,
            'gtkdoc_html_dir': self.gtkdoc_html_dir,
            'gdbus_codegen': self.gdbus_codegen,
            'mkenums': self.mkenums,
            'mkenums_simple': self.mkenums_simple,
            'genmarshal': self.genmarshal,
            'generate_vapi': self.generate_vapi,
        })

    def _get_native_glib_version(self, state: 'ModuleState') -> str:
        if self.native_glib_version is None:
            glib_dep = PkgConfigDependency('glib-2.0', state.environment,
                                           {'native': True, 'required': False})
            if glib_dep.found():
                self.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.')
                self.native_glib_version = '2.54'
        return self.native_glib_version

    @mesonlib.run_once
    def __print_gresources_warning(self, state: 'ModuleState') -> None:
        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'),
                         once=True, fatal=False)

    @staticmethod
    def _print_gdbus_warning() -> None:
        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'),
                     once=True, fatal=False)

    @staticmethod
    def _find_tool(state: 'ModuleState', tool: str) -> 'ToolType':
        tool_map = {
            'gio-querymodules': 'gio-2.0',
            'glib-compile-schemas': 'gio-2.0',
            'glib-compile-resources': 'gio-2.0',
            'gdbus-codegen': 'gio-2.0',
            'glib-genmarshal': 'glib-2.0',
            'glib-mkenums': 'glib-2.0',
            'g-ir-scanner': 'gobject-introspection-1.0',
            'g-ir-compiler': 'gobject-introspection-1.0',
        }
        depname = tool_map[tool]
        varname = tool.replace('-', '_')
        return state.find_tool(tool, depname, varname)

    @typed_kwargs(
        'gnome.post_install',
        KwargInfo('glib_compile_schemas', bool, default=False),
        KwargInfo('gio_querymodules', ContainerTypeInfo(list, str), default=[], listify=True),
        KwargInfo('gtk_update_icon_cache', bool, default=False),
        KwargInfo('update_desktop_database', bool, default=False, since='0.59.0'),
        KwargInfo('update_mime_database', bool, default=False, since='0.64.0'),
    )
    @noPosargs
    @FeatureNew('gnome.post_install', '0.57.0')
    def post_install(self, state: 'ModuleState', args: T.List['TYPE_var'], kwargs: 'PostInstall') -> ModuleReturnValue:
        rv: T.List['mesonlib.ExecutableSerialisation'] = []
        datadir_abs = os.path.join(state.environment.get_prefix(), state.environment.get_datadir())
        if kwargs['glib_compile_schemas'] and not self.install_glib_compile_schemas:
            self.install_glib_compile_schemas = True
            prog = self._find_tool(state, 'glib-compile-schemas')
            schemasdir = os.path.join(datadir_abs, 'glib-2.0', 'schemas')
            script = state.backend.get_executable_serialisation([prog, schemasdir])
            script.skip_if_destdir = True
            rv.append(script)
        for d in kwargs['gio_querymodules']:
            if d not in self.install_gio_querymodules:
                self.install_gio_querymodules.append(d)
                prog = self._find_tool(state, 'gio-querymodules')
                moduledir = os.path.join(state.environment.get_prefix(), d)
                script = state.backend.get_executable_serialisation([prog, moduledir])
                script.skip_if_destdir = True
                rv.append(script)
        if kwargs['gtk_update_icon_cache'] and not self.install_gtk_update_icon_cache:
            self.install_gtk_update_icon_cache = True
            prog = state.find_program('gtk4-update-icon-cache', required=False)
            found = isinstance(prog, Executable) or prog.found()
            if not found:
                prog = state.find_program('gtk-update-icon-cache')
            icondir = os.path.join(datadir_abs, 'icons', 'hicolor')
            script = state.backend.get_executable_serialisation([prog, '-q', '-t', '-f', icondir])
            script.skip_if_destdir = True
            rv.append(script)
        if kwargs['update_desktop_database'] and not self.install_update_desktop_database:
            self.install_update_desktop_database = True
            prog = state.find_program('update-desktop-database')
            appdir = os.path.join(datadir_abs, 'applications')
            script = state.backend.get_executable_serialisation([prog, '-q', appdir])
            script.skip_if_destdir = True
            rv.append(script)
        if kwargs['update_mime_database'] and not self.install_update_mime_database:
            self.install_update_mime_database = True
            prog = state.find_program('update-mime-database')
            appdir = os.path.join(datadir_abs, 'mime')
            script = state.backend.get_executable_serialisation([prog, appdir])
            script.skip_if_destdir = True
            rv.append(script)
        return ModuleReturnValue(None, rv)

    @typed_pos_args('gnome.compile_resources', str, (str, mesonlib.File, CustomTarget, CustomTargetIndex, GeneratedList))
    @typed_kwargs(
        'gnome.compile_resources',
        _BUILD_BY_DEFAULT,
        _EXTRA_ARGS_KW,
        INSTALL_KW,
        INSTALL_KW.evolve(name='install_header', since='0.37.0'),
        INSTALL_DIR_KW,
        KwargInfo('c_name', (str, NoneType)),
        KwargInfo('dependencies', ContainerTypeInfo(list, (mesonlib.File, CustomTarget, CustomTargetIndex)), default=[], listify=True),
        KwargInfo('export', bool, default=False, since='0.37.0'),
        KwargInfo('gresource_bundle', bool, default=False, since='0.37.0'),
        KwargInfo('source_dir', ContainerTypeInfo(list, str), default=[], listify=True),
    )
    def compile_resources(self, state: 'ModuleState', args: T.Tuple[str, 'FileOrString'],
                          kwargs: 'CompileResources') -> 'ModuleReturnValue':
        self.__print_gresources_warning(state)
        glib_version = self._get_native_glib_version(state)

        glib_compile_resources = self._find_tool(state, 'glib-compile-resources')
        cmd: T.List[T.Union['ToolType', str]] = [glib_compile_resources, '@INPUT@']

        source_dirs = kwargs['source_dir']
        dependencies = kwargs['dependencies']

        target_name, input_file = args

        # Validate dependencies
        subdirs: T.List[str] = []
        depends: T.List[T.Union[CustomTarget, CustomTargetIndex]] = []
        for dep in dependencies:
            if isinstance(dep, mesonlib.File):
                subdirs.append(dep.subdir)
            else:
                depends.append(dep)
                subdirs.append(dep.get_subdir())
                if not mesonlib.version_compare(glib_version, gresource_dep_needed_version):
                    m = 'The "dependencies" argument of gnome.compile_resources() cannot\n' \
                        'be used with the current version of glib-compile-resources due to\n' \
                        ''
                    raise MesonException(m)

        if not mesonlib.version_compare(glib_version, gresource_dep_needed_version):
            # 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
            if isinstance(input_file, 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 input_file.is_built:
                    ifile = os.path.join(state.environment.get_build_dir(), input_file.subdir, input_file.fname)
                else:
                    ifile = os.path.join(input_file.subdir, input_file.fname)

            elif isinstance(input_file, (CustomTarget, CustomTargetIndex, GeneratedList)):
                raise MesonException('Resource xml files generated at build-time cannot be used with '
                                     'gnome.compile_resources() in the current version of glib-compile-resources '
                                     'because we need to scan the xml for dependencies due to '
                                     '\nUse '
                                     'configure_file() instead to generate it at configure-time.')
            else:
                ifile = os.path.join(state.subdir, input_file)

            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 kwargs['c_name']:
            cmd += ['--c-name', kwargs['c_name']]
        if not kwargs['export']:
            cmd += ['--internal']

        cmd += ['--generate', '--target', '@OUTPUT@']
        cmd += kwargs['extra_args']

        gresource = kwargs['gresource_bundle']
        if gresource:
            output = f'{target_name}.gresource'
            name = f'{target_name}_gresource'
        else:
            if 'c' in state.environment.coredata.compilers.host:
                output = f'{target_name}.c'
                name = f'{target_name}_c'
            elif 'cpp' in state.environment.coredata.compilers.host:
                output = f'{target_name}.cpp'
                name = f'{target_name}_cpp'
            else:
                raise MesonException('Compiling GResources into code is only supported in C and C++ projects')

        if kwargs['install'] and not gresource:
            raise MesonException('The install kwarg only applies to gresource bundles, see install_header')

        install_header = kwargs['install_header']
        if install_header and gresource:
            raise MesonException('The install_header kwarg does not apply to gresource bundles')
        if install_header and not kwargs['export']:
            raise MesonException('GResource header is installed yet export is not enabled')

        depfile: T.Optional[str] = None
        target_cmd: T.List[T.Union['ToolType', str]]
        if not mesonlib.version_compare(glib_version, gresource_dep_needed_version):
            # This will eventually go out of sync if dependencies are added
            target_cmd = cmd
        else:
            depfile = f'{output}.d'
            depend_files = []
            target_cmd = copy.copy(cmd) + ['--dependency-file', '@DEPFILE@']
        target_c = GResourceTarget(
            name,
            state.subdir,
            state.subproject,
            state.environment,
            target_cmd,
            [input_file],
            [output],
            build_by_default=kwargs['build_by_default'],
            depfile=depfile,
            depend_files=depend_files,
            extra_depends=depends,
            install=kwargs['install'],
            install_dir=[kwargs['install_dir']] if kwargs['install_dir'] else [],
            install_tag=['runtime'],
        )

        if gresource: # Only one target for .gresource files
            return ModuleReturnValue(target_c, [target_c])

        install_dir = kwargs['install_dir'] or state.environment.coredata.get_option(mesonlib.OptionKey('includedir'))
        assert isinstance(install_dir, str), 'for mypy'
        target_h = GResourceHeaderTarget(
            f'{target_name}_h',
            state.subdir,
            state.subproject,
            state.environment,
            cmd,
            [input_file],
            [f'{target_name}.h'],
            build_by_default=kwargs['build_by_default'],
            extra_depends=depends,
            install=install_header,
            install_dir=[install_dir],
            install_tag=['devel'],
        )
        rv = [target_c, target_h]
        return ModuleReturnValue(rv, rv)

    @staticmethod
    def _get_gresource_dependencies(
            state: 'ModuleState', input_file: str, source_dirs: T.List[str],
            dependencies: T.Sequence[T.Union[mesonlib.File, CustomTarget, CustomTargetIndex]]
            ) -> T.Tuple[T.List[mesonlib.FileOrString], T.List[T.Union[CustomTarget, CustomTargetIndex]], T.List[str]]:

        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)]

        try:
            pc, stdout, stderr = Popen_safe(cmd, cwd=state.environment.get_source_dir())
        except (FileNotFoundError, PermissionError):
            raise MesonException('Could not execute glib-compile-resources.')
        if pc.returncode != 0:
            m = f'glib-compile-resources failed to get dependencies for {cmd[1]}:\n{stderr}'
            mlog.warning(m)
            raise subprocess.CalledProcessError(pc.returncode, cmd)

        raw_dep_files: T.List[str] = stdout.split('\n')[:-1]

        depends: T.List[T.Union[CustomTarget, CustomTargetIndex]] = []
        subdirs: T.List[str] = []
        dep_files: T.List[mesonlib.FileOrString] = []
        for resfile in raw_dep_files.copy():
            resbasename = os.path.basename(resfile)
            for dep in dependencies:
                if isinstance(dep, mesonlib.File):
                    if dep.fname != resbasename:
                        continue
                    raw_dep_files.remove(resfile)
                    dep_files.append(dep)
                    subdirs.append(dep.subdir)
                    break
                elif isinstance(dep, (CustomTarget, 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:
                        raw_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(
                        f'Resource "{resfile}" listed in "{input_file}" was not found. '
                        'If this is a generated file, pass the target that generates '
                        'it to gnome.compile_resources() using the "dependencies" '
                        'keyword argument.')
                raw_dep_files.remove(resfile)
                dep_files.append(f)
        dep_files.extend(raw_dep_files)
        return dep_files, depends, subdirs

    def _get_link_args(self, state: 'ModuleState',
                       lib: T.Union[build.SharedLibrary, build.StaticLibrary],
                       depends: T.Sequence[T.Union[build.BuildTarget, 'build.GeneratedTypes', 'FileOrString', build.StructuredSources]],
                       include_rpath: bool = False,
                       use_gir_args: bool = False
                       ) -> T.Tuple[T.List[str], T.List[T.Union[build.BuildTarget, 'build.GeneratedTypes', 'FileOrString', build.StructuredSources]]]:
        link_command: T.List[str] = []
        new_depends = list(depends)
        # 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)
            new_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 use_gir_args and self._gir_has_option('--extra-library'):
            link_command.append('--extra-library=' + lib.name)
        else:
            link_command.append('-l' + lib.name)
        return link_command, new_depends

    def _get_dependencies_flags_raw(
            self, deps: T.Sequence[T.Union['Dependency', build.BuildTarget, CustomTarget, CustomTargetIndex]],
            state: 'ModuleState',
            depends: T.Sequence[T.Union[build.BuildTarget, 'build.GeneratedTypes', 'FileOrString', build.StructuredSources]],
            include_rpath: bool,
            use_gir_args: bool,
            ) -> T.Tuple[OrderedSet[str], OrderedSet[T.Union[str, T.Tuple[str, str]]], OrderedSet[T.Union[str, T.Tuple[str, str]]], OrderedSet[str],
                         T.List[T.Union[build.BuildTarget, 'build.GeneratedTypes', 'FileOrString', build.StructuredSources]]]:
        cflags: OrderedSet[str] = OrderedSet()
        # External linker flags that can't be de-duped reliably because they
        # require two args in order, such as -framework AVFoundation will be stored as a tuple.
        internal_ldflags: OrderedSet[T.Union[str, T.Tuple[str, str]]] = OrderedSet()
        external_ldflags: OrderedSet[T.Union[str, T.Tuple[str, str]]] = OrderedSet()
        gi_includes: OrderedSet[str] = OrderedSet()
        deps = mesonlib.listify(deps)
        depends = list(depends)

        for dep in deps:
            if isinstance(dep, Dependency):
                girdir = dep.get_variable(pkgconfig='girdir', internal='girdir', default_value='')
                if girdir:
                    assert isinstance(girdir, str), 'for mypy'
                    gi_includes.update([girdir])
            if isinstance(dep, InternalDependency):
                cflags.update(dep.get_compile_args())
                cflags.update(state.get_include_args(dep.include_directories))
                for lib in dep.libraries:
                    if isinstance(lib, build.SharedLibrary):
                        _ld, depends = self._get_link_args(state, lib, depends, include_rpath)
                        internal_ldflags.update(_ld)
                        libdepflags = self._get_dependencies_flags_raw(lib.get_external_deps(), state, depends, include_rpath,
                                                                       use_gir_args)
                        cflags.update(libdepflags[0])
                        internal_ldflags.update(libdepflags[1])
                        external_ldflags.update(libdepflags[2])
                        gi_includes.update(libdepflags[3])
                        depends = libdepflags[4]
                extdepflags = self._get_dependencies_flags_raw(dep.ext_deps, state, depends, include_rpath,
                                                               use_gir_args)
                cflags.update(extdepflags[0])
                internal_ldflags.update(extdepflags[1])
                external_ldflags.update(extdepflags[2])
                gi_includes.update(extdepflags[3])
                depends = extdepflags[4]
                for source in dep.sources:
                    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 flag in ldflags:
                    if (os.path.isabs(flag) and
                            # For PkgConfigDependency only:
                            getattr(dep, 'is_libtool', False)):
                        lib_dir = os.path.dirname(flag)
                        external_ldflags.update([f'-L{lib_dir}'])
                        if include_rpath:
                            external_ldflags.update([f'-Wl,-rpath {lib_dir}'])
                        libname = os.path.basename(flag)
                        if libname.startswith("lib"):
                            libname = libname[3:]
                        libname = libname.split(".so")[0]
                        flag = f"-l{libname}"
                    # FIXME: Hack to avoid passing some compiler options in
                    if flag.startswith("-W"):
                        continue
                    # If it's a framework arg, slurp the framework name too
                    # to preserve the order of arguments
                    if flag == '-framework':
                        external_ldflags.update([(flag, next(ldflags))])
                    else:
                        external_ldflags.update([flag])
            elif isinstance(dep, (build.StaticLibrary, build.SharedLibrary)):
                cflags.update(state.get_include_args(dep.get_include_dirs()))
                depends.append(dep)
            else:
                mlog.log(f'dependency {dep!r} not handled to build gir files')
                continue

        if use_gir_args and self._gir_has_option('--extra-library'):
            def fix_ldflags(ldflags: T.Iterable[T.Union[str, T.Tuple[str, str]]]) -> OrderedSet[T.Union[str, T.Tuple[str, str]]]:
                fixed_ldflags: OrderedSet[T.Union[str, T.Tuple[str, str]]] = OrderedSet()
                for ldflag in ldflags:
                    if isinstance(ldflag, str) and 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)
        return cflags, internal_ldflags, external_ldflags, gi_includes, depends

    def _get_dependencies_flags(
            self, deps: T.Sequence[T.Union['Dependency', build.BuildTarget, CustomTarget, CustomTargetIndex]],
            state: 'ModuleState',
            depends: T.Sequence[T.Union[build.BuildTarget, 'build.GeneratedTypes', 'FileOrString', build.StructuredSources]],
            include_rpath: bool = False,
            use_gir_args: bool = False,
            ) -> T.Tuple[OrderedSet[str], T.List[str], T.List[str], OrderedSet[str],
                         T.List[T.Union[build.BuildTarget, 'build.GeneratedTypes', 'FileOrString', build.StructuredSources]]]:

        cflags, internal_ldflags_raw, external_ldflags_raw, gi_includes, depends = self._get_dependencies_flags_raw(deps, state, depends, include_rpath, use_gir_args)
        internal_ldflags: T.List[str] = []
        external_ldflags: T.List[str] = []

        # Extract non-deduplicable argument groups out of the tuples.
        for ldflag in internal_ldflags_raw:
            if isinstance(ldflag, str):
                internal_ldflags.append(ldflag)
            else:
                internal_ldflags.extend(ldflag)
        for ldflag in external_ldflags_raw:
            if isinstance(ldflag, str):
                external_ldflags.append(ldflag)
            else:
                external_ldflags.extend(ldflag)

        return cflags, internal_ldflags, external_ldflags, gi_includes, depends

    def _unwrap_gir_target(self, girtarget: T.Union[Executable, build.StaticLibrary, build.SharedLibrary], state: 'ModuleState'
                           ) -> T.Union[Executable, build.StaticLibrary, build.SharedLibrary]:
        if not isinstance(girtarget, (Executable, build.SharedLibrary,
                                      build.StaticLibrary)):
            raise MesonException(f'Gir target must be an executable or library but is "{girtarget}" of type {type(girtarget).__name__}')

        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 _devenv_prepend(self, varname: str, value: str) -> None:
        if self.devenv is None:
            self.devenv = mesonlib.EnvironmentVariables()
        self.devenv.prepend(varname, [value])

    def postconf_hook(self, b: build.Build) -> None:
        if self.devenv is not None:
            b.devenv.append(self.devenv)

    def _get_gir_dep(self, state: 'ModuleState') -> T.Tuple[Dependency, T.Union[Executable, 'ExternalProgram', 'OverrideProgram'],
                                                            T.Union[Executable, 'ExternalProgram', 'OverrideProgram']]:
        if not self.gir_dep:
            self.gir_dep = state.dependency('gobject-introspection-1.0')
            self.giscanner = self._find_tool(state, 'g-ir-scanner')
            self.gicompiler = self._find_tool(state, 'g-ir-compiler')
        return self.gir_dep, self.giscanner, self.gicompiler

    @functools.lru_cache(maxsize=None)
    def _gir_has_option(self, option: str) -> bool:
        exe = self.giscanner
        if isinstance(exe, OverrideProgram):
            # Handle overridden g-ir-scanner
            assert option in {'--extra-library', '--sources-top-dirs'}
            return True
        p, o, _ = Popen_safe(exe.get_command() + ['--help'], stderr=subprocess.STDOUT)
        return p.returncode == 0 and option in o

    # May mutate depends and gir_inc_dirs
    @staticmethod
    def _scan_include(state: 'ModuleState', includes: T.List[T.Union[str, GirTarget]]
                      ) -> T.Tuple[T.List[str], T.List[str], T.List[GirTarget]]:
        ret: T.List[str] = []
        gir_inc_dirs: T.List[str] = []
        depends: T.List[GirTarget] = []

        for inc in includes:
            if isinstance(inc, str):
                ret += [f'--include={inc}']
            elif isinstance(inc, GirTarget):
                gir_inc_dirs .append(os.path.join(state.environment.get_build_dir(), inc.get_subdir()))
                ret.append(f"--include-uninstalled={os.path.join(inc.get_subdir(), inc.get_basename())}")
                depends.append(inc)

        return ret, gir_inc_dirs, depends

    @staticmethod
    def _scan_langs(state: 'ModuleState', langs: T.Iterable[str]) -> T.List[str]:
        ret: T.List[str] = []

        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

    @staticmethod
    def _scan_gir_targets(state: 'ModuleState', girtargets: T.Sequence[build.BuildTarget]) -> T.List[T.Union[str, Executable]]:
        ret: T.List[T.Union[str, Executable]] = []

        for girtarget in girtargets:
            if isinstance(girtarget, 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.
                libpath = os.path.join(girtarget.get_subdir(), girtarget.get_filename())
                # Must use absolute paths here because g-ir-scanner will not
                # add them to the runtime path list if they're relative. This
                # means we cannot use @BUILD_ROOT@
                build_root = state.environment.get_build_dir()
                if isinstance(girtarget, build.SharedLibrary):
                    # 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{}/{}".format(build_root, os.path.dirname(libpath))]
                    libname = girtarget.get_basename()
                else:
                    libname = os.path.join(f"{build_root}/{libpath}")
                ret += ['--library', libname]
                # 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

    @staticmethod
    def _get_girtargets_langs_compilers(girtargets: T.Sequence[build.BuildTarget]) -> T.List[T.Tuple[str, 'Compiler']]:
        ret: T.List[T.Tuple[str, 'Compiler']] = []
        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

    @staticmethod
    def _get_gir_targets_deps(girtargets: T.Sequence[build.BuildTarget]
                              ) -> T.List[T.Union[build.BuildTarget, CustomTarget, CustomTargetIndex, Dependency]]:
        ret: T.List[T.Union[build.BuildTarget, CustomTarget, CustomTargetIndex, Dependency]] = []
        for girtarget in girtargets:
            ret += girtarget.get_all_link_deps()
            ret += girtarget.get_external_deps()
        return ret

    @staticmethod
    def _get_gir_targets_inc_dirs(girtargets: T.Sequence[build.BuildTarget]) -> OrderedSet[build.IncludeDirs]:
        ret: OrderedSet = OrderedSet()
        for girtarget in girtargets:
            ret.update(girtarget.get_include_dirs())
        return ret

    @staticmethod
    def _get_langs_compilers_flags(state: 'ModuleState', langs_compilers: T.List[T.Tuple[str, 'Compiler']]
                                   ) -> T.Tuple[T.List[str], T.List[str], T.List[str]]:
        cflags: T.List[str] = []
        internal_ldflags: T.List[str] = []
        external_ldflags: T.List[str] = []

        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 mesonlib.OptionKey('b_sanitize') in compiler.base_options:
                sanitize = state.environment.coredata.options[mesonlib.OptionKey('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

    @staticmethod
    def _make_gir_filelist(state: 'ModuleState', srcdir: str, ns: str,
                           nsversion: str, girtargets: T.Sequence[build.BuildTarget],
                           libsources: T.Sequence[T.Union[
                               str, mesonlib.File, GeneratedList,
                               CustomTarget, CustomTargetIndex]]
                           ) -> str:
        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, f'{ns}_{nsversion}_gir_filelist')

        with open(gir_filelist_filename, 'w', encoding='utf-8') as gir_filelist:
            for s in libsources:
                if isinstance(s, (CustomTarget, 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, 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

    @staticmethod
    def _make_gir_target(
            state: 'ModuleState',
            girfile: str,
            scan_command: T.Sequence[T.Union['FileOrString', Executable, ExternalProgram, OverrideProgram]],
            generated_files: T.Sequence[T.Union[str, mesonlib.File, CustomTarget, CustomTargetIndex, GeneratedList]],
            depends: T.Sequence[T.Union['FileOrString', build.BuildTarget, 'build.GeneratedTypes', build.StructuredSources]],
            kwargs: T.Dict[str, T.Any]) -> GirTarget:
        install = kwargs['install_gir']
        if install is None:
            install = kwargs['install']

        install_dir = kwargs['install_dir_gir']
        if install_dir is None:
            install_dir = os.path.join(state.environment.get_datadir(), 'gir-1.0')
        elif install_dir is False:
            install = False

        # g-ir-scanner uses pkg-config to find libraries such as glib. They could
        # be built as subproject in which case we need to trick it to use
        # -uninstalled.pc files Meson generated. It also must respect pkgconfig
        # settings user could have set in machine file, like PKG_CONFIG_LIBDIR,
        # SYSROOT, etc.
        run_env = PkgConfigInterface.get_env(state.environment, MachineChoice.HOST, uninstalled=True)
        # g-ir-scanner uses Python's distutils to find the compiler, which uses 'CC'
        cc_exelist = state.environment.coredata.compilers.host['c'].get_exelist()
        run_env.set('CC', [quote_arg(x) for x in cc_exelist], ' ')
        run_env.merge(kwargs['env'])

        return GirTarget(
            girfile,
            state.subdir,
            state.subproject,
            state.environment,
            scan_command,
            generated_files,
            [girfile],
            build_by_default=kwargs['build_by_default'],
            extra_depends=depends,
            install=install,
            install_dir=[install_dir],
            install_tag=['devel'],
            env=run_env,
        )

    @staticmethod
    def _make_typelib_target(state: 'ModuleState', typelib_output: str,
                             typelib_cmd: T.Sequence[T.Union[str, Executable, ExternalProgram, CustomTarget]],
                             generated_files: T.Sequence[T.Union[str, mesonlib.File, CustomTarget, CustomTargetIndex, GeneratedList]],
                             kwargs: T.Dict[str, T.Any]) -> TypelibTarget:
        install = kwargs['install_typelib']
        if install is None:
            install = kwargs['install']

        install_dir = kwargs['install_dir_typelib']
        if install_dir is None:
            install_dir = os.path.join(state.environment.get_libdir(), 'girepository-1.0')
        elif install_dir is False:
            install = False

        return TypelibTarget(
            typelib_output,
            state.subdir,
            state.subproject,
            state.environment,
            typelib_cmd,
            generated_files,
            [typelib_output],
            install=install,
            install_dir=[install_dir],
            install_tag=['typelib'],
            build_by_default=kwargs['build_by_default'],
            env=kwargs['env'],
        )

    @staticmethod
    def _gather_typelib_includes_and_update_depends(
            state: 'ModuleState',
            deps: T.Sequence[T.Union[Dependency, build.BuildTarget, CustomTarget, CustomTargetIndex]],
            depends: T.Sequence[T.Union[build.BuildTarget, 'build.GeneratedTypes', 'FileOrString', build.StructuredSources]]
            ) -> T.Tuple[T.List[str], T.List[T.Union[build.BuildTarget, 'build.GeneratedTypes', 'FileOrString', build.StructuredSources]]]:
        # 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: T.List[str] = []
        new_depends = list(depends)
        for dep in deps:
            # 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 isinstance(source, GirTarget) and source not in depends:
                        new_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 g_source in dep.generated:
                    if isinstance(g_source, GirTarget):
                        subdir = os.path.join(state.environment.get_build_dir(),
                                              g_source.get_subdir())
                        if subdir not in typelib_includes:
                            typelib_includes.append(subdir)
            if isinstance(dep, Dependency):
                girdir = dep.get_variable(pkgconfig='girdir', internal='girdir', default_value='')
                assert isinstance(girdir, str), 'for mypy'
                if girdir and girdir not in typelib_includes:
                    typelib_includes.append(girdir)
        return typelib_includes, new_depends

    @staticmethod
    def _get_external_args_for_langs(state: 'ModuleState', langs: T.List[str]) -> T.List[str]:
        ret: T.List[str] = []
        for lang in langs:
            ret += mesonlib.listify(state.environment.coredata.get_external_args(MachineChoice.HOST, lang))
        return ret

    @staticmethod
    def _get_scanner_cflags(cflags: T.Iterable[str]) -> T.Iterable[str]:
        'g-ir-scanner only accepts -I/-D/-U; must ignore all other flags'
        for f in cflags:
            # _FORTIFY_SOURCE depends on / works together with -O, on the other hand this
            # just invokes the preprocessor anyway
            if f.startswith(('-D', '-U', '-I')) and not f.startswith('-D_FORTIFY_SOURCE'):
                yield f

    @staticmethod
    def _get_scanner_ldflags(ldflags: T.Iterable[str]) -> T.Iterable[str]:
        '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

    @typed_pos_args('gnome.generate_gir', varargs=(Executable, build.SharedLibrary, build.StaticLibrary), min_varargs=1)
    @typed_kwargs(
        'gnome.generate_gir',
        INSTALL_KW,
        _BUILD_BY_DEFAULT.evolve(since='0.40.0'),
        _EXTRA_ARGS_KW,
        ENV_KW.evolve(since='1.2.0'),
        KwargInfo('dependencies', ContainerTypeInfo(list, Dependency), default=[], listify=True),
        KwargInfo('export_packages', ContainerTypeInfo(list, str), default=[], listify=True),
        KwargInfo('fatal_warnings', bool, default=False, since='0.55.0'),
        KwargInfo('header', ContainerTypeInfo(list, str), default=[], listify=True),
        KwargInfo('identifier_prefix', ContainerTypeInfo(list, str), default=[], listify=True),
        KwargInfo('include_directories', ContainerTypeInfo(list, (str, build.IncludeDirs)), default=[], listify=True),
        KwargInfo('includes', ContainerTypeInfo(list, (str, GirTarget)), default=[], listify=True),
        KwargInfo('install_gir', (bool, NoneType), since='0.61.0'),
        KwargInfo('install_dir_gir', (str, bool, NoneType),
                  deprecated_values={False: ('0.61.0', 'Use install_gir to disable installation')},
                  validator=lambda x: 'as boolean can only be false' if x is True else None),
        KwargInfo('install_typelib', (bool, NoneType), since='0.61.0'),
        KwargInfo('install_dir_typelib', (str, bool, NoneType),
                  deprecated_values={False: ('0.61.0', 'Use install_typelib to disable installation')},
                  validator=lambda x: 'as boolean can only be false' if x is True else None),
        KwargInfo('link_with', ContainerTypeInfo(list, (build.SharedLibrary, build.StaticLibrary)), default=[], listify=True),
        KwargInfo('namespace', str, required=True),
        KwargInfo('nsversion', str, required=True),
        KwargInfo('sources', ContainerTypeInfo(list, (str, mesonlib.File, GeneratedList, CustomTarget, CustomTargetIndex)), default=[], listify=True),
        KwargInfo('symbol_prefix', ContainerTypeInfo(list, str), default=[], listify=True),
    )
    def generate_gir(self, state: 'ModuleState', args: T.Tuple[T.List[T.Union[Executable, build.SharedLibrary, build.StaticLibrary]]],
                     kwargs: 'GenerateGir') -> ModuleReturnValue:
        # Ensure we have a C compiler even in C++ projects.
        state.add_language('c', MachineChoice.HOST)

        girtargets = [self._unwrap_gir_target(arg, state) for arg in args[0]]
        if len(girtargets) > 1 and any(isinstance(el, Executable) for el in girtargets):
            raise MesonException('generate_gir only accepts a single argument when one of the arguments is an executable')

        gir_dep, giscanner, gicompiler = self._get_gir_dep(state)

        ns = kwargs['namespace']
        nsversion = kwargs['nsversion']
        libsources = kwargs['sources']

        girfile = f'{ns}-{nsversion}.gir'
        srcdir = os.path.join(state.environment.get_source_dir(), state.subdir)
        builddir = os.path.join(state.environment.get_build_dir(), state.subdir)

        depends: T.List[T.Union['FileOrString', 'build.GeneratedTypes', build.BuildTarget, build.StructuredSources]] = []
        depends.extend(gir_dep.sources)
        depends.extend(girtargets)

        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 += kwargs['dependencies']
        deps += [gir_dep]
        typelib_includes, depends = 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, depends = \
            self._get_dependencies_flags(deps, state, depends, use_gir_args=True)
        scan_cflags = []
        scan_cflags += list(self._get_scanner_cflags(cflags))
        scan_cflags += list(self._get_scanner_cflags(dep_cflags))
        scan_cflags += list(self._get_scanner_cflags(self._get_external_args_for_langs(state, [lc[0] for lc in langs_compilers])))
        scan_internal_ldflags = []
        scan_internal_ldflags += list(self._get_scanner_ldflags(internal_ldflags))
        scan_internal_ldflags += list(self._get_scanner_ldflags(dep_internal_ldflags))
        scan_external_ldflags = []
        scan_external_ldflags += list(self._get_scanner_ldflags(external_ldflags))
        scan_external_ldflags += list(self._get_scanner_ldflags(dep_external_ldflags))
        girtargets_inc_dirs = self._get_gir_targets_inc_dirs(girtargets)
        inc_dirs = kwargs['include_directories']

        gir_inc_dirs: T.List[str] = []

        scan_command: T.List[T.Union[str, Executable, 'ExternalProgram', 'OverrideProgram']] = [giscanner]
        scan_command += ['--quiet']
        scan_command += ['--no-libtool']
        scan_command += ['--namespace=' + ns, '--nsversion=' + nsversion]
        scan_command += ['--warn-all']
        scan_command += ['--output', '@OUTPUT@']
        scan_command += [f'--c-include={h}' for h in kwargs['header']]
        scan_command += kwargs['extra_args']
        scan_command += ['-I' + srcdir, '-I' + builddir]
        scan_command += state.get_include_args(girtargets_inc_dirs)
        scan_command += ['--filelist=' + self._make_gir_filelist(state, srcdir, ns, nsversion, girtargets, libsources)]
        for l in kwargs['link_with']:
            _cflags, depends = self._get_link_args(state, l, depends, use_gir_args=True)
            scan_command.extend(_cflags)
        _cmd, _ginc, _deps = self._scan_include(state, kwargs['includes'])
        scan_command.extend(_cmd)
        gir_inc_dirs.extend(_ginc)
        depends.extend(_deps)

        scan_command += [f'--symbol-prefix={p}' for p in kwargs['symbol_prefix']]
        scan_command += [f'--identifier-prefix={p}' for p in kwargs['identifier_prefix']]
        scan_command += [f'--pkg-export={p}' for p in kwargs['export_packages']]
        scan_command += ['--cflags-begin']
        scan_command += scan_cflags
        scan_command += ['--cflags-end']
        scan_command += state.get_include_args(inc_dirs)
        scan_command += state.get_include_args(itertools.chain(gi_includes, gir_inc_dirs, inc_dirs), prefix='--add-include-path=')
        scan_command += list(scan_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(scan_external_ldflags)

        if self._gir_has_option('--sources-top-dirs'):
            scan_command += ['--sources-top-dirs', os.path.join(state.environment.get_source_dir(), state.root_subdir)]
            scan_command += ['--sources-top-dirs', os.path.join(state.environment.get_build_dir(), state.root_subdir)]

        if '--warn-error' in scan_command:
            FeatureDeprecated.single_use('gnome.generate_gir argument --warn-error', '0.55.0',
                                         state.subproject, 'Use "fatal_warnings" keyword argument', state.current_node)
        if kwargs['fatal_warnings']:
            scan_command.append('--warn-error')

        generated_files = [f for f in libsources if isinstance(f, (GeneratedList, CustomTarget, CustomTargetIndex))]

        scan_target = self._make_gir_target(
            state, girfile, scan_command, generated_files, depends,
            # We have to cast here because mypy can't figure this out
            T.cast('T.Dict[str, T.Any]', kwargs))

        typelib_output = f'{ns}-{nsversion}.typelib'
        typelib_cmd = [gicompiler, scan_target, '--output', '@OUTPUT@']
        typelib_cmd += state.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, generated_files, T.cast('T.Dict[str, T.Any]', kwargs))

        self._devenv_prepend('GI_TYPELIB_PATH', os.path.join(state.environment.get_build_dir(), state.subdir))

        rv = [scan_target, typelib_target]

        return ModuleReturnValue(rv, rv)

    @noPosargs
    @typed_kwargs('gnome.compile_schemas', _BUILD_BY_DEFAULT.evolve(since='0.40.0'), DEPEND_FILES_KW)
    def compile_schemas(self, state: 'ModuleState', args: T.List['TYPE_var'], kwargs: 'CompileSchemas') -> ModuleReturnValue:
        srcdir = os.path.join(state.build_to_src, state.subdir)
        outdir = state.subdir

        cmd: T.List[T.Union['ToolType', str]] = [self._find_tool(state, 'glib-compile-schemas'), '--targetdir', outdir, srcdir]
        if state.subdir == '':
            targetname = 'gsettings-compile'
        else:
            targetname = 'gsettings-compile-' + state.subdir.replace('/', '_')
        target_g = CustomTarget(
            targetname,
            state.subdir,
            state.subproject,
            state.environment,
            cmd,
            [],
            ['gschemas.compiled'],
            build_by_default=kwargs['build_by_default'],
            depend_files=kwargs['depend_files'],
            description='Compiling gschemas {}',
        )
        self._devenv_prepend('GSETTINGS_SCHEMA_DIR', os.path.join(state.environment.get_build_dir(), state.subdir))
        return ModuleReturnValue(target_g, [target_g])

    @typed_pos_args('gnome.yelp', str, varargs=str)
    @typed_kwargs(
        'gnome.yelp',
        KwargInfo(
            'languages', ContainerTypeInfo(list, str),
            listify=True, default=[],
            deprecated='0.43.0',
            deprecated_message='Use a LINGUAS file in the source directory instead',
        ),
        KwargInfo('media', ContainerTypeInfo(list, str), listify=True, default=[]),
        KwargInfo('sources', ContainerTypeInfo(list, str), listify=True, default=[]),
        KwargInfo('symlink_media', bool, default=True),
    )
    def yelp(self, state: 'ModuleState', args: T.Tuple[str, T.List[str]], kwargs: 'Yelp') -> ModuleReturnValue:
        project_id = args[0]
        sources = kwargs['sources']
        if args[1]:
            FeatureDeprecated.single_use('gnome.yelp more than one positional argument', '0.60.0',
                                         state.subproject, 'use the "sources" keyword argument instead.', state.current_node)
        if not sources:
            sources = args[1]
            if not sources:
                raise MesonException('Yelp requires a list of sources')
        elif args[1]:
            mlog.warning('"gnome.yelp" ignores positional sources arguments when the "sources" keyword argument is set')
        sources_files = [mesonlib.File.from_source_file(state.environment.source_dir,
                                                        os.path.join(state.subdir, 'C'),
                                                        s) for s in sources]

        langs = kwargs['languages']
        if not langs:
            langs = read_linguas(os.path.join(state.environment.source_dir, state.subdir))

        media = kwargs['media']
        symlinks = kwargs['symlink_media']
        targets: T.List[T.Union['build.Target', build.Data, build.SymlinkData]] = []
        potargets: T.List[build.RunTarget] = []

        itstool = state.find_program('itstool')
        msgmerge = state.find_program('msgmerge')
        msgfmt = state.find_program('msgfmt')

        install_dir = os.path.join(state.environment.get_datadir(), 'help')
        c_install_dir = os.path.join(install_dir, 'C', project_id)
        c_data = build.Data(sources_files, c_install_dir, c_install_dir,
                            mesonlib.FileMode(), state.subproject, install_tag='doc')
        targets.append(c_data)

        media_files: T.List[mesonlib.File] = []
        for m in media:
            f = mesonlib.File.from_source_file(state.environment.source_dir,
                                               os.path.join(state.subdir, 'C'), m)
            media_files.append(f)
            m_install_dir = os.path.join(c_install_dir, os.path.dirname(m))
            m_data = build.Data([f], m_install_dir, m_install_dir,
                                mesonlib.FileMode(), state.subproject, install_tag='doc')
            targets.append(m_data)

        pot_file = os.path.join('@SOURCE_ROOT@', state.subdir, 'C', project_id + '.pot')
        pot_sources = [os.path.join('@SOURCE_ROOT@', state.subdir, 'C', s) for s in sources]
        pot_args: T.List[T.Union[ExternalProgram, Executable, OverrideProgram, str]] = [itstool, '-o', pot_file]
        pot_args.extend(pot_sources)
        pottarget = build.RunTarget(f'help-{project_id}-pot', pot_args, [],
                                    os.path.join(state.subdir, 'C'), state.subproject,
                                    state.environment)
        targets.append(pottarget)

        for l in langs:
            l_subdir = os.path.join(state.subdir, l)
            l_install_dir = os.path.join(install_dir, l, project_id)

            for i, m in enumerate(media):
                m_dir = os.path.dirname(m)
                m_install_dir = os.path.join(l_install_dir, m_dir)
                l_data: T.Union[build.Data, build.SymlinkData]
                if symlinks:
                    link_target = os.path.join(os.path.relpath(c_install_dir, start=m_install_dir), m)
                    l_data = build.SymlinkData(link_target, os.path.basename(m),
                                               m_install_dir, state.subproject, install_tag='doc')
                else:
                    try:
                        m_file = mesonlib.File.from_source_file(state.environment.source_dir, l_subdir, m)
                    except MesonException:
                        m_file = media_files[i]
                    l_data = build.Data([m_file], m_install_dir, m_install_dir,
                                        mesonlib.FileMode(), state.subproject, install_tag='doc')
                targets.append(l_data)

            po_file = l + '.po'
            po_args: T.List[T.Union[ExternalProgram, Executable, OverrideProgram, str]] = [
                msgmerge, '-q', '-o',
                os.path.join('@SOURCE_ROOT@', l_subdir, po_file),
                os.path.join('@SOURCE_ROOT@', l_subdir, po_file), pot_file]
            potarget = build.RunTarget(f'help-{project_id}-{l}-update-po',
                                       po_args, [pottarget], l_subdir, state.subproject,
                                       state.environment)
            targets.append(potarget)
            potargets.append(potarget)

            gmo_file = project_id + '-' + l + '.gmo'
            gmotarget = CustomTarget(
                f'help-{project_id}-{l}-gmo',
                l_subdir,
                state.subproject,
                state.environment,
                [msgfmt, '@INPUT@', '-o', '@OUTPUT@'],
                [po_file],
                [gmo_file],
                install_tag=['doc'],
                description='Generating yelp doc {}',
            )
            targets.append(gmotarget)

            mergetarget = CustomTarget(
                f'help-{project_id}-{l}',
                l_subdir,
                state.subproject,
                state.environment,
                [itstool, '-m', os.path.join(l_subdir, gmo_file), '--lang', l, '-o', '@OUTDIR@', '@INPUT@'],
                sources_files,
                sources,
                extra_depends=[gmotarget],
                install=True,
                install_dir=[l_install_dir],
                install_tag=['doc'],
                description='Generating yelp doc {}',
            )
            targets.append(mergetarget)

        allpotarget = build.AliasTarget(f'help-{project_id}-update-po', potargets,
                                        state.subdir, state.subproject, state.environment)
        targets.append(allpotarget)

        return ModuleReturnValue(None, targets)

    @typed_pos_args('gnome.gtkdoc', str)
    @typed_kwargs(
        'gnome.gtkdoc',
        KwargInfo('c_args', ContainerTypeInfo(list, str), since='0.48.0', default=[], listify=True),
        KwargInfo('check', bool, default=False, since='0.52.0'),
        KwargInfo('content_files', ContainerTypeInfo(list, (str, mesonlib.File, GeneratedList, CustomTarget, CustomTargetIndex)), default=[], listify=True),
        KwargInfo(
            'dependencies',
            ContainerTypeInfo(list, (Dependency, build.SharedLibrary, build.StaticLibrary)),
            listify=True, default=[]),
        KwargInfo('expand_content_files', ContainerTypeInfo(list, (str, mesonlib.File)), default=[], listify=True),
        KwargInfo('fixxref_args', ContainerTypeInfo(list, str), default=[], listify=True),
        KwargInfo('gobject_typesfile', ContainerTypeInfo(list, (str, mesonlib.File)), default=[], listify=True),
        KwargInfo('html_args', ContainerTypeInfo(list, str), default=[], listify=True),
        KwargInfo('html_assets', ContainerTypeInfo(list, (str, mesonlib.File)), default=[], listify=True),
        KwargInfo('ignore_headers', ContainerTypeInfo(list, str), default=[], listify=True),
        KwargInfo(
            'include_directories',
            ContainerTypeInfo(list, (str, build.IncludeDirs)),
            listify=True, default=[]),
        KwargInfo('install', bool, default=True),
        KwargInfo('install_dir', ContainerTypeInfo(list, str), default=[], listify=True),
        KwargInfo('main_sgml', (str, NoneType)),
        KwargInfo('main_xml', (str, NoneType)),
        KwargInfo('mkdb_args', ContainerTypeInfo(list, str), default=[], listify=True),
        KwargInfo(
            'mode', str, default='auto', since='0.37.0',
            validator=in_set_validator({'xml', 'sgml', 'none', 'auto'})),
        KwargInfo('module_version', str, default='', since='0.48.0'),
        KwargInfo('namespace', str, default='', since='0.37.0'),
        KwargInfo('scan_args', ContainerTypeInfo(list, str), default=[], listify=True),
        KwargInfo('scanobjs_args', ContainerTypeInfo(list, str), default=[], listify=True),
        KwargInfo('src_dir', ContainerTypeInfo(list, (str, build.IncludeDirs)), listify=True, required=True),
    )
    def gtkdoc(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'GtkDoc') -> ModuleReturnValue:
        modulename = args[0]
        main_file = kwargs['main_sgml']
        main_xml = kwargs['main_xml']
        if main_xml is not None:
            if main_file is not None:
                raise InvalidArguments('gnome.gtkdoc: main_xml and main_sgml are exclusive arguments')
            main_file = main_xml
        moduleversion = kwargs['module_version']
        targetname = modulename + ('-' + moduleversion if moduleversion else '') + '-doc'
        command = state.environment.get_build_command()

        namespace = kwargs['namespace']

        # Ensure we have a C compiler even in C++ projects.
        state.add_language('c', MachineChoice.HOST)

        def abs_filenames(files: T.Iterable['FileOrString']) -> T.Iterator[str]:
            for f in files:
                if isinstance(f, mesonlib.File):
                    yield f.absolute_path(state.environment.get_source_dir(), state.environment.get_build_dir())
                else:
                    yield os.path.join(state.environment.get_source_dir(), state.subdir, f)

        src_dirs = kwargs['src_dir']
        header_dirs: T.List[str] = []
        for src_dir in src_dirs:
            if isinstance(src_dir, build.IncludeDirs):
                header_dirs.extend(src_dir.to_string_list(state.environment.get_source_dir(),
                                                          state.environment.get_build_dir()))
            else:
                header_dirs.append(src_dir)

        t_args: T.List[str] = [
            '--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=' + kwargs['mode']]
        for tool in ['scan', 'scangobj', 'mkdb', 'mkhtml', 'fixxref']:
            program_name = 'gtkdoc-' + tool
            program = state.find_program(program_name)
            path = program.get_path()
            assert path is not None, "This shouldn't be possible since program should be found"
            t_args.append(f'--{program_name}={path}')
        if namespace:
            t_args.append('--namespace=' + namespace)
        exe_wrapper = state.environment.get_exe_wrapper()
        if exe_wrapper:
            t_args.append('--run=' + ' '.join(exe_wrapper.get_command()))
        t_args.append(f'--htmlargs={"@@".join(kwargs["html_args"])}')
        t_args.append(f'--scanargs={"@@".join(kwargs["scan_args"])}')
        t_args.append(f'--scanobjsargs={"@@".join(kwargs["scanobjs_args"])}')
        t_args.append(f'--gobjects-types-file={"@@".join(abs_filenames(kwargs["gobject_typesfile"]))}')
        t_args.append(f'--fixxrefargs={"@@".join(kwargs["fixxref_args"])}')
        t_args.append(f'--mkdbargs={"@@".join(kwargs["mkdb_args"])}')
        t_args.append(f'--html-assets={"@@".join(abs_filenames(kwargs["html_assets"]))}')

        depends: T.List['build.GeneratedTypes'] = []
        content_files = []
        for s in kwargs['content_files']:
            if isinstance(s, (CustomTarget, 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, 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))
            else:
                content_files.append(os.path.join(state.environment.get_source_dir(),
                                                  state.subdir,
                                                  s))
        t_args += ['--content-files=' + '@@'.join(content_files)]

        t_args.append(f'--expand-content-files={"@@".join(abs_filenames(kwargs["expand_content_files"]))}')
        t_args.append(f'--ignore-headers={"@@".join(kwargs["ignore_headers"])}')
        t_args.append(f'--installdir={"@@".join(kwargs["install_dir"])}')
        build_args, new_depends = self._get_build_args(kwargs['c_args'], kwargs['include_directories'],
                                                       kwargs['dependencies'], state, depends)
        t_args.extend(build_args)
        new_depends.extend(depends)
        custom_target = CustomTarget(
            targetname,
            state.subdir,
            state.subproject,
            state.environment,
            command + t_args,
            [],
            [f'{modulename}-decl.txt'],
            build_always_stale=True,
            extra_depends=new_depends,
            description='Generating gtkdoc {}',
        )
        alias_target = build.AliasTarget(targetname, [custom_target], state.subdir, state.subproject, state.environment)
        if kwargs['check']:
            check_cmd = state.find_program('gtkdoc-check')
            check_env = ['DOC_MODULE=' + modulename,
                         'DOC_MAIN_SGML_FILE=' + main_file]
            check_args = (targetname + '-check', check_cmd)
            check_workdir = os.path.join(state.environment.get_build_dir(), state.subdir)
            state.test(check_args, env=check_env, workdir=check_workdir, depends=[custom_target])
        res: T.List[T.Union[build.Target, mesonlib.ExecutableSerialisation]] = [custom_target, alias_target]
        if kwargs['install']:
            res.append(state.backend.get_executable_serialisation(command + t_args, tag='doc'))
        return ModuleReturnValue(custom_target, res)

    def _get_build_args(self, c_args: T.List[str], inc_dirs: T.List[T.Union[str, build.IncludeDirs]],
                        deps: T.List[T.Union[Dependency, build.SharedLibrary, build.StaticLibrary]],
                        state: 'ModuleState',
                        depends: T.Sequence[T.Union[build.BuildTarget, 'build.GeneratedTypes']]) -> T.Tuple[
                                T.List[str], T.List[T.Union[build.BuildTarget, 'build.GeneratedTypes', 'FileOrString', build.StructuredSources]]]:
        args: T.List[str] = []
        cflags = c_args.copy()
        deps_cflags, internal_ldflags, external_ldflags, _gi_includes, new_depends = \
            self._get_dependencies_flags(deps, state, depends, include_rpath=True)

        cflags.extend(deps_cflags)
        cflags.extend(state.get_include_args(inc_dirs))
        ldflags: T.List[str] = []
        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, new_depends

    @noKwargs
    @typed_pos_args('gnome.gtkdoc_html_dir', str)
    def gtkdoc_html_dir(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'TYPE_kwargs') -> str:
        return os.path.join('share/gtk-doc/html', args[0])

    @typed_pos_args('gnome.gdbus_codegen', str, optargs=[(str, mesonlib.File, CustomTarget, CustomTargetIndex, GeneratedList)])
    @typed_kwargs(
        'gnome.gdbus_codegen',
        _BUILD_BY_DEFAULT.evolve(since='0.40.0'),
        DEPENDENCY_SOURCES_KW.evolve(since='0.46.0'),
        KwargInfo('extra_args', ContainerTypeInfo(list, str), since='0.47.0', default=[], listify=True),
        KwargInfo('interface_prefix', (str, NoneType)),
        KwargInfo('namespace', (str, NoneType)),
        KwargInfo('object_manager', bool, default=False),
        KwargInfo(
            'annotations', ContainerTypeInfo(list, (list, str)),
            default=[],
            validator=annotations_validator,
            convertor=lambda x: [x] if x and isinstance(x[0], str) else x,
        ),
        KwargInfo('install_header', bool, default=False, since='0.46.0'),
        KwargInfo('docbook', (str, NoneType)),
        KwargInfo(
            'autocleanup', str, default='default', since='0.47.0',
            validator=in_set_validator({'all', 'none', 'objects'})),
        INSTALL_DIR_KW.evolve(since='0.46.0')
    )
    def gdbus_codegen(self, state: 'ModuleState', args: T.Tuple[str, T.Optional[T.Union['FileOrString', build.GeneratedTypes]]],
                      kwargs: 'GdbusCodegen') -> ModuleReturnValue:
        namebase = args[0]
        xml_files: T.List[T.Union['FileOrString', build.GeneratedTypes]] = [args[1]] if args[1] else []
        cmd: T.List[T.Union['ToolType', str]] = [self._find_tool(state, 'gdbus-codegen')]
        cmd.extend(kwargs['extra_args'])

        # Autocleanup supported?
        glib_version = self._get_native_glib_version(state)
        if not mesonlib.version_compare(glib_version, '>= 2.49.1'):
            # Warn if requested, silently disable if not
            if kwargs['autocleanup'] != 'default':
                mlog.warning(f'Glib version ({glib_version}) is too old to support the \'autocleanup\' '
                             'kwarg, need 2.49.1 or newer')
        else:
            # Handle legacy glib versions that don't have autocleanup
            ac = kwargs['autocleanup']
            if ac == 'default':
                ac = 'all'
            cmd.extend(['--c-generate-autocleanup', ac])

        if kwargs['interface_prefix'] is not None:
            cmd.extend(['--interface-prefix', kwargs['interface_prefix']])
        if kwargs['namespace'] is not None:
            cmd.extend(['--c-namespace', kwargs['namespace']])
        if kwargs['object_manager']:
            cmd.extend(['--c-generate-object-manager'])
        xml_files.extend(kwargs['sources'])
        build_by_default = kwargs['build_by_default']

        # Annotations are a bit ugly in that they are a list of lists of strings...
        for annot in kwargs['annotations']:
            cmd.append('--annotate')
            cmd.extend(annot)

        targets = []
        install_header = kwargs['install_header']
        install_dir = kwargs['install_dir'] or state.environment.coredata.get_option(mesonlib.OptionKey('includedir'))
        assert isinstance(install_dir, str), 'for mypy'

        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'):
            c_cmd = cmd + ['--body', '--output', '@OUTPUT@', '@INPUT@']
        else:
            if kwargs['docbook'] is not None:
                docbook = kwargs['docbook']

                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@']
            c_cmd = cmd

        cfile_custom_target = CustomTarget(
            output,
            state.subdir,
            state.subproject,
            state.environment,
            c_cmd,
            xml_files,
            [output],
            build_by_default=build_by_default,
            description='Generating gdbus source {}',
        )
        targets.append(cfile_custom_target)

        output = namebase + '.h'
        if mesonlib.version_compare(glib_version, '>= 2.56.2'):
            hfile_cmd = cmd + ['--header', '--output', '@OUTPUT@', '@INPUT@']
            depends = []
        else:
            hfile_cmd = cmd
            depends = [cfile_custom_target]

        hfile_custom_target = CustomTarget(
            output,
            state.subdir,
            state.subproject,
            state.environment,
            hfile_cmd,
            xml_files,
            [output],
            build_by_default=build_by_default,
            extra_depends=depends,
            install=install_header,
            install_dir=[install_dir],
            install_tag=['devel'],
            description='Generating gdbus header {}',
        )
        targets.append(hfile_custom_target)

        if kwargs['docbook'] is not None:
            docbook = kwargs['docbook']
            # 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'):
                docbook_cmd = cmd + ['--output-directory', '@OUTDIR@', '--generate-docbook', docbook, '@INPUT@']
                depends = []
            else:
                docbook_cmd = cmd
                depends = [cfile_custom_target]

            docbook_custom_target = CustomTarget(
                output,
                state.subdir,
                state.subproject,
                state.environment,
                docbook_cmd,
                xml_files,
                outputs,
                build_by_default=build_by_default,
                extra_depends=depends,
                description='Generating gdbus docbook {}',
            )
            targets.append(docbook_custom_target)

        return ModuleReturnValue(targets, targets)

    @typed_pos_args('gnome.mkenums', str)
    @typed_kwargs(
        'gnome.mkenums',
        *_MK_ENUMS_COMMON_KWS,
        DEPENDS_KW,
        KwargInfo(
            'sources',
            ContainerTypeInfo(list, (str, mesonlib.File, CustomTarget, CustomTargetIndex,
                                     GeneratedList)),
            listify=True,
            required=True,
        ),
        KwargInfo('c_template', (str, mesonlib.File, NoneType)),
        KwargInfo('h_template', (str, mesonlib.File, NoneType)),
        KwargInfo('comments', (str, NoneType)),
        KwargInfo('eprod', (str, NoneType)),
        KwargInfo('fhead', (str, NoneType)),
        KwargInfo('fprod', (str, NoneType)),
        KwargInfo('ftail', (str, NoneType)),
        KwargInfo('vhead', (str, NoneType)),
        KwargInfo('vprod', (str, NoneType)),
        KwargInfo('vtail', (str, NoneType)),
    )
    def mkenums(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'MkEnums') -> ModuleReturnValue:
        basename = args[0]

        c_template = kwargs['c_template']
        if isinstance(c_template, mesonlib.File):
            c_template = c_template.absolute_path(state.environment.source_dir, state.environment.build_dir)
        h_template = kwargs['h_template']
        if isinstance(h_template, mesonlib.File):
            h_template = h_template.absolute_path(state.environment.source_dir, state.environment.build_dir)

        cmd: T.List[str] = []
        known_kwargs = ['comments', 'eprod', 'fhead', 'fprod', 'ftail',
                        'identifier_prefix', 'symbol_prefix',
                        'vhead', 'vprod', 'vtail']
        for arg in known_kwargs:
            # Mypy can't figure out that this TypedDict index is correct, without repeating T.Literal for the entire list
            if kwargs[arg]:                                         # type: ignore
                cmd += ['--' + arg.replace('_', '-'), kwargs[arg]]  # type: ignore

        targets: T.List[CustomTarget] = []

        h_target: T.Optional[CustomTarget] = None
        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: T.List[T.Union[FileOrString, 'build.GeneratedTypes']] = [h_template]
            h_sources.extend(kwargs['sources'])
            h_target = self._make_mkenum_impl(
                state, h_sources, h_output, h_cmd, install=kwargs['install_header'],
                install_dir=kwargs['install_dir'])
            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: T.List[T.Union[FileOrString, 'build.GeneratedTypes']] = [c_template]
            c_sources.extend(kwargs['sources'])

            depends = kwargs['depends'].copy()
            if h_target is not None:
                depends.append(h_target)
            c_target = self._make_mkenum_impl(
                state, c_sources, c_output, c_cmd, depends=depends)
            targets.insert(0, c_target)

        if c_template is None and h_template is None:
            generic_cmd = cmd + ['@INPUT@']
            target = self._make_mkenum_impl(
                state, kwargs['sources'], basename, generic_cmd,
                install=kwargs['install_header'],
                install_dir=kwargs['install_dir'])
            return ModuleReturnValue(target, [target])
        else:
            return ModuleReturnValue(targets, targets)

    @FeatureNew('gnome.mkenums_simple', '0.42.0')
    @typed_pos_args('gnome.mkenums_simple', str)
    @typed_kwargs(
        'gnome.mkenums_simple',
        *_MK_ENUMS_COMMON_KWS,
        KwargInfo(
            'sources',
            ContainerTypeInfo(list, (str, mesonlib.File)),
            listify=True,
            required=True,
        ),
        KwargInfo('header_prefix', str, default=''),
        KwargInfo('function_prefix', str, default=''),
        KwargInfo('body_prefix', str, default=''),
        KwargInfo('decorator', str, default=''),
    )
    def mkenums_simple(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'MkEnumsSimple') -> ModuleReturnValue:
        hdr_filename = f'{args[0]}.h'
        body_filename = f'{args[0]}.c'

        header_prefix = kwargs['header_prefix']
        decl_decorator = kwargs['decorator']
        func_prefix = kwargs['function_prefix']
        body_prefix = kwargs['body_prefix']

        cmd: T.List[str] = []
        if kwargs['identifier_prefix']:
            cmd.extend(['--identifier-prefix', kwargs['identifier_prefix']])
        if kwargs['symbol_prefix']:
            cmd.extend(['--symbol-prefix', kwargs['symbol_prefix']])

        c_cmd = cmd.copy()
        # 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 self.interpreter.source_strings_to_files(kwargs['sources']):
            hdr_path = os.path.relpath(hdr.relative_name(), state.subdir)
            fhead += f'#include "{hdr_path}"\n'
        fhead += textwrap.dedent(
            '''
            #define C_ENUM(v) ((gint) v)
            #define C_FLAGS(v) ((guint) v)
            ''')
        c_cmd.extend(['--fhead', fhead])

        c_cmd.append('--fprod')
        c_cmd.append(textwrap.dedent(
            '''
            /* enumerations from "@basename@" */
            '''))

        c_cmd.append('--vhead')
        c_cmd.append(textwrap.dedent(
            f'''
            GType
            {func_prefix}@enum_name@_get_type (void)
            {{
            static gsize gtype_id = 0;
            static const G@Type@Value values[] = {{'''))

        c_cmd.extend(['--vprod', '    { C_@TYPE@(@VALUENAME@), "@VALUENAME@", "@valuenick@" },'])

        c_cmd.append('--vtail')
        c_cmd.append(textwrap.dedent(
            '''    { 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;
            }'''))
        c_cmd.append('@INPUT@')

        c_file = self._make_mkenum_impl(state, kwargs['sources'], body_filename, c_cmd)

        # .h file generation
        h_cmd = cmd.copy()

        h_cmd.append('--fhead')
        h_cmd.append(textwrap.dedent(
            f'''#pragma once

            #include 
            {header_prefix}

            G_BEGIN_DECLS
            '''))

        h_cmd.append('--fprod')
        h_cmd.append(textwrap.dedent(
            '''
            /* enumerations from "@basename@" */
            '''))

        h_cmd.append('--vhead')
        h_cmd.append(textwrap.dedent(
            f'''
            {decl_decorator}
            GType {func_prefix}@enum_name@_get_type (void);
            #define @ENUMPREFIX@_TYPE_@ENUMSHORT@ ({func_prefix}@enum_name@_get_type())'''))

        h_cmd.append('--ftail')
        h_cmd.append(textwrap.dedent(
            '''
            G_END_DECLS'''))
        h_cmd.append('@INPUT@')

        h_file = self._make_mkenum_impl(
            state, kwargs['sources'], hdr_filename, h_cmd,
            install=kwargs['install_header'],
            install_dir=kwargs['install_dir'])

        return ModuleReturnValue([c_file, h_file], [c_file, h_file])

    def _make_mkenum_impl(
            self,
            state: 'ModuleState',
            sources: T.Sequence[T.Union[str, mesonlib.File, CustomTarget, CustomTargetIndex, GeneratedList]],
            output: str,
            cmd: T.List[str],
            *,
            install: bool = False,
            install_dir: T.Optional[T.Sequence[T.Union[str, bool]]] = None,
            depends: T.Optional[T.Sequence[T.Union[CustomTarget, CustomTargetIndex, BuildTarget]]] = None
            ) -> build.CustomTarget:
        real_cmd: T.List[T.Union[str, 'ToolType']] = [self._find_tool(state, 'glib-mkenums')]
        real_cmd.extend(cmd)
        _install_dir = install_dir or state.environment.coredata.get_option(mesonlib.OptionKey('includedir'))
        assert isinstance(_install_dir, str), 'for mypy'

        return CustomTarget(
            output,
            state.subdir,
            state.subproject,
            state.environment,
            real_cmd,
            sources,
            [output],
            capture=True,
            install=install,
            install_dir=[_install_dir],
            install_tag=['devel'],
            extra_depends=depends,
            # https://github.com/mesonbuild/meson/issues/973
            absolute_paths=True,
            description='Generating GObject enum file {}',
        )

    @typed_pos_args('gnome.genmarshal', str)
    @typed_kwargs(
        'gnome.genmarshal',
        DEPEND_FILES_KW.evolve(since='0.61.0'),
        DEPENDS_KW.evolve(since='0.61.0'),
        INSTALL_KW.evolve(name='install_header'),
        INSTALL_DIR_KW,
        KwargInfo('extra_args', ContainerTypeInfo(list, str), listify=True, default=[]),
        KwargInfo('internal', bool, default=False),
        KwargInfo('nostdinc', bool, default=False),
        KwargInfo('prefix', (str, NoneType)),
        KwargInfo('skip_source', bool, default=False),
        KwargInfo('sources', ContainerTypeInfo(list, (str, mesonlib.File), allow_empty=False), listify=True, required=True),
        KwargInfo('stdinc', bool, default=False),
        KwargInfo('valist_marshallers', bool, default=False),
    )
    def genmarshal(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'GenMarshal') -> ModuleReturnValue:
        output = args[0]
        sources = kwargs['sources']

        new_genmarshal = mesonlib.version_compare(self._get_native_glib_version(state), '>= 2.53.3')

        cmd: T.List[T.Union['ToolType', str]] = [self._find_tool(state, 'glib-genmarshal')]
        if kwargs['prefix']:
            cmd.extend(['--prefix', kwargs['prefix']])
        if kwargs['extra_args']:
            if new_genmarshal:
                cmd.extend(kwargs['extra_args'])
            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'),
                             once=True, fatal=False)
        for k in ['internal', 'nostdinc', 'skip_source', 'stdinc', 'valist_marshallers']:
            # Mypy can't figure out that this TypedDict index is correct, without repeating T.Literal for the entire list
            if kwargs[k]:                                            # type: ignore
                cmd.append(f'--{k.replace("_", "-")}')

        install_header = kwargs['install_header']
        capture = False

        # https://github.com/GNOME/glib/commit/0fbc98097fac4d3e647684f344e508abae109fdf
        if mesonlib.version_compare(self._get_native_glib_version(state), '>= 2.51.0'):
            cmd += ['--output', '@OUTPUT@']
        else:
            capture = True

        header_file = output + '.h'
        h_cmd = cmd + ['--header', '@INPUT@']
        if new_genmarshal:
            h_cmd += ['--pragma-once']
        header = CustomTarget(
            output + '_h',
            state.subdir,
            state.subproject,
            state.environment,
            h_cmd,
            sources,
            [header_file],
            install=install_header,
            install_dir=[kwargs['install_dir']] if kwargs['install_dir'] else [],
            install_tag=['devel'],
            capture=capture,
            depend_files=kwargs['depend_files'],
            description='Generating glib marshaller header {}',
        )

        c_cmd = cmd + ['--body', '@INPUT@']
        extra_deps: T.List[CustomTarget] = []
        if mesonlib.version_compare(self._get_native_glib_version(state), '>= 2.53.4'):
            # Silence any warnings about missing prototypes
            c_cmd += ['--include-header', header_file]
            extra_deps.append(header)
        body = CustomTarget(
            output + '_c',
            state.subdir,
            state.subproject,
            state.environment,
            c_cmd,
            sources,
            [f'{output}.c'],
            capture=capture,
            depend_files=kwargs['depend_files'],
            extra_depends=extra_deps,
            description='Generating glib marshaller source {}',
        )

        rv = [body, header]
        return ModuleReturnValue(rv, rv)

    def _extract_vapi_packages(self, state: 'ModuleState', packages: T.List[T.Union[InternalDependency, str]],
                               ) -> T.Tuple[T.List[str], T.List[VapiTarget], T.List[str], T.List[str], T.List[str]]:
        '''
        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
        '''
        if not packages:
            return [], [], [], [], []
        vapi_depends: T.List[VapiTarget] = []
        vapi_packages: T.List[str] = []
        vapi_includes: T.List[str] = []
        vapi_args: T.List[str] = []
        remaining_args = []
        for arg in packages:
            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
                    vapi_args.append('--vapidir=' + outdir)
                    vapi_args.append('--girdir=' + outdir)
                    vapi_args.append('--pkg=' + outfile)
                    vapi_depends.append(target)
                    vapi_packages.append(outfile)
                    vapi_includes.append(srcdir)
            else:
                assert isinstance(arg, str), 'for mypy'
                vapi_args.append(f'--pkg={arg}')
                vapi_packages.append(arg)
                remaining_args.append(arg)

        # TODO: this is supposed to take IncludeDirs, but it never worked
        return vapi_args, vapi_depends, vapi_packages, vapi_includes, remaining_args

    def _generate_deps(self, state: 'ModuleState', library: str, packages: T.List[str], install_dir: str) -> build.Data:
        outdir = state.environment.scratch_dir
        fname = os.path.join(outdir, library + '.deps')
        with open(fname, 'w', encoding='utf-8') as ofile:
            for package in packages:
                ofile.write(package + '\n')
        return build.Data([mesonlib.File(True, outdir, fname)], install_dir, install_dir, mesonlib.FileMode(), state.subproject)

    def _get_vapi_link_with(self, target: CustomTarget) -> T.List[build.LibTypes]:
        link_with: T.List[build.LibTypes] = []
        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

    @typed_pos_args('gnome.generate_vapi', str)
    @typed_kwargs(
        'gnome.generate_vapi',
        INSTALL_KW,
        INSTALL_DIR_KW,
        KwargInfo(
            'sources',
            ContainerTypeInfo(list, (str, GirTarget), allow_empty=False),
            listify=True,
            required=True,
        ),
        KwargInfo('vapi_dirs', ContainerTypeInfo(list, str), listify=True, default=[]),
        KwargInfo('metadata_dirs', ContainerTypeInfo(list, str), listify=True, default=[]),
        KwargInfo('gir_dirs', ContainerTypeInfo(list, str), listify=True, default=[]),
        KwargInfo('packages', ContainerTypeInfo(list, (str, InternalDependency)), listify=True, default=[]),
    )
    def generate_vapi(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'GenerateVapi') -> ModuleReturnValue:
        created_values: T.List[T.Union[Dependency, build.Data]] = []
        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, packages = self._extract_vapi_packages(state, kwargs['packages'])
        cmd: T.List[T.Union[ExternalProgram, Executable, OverrideProgram, str]]
        cmd = [state.find_program('vapigen'), '--quiet', f'--library={library}', f'--directory={build_dir}']
        cmd.extend([f'--vapidir={d}' for d in kwargs['vapi_dirs']])
        cmd.extend([f'--metadatadir={d}' for d in kwargs['metadata_dirs']])
        cmd.extend([f'--girdir={d}' for d in kwargs['gir_dirs']])
        cmd += pkg_cmd
        cmd += ['--metadatadir=' + source_dir]

        inputs = kwargs['sources']

        link_with: T.List[build.LibTypes] = []
        for i in inputs:
            if isinstance(i, str):
                cmd.append(os.path.join(source_dir, i))
            elif isinstance(i, GirTarget):
                link_with += self._get_vapi_link_with(i)
                subdir = os.path.join(state.environment.get_build_dir(),
                                      i.get_subdir())
                gir_file = os.path.join(subdir, i.get_outputs()[0])
                cmd.append(gir_file)

        vapi_output = library + '.vapi'
        datadir = state.environment.coredata.get_option(mesonlib.OptionKey('datadir'))
        assert isinstance(datadir, str), 'for mypy'
        install_dir = kwargs['install_dir'] or os.path.join(datadir, 'vala', 'vapi')

        if kwargs['install']:
            # 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,
            state.environment,
            command=cmd,
            sources=inputs,
            outputs=[vapi_output],
            extra_depends=vapi_depends,
            install=kwargs['install'],
            install_dir=[install_dir],
            install_tag=['devel'],
        )

        # So to try our best to get this to just work we need:
        # - link 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(interp: 'Interpreter') -> GnomeModule:
    mod = GnomeModule(interp)
    mod.interpreter.append_holder_map(GResourceTarget, interpreter.CustomTargetHolder)
    mod.interpreter.append_holder_map(GResourceHeaderTarget, interpreter.CustomTargetHolder)
    mod.interpreter.append_holder_map(GirTarget, interpreter.CustomTargetHolder)
    mod.interpreter.append_holder_map(TypelibTarget, interpreter.CustomTargetHolder)
    mod.interpreter.append_holder_map(VapiTarget, interpreter.CustomTargetHolder)
    return mod
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/hotdoc.py0000644000175000017500000005221514562742363020514 0ustar00jpakkanejpakkane# 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.
from __future__ import annotations

'''This module provides helper functions for generating documentation using hotdoc'''

import os, subprocess
import typing as T

from . import ExtensionModule, ModuleReturnValue, ModuleInfo
from .. import build, mesonlib, mlog
from ..build import CustomTarget, CustomTargetIndex
from ..dependencies import Dependency, InternalDependency
from ..interpreterbase import (
    InvalidArguments, noPosargs, noKwargs, typed_kwargs, FeatureDeprecated,
    ContainerTypeInfo, KwargInfo, typed_pos_args
)
from ..interpreter.interpreterobjects import _CustomTargetHolder
from ..interpreter.type_checking import NoneType
from ..mesonlib import File, MesonException
from ..programs import ExternalProgram

if T.TYPE_CHECKING:
    from typing_extensions import TypedDict

    from . import ModuleState
    from ..environment import Environment
    from ..interpreter import Interpreter
    from ..interpreterbase import TYPE_kwargs, TYPE_var

    _T = T.TypeVar('_T')

    class GenerateDocKwargs(TypedDict):
        sitemap: T.Union[str, File, CustomTarget, CustomTargetIndex]
        index: T.Union[str, File, CustomTarget, CustomTargetIndex]
        project_version: str
        html_extra_theme: T.Optional[str]
        include_paths: T.List[str]
        dependencies: T.List[T.Union[Dependency, build.StaticLibrary, build.SharedLibrary, CustomTarget, CustomTargetIndex]]
        depends: T.List[T.Union[CustomTarget, CustomTargetIndex]]
        gi_c_source_roots: T.List[str]
        extra_assets: T.List[str]
        extra_extension_paths: T.List[str]
        subprojects: T.List['HotdocTarget']
        install: bool

def ensure_list(value: T.Union[_T, T.List[_T]]) -> T.List[_T]:
    if not isinstance(value, list):
        return [value]
    return value


MIN_HOTDOC_VERSION = '0.8.100'

file_types = (str, File, CustomTarget, CustomTargetIndex)


class HotdocExternalProgram(ExternalProgram):
    def run_hotdoc(self, cmd: T.List[str]) -> int:
        return subprocess.run(self.get_command() + cmd, stdout=subprocess.DEVNULL).returncode


class HotdocTargetBuilder:

    def __init__(self, name: str, state: ModuleState, hotdoc: HotdocExternalProgram, interpreter: 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: mesonlib.OrderedSet[str] = mesonlib.OrderedSet()

        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: T.List[TYPE_var] = ['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.extra_depends = []
        self._subprojects = []

    def process_known_arg(self, option: str, argname: T.Optional[str] = None, value_processor: T.Optional[T.Callable] = None) -> None:
        if not argname:
            argname = option.strip("-").replace("-", "_")

        value = self.kwargs.pop(argname)
        if value is not None and value_processor:
            value = value_processor(value)

        self.set_arg_value(option, value)

    def set_arg_value(self, option: str, value: TYPE_var) -> None:
        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([f'{option}={value}'])
            else:
                self.cmd.extend([option, value])

    def check_extra_arg_type(self, arg: str, value: TYPE_var) -> None:
        if isinstance(value, list):
            for v in value:
                self.check_extra_arg_type(arg, v)
            return

        valid_types = (str, bool, File, build.IncludeDirs, CustomTarget, CustomTargetIndex, build.BuildTarget)
        if not isinstance(value, valid_types):
            raise InvalidArguments('Argument "{}={}" should be of type: {}.'.format(
                arg, value, [t.__name__ for t in valid_types]))

    def process_extra_args(self) -> None:
        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(f"{argname} field value {value} is not valid,"
                                 f" valid types are {types}")
        except KeyError:
            if mandatory:
                raise MesonException(f"{argname} mandatory field not found")

            if default is not None:
                return default, default

        return None, None

    def add_extension_paths(self, paths: T.Union[T.List[str], T.Set[str]]) -> None:
        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 replace_dirs_in_string(self, string: str) -> str:
        return string.replace("@SOURCE_ROOT@", self.sourcedir).replace("@BUILD_ROOT@", self.builddir)

    def process_gi_c_source_roots(self) -> None:
        if self.hotdoc.run_hotdoc(['--has-extension=gi-extension']) != 0:
            return

        value = self.kwargs.pop('gi_c_source_roots')
        value.extend([
            os.path.join(self.sourcedir, self.state.root_subdir),
            os.path.join(self.builddir, self.state.root_subdir)
        ])

        self.cmd += ['--gi-c-source-roots'] + value

    def process_dependencies(self, deps: T.List[T.Union[Dependency, build.StaticLibrary, build.SharedLibrary, CustomTarget, CustomTargetIndex]]) -> T.List[str]:
        cflags = set()
        for dep in mesonlib.listify(ensure_list(deps)):
            if isinstance(dep, InternalDependency):
                inc_args = self.state.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.extra_depends.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.include_paths.add(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, (CustomTarget, build.BuildTarget)):
                self.extra_depends.append(dep)
            elif isinstance(dep, CustomTargetIndex):
                self.extra_depends.append(dep.target)

        return [f.strip('-I') for f in cflags]

    def process_extra_assets(self) -> None:
        self._extra_assets = self.kwargs.pop('extra_assets')

        for assets_path in self._extra_assets:
            self.cmd.extend(["--extra-assets", assets_path])

    def process_subprojects(self) -> None:
        value = self.kwargs.pop('subprojects')

        self.process_dependencies(value)
        self._subprojects.extend(value)

    def flatten_config_command(self) -> T.List[str]:
        cmd = []
        for arg in mesonlib.listify(self.cmd, flatten=True):
            if isinstance(arg, 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.BuildTarget, CustomTarget)):
                self.extra_depends.append(arg)
                arg = self.interpreter.backend.get_target_filename_abs(arg)
            elif isinstance(arg, CustomTargetIndex):
                self.extra_depends.append(arg.target)
                arg = self.interpreter.backend.get_target_filename_abs(arg)

            cmd.append(arg)

        return cmd

    def generate_hotdoc_config(self) -> None:
        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)
        if self.hotdoc.run_hotdoc(self.flatten_config_command()) != 0:
            raise MesonException('hotdoc failed to configure')
        os.chdir(cwd)

    def ensure_file(self, value: T.Union[str, File, CustomTarget, CustomTargetIndex]) -> T.Union[File, CustomTarget, CustomTargetIndex]:
        if isinstance(value, list):
            res = []
            for val in value:
                res.append(self.ensure_file(val))
            return res

        if isinstance(value, str):
            return File.from_source_file(self.sourcedir, self.subdir, value)

        return value

    def ensure_dir(self, value: str) -> str:
        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(f'"{_dir}" is not a directory.')

        return os.path.relpath(_dir, os.path.join(self.builddir, self.subdir))

    def check_forbidden_args(self) -> None:
        for arg in ['conf_file']:
            if arg in self.kwargs:
                raise InvalidArguments(f'Argument "{arg}" is forbidden.')

    def make_targets(self) -> T.Tuple[HotdocTarget, mesonlib.ExecutableSerialisation]:
        self.check_forbidden_args()
        self.process_known_arg("--index", value_processor=self.ensure_file)
        self.process_known_arg("--project-version")
        self.process_known_arg("--sitemap", value_processor=self.ensure_file)
        self.process_known_arg("--html-extra-theme", value_processor=self.ensure_dir)
        self.include_paths.update(self.ensure_dir(v) for v in self.kwargs.pop('include_paths'))
        self.process_known_arg('--c-include-directories', argname="dependencies", value_processor=self.process_dependencies)
        self.process_gi_c_source_roots()
        self.process_extra_assets()
        self.add_extension_paths(self.kwargs.pop('extra_extension_paths'))
        self.process_subprojects()
        self.extra_depends.extend(self.kwargs.pop('depends'))

        install = self.kwargs.pop('install')
        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', encoding='utf-8') as f:
            f.write('{}')

        self.cmd += ['--conf-file', hotdoc_config_path]
        self.include_paths.add(os.path.join(self.builddir, self.subdir))
        self.include_paths.add(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:
            self.cmd.extend(['--include-path', path])

        if self.state.environment.coredata.get_option(mesonlib.OptionKey('werror', subproject=self.state.subproject)):
            self.cmd.append('--fatal-warnings')
        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,
                              environment=self.state.environment,
                              hotdoc_conf=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,
                              extra_depends=self.extra_depends,
                              outputs=[fullname],
                              sources=[],
                              depfile=os.path.basename(depfile),
                              build_by_default=self.build_by_default)

        install_script = None
        if install:
            datadir = os.path.join(self.state.get_option('prefix'), self.state.get_option('datadir'))
            devhelp = self.kwargs.get('devhelp_activate', False)
            if not isinstance(devhelp, bool):
                FeatureDeprecated.single_use('hotdoc.generate_doc() devhelp_activate must be boolean', '1.1.0', self.state.subproject)
                devhelp = False
            if devhelp:
                install_from = os.path.join(fullname, 'devhelp')
                install_to = os.path.join(datadir, 'devhelp')
            else:
                install_from = os.path.join(fullname, 'html')
                install_to = os.path.join(datadir, 'doc', self.name, 'html')

            install_script = self.state.backend.get_executable_serialisation(self.build_command + [
                "--internal", "hotdoc",
                "--install", install_from,
                "--docdir", install_to,
                '--name', self.name,
                '--builddir', os.path.join(self.builddir, self.subdir)] +
                self.hotdoc.get_command() +
                ['run', '--conf-file', hotdoc_config_name])
            install_script.tag = 'doc'

        return (target, install_script)


class HotdocTargetHolder(_CustomTargetHolder['HotdocTarget']):
    def __init__(self, target: HotdocTarget, interp: Interpreter):
        super().__init__(target, interp)
        self.methods.update({'config_path': self.config_path_method})

    @noPosargs
    @noKwargs
    def config_path_method(self, *args: T.Any, **kwargs: T.Any) -> str:
        conf = self.held_object.hotdoc_conf.absolute_path(self.interpreter.environment.source_dir,
                                                          self.interpreter.environment.build_dir)
        return conf


class HotdocTarget(CustomTarget):
    def __init__(self, name: str, subdir: str, subproject: str, hotdoc_conf: File,
                 extra_extension_paths: T.Set[str], extra_assets: T.List[str],
                 subprojects: T.List['HotdocTarget'], environment: Environment, **kwargs: T.Any):
        super().__init__(name, subdir, subproject, environment, **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) -> dict:
        # Make sure we do not try to pickle subprojects
        res = self.__dict__.copy()
        res['subprojects'] = []

        return res


class HotDocModule(ExtensionModule):

    INFO = ModuleInfo('hotdoc', '0.48.0')

    def __init__(self, interpreter: Interpreter):
        super().__init__(interpreter)
        self.hotdoc = HotdocExternalProgram('hotdoc')
        if not self.hotdoc.found():
            raise MesonException('hotdoc executable not found')
        version = self.hotdoc.get_version(interpreter)
        if not mesonlib.version_compare(version, f'>={MIN_HOTDOC_VERSION}'):
            raise MesonException(f'hotdoc {MIN_HOTDOC_VERSION} required but not found.)')

        self.methods.update({
            'has_extensions': self.has_extensions,
            'generate_doc': self.generate_doc,
        })

    @noKwargs
    @typed_pos_args('hotdoc.has_extensions', varargs=str, min_varargs=1)
    def has_extensions(self, state: ModuleState, args: T.Tuple[T.List[str]], kwargs: TYPE_kwargs) -> bool:
        return self.hotdoc.run_hotdoc([f'--has-extension={extension}' for extension in args[0]]) == 0

    @typed_pos_args('hotdoc.generate_doc', str)
    @typed_kwargs(
        'hotdoc.generate_doc',
        KwargInfo('sitemap', file_types, required=True),
        KwargInfo('index', file_types, required=True),
        KwargInfo('project_version', str, required=True),
        KwargInfo('html_extra_theme', (str, NoneType)),
        KwargInfo('include_paths', ContainerTypeInfo(list, str), listify=True, default=[]),
        # --c-include-directories
        KwargInfo(
            'dependencies',
            ContainerTypeInfo(list, (Dependency, build.StaticLibrary, build.SharedLibrary,
                                     CustomTarget, CustomTargetIndex)),
            listify=True,
            default=[],
        ),
        KwargInfo(
            'depends',
            ContainerTypeInfo(list, (CustomTarget, CustomTargetIndex)),
            listify=True,
            default=[],
            since='0.64.1',
        ),
        KwargInfo('gi_c_source_roots', ContainerTypeInfo(list, str), listify=True, default=[]),
        KwargInfo('extra_assets', ContainerTypeInfo(list, str), listify=True, default=[]),
        KwargInfo('extra_extension_paths', ContainerTypeInfo(list, str), listify=True, default=[]),
        KwargInfo('subprojects', ContainerTypeInfo(list, HotdocTarget), listify=True, default=[]),
        KwargInfo('install', bool, default=False),
        allow_unknown=True
    )
    def generate_doc(self, state: ModuleState, args: T.Tuple[str], kwargs: GenerateDocKwargs) -> ModuleReturnValue:
        project_name = args[0]
        if any(isinstance(x, (CustomTarget, CustomTargetIndex)) for x in kwargs['dependencies']):
            FeatureDeprecated.single_use('hotdoc.generate_doc dependencies argument with custom_target',
                                         '0.64.1', state.subproject, 'use `depends`', state.current_node)
        builder = HotdocTargetBuilder(project_name, state, self.hotdoc, self.interpreter, kwargs)
        target, install_script = builder.make_targets()
        targets: T.List[T.Union[HotdocTarget, mesonlib.ExecutableSerialisation]] = [target]
        if install_script:
            targets.append(install_script)

        return ModuleReturnValue(target, targets)


def initialize(interpreter: Interpreter) -> HotDocModule:
    mod = HotDocModule(interpreter)
    mod.interpreter.append_holder_map(HotdocTarget, HotdocTargetHolder)
    return mod
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/i18n.py0000644000175000017500000003762314562742363020021 0ustar00jpakkanejpakkane# 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 __future__ import annotations

from os import path
import shlex
import typing as T

from . import ExtensionModule, ModuleReturnValue, ModuleInfo
from .. import build
from .. import mesonlib
from .. import mlog
from ..interpreter.type_checking import CT_BUILD_BY_DEFAULT, CT_INPUT_KW, INSTALL_TAG_KW, OUTPUT_KW, INSTALL_DIR_KW, INSTALL_KW, NoneType, in_set_validator
from ..interpreterbase import FeatureNew
from ..interpreterbase.decorators import ContainerTypeInfo, KwargInfo, noPosargs, typed_kwargs, typed_pos_args
from ..programs import ExternalProgram
from ..scripts.gettext import read_linguas

if T.TYPE_CHECKING:
    from typing_extensions import Literal, TypedDict

    from . import ModuleState
    from ..build import Target
    from ..interpreter import Interpreter
    from ..interpreterbase import TYPE_var

    class MergeFile(TypedDict):

        input: T.List[T.Union[
            str, build.BuildTarget, build.CustomTarget, build.CustomTargetIndex,
            build.ExtractedObjects, build.GeneratedList, ExternalProgram,
            mesonlib.File]]
        output: str
        build_by_default: bool
        install: bool
        install_dir: T.Optional[str]
        install_tag: T.Optional[str]
        args: T.List[str]
        data_dirs: T.List[str]
        po_dir: str
        type: Literal['xml', 'desktop']

    class Gettext(TypedDict):

        args: T.List[str]
        data_dirs: T.List[str]
        install: bool
        install_dir: T.Optional[str]
        languages: T.List[str]
        preset: T.Optional[str]

    class ItsJoinFile(TypedDict):

        input: T.List[T.Union[
            str, build.BuildTarget, build.CustomTarget, build.CustomTargetIndex,
            build.ExtractedObjects, build.GeneratedList, ExternalProgram,
            mesonlib.File]]
        output: str
        build_by_default: bool
        install: bool
        install_dir: T.Optional[str]
        install_tag: T.Optional[str]
        its_files: T.List[str]
        mo_targets: T.List[T.Union[build.BuildTarget, build.CustomTarget, build.CustomTargetIndex]]


_ARGS: KwargInfo[T.List[str]] = KwargInfo(
    'args',
    ContainerTypeInfo(list, str),
    default=[],
    listify=True,
)

_DATA_DIRS: KwargInfo[T.List[str]] = KwargInfo(
    'data_dirs',
    ContainerTypeInfo(list, str),
    default=[],
    listify=True
)

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):

    INFO = ModuleInfo('i18n')

    def __init__(self, interpreter: 'Interpreter'):
        super().__init__(interpreter)
        self.methods.update({
            'merge_file': self.merge_file,
            'gettext': self.gettext,
            'itstool_join': self.itstool_join,
        })
        self.tools: T.Dict[str, T.Optional[T.Union[ExternalProgram, build.Executable]]] = {
            'itstool': None,
            'msgfmt': None,
            'msginit': None,
            'msgmerge': None,
            'xgettext': None,
        }

    @staticmethod
    def _get_data_dirs(state: 'ModuleState', dirs: T.Iterable[str]) -> T.List[str]:
        """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')
    @noPosargs
    @typed_kwargs(
        'i18n.merge_file',
        CT_BUILD_BY_DEFAULT,
        CT_INPUT_KW,
        KwargInfo('install_dir', (str, NoneType)),
        INSTALL_TAG_KW,
        OUTPUT_KW,
        INSTALL_KW,
        _ARGS.evolve(since='0.51.0'),
        _DATA_DIRS.evolve(since='0.41.0'),
        KwargInfo('po_dir', str, required=True),
        KwargInfo('type', str, default='xml', validator=in_set_validator({'xml', 'desktop'})),
    )
    def merge_file(self, state: 'ModuleState', args: T.List['TYPE_var'], kwargs: 'MergeFile') -> ModuleReturnValue:
        if self.tools['msgfmt'] is None or not self.tools['msgfmt'].found():
            self.tools['msgfmt'] = state.find_program('msgfmt', for_machine=mesonlib.MachineChoice.BUILD)
        if isinstance(self.tools['msgfmt'], ExternalProgram):
            try:
                have_version = self.tools['msgfmt'].get_version()
            except mesonlib.MesonException as e:
                raise mesonlib.MesonException('i18n.merge_file requires GNU msgfmt') from e
            want_version = '>=0.19' if kwargs['type'] == 'desktop' else '>=0.19.7'
            if not mesonlib.version_compare(have_version, want_version):
                msg = f'i18n.merge_file requires GNU msgfmt {want_version} to produce files of type: ' + kwargs['type'] + f' (got: {have_version})'
                raise mesonlib.MesonException(msg)
        podir = path.join(state.build_to_src, state.subdir, kwargs['po_dir'])

        ddirs = self._get_data_dirs(state, kwargs['data_dirs'])
        datadirs = '--datadirs=' + ':'.join(ddirs) if ddirs else None

        command: T.List[T.Union[str, build.BuildTarget, build.CustomTarget,
                                build.CustomTargetIndex, 'ExternalProgram', mesonlib.File]] = []
        command.extend(state.environment.get_build_command())
        command.extend([
            '--internal', 'msgfmthelper',
            '--msgfmt=' + self.tools['msgfmt'].get_path(),
        ])
        if datadirs:
            command.append(datadirs)
        command.extend(['@INPUT@', '@OUTPUT@', kwargs['type'], podir])
        if kwargs['args']:
            command.append('--')
            command.extend(kwargs['args'])

        build_by_default = kwargs['build_by_default']
        if build_by_default is None:
            build_by_default = kwargs['install']

        install_tag = [kwargs['install_tag']] if kwargs['install_tag'] is not None else None

        ct = build.CustomTarget(
            '',
            state.subdir,
            state.subproject,
            state.environment,
            command,
            kwargs['input'],
            [kwargs['output']],
            build_by_default=build_by_default,
            install=kwargs['install'],
            install_dir=[kwargs['install_dir']] if kwargs['install_dir'] is not None else None,
            install_tag=install_tag,
            description='Merging translations for {}',
        )

        return ModuleReturnValue(ct, [ct])

    @typed_pos_args('i18n.gettext', str)
    @typed_kwargs(
        'i18n.gettext',
        _ARGS,
        _DATA_DIRS.evolve(since='0.36.0'),
        INSTALL_KW.evolve(default=True),
        INSTALL_DIR_KW.evolve(since='0.50.0'),
        KwargInfo('languages', ContainerTypeInfo(list, str), default=[], listify=True),
        KwargInfo(
            'preset',
            (str, NoneType),
            validator=in_set_validator(set(PRESET_ARGS)),
            since='0.37.0',
        ),
    )
    def gettext(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'Gettext') -> ModuleReturnValue:
        for tool, strict in [('msgfmt', True), ('msginit', False), ('msgmerge', False), ('xgettext', False)]:
            if self.tools[tool] is None:
                self.tools[tool] = state.find_program(tool, required=False, for_machine=mesonlib.MachineChoice.BUILD)
            # still not found?
            if not self.tools[tool].found():
                if strict:
                    mlog.warning('Gettext not found, all translation (po) targets will be ignored.',
                                 once=True, location=state.current_node)
                    return ModuleReturnValue(None, [])
                else:
                    mlog.warning(f'{tool!r} not found, maintainer targets will not work',
                                 once=True, fatal=False, location=state.current_node)
        packagename = args[0]
        pkg_arg = f'--pkgname={packagename}'

        languages = kwargs['languages']
        lang_arg = '--langs=' + '@@'.join(languages) if languages else None

        _datadirs = ':'.join(self._get_data_dirs(state, kwargs['data_dirs']))
        datadirs = f'--datadirs={_datadirs}' if _datadirs else None

        extra_args = kwargs['args']
        targets: T.List['Target'] = []
        gmotargets: T.List['build.CustomTarget'] = []

        preset = kwargs['preset']
        if preset:
            preset_args = PRESET_ARGS[preset]
            extra_args = list(mesonlib.OrderedSet(preset_args + extra_args))

        extra_arg = '--extra-args=' + '@@'.join(extra_args) if extra_args else None

        source_root = path.join(state.source_root, state.root_subdir)
        subdir = path.relpath(state.subdir, start=state.root_subdir) if state.subdir else None

        potargs = state.environment.get_build_command() + ['--internal', 'gettext', 'pot', pkg_arg]
        potargs.append(f'--source-root={source_root}')
        if subdir:
            potargs.append(f'--subdir={subdir}')
        if datadirs:
            potargs.append(datadirs)
        if extra_arg:
            potargs.append(extra_arg)
        if self.tools['xgettext'].found():
            potargs.append('--xgettext=' + self.tools['xgettext'].get_path())
        pottarget = build.RunTarget(packagename + '-pot', potargs, [], state.subdir, state.subproject,
                                    state.environment, default_env=False)
        targets.append(pottarget)

        install = kwargs['install']
        install_dir = kwargs['install_dir'] or state.environment.coredata.get_option(mesonlib.OptionKey('localedir'))
        assert isinstance(install_dir, str), 'for mypy'
        if not languages:
            languages = read_linguas(path.join(state.environment.source_dir, state.subdir))
        for l in languages:
            po_file = mesonlib.File.from_source_file(state.environment.source_dir,
                                                     state.subdir, l+'.po')
            gmotarget = build.CustomTarget(
                f'{packagename}-{l}.mo',
                path.join(state.subdir, l, 'LC_MESSAGES'),
                state.subproject,
                state.environment,
                [self.tools['msgfmt'], '-o', '@OUTPUT@', '@INPUT@'],
                [po_file],
                [f'{packagename}.mo'],
                install=install,
                # We have multiple files all installed as packagename+'.mo' in different install subdirs.
                # What we really wanted to do, probably, is have a rename: kwarg, but that's not available
                # to custom_targets. Crude hack: set the build target's subdir manually.
                # Bonus: the build tree has something usable as an uninstalled bindtextdomain() target dir.
                install_dir=[path.join(install_dir, l, 'LC_MESSAGES')],
                install_tag=['i18n'],
                description='Building translation {}',
            )
            targets.append(gmotarget)
            gmotargets.append(gmotarget)

        allgmotarget = build.AliasTarget(packagename + '-gmo', gmotargets, state.subdir, state.subproject,
                                         state.environment)
        targets.append(allgmotarget)

        updatepoargs = state.environment.get_build_command() + ['--internal', 'gettext', 'update_po', pkg_arg]
        updatepoargs.append(f'--source-root={source_root}')
        if subdir:
            updatepoargs.append(f'--subdir={subdir}')
        if lang_arg:
            updatepoargs.append(lang_arg)
        if datadirs:
            updatepoargs.append(datadirs)
        if extra_arg:
            updatepoargs.append(extra_arg)
        for tool in ['msginit', 'msgmerge']:
            if self.tools[tool].found():
                updatepoargs.append(f'--{tool}=' + self.tools[tool].get_path())
        updatepotarget = build.RunTarget(packagename + '-update-po', updatepoargs, [], state.subdir, state.subproject,
                                         state.environment, default_env=False)
        targets.append(updatepotarget)

        return ModuleReturnValue([gmotargets, pottarget, updatepotarget], targets)

    @FeatureNew('i18n.itstool_join', '0.62.0')
    @noPosargs
    @typed_kwargs(
        'i18n.itstool_join',
        CT_BUILD_BY_DEFAULT,
        CT_INPUT_KW,
        KwargInfo('install_dir', (str, NoneType)),
        INSTALL_TAG_KW,
        OUTPUT_KW,
        INSTALL_KW,
        _ARGS.evolve(),
        KwargInfo('its_files', ContainerTypeInfo(list, str)),
        KwargInfo('mo_targets', ContainerTypeInfo(list, build.CustomTarget), required=True),
    )
    def itstool_join(self, state: 'ModuleState', args: T.List['TYPE_var'], kwargs: 'ItsJoinFile') -> ModuleReturnValue:
        if self.tools['itstool'] is None:
            self.tools['itstool'] = state.find_program('itstool', for_machine=mesonlib.MachineChoice.BUILD)
        mo_targets = kwargs['mo_targets']
        its_files = kwargs.get('its_files', [])

        mo_fnames = []
        for target in mo_targets:
            mo_fnames.append(path.join(target.get_subdir(), target.get_outputs()[0]))

        command: T.List[T.Union[str, build.BuildTarget, build.CustomTarget,
                                build.CustomTargetIndex, 'ExternalProgram', mesonlib.File]] = []
        command.extend(state.environment.get_build_command())

        itstool_cmd = self.tools['itstool'].get_command()
        # TODO: python 3.8 can use shlex.join()
        command.extend([
            '--internal', 'itstool', 'join',
            '-i', '@INPUT@',
            '-o', '@OUTPUT@',
            '--itstool=' + ' '.join(shlex.quote(c) for c in itstool_cmd),
        ])
        if its_files:
            for fname in its_files:
                if not path.isabs(fname):
                    fname = path.join(state.environment.source_dir, state.subdir, fname)
                command.extend(['--its', fname])
        command.extend(mo_fnames)

        build_by_default = kwargs['build_by_default']
        if build_by_default is None:
            build_by_default = kwargs['install']

        install_tag = [kwargs['install_tag']] if kwargs['install_tag'] is not None else None

        ct = build.CustomTarget(
            '',
            state.subdir,
            state.subproject,
            state.environment,
            command,
            kwargs['input'],
            [kwargs['output']],
            build_by_default=build_by_default,
            extra_depends=mo_targets,
            install=kwargs['install'],
            install_dir=[kwargs['install_dir']] if kwargs['install_dir'] is not None else None,
            install_tag=install_tag,
            description='Merging translations for {}',
        )

        return ModuleReturnValue(ct, [ct])


def initialize(interp: 'Interpreter') -> I18nModule:
    return I18nModule(interp)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/icestorm.py0000644000175000017500000001077414562742363021065 0ustar00jpakkanejpakkane# 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 __future__ import annotations
import itertools
import typing as T

from . import ExtensionModule, ModuleReturnValue, ModuleInfo
from .. import build
from .. import mesonlib
from ..interpreter.type_checking import CT_INPUT_KW
from ..interpreterbase.decorators import KwargInfo, typed_kwargs, typed_pos_args

if T.TYPE_CHECKING:
    from typing_extensions import TypedDict

    from . import ModuleState
    from ..interpreter import Interpreter
    from ..programs import ExternalProgram

    class ProjectKwargs(TypedDict):

        sources: T.List[T.Union[mesonlib.FileOrString, build.GeneratedTypes]]
        constraint_file: T.Union[mesonlib.FileOrString, build.GeneratedTypes]

class IceStormModule(ExtensionModule):

    INFO = ModuleInfo('FPGA/Icestorm', '0.45.0', unstable=True)

    def __init__(self, interpreter: Interpreter) -> None:
        super().__init__(interpreter)
        self.tools: T.Dict[str, T.Union[ExternalProgram, build.Executable]] = {}
        self.methods.update({
            'project': self.project,
        })

    def detect_tools(self, state: ModuleState) -> None:
        self.tools['yosys'] = state.find_program('yosys')
        self.tools['arachne'] = state.find_program('arachne-pnr')
        self.tools['icepack'] = state.find_program('icepack')
        self.tools['iceprog'] = state.find_program('iceprog')
        self.tools['icetime'] = state.find_program('icetime')

    @typed_pos_args('icestorm.project', str,
                    varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex,
                             build.GeneratedList))
    @typed_kwargs(
        'icestorm.project',
        CT_INPUT_KW.evolve(name='sources'),
        KwargInfo(
            'constraint_file',
            (str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList),
            required=True,
        )
    )
    def project(self, state: ModuleState,
                args: T.Tuple[str, T.List[T.Union[mesonlib.FileOrString, build.GeneratedTypes]]],
                kwargs: ProjectKwargs) -> ModuleReturnValue:
        if not self.tools:
            self.detect_tools(state)
        proj_name, arg_sources = args
        all_sources = self.interpreter.source_strings_to_files(
            list(itertools.chain(arg_sources, kwargs['sources'])))

        blif_target = build.CustomTarget(
            f'{proj_name}_blif',
            state.subdir,
            state.subproject,
            state.environment,
            [self.tools['yosys'], '-q', '-p', 'synth_ice40 -blif @OUTPUT@', '@INPUT@'],
            all_sources,
            [f'{proj_name}.blif'],
        )

        asc_target = build.CustomTarget(
            f'{proj_name}_asc',
            state.subdir,
            state.subproject,
            state.environment,
            [self.tools['arachne'], '-q', '-d', '1k', '-p', '@INPUT@', '-o', '@OUTPUT@'],
            [kwargs['constraint_file'], blif_target],
            [f'{proj_name}.asc'],
        )

        bin_target = build.CustomTarget(
            f'{proj_name}_bin',
            state.subdir,
            state.subproject,
            state.environment,
            [self.tools['icepack'], '@INPUT@', '@OUTPUT@'],
            [asc_target],
            [f'{proj_name}.bin'],
            build_by_default=True,
        )

        upload_target = build.RunTarget(
            f'{proj_name}-upload',
            [self.tools['iceprog'], bin_target],
            [],
            state.subdir,
            state.subproject,
            state.environment,
        )

        time_target = build.RunTarget(
            f'{proj_name}-time',
            [self.tools['icetime'], bin_target],
            [],
            state.subdir,
            state.subproject,
            state.environment,
        )

        return ModuleReturnValue(
            None,
            [blif_target, asc_target, bin_target, upload_target, time_target])


def initialize(interp: Interpreter) -> IceStormModule:
    return IceStormModule(interp)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/java.py0000644000175000017500000001162414562742363020154 0ustar00jpakkanejpakkane# Copyright 2021 The Meson development team

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

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

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

import pathlib
import typing as T

from mesonbuild import mesonlib
from mesonbuild.build import CustomTarget, CustomTargetIndex, GeneratedList, Target
from mesonbuild.compilers import detect_compiler_for
from mesonbuild.interpreterbase.decorators import ContainerTypeInfo, FeatureDeprecated, FeatureNew, KwargInfo, typed_pos_args, typed_kwargs
from mesonbuild.mesonlib import version_compare, MachineChoice
from . import NewExtensionModule, ModuleReturnValue, ModuleInfo
from ..interpreter.type_checking import NoneType

if T.TYPE_CHECKING:
    from . import ModuleState
    from ..compilers import Compiler
    from ..interpreter import Interpreter

class JavaModule(NewExtensionModule):

    INFO = ModuleInfo('java', '0.60.0')

    def __init__(self, interpreter: Interpreter):
        super().__init__()
        self.methods.update({
            'generate_native_headers': self.generate_native_headers,
            'native_headers': self.native_headers,
        })

    def __get_java_compiler(self, state: ModuleState) -> Compiler:
        if 'java' not in state.environment.coredata.compilers[MachineChoice.BUILD]:
            detect_compiler_for(state.environment, 'java', MachineChoice.BUILD, False)
        return state.environment.coredata.compilers[MachineChoice.BUILD]['java']

    @FeatureNew('java.generate_native_headers', '0.62.0')
    @FeatureDeprecated('java.generate_native_headers', '1.0.0')
    @typed_pos_args(
        'java.generate_native_headers',
        varargs=(str, mesonlib.File, Target, CustomTargetIndex, GeneratedList))
    @typed_kwargs(
        'java.generate_native_headers',
        KwargInfo('classes', ContainerTypeInfo(list, str), default=[], listify=True, required=True),
        KwargInfo('package', (str, NoneType), default=None))
    def generate_native_headers(self, state: ModuleState, args: T.Tuple[T.List[mesonlib.FileOrString]],
                                kwargs: T.Dict[str, T.Optional[str]]) -> ModuleReturnValue:
        return self.__native_headers(state, args, kwargs)

    @FeatureNew('java.native_headers', '1.0.0')
    @typed_pos_args(
        'java.native_headers',
        varargs=(str, mesonlib.File, Target, CustomTargetIndex, GeneratedList))
    @typed_kwargs(
        'java.native_headers',
        KwargInfo('classes', ContainerTypeInfo(list, str), default=[], listify=True, required=True),
        KwargInfo('package', (str, NoneType), default=None))
    def native_headers(self, state: ModuleState, args: T.Tuple[T.List[mesonlib.FileOrString]],
                       kwargs: T.Dict[str, T.Optional[str]]) -> ModuleReturnValue:
        return self.__native_headers(state, args, kwargs)

    def __native_headers(self, state: ModuleState, args: T.Tuple[T.List[mesonlib.FileOrString]],
                         kwargs: T.Dict[str, T.Optional[str]]) -> ModuleReturnValue:
        classes = T.cast('T.List[str]', kwargs.get('classes'))
        package = kwargs.get('package')

        if package:
            sanitized_package = package.replace("-", "_").replace(".", "_")

        headers: T.List[str] = []
        for clazz in classes:
            sanitized_clazz = clazz.replace(".", "_")
            if package:
                headers.append(f'{sanitized_package}_{sanitized_clazz}.h')
            else:
                headers.append(f'{sanitized_clazz}.h')

        javac = self.__get_java_compiler(state)

        command = mesonlib.listify([
            javac.exelist,
            '-d',
            '@PRIVATE_DIR@',
            '-h',
            state.subdir,
            '@INPUT@',
        ])

        prefix = classes[0] if not package else package

        target = CustomTarget(f'{prefix}-native-headers',
                              state.subdir,
                              state.subproject,
                              state.environment,
                              command,
                              sources=args[0], outputs=headers, backend=state.backend)

        # It is only known that 1.8.0 won't pre-create the directory. 11 and 16
        # do not exhibit this behavior.
        if version_compare(javac.version, '1.8.0'):
            pathlib.Path(state.backend.get_target_private_dir_abs(target)).mkdir(parents=True, exist_ok=True)

        return ModuleReturnValue(target, [target])

def initialize(*args: T.Any, **kwargs: T.Any) -> JavaModule:
    return JavaModule(*args, **kwargs)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/keyval.py0000644000175000017500000000506214562742363020525 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import os
import typing as T

from . import ExtensionModule, ModuleInfo
from .. import mesonlib
from ..interpreterbase import noKwargs, typed_pos_args

if T.TYPE_CHECKING:
    from ..interpreter import Interpreter
    from . import ModuleState

class KeyvalModule(ExtensionModule):

    INFO = ModuleInfo('keyval', '0.55.0', stabilized='0.56.0')

    def __init__(self, interp: 'Interpreter'):
        super().__init__(interp)
        self.methods.update({
            'load': self.load,
        })

    @staticmethod
    def _load_file(path_to_config: str) -> T.Dict[str, str]:
        result: T.Dict[str, str] = {}
        try:
            with open(path_to_config, encoding='utf-8') 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 OSError as e:
            raise mesonlib.MesonException(f'Failed to load {path_to_config}: {e}')

        return result

    @noKwargs
    @typed_pos_args('keyval.load', (str, mesonlib.File))
    def load(self, state: 'ModuleState', args: T.Tuple['mesonlib.FileOrString'], kwargs: T.Dict[str, T.Any]) -> T.Dict[str, str]:
        s = args[0]
        is_built = False
        if isinstance(s, mesonlib.File):
            is_built = is_built or s.is_built
            s = s.absolute_path(self.interpreter.environment.source_dir, self.interpreter.environment.build_dir)
        else:
            s = os.path.join(self.interpreter.environment.source_dir, s)

        if not is_built:
            self.interpreter.build_def_files.add(s)

        return self._load_file(s)


def initialize(interp: 'Interpreter') -> KeyvalModule:
    return KeyvalModule(interp)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/modtest.py0000644000175000017500000000260514562742363020711 0ustar00jpakkanejpakkane# 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 __future__ import annotations
import typing as T

from . import NewExtensionModule, ModuleInfo
from ..interpreterbase import noKwargs, noPosargs

if T.TYPE_CHECKING:
    from . import ModuleState
    from ..interpreter.interpreter import Interpreter
    from ..interpreterbase.baseobjects import TYPE_kwargs, TYPE_var


class TestModule(NewExtensionModule):

    INFO = ModuleInfo('modtest')

    def __init__(self, interpreter: Interpreter) -> None:
        super().__init__()
        self.methods.update({
            'print_hello': self.print_hello,
        })

    @noKwargs
    @noPosargs
    def print_hello(self, state: ModuleState, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> None:
        print('Hello from a Meson module')


def initialize(interp: Interpreter) -> TestModule:
    return TestModule(interp)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/pkgconfig.py0000644000175000017500000011310214562742363021174 0ustar00jpakkanejpakkane# Copyright 2015-2022 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 __future__ import annotations
from collections import defaultdict
from dataclasses import dataclass
from pathlib import PurePath
import os
import typing as T

from . import NewExtensionModule, ModuleInfo
from . import ModuleReturnValue
from .. import build
from .. import dependencies
from .. import mesonlib
from .. import mlog
from ..coredata import BUILTIN_DIR_OPTIONS
from ..dependencies.pkgconfig import PkgConfigDependency, PkgConfigInterface
from ..interpreter.type_checking import D_MODULE_VERSIONS_KW, INSTALL_DIR_KW, VARIABLES_KW, NoneType
from ..interpreterbase import FeatureNew, FeatureDeprecated
from ..interpreterbase.decorators import ContainerTypeInfo, KwargInfo, typed_kwargs, typed_pos_args

if T.TYPE_CHECKING:
    from typing_extensions import TypedDict

    from . import ModuleState
    from .. import mparser
    from ..interpreter import Interpreter

    ANY_DEP = T.Union[dependencies.Dependency, build.BuildTargetTypes, str]
    LIBS = T.Union[build.LibTypes, str]

    class GenerateKw(TypedDict):

        version: T.Optional[str]
        name: T.Optional[str]
        filebase: T.Optional[str]
        description: T.Optional[str]
        url: str
        subdirs: T.List[str]
        conflicts: T.List[str]
        dataonly: bool
        libraries: T.List[ANY_DEP]
        libraries_private: T.List[ANY_DEP]
        requires: T.List[T.Union[str, build.StaticLibrary, build.SharedLibrary, dependencies.Dependency]]
        requires_private: T.List[T.Union[str, build.StaticLibrary, build.SharedLibrary, dependencies.Dependency]]
        install_dir: T.Optional[str]
        d_module_versions: T.List[T.Union[str, int]]
        extra_cflags: T.List[str]
        variables: T.Dict[str, str]
        uninstalled_variables: T.Dict[str, str]
        unescaped_variables: T.Dict[str, str]
        unescaped_uninstalled_variables: T.Dict[str, str]


_PKG_LIBRARIES: KwargInfo[T.List[T.Union[str, dependencies.Dependency, build.SharedLibrary, build.StaticLibrary, build.CustomTarget, build.CustomTargetIndex]]] = KwargInfo(
    'libraries',
    ContainerTypeInfo(list, (str, dependencies.Dependency,
                             build.SharedLibrary, build.StaticLibrary,
                             build.CustomTarget, build.CustomTargetIndex)),
    default=[],
    listify=True,
)

_PKG_REQUIRES: KwargInfo[T.List[T.Union[str, build.SharedLibrary, build.StaticLibrary, dependencies.Dependency]]] = KwargInfo(
    'requires',
    ContainerTypeInfo(list, (str, build.SharedLibrary, build.StaticLibrary, dependencies.Dependency)),
    default=[],
    listify=True,
)


def _as_str(obj: object) -> str:
    assert isinstance(obj, str)
    return obj


@dataclass
class MetaData:

    filebase: str
    display_name: str
    location: mparser.BaseNode
    warned: bool = False


class DependenciesHelper:
    def __init__(self, state: ModuleState, name: str, metadata: T.Dict[str, MetaData]) -> None:
        self.state = state
        self.name = name
        self.metadata = metadata
        self.pub_libs: T.List[LIBS] = []
        self.pub_reqs: T.List[str] = []
        self.priv_libs: T.List[LIBS] = []
        self.priv_reqs: T.List[str] = []
        self.cflags: T.List[str] = []
        self.version_reqs: T.DefaultDict[str, T.Set[str]] = defaultdict(set)
        self.link_whole_targets: T.List[T.Union[build.CustomTarget, build.CustomTargetIndex, build.StaticLibrary]] = []
        self.uninstalled_incdirs: mesonlib.OrderedSet[str] = mesonlib.OrderedSet()

    def add_pub_libs(self, libs: T.List[ANY_DEP]) -> None:
        p_libs, reqs, cflags = self._process_libs(libs, True)
        self.pub_libs = p_libs + self.pub_libs # prepend to preserve dependencies
        self.pub_reqs += reqs
        self.cflags += cflags

    def add_priv_libs(self, libs: T.List[ANY_DEP]) -> None:
        p_libs, reqs, _ = self._process_libs(libs, False)
        self.priv_libs = p_libs + self.priv_libs
        self.priv_reqs += reqs

    def add_pub_reqs(self, reqs: T.List[T.Union[str, build.StaticLibrary, build.SharedLibrary, dependencies.Dependency]]) -> None:
        self.pub_reqs += self._process_reqs(reqs)

    def add_priv_reqs(self, reqs: T.List[T.Union[str, build.StaticLibrary, build.SharedLibrary, dependencies.Dependency]]) -> None:
        self.priv_reqs += self._process_reqs(reqs)

    def _check_generated_pc_deprecation(self, obj: T.Union[build.CustomTarget, build.CustomTargetIndex, build.StaticLibrary, build.SharedLibrary]) -> None:
        if obj.get_id() in self.metadata:
            return
        data = self.metadata[obj.get_id()]
        if data.warned:
            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(data.display_name),
                         '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=data.location)
        data.warned = True

    def _process_reqs(self, reqs: T.Sequence[T.Union[str, build.StaticLibrary, build.SharedLibrary, dependencies.Dependency]]) -> T.List[str]:
        '''Returns string names of requirements'''
        processed_reqs: T.List[str] = []
        for obj in mesonlib.listify(reqs):
            if not isinstance(obj, str):
                FeatureNew.single_use('pkgconfig.generate requirement from non-string object', '0.46.0', self.state.subproject)
            if (isinstance(obj, (build.CustomTarget, build.CustomTargetIndex, build.SharedLibrary, build.StaticLibrary))
                    and obj.get_id() in self.metadata):
                self._check_generated_pc_deprecation(obj)
                processed_reqs.append(self.metadata[obj.get_id()].filebase)
            elif isinstance(obj, 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] if version_req is not None else None)
            elif isinstance(obj, dependencies.Dependency) and not obj.found():
                pass
            elif isinstance(obj, dependencies.ExternalDependency) and obj.name == 'threads':
                pass
            else:
                raise mesonlib.MesonException('requires argument not a string, '
                                              'library with pkgconfig-generated file '
                                              f'or pkgconfig-dependency object, got {obj!r}')
        return processed_reqs

    def add_cflags(self, cflags: T.List[str]) -> None:
        self.cflags += mesonlib.stringlistify(cflags)

    def _add_uninstalled_incdirs(self, incdirs: T.List[build.IncludeDirs], subdir: T.Optional[str] = None) -> None:
        for i in incdirs:
            curdir = i.get_curdir()
            for d in i.get_incdirs():
                path = os.path.join(curdir, d)
                self.uninstalled_incdirs.add(path)
        if subdir is not None:
            self.uninstalled_incdirs.add(subdir)

    def _process_libs(
            self, libs: T.List[ANY_DEP], public: bool
            ) -> T.Tuple[T.List[T.Union[str, build.SharedLibrary, build.StaticLibrary, build.CustomTarget, build.CustomTargetIndex]], T.List[str], T.List[str]]:
        libs = mesonlib.listify(libs)
        processed_libs: T.List[T.Union[str, build.SharedLibrary, build.StaticLibrary, build.CustomTarget, build.CustomTargetIndex]] = []
        processed_reqs: T.List[str] = []
        processed_cflags: T.List[str] = []
        for obj in libs:
            if (isinstance(obj, (build.CustomTarget, build.CustomTargetIndex, build.SharedLibrary, build.StaticLibrary))
                    and obj.get_id() in self.metadata):
                self._check_generated_pc_deprecation(obj)
                processed_reqs.append(self.metadata[obj.get_id()].filebase)
            elif isinstance(obj, dependencies.ExternalDependency) and obj.name == 'valgrind':
                pass
            elif isinstance(obj, PkgConfigDependency):
                if obj.found():
                    processed_reqs.append(obj.name)
                    self.add_version_reqs(obj.name, obj.version_reqs)
            elif isinstance(obj, dependencies.InternalDependency):
                if obj.found():
                    if obj.objects:
                        raise mesonlib.MesonException('.pc file cannot refer to individual object files.')
                    processed_libs += obj.get_link_args()
                    processed_cflags += obj.get_compile_args()
                    self._add_lib_dependencies(obj.libraries, obj.whole_libraries, obj.ext_deps, public, private_external_deps=True)
                    self._add_uninstalled_incdirs(obj.get_include_dirs())
            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 obj.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)
                self._add_uninstalled_incdirs(obj.get_include_dirs(), obj.get_subdir())
            elif isinstance(obj, (build.SharedLibrary, build.StaticLibrary)):
                processed_libs.append(obj)
                self._add_uninstalled_incdirs(obj.get_include_dirs(), obj.get_subdir())
                # If there is a static library in `Libs:` all its deps must be
                # public too, otherwise the generated pc file will never be
                # usable without --static.
                self._add_lib_dependencies(obj.link_targets,
                                           obj.link_whole_targets,
                                           obj.external_deps,
                                           isinstance(obj, build.StaticLibrary) and public)
            elif isinstance(obj, (build.CustomTarget, build.CustomTargetIndex)):
                if not obj.is_linkable_target():
                    raise mesonlib.MesonException('library argument contains a not linkable custom_target.')
                FeatureNew.single_use('custom_target in pkgconfig.generate libraries', '0.58.0', self.state.subproject)
                processed_libs.append(obj)
            elif isinstance(obj, str):
                processed_libs.append(obj)
            else:
                raise mesonlib.MesonException(f'library argument of type {type(obj).__name__} not a string, library or dependency object.')

        return processed_libs, processed_reqs, processed_cflags

    def _add_lib_dependencies(
            self, link_targets: T.Sequence[build.BuildTargetTypes],
            link_whole_targets: T.Sequence[T.Union[build.StaticLibrary, build.CustomTarget, build.CustomTargetIndex]],
            external_deps: T.List[dependencies.Dependency],
            public: bool,
            private_external_deps: bool = False) -> None:
        add_libs = self.add_pub_libs if public else self.add_priv_libs
        # Recursively add all linked libraries
        for t in link_targets:
            # Internal libraries (uninstalled static library) will be promoted
            # to link_whole, treat them as such here.
            if t.is_internal():
                # `is_internal` shouldn't return True for anything but a
                # StaticLibrary, or a CustomTarget that is a StaticLibrary
                assert isinstance(t, (build.StaticLibrary, build.CustomTarget, build.CustomTargetIndex)), 'for mypy'
                self._add_link_whole(t, public)
            else:
                add_libs([t])
        for t in link_whole_targets:
            self._add_link_whole(t, public)
        # And finally its external dependencies
        if private_external_deps:
            self.add_priv_libs(T.cast('T.List[ANY_DEP]', external_deps))
        else:
            add_libs(T.cast('T.List[ANY_DEP]', external_deps))

    def _add_link_whole(self, t: T.Union[build.CustomTarget, build.CustomTargetIndex, build.StaticLibrary], public: bool) -> None:
        # Don't include static libraries that we link_whole. But we still need to
        # include their dependencies: a static library we link_whole
        # could itself link to a shared library or an installed static library.
        # Keep track of link_whole_targets so we can remove them from our
        # lists in case a library is link_with and link_whole at the same time.
        # See remove_dups() below.
        self.link_whole_targets.append(t)
        if isinstance(t, build.BuildTarget):
            self._add_lib_dependencies(t.link_targets, t.link_whole_targets, t.external_deps, public)

    def add_version_reqs(self, name: str, version_reqs: T.Optional[T.List[str]]) -> None:
        if version_reqs:
            # 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.
            self.version_reqs[name].update(version_reqs)

    def split_version_req(self, s: str) -> T.Tuple[str, T.Optional[str]]:
        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: str) -> str:
        # 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: T.List[str]) -> str:
        result: T.List[str] = []
        for name in reqs:
            vreqs = self.version_reqs.get(name, None)
            if vreqs:
                result += [name + ' ' + self.format_vreq(vreq) for vreq in sorted(vreqs)]
            else:
                result += [name]
        return ', '.join(result)

    def remove_dups(self) -> None:
        # Set of ids that have already been handled and should not be added any more
        exclude: T.Set[str] = set()

        # We can't just check if 'x' is excluded because we could have copies of
        # the same SharedLibrary object for example.
        def _ids(x: T.Union[str, build.CustomTarget, build.CustomTargetIndex, build.StaticLibrary, build.SharedLibrary]) -> T.Iterable[str]:
            if isinstance(x, str):
                yield x
            else:
                if x.get_id() in self.metadata:
                    yield self.metadata[x.get_id()].display_name
                yield x.get_id()

        # Exclude 'x' in all its forms and return if it was already excluded
        def _add_exclude(x: T.Union[str, build.CustomTarget, build.CustomTargetIndex, build.StaticLibrary, build.SharedLibrary]) -> bool:
            was_excluded = False
            for i in _ids(x):
                if i in exclude:
                    was_excluded = True
                else:
                    exclude.add(i)
            return was_excluded

        # link_whole targets are already part of other targets, exclude them all.
        for t in self.link_whole_targets:
            _add_exclude(t)

        # Mypy thinks these overlap, but since List is invariant they don't,
        # `List[str]`` is not a valid input to `List[str | BuildTarget]`.
        # pylance/pyright gets this right, but for mypy we have to ignore the
        # error
        @T.overload
        def _fn(xs: T.List[str], libs: bool = False) -> T.List[str]: ...  # type: ignore

        @T.overload
        def _fn(xs: T.List[LIBS], libs: bool = False) -> T.List[LIBS]: ...

        def _fn(xs: T.Union[T.List[str], T.List[LIBS]], libs: bool = False) -> T.Union[T.List[str], T.List[LIBS]]:
            # 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 not cannot_dedup and _add_exclude(x):
                    continue
                result.append(x)
            return result

        # Handle lists in priority order: public items can be excluded from
        # private and Requires can excluded from Libs.
        self.pub_reqs = _fn(self.pub_reqs)
        self.pub_libs = _fn(self.pub_libs, True)
        self.priv_reqs = _fn(self.priv_reqs)
        self.priv_libs = _fn(self.priv_libs, True)
        # Reset exclude list just in case some values can be both cflags and libs.
        exclude = set()
        self.cflags = _fn(self.cflags)

class PkgConfigModule(NewExtensionModule):

    INFO = ModuleInfo('pkgconfig')

    # Track already generated pkg-config files This is stored as a class
    # variable so that multiple `import()`s share metadata
    devenv: T.Optional[mesonlib.EnvironmentVariables] = None
    _metadata: T.ClassVar[T.Dict[str, MetaData]] = {}

    def __init__(self) -> None:
        super().__init__()
        self.methods.update({
            'generate': self.generate,
        })

    def postconf_hook(self, b: build.Build) -> None:
        if self.devenv is not None:
            b.devenv.append(self.devenv)

    def _get_lname(self, l: T.Union[build.SharedLibrary, build.StaticLibrary, build.CustomTarget, build.CustomTargetIndex],
                   msg: str, pcfile: str) -> str:
        if isinstance(l, (build.CustomTargetIndex, build.CustomTarget)):
            basename = os.path.basename(l.get_filename())
            name = os.path.splitext(basename)[0]
            if name.startswith('lib'):
                name = name[3:]
            return name
        # 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: T.Union[str, PurePath]) -> str:
        '''
        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: T.Union[PurePath, str], subdir: T.Union[PurePath, str]) -> str:
        prefix = PurePath(prefix)
        subdir = PurePath(subdir)
        try:
            libdir = subdir.relative_to(prefix)
        except ValueError:
            libdir = subdir
        # pathlib joining makes sure absolute libdir is not appended to '${prefix}'
        return ('${prefix}' / libdir).as_posix()

    def _generate_pkgconfig_file(self, state: ModuleState, deps: DependenciesHelper,
                                 subdirs: T.List[str], name: str,
                                 description: str, url: str, version: str,
                                 pcfile: str, conflicts: T.List[str],
                                 variables: T.List[T.Tuple[str, str]],
                                 unescaped_variables: T.List[T.Tuple[str, str]],
                                 uninstalled: bool = False, dataonly: bool = False,
                                 pkgroot: T.Optional[str] = None) -> None:
        coredata = state.environment.get_coredata()
        referenced_vars = set()
        optnames = [x.name for x in BUILTIN_DIR_OPTIONS.keys()]

        if not dataonly:
            # includedir is always implied, although libdir may not be
            # needed for header-only libraries
            referenced_vars |= {'prefix', 'includedir'}
            if deps.pub_libs or deps.priv_libs:
                referenced_vars |= {'libdir'}
        # also automatically infer variables referenced in other variables
        implicit_vars_warning = False
        redundant_vars_warning = False
        varnames = set()
        varstrings = set()
        for k, v in variables + unescaped_variables:
            varnames |= {k}
            varstrings |= {v}
        for optname in optnames:
            optvar = f'${{{optname}}}'
            if any(x.startswith(optvar) for x in varstrings):
                if optname in varnames:
                    redundant_vars_warning = True
                else:
                    # these 3 vars were always "implicit"
                    if dataonly or optname not in {'prefix', 'includedir', 'libdir'}:
                        implicit_vars_warning = True
                    referenced_vars |= {'prefix', optname}
        if redundant_vars_warning:
            FeatureDeprecated.single_use('pkgconfig.generate variable for builtin directories', '0.62.0',
                                         state.subproject, 'They will be automatically included when referenced',
                                         state.current_node)
        if implicit_vars_warning:
            FeatureNew.single_use('pkgconfig.generate implicit variable for builtin directories', '0.62.0',
                                  state.subproject, location=state.current_node)

        if uninstalled:
            outdir = os.path.join(state.environment.build_dir, 'meson-uninstalled')
            if not os.path.exists(outdir):
                os.mkdir(outdir)
            prefix = PurePath(state.environment.get_build_dir())
            srcdir = PurePath(state.environment.get_source_dir())
        else:
            outdir = state.environment.scratch_dir
            prefix = PurePath(_as_str(coredata.get_option(mesonlib.OptionKey('prefix'))))
            if pkgroot:
                pkgroot_ = PurePath(pkgroot)
                if not pkgroot_.is_absolute():
                    pkgroot_ = prefix / pkgroot
                elif prefix not in pkgroot_.parents:
                    raise mesonlib.MesonException('Pkgconfig prefix cannot be outside of the prefix '
                                                  'when pkgconfig.relocatable=true. '
                                                  f'Pkgconfig prefix is {pkgroot_.as_posix()}.')
                prefix = PurePath('${pcfiledir}', os.path.relpath(prefix, pkgroot_))
        fname = os.path.join(outdir, pcfile)
        with open(fname, 'w', encoding='utf-8') as ofile:
            for optname in optnames:
                if optname in referenced_vars - varnames:
                    if optname == 'prefix':
                        ofile.write('prefix={}\n'.format(self._escape(prefix)))
                    else:
                        dirpath = PurePath(_as_str(coredata.get_option(mesonlib.OptionKey(optname))))
                        ofile.write('{}={}\n'.format(optname, self._escape('${prefix}' / dirpath)))
            if uninstalled and not dataonly:
                ofile.write('srcdir={}\n'.format(self._escape(srcdir)))
            if variables or unescaped_variables:
                ofile.write('\n')
            for k, v in variables:
                ofile.write('{}={}\n'.format(k, self._escape(v)))
            for k, v in unescaped_variables:
                ofile.write(f'{k}={v}\n')
            ofile.write('\n')
            ofile.write(f'Name: {name}\n')
            if len(description) > 0:
                ofile.write(f'Description: {description}\n')
            if len(url) > 0:
                ofile.write(f'URL: {url}\n')
            ofile.write(f'Version: {version}\n')
            reqs_str = deps.format_reqs(deps.pub_reqs)
            if len(reqs_str) > 0:
                ofile.write(f'Requires: {reqs_str}\n')
            reqs_str = deps.format_reqs(deps.priv_reqs)
            if len(reqs_str) > 0:
                ofile.write(f'Requires.private: {reqs_str}\n')
            if len(conflicts) > 0:
                ofile.write('Conflicts: {}\n'.format(' '.join(conflicts)))

            def generate_libs_flags(libs: T.List[LIBS]) -> T.Iterable[str]:
                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: T.Union[str, bool]
                        if uninstalled:
                            install_dir = os.path.dirname(state.backend.get_target_filename_abs(l))
                        else:
                            _i = l.get_custom_install_dir()
                            install_dir = _i[0] if _i else None
                        if install_dir is False:
                            continue
                        if isinstance(l, build.BuildTarget) and 'cs' in l.compilers:
                            if isinstance(install_dir, str):
                                Lflag = '-r{}/{}'.format(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{}'.format(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 isinstance(l, build.BuildTarget) and l.name_suffix_set:
                            mlog.warning(msg.format(l.name, 'name_suffix', lname, pcfile))
                        if isinstance(l, (build.CustomTarget, build.CustomTargetIndex)) or 'cs' not in l.compilers:
                            yield f'-l{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))))

            cflags: T.List[str] = []
            if uninstalled:
                for d in deps.uninstalled_incdirs:
                    for basedir in ['${prefix}', '${srcdir}']:
                        path = self._escape(PurePath(basedir, d).as_posix())
                        cflags.append(f'-I{path}')
            else:
                for d in subdirs:
                    if d == '.':
                        cflags.append('-I${includedir}')
                    else:
                        cflags.append(self._escape(PurePath('-I${includedir}') / d))
            cflags += [self._escape(f) for f in deps.cflags]
            if cflags and not dataonly:
                ofile.write('Cflags: {}\n'.format(' '.join(cflags)))

    @typed_pos_args('pkgconfig.generate', optargs=[(build.SharedLibrary, build.StaticLibrary)])
    @typed_kwargs(
        'pkgconfig.generate',
        D_MODULE_VERSIONS_KW.evolve(since='0.43.0'),
        INSTALL_DIR_KW,
        KwargInfo('conflicts', ContainerTypeInfo(list, str), default=[], listify=True),
        KwargInfo('dataonly', bool, default=False, since='0.54.0'),
        KwargInfo('description', (str, NoneType)),
        KwargInfo('extra_cflags', ContainerTypeInfo(list, str), default=[], listify=True, since='0.42.0'),
        KwargInfo('filebase', (str, NoneType), validator=lambda x: 'must not be an empty string' if x == '' else None),
        KwargInfo('name', (str, NoneType), validator=lambda x: 'must not be an empty string' if x == '' else None),
        KwargInfo('subdirs', ContainerTypeInfo(list, str), default=[], listify=True),
        KwargInfo('url', str, default=''),
        KwargInfo('version', (str, NoneType)),
        VARIABLES_KW.evolve(name="unescaped_uninstalled_variables", since='0.59.0'),
        VARIABLES_KW.evolve(name="unescaped_variables", since='0.59.0'),
        VARIABLES_KW.evolve(name="uninstalled_variables", since='0.54.0', since_values={dict: '0.56.0'}),
        VARIABLES_KW.evolve(since='0.41.0', since_values={dict: '0.56.0'}),
        _PKG_LIBRARIES,
        _PKG_LIBRARIES.evolve(name='libraries_private'),
        _PKG_REQUIRES,
        _PKG_REQUIRES.evolve(name='requires_private'),
    )
    def generate(self, state: ModuleState,
                 args: T.Tuple[T.Optional[T.Union[build.SharedLibrary, build.StaticLibrary]]],
                 kwargs: GenerateKw) -> ModuleReturnValue:
        default_version = state.project_version
        default_install_dir: T.Optional[str] = None
        default_description: T.Optional[str] = None
        default_name: T.Optional[str] = None
        mainlib: T.Optional[T.Union[build.SharedLibrary, build.StaticLibrary]] = None
        default_subdirs = ['.']
        if args[0]:
            FeatureNew.single_use('pkgconfig.generate optional positional argument', '0.46.0', state.subproject)
            mainlib = args[0]
            default_name = mainlib.name
            default_description = state.project_name + ': ' + mainlib.name
            install_dir = mainlib.get_custom_install_dir()
            if install_dir and isinstance(install_dir[0], str):
                default_install_dir = os.path.join(install_dir[0], 'pkgconfig')
        else:
            if kwargs['version'] is None:
                FeatureNew.single_use('pkgconfig.generate implicit version keyword', '0.46.0', state.subproject)
            msg = ('pkgconfig.generate: if a library is not passed as a '
                   'positional argument, the {!r} keyword argument is '
                   'required.')
            if kwargs['name'] is None:
                raise build.InvalidArguments(msg.format('name'))
            if kwargs['description'] is None:
                raise build.InvalidArguments(msg.format('description'))

        dataonly = kwargs['dataonly']
        if dataonly:
            default_subdirs = []
            blocked_vars = ['libraries', 'libraries_private', 'requires_private', 'extra_cflags', 'subdirs']
            # Mypy can't figure out that this TypedDict index is correct, without repeating T.Literal for the entire list
            if any(kwargs[k] for k in blocked_vars):  # type: ignore
                raise mesonlib.MesonException(f'Cannot combine dataonly with any of {blocked_vars}')
            default_install_dir = os.path.join(state.environment.get_datadir(), 'pkgconfig')

        subdirs = kwargs['subdirs'] or default_subdirs
        version = kwargs['version'] if kwargs['version'] is not None else default_version
        name = kwargs['name'] if kwargs['name'] is not None else default_name
        assert isinstance(name, str), 'for mypy'
        filebase = kwargs['filebase'] if kwargs['filebase'] is not None else name
        description = kwargs['description'] if kwargs['description'] is not None else default_description
        url = kwargs['url']
        conflicts = kwargs['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 = kwargs['libraries'].copy()
        if mainlib:
            libraries.insert(0, mainlib)

        deps = DependenciesHelper(state, filebase, self._metadata)
        deps.add_pub_libs(libraries)
        deps.add_priv_libs(kwargs['libraries_private'])
        deps.add_pub_reqs(kwargs['requires'])
        deps.add_priv_reqs(kwargs['requires_private'])
        deps.add_cflags(kwargs['extra_cflags'])

        dversions = kwargs['d_module_versions']
        if dversions:
            compiler = state.environment.coredata.compilers.host.get('d')
            if compiler:
                deps.add_cflags(compiler.get_feature_args(
                    {'versions': dversions, 'import_dirs': [], 'debug': [], 'unittest': False}, None))

        deps.remove_dups()

        def parse_variable_list(vardict: T.Dict[str, str]) -> T.List[T.Tuple[str, str]]:
            reserved = ['prefix', 'libdir', 'includedir']
            variables = []
            for name, value in vardict.items():
                if not dataonly and name in reserved:
                    raise mesonlib.MesonException(f'Variable "{name}" is reserved')
                variables.append((name, value))
            return variables

        variables = parse_variable_list(kwargs['variables'])
        unescaped_variables = parse_variable_list(kwargs['unescaped_variables'])

        pcfile = filebase + '.pc'
        pkgroot = pkgroot_name = kwargs['install_dir'] or default_install_dir
        if pkgroot is None:
            if mesonlib.is_freebsd():
                pkgroot = os.path.join(_as_str(state.environment.coredata.get_option(mesonlib.OptionKey('prefix'))), 'libdata', 'pkgconfig')
                pkgroot_name = os.path.join('{prefix}', 'libdata', 'pkgconfig')
            elif mesonlib.is_haiku():
                pkgroot = os.path.join(_as_str(state.environment.coredata.get_option(mesonlib.OptionKey('prefix'))), 'develop', 'lib', 'pkgconfig')
                pkgroot_name = os.path.join('{prefix}', 'develop', 'lib', 'pkgconfig')
            else:
                pkgroot = os.path.join(_as_str(state.environment.coredata.get_option(mesonlib.OptionKey('libdir'))), 'pkgconfig')
                pkgroot_name = os.path.join('{libdir}', 'pkgconfig')
        relocatable = state.get_option('relocatable', module='pkgconfig')
        self._generate_pkgconfig_file(state, deps, subdirs, name, description, url,
                                      version, pcfile, conflicts, variables,
                                      unescaped_variables, False, dataonly,
                                      pkgroot=pkgroot if relocatable else None)
        res = build.Data([mesonlib.File(True, state.environment.get_scratch_dir(), pcfile)], pkgroot, pkgroot_name, None, state.subproject, install_tag='devel')
        variables = parse_variable_list(kwargs['uninstalled_variables'])
        unescaped_variables = parse_variable_list(kwargs['unescaped_uninstalled_variables'])

        pcfile = filebase + '-uninstalled.pc'
        self._generate_pkgconfig_file(state, deps, subdirs, name, description, url,
                                      version, pcfile, conflicts, variables,
                                      unescaped_variables, uninstalled=True, dataonly=dataonly)
        # 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 mainlib.get_id() not in self._metadata:
                self._metadata[mainlib.get_id()] = MetaData(
                    filebase, name, state.current_node)
            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 lib.get_id() not in self._metadata:
                    self._metadata[lib.get_id()] = MetaData(
                        filebase, name, state.current_node)
        if self.devenv is None:
            self.devenv = PkgConfigInterface.get_env(state.environment, mesonlib.MachineChoice.HOST, uninstalled=True)
        return ModuleReturnValue(res, [res])


def initialize(interp: Interpreter) -> PkgConfigModule:
    return PkgConfigModule()
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/python.py0000644000175000017500000006363014562742363020560 0ustar00jpakkanejpakkane# 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.
from __future__ import annotations

import copy, json, os, shutil, re
import typing as T

from . import ExtensionModule, ModuleInfo
from .. import mesonlib
from .. import mlog
from ..coredata import UserFeatureOption
from ..build import known_shmod_kwargs, CustomTarget, CustomTargetIndex, BuildTarget, GeneratedList, StructuredSources, ExtractedObjects, SharedModule
from ..dependencies import NotFoundDependency
from ..dependencies.detect import get_dep_identifier, find_external_dependency
from ..dependencies.python import BasicPythonExternalProgram, python_factory, _PythonDependencyBase
from ..interpreter import extract_required_kwarg, permitted_dependency_kwargs, primitives as P_OBJ
from ..interpreter.interpreterobjects import _ExternalProgramHolder
from ..interpreter.type_checking import NoneType, PRESERVE_PATH_KW, SHARED_MOD_KWS
from ..interpreterbase import (
    noPosargs, noKwargs, permittedKwargs, ContainerTypeInfo,
    InvalidArguments, typed_pos_args, typed_kwargs, KwargInfo,
    FeatureNew, FeatureNewKwargs, disablerIfNotFound
)
from ..mesonlib import MachineChoice, OptionKey
from ..programs import ExternalProgram, NonExistingExternalProgram

if T.TYPE_CHECKING:
    from typing_extensions import TypedDict, NotRequired

    from . import ModuleState
    from ..build import Build, Data
    from ..dependencies import Dependency
    from ..interpreter import Interpreter
    from ..interpreter.interpreter import BuildTargetSource
    from ..interpreter.kwargs import ExtractRequired, SharedModule as SharedModuleKw
    from ..interpreterbase.baseobjects import TYPE_var, TYPE_kwargs

    class PyInstallKw(TypedDict):

        pure: T.Optional[bool]
        subdir: str
        install_tag: T.Optional[str]

    class FindInstallationKw(ExtractRequired):

        disabler: bool
        modules: T.List[str]
        pure: T.Optional[bool]

    class ExtensionModuleKw(SharedModuleKw):

        subdir: NotRequired[T.Optional[str]]

    MaybePythonProg = T.Union[NonExistingExternalProgram, 'PythonExternalProgram']


mod_kwargs = {'subdir', 'limited_api'}
mod_kwargs.update(known_shmod_kwargs)
mod_kwargs -= {'name_prefix', 'name_suffix'}

_MOD_KWARGS = [k for k in SHARED_MOD_KWS if k.name not in {'name_prefix', 'name_suffix'}]


class PythonExternalProgram(BasicPythonExternalProgram):

    # This is a ClassVar instead of an instance bool, because although an
    # installation is cached, we actually copy it, modify attributes such as pure,
    # and return a temporary one rather than the cached object.
    run_bytecompile: T.ClassVar[T.Dict[str, bool]] = {}

    def sanity(self, state: T.Optional['ModuleState'] = None) -> bool:
        ret = super().sanity()
        if ret:
            self.platlib = self._get_path(state, 'platlib')
            self.purelib = self._get_path(state, 'purelib')
        return ret

    def _get_path(self, state: T.Optional['ModuleState'], key: str) -> str:
        rel_path = self.info['install_paths'][key][1:]
        if not state:
            # This happens only from run_project_tests.py
            return rel_path
        value = T.cast('str', state.get_option(f'{key}dir', module='python'))
        if value:
            if state.is_user_defined_option('install_env', module='python'):
                raise mesonlib.MesonException(f'python.{key}dir and python.install_env are mutually exclusive')
            return value

        install_env = state.get_option('install_env', module='python')
        if install_env == 'auto':
            install_env = 'venv' if self.info['is_venv'] else 'system'

        if install_env == 'system':
            rel_path = os.path.join(self.info['variables']['prefix'], rel_path)
        elif install_env == 'venv':
            if not self.info['is_venv']:
                raise mesonlib.MesonException('python.install_env cannot be set to "venv" unless you are in a venv!')
            # inside a venv, deb_system is *never* active hence info['paths'] may be wrong
            rel_path = self.info['sysconfig_paths'][key]

        return rel_path


_PURE_KW = KwargInfo('pure', (bool, NoneType))
_SUBDIR_KW = KwargInfo('subdir', str, default='')
_LIMITED_API_KW = KwargInfo('limited_api', str, default='', since='1.3.0')
_DEFAULTABLE_SUBDIR_KW = KwargInfo('subdir', (str, NoneType))

class PythonInstallation(_ExternalProgramHolder['PythonExternalProgram']):
    def __init__(self, python: 'PythonExternalProgram', interpreter: 'Interpreter'):
        _ExternalProgramHolder.__init__(self, python, interpreter)
        info = python.info
        prefix = self.interpreter.environment.coredata.get_option(mesonlib.OptionKey('prefix'))
        assert isinstance(prefix, str), 'for mypy'
        self.variables = info['variables']
        self.suffix = info['suffix']
        self.limited_api_suffix = info['limited_api_suffix']
        self.paths = info['paths']
        self.pure = python.pure
        self.platlib_install_path = os.path.join(prefix, python.platlib)
        self.purelib_install_path = os.path.join(prefix, python.purelib)
        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)
    @typed_pos_args('python.extension_module', str, varargs=(str, mesonlib.File, CustomTarget, CustomTargetIndex, GeneratedList, StructuredSources, ExtractedObjects, BuildTarget))
    @typed_kwargs('python.extension_module', *_MOD_KWARGS, _DEFAULTABLE_SUBDIR_KW, _LIMITED_API_KW, allow_unknown=True)
    def extension_module_method(self, args: T.Tuple[str, T.List[BuildTargetSource]], kwargs: ExtensionModuleKw) -> 'SharedModule':
        if 'install_dir' in kwargs:
            if kwargs['subdir'] is not None:
                raise InvalidArguments('"subdir" and "install_dir" are mutually exclusive')
        else:
            # We want to remove 'subdir', but it may be None and we want to replace it with ''
            # It must be done this way since we don't allow both `install_dir`
            # and `subdir` to be set at the same time
            subdir = kwargs.pop('subdir') or ''

            kwargs['install_dir'] = self._get_install_dir_impl(False, subdir)

        target_suffix = self.suffix

        new_deps = mesonlib.extract_as_list(kwargs, 'dependencies')
        pydep = next((dep for dep in new_deps if isinstance(dep, _PythonDependencyBase)), None)
        if pydep is None:
            pydep = self._dependency_method_impl({})
            if not pydep.found():
                raise mesonlib.MesonException('Python dependency not found')
            new_deps.append(pydep)
            FeatureNew.single_use('python_installation.extension_module with implicit dependency on python',
                                  '0.63.0', self.subproject, 'use python_installation.dependency()',
                                  self.current_node)

        limited_api_version = kwargs.pop('limited_api')
        allow_limited_api = self.interpreter.environment.coredata.get_option(OptionKey('allow_limited_api', module='python'))
        if limited_api_version != '' and allow_limited_api:

            target_suffix = self.limited_api_suffix

            limited_api_version_hex = self._convert_api_version_to_py_version_hex(limited_api_version, pydep.version)
            limited_api_definition = f'-DPy_LIMITED_API={limited_api_version_hex}'

            new_c_args = mesonlib.extract_as_list(kwargs, 'c_args')
            new_c_args.append(limited_api_definition)
            kwargs['c_args'] = new_c_args

            new_cpp_args = mesonlib.extract_as_list(kwargs, 'cpp_args')
            new_cpp_args.append(limited_api_definition)
            kwargs['cpp_args'] = new_cpp_args

            # When compiled under MSVC, Python's PC/pyconfig.h forcibly inserts pythonMAJOR.MINOR.lib
            # into the linker path when not running in debug mode via a series #pragma comment(lib, "")
            # directives. We manually override these here as this interferes with the intended
            # use of the 'limited_api' kwarg
            for_machine = kwargs['native']
            compilers = self.interpreter.environment.coredata.compilers[for_machine]
            if any(compiler.get_id() == 'msvc' for compiler in compilers.values()):
                pydep_copy = copy.copy(pydep)
                pydep_copy.find_libpy_windows(self.env, limited_api=True)
                if not pydep_copy.found():
                    raise mesonlib.MesonException('Python dependency supporting limited API not found')

                new_deps.remove(pydep)
                new_deps.append(pydep_copy)

                pyver = pydep.version.replace('.', '')
                python_windows_debug_link_exception = f'/NODEFAULTLIB:python{pyver}_d.lib'
                python_windows_release_link_exception = f'/NODEFAULTLIB:python{pyver}.lib'

                new_link_args = mesonlib.extract_as_list(kwargs, 'link_args')

                is_debug = self.interpreter.environment.coredata.options[OptionKey('debug')].value
                if is_debug:
                    new_link_args.append(python_windows_debug_link_exception)
                else:
                    new_link_args.append(python_windows_release_link_exception)

                kwargs['link_args'] = new_link_args

        kwargs['dependencies'] = new_deps

        # msys2's python3 has "-cpython-36m.dll", we have to be clever
        # FIXME: explain what the specific cleverness is here
        split, target_suffix = target_suffix.rsplit('.', 1)
        args = (args[0] + split, args[1])

        kwargs['name_prefix'] = ''
        kwargs['name_suffix'] = target_suffix

        if kwargs['gnu_symbol_visibility'] == '' and \
                (self.is_pypy or mesonlib.version_compare(self.version, '>=3.9')):
            kwargs['gnu_symbol_visibility'] = 'inlineshidden'

        return self.interpreter.build_target(self.current_node, args, kwargs, SharedModule)

    def _convert_api_version_to_py_version_hex(self, api_version: str, detected_version: str) -> str:
        python_api_version_format = re.compile(r'[0-9]\.[0-9]{1,2}')
        decimal_match = python_api_version_format.fullmatch(api_version)
        if not decimal_match:
            raise InvalidArguments(f'Python API version invalid: "{api_version}".')
        if mesonlib.version_compare(api_version, '<3.2'):
            raise InvalidArguments(f'Python Limited API version invalid: {api_version} (must be greater than 3.2)')
        if mesonlib.version_compare(api_version, '>' + detected_version):
            raise InvalidArguments(f'Python Limited API version too high: {api_version} (detected {detected_version})')

        version_components = api_version.split('.')
        major = int(version_components[0])
        minor = int(version_components[1])

        return '0x{:02x}{:02x}0000'.format(major, minor)

    def _dependency_method_impl(self, kwargs: TYPE_kwargs) -> Dependency:
        for_machine = self.interpreter.machine_from_native_kwarg(kwargs)
        identifier = get_dep_identifier(self._full_path(), kwargs)

        dep = self.interpreter.coredata.deps[for_machine].get(identifier)
        if dep is not None:
            return dep

        new_kwargs = kwargs.copy()
        new_kwargs['required'] = False
        candidates = python_factory(self.interpreter.environment, for_machine, new_kwargs, self.held_object)
        dep = find_external_dependency('python', self.interpreter.environment, new_kwargs, candidates)

        self.interpreter.coredata.deps[for_machine].put(identifier, dep)
        return dep

    @disablerIfNotFound
    @permittedKwargs(permitted_dependency_kwargs | {'embed'})
    @FeatureNewKwargs('python_installation.dependency', '0.53.0', ['embed'])
    @noPosargs
    def dependency_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> 'Dependency':
        disabled, required, feature = extract_required_kwarg(kwargs, self.subproject)
        if disabled:
            mlog.log('Dependency', mlog.bold('python'), 'skipped: feature', mlog.bold(feature), 'disabled')
            return NotFoundDependency('python', self.interpreter.environment)
        else:
            dep = self._dependency_method_impl(kwargs)
            if required and not dep.found():
                raise mesonlib.MesonException('Python dependency not found')
            return dep

    @typed_pos_args('install_data', varargs=(str, mesonlib.File))
    @typed_kwargs(
        'python_installation.install_sources',
        _PURE_KW,
        _SUBDIR_KW,
        PRESERVE_PATH_KW,
        KwargInfo('install_tag', (str, NoneType), since='0.60.0')
    )
    def install_sources_method(self, args: T.Tuple[T.List[T.Union[str, mesonlib.File]]],
                               kwargs: 'PyInstallKw') -> 'Data':
        self.held_object.run_bytecompile[self.version] = True
        tag = kwargs['install_tag'] or 'python-runtime'
        pure = kwargs['pure'] if kwargs['pure'] is not None else self.pure
        install_dir = self._get_install_dir_impl(pure, kwargs['subdir'])
        return self.interpreter.install_data_impl(
            self.interpreter.source_strings_to_files(args[0]),
            install_dir,
            mesonlib.FileMode(), rename=None, tag=tag, install_data_type='python',
            preserve_path=kwargs['preserve_path'])

    @noPosargs
    @typed_kwargs('python_installation.install_dir', _PURE_KW, _SUBDIR_KW)
    def get_install_dir_method(self, args: T.List['TYPE_var'], kwargs: 'PyInstallKw') -> str:
        self.held_object.run_bytecompile[self.version] = True
        pure = kwargs['pure'] if kwargs['pure'] is not None else self.pure
        return self._get_install_dir_impl(pure, kwargs['subdir'])

    def _get_install_dir_impl(self, pure: bool, subdir: str) -> P_OBJ.OptionString:
        if pure:
            base = self.purelib_install_path
            name = '{py_purelib}'
        else:
            base = self.platlib_install_path
            name = '{py_platlib}'

        return P_OBJ.OptionString(os.path.join(base, subdir), os.path.join(name, subdir))

    @noPosargs
    @noKwargs
    def language_version_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
        return self.version

    @typed_pos_args('python_installation.has_path', str)
    @noKwargs
    def has_path_method(self, args: T.Tuple[str], kwargs: 'TYPE_kwargs') -> bool:
        return args[0] in self.paths

    @typed_pos_args('python_installation.get_path', str, optargs=[object])
    @noKwargs
    def get_path_method(self, args: T.Tuple[str, T.Optional['TYPE_var']], kwargs: 'TYPE_kwargs') -> 'TYPE_var':
        path_name, fallback = args
        try:
            return self.paths[path_name]
        except KeyError:
            if fallback is not None:
                return fallback
            raise InvalidArguments(f'{path_name} is not a valid path name')

    @typed_pos_args('python_installation.has_variable', str)
    @noKwargs
    def has_variable_method(self, args: T.Tuple[str], kwargs: 'TYPE_kwargs') -> bool:
        return args[0] in self.variables

    @typed_pos_args('python_installation.get_variable', str, optargs=[object])
    @noKwargs
    def get_variable_method(self, args: T.Tuple[str, T.Optional['TYPE_var']], kwargs: 'TYPE_kwargs') -> 'TYPE_var':
        var_name, fallback = args
        try:
            return self.variables[var_name]
        except KeyError:
            if fallback is not None:
                return fallback
            raise InvalidArguments(f'{var_name} is not a valid variable name')

    @noPosargs
    @noKwargs
    @FeatureNew('Python module path method', '0.50.0')
    def path_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
        return super().path_method(args, kwargs)


class PythonModule(ExtensionModule):

    INFO = ModuleInfo('python', '0.46.0')

    def __init__(self, interpreter: 'Interpreter') -> None:
        super().__init__(interpreter)
        self.installations: T.Dict[str, MaybePythonProg] = {}
        self.methods.update({
            'find_installation': self.find_installation,
        })

    def _get_install_scripts(self) -> T.List[mesonlib.ExecutableSerialisation]:
        backend = self.interpreter.backend
        ret = []
        optlevel = self.interpreter.environment.coredata.get_option(mesonlib.OptionKey('bytecompile', module='python'))
        if optlevel == -1:
            return ret
        if not any(PythonExternalProgram.run_bytecompile.values()):
            return ret

        installdata = backend.create_install_data()
        py_files = []

        def should_append(f, isdir: bool = False):
            # This uses the install_plan decorated names to see if the original source was propagated via
            # install_sources() or get_install_dir().
            return f.startswith(('{py_platlib}', '{py_purelib}')) and (f.endswith('.py') or isdir)

        for t in installdata.targets:
            if should_append(t.out_name):
                py_files.append((t.out_name, os.path.join(installdata.prefix, t.outdir, os.path.basename(t.fname))))
        for d in installdata.data:
            if should_append(d.install_path_name):
                py_files.append((d.install_path_name, os.path.join(installdata.prefix, d.install_path)))
        for d in installdata.install_subdirs:
            if should_append(d.install_path_name, True):
                py_files.append((d.install_path_name, os.path.join(installdata.prefix, d.install_path)))

        import importlib.resources
        pycompile = os.path.join(self.interpreter.environment.get_scratch_dir(), 'pycompile.py')
        with open(pycompile, 'wb') as f:
            f.write(importlib.resources.read_binary('mesonbuild.scripts', 'pycompile.py'))

        for i in self.installations.values():
            if isinstance(i, PythonExternalProgram) and i.run_bytecompile[i.info['version']]:
                i = T.cast('PythonExternalProgram', i)
                manifest = f'python-{i.info["version"]}-installed.json'
                manifest_json = []
                for name, f in py_files:
                    if f.startswith((os.path.join(installdata.prefix, i.platlib), os.path.join(installdata.prefix, i.purelib))):
                        manifest_json.append(name)
                with open(os.path.join(self.interpreter.environment.get_scratch_dir(), manifest), 'w', encoding='utf-8') as f:
                    json.dump(manifest_json, f)
                cmd = i.command + [pycompile, manifest, str(optlevel)]

                script = backend.get_executable_serialisation(cmd, verbose=True, tag='python-runtime',
                                                              installdir_map={'py_purelib': i.purelib, 'py_platlib': i.platlib})
                ret.append(script)
        return ret

    def postconf_hook(self, b: Build) -> None:
        b.install_scripts.extend(self._get_install_scripts())

    # https://www.python.org/dev/peps/pep-0397/
    @staticmethod
    def _get_win_pythonpath(name_or_path: str) -> T.Optional[str]:
        if not name_or_path.startswith(('python2', 'python3')):
            return None
        if not shutil.which('py'):
            # program not installed, return without an exception
            return None
        ver = f'-{name_or_path[6:]}'
        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 _find_installation_impl(self, state: 'ModuleState', display_name: str, name_or_path: str, required: bool) -> MaybePythonProg:
        if not name_or_path:
            python = PythonExternalProgram('python3', mesonlib.python_command)
        else:
            tmp_python = ExternalProgram.from_entry(display_name, name_or_path)
            python = PythonExternalProgram(display_name, ext_prog=tmp_python)

            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 = PythonExternalProgram(name_or_path)

            # 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'}:
                tmp_python = ExternalProgram.from_entry(display_name, 'python')
                python = PythonExternalProgram(name_or_path, ext_prog=tmp_python)

        if python.found():
            if python.sanity(state):
                return python
            else:
                sanitymsg = f'{python} is not a valid python or it is missing distutils'
                if required:
                    raise mesonlib.MesonException(sanitymsg)
                else:
                    mlog.warning(sanitymsg, location=state.current_node)

        return NonExistingExternalProgram(python.name)

    @disablerIfNotFound
    @typed_pos_args('python.find_installation', optargs=[str])
    @typed_kwargs(
        'python.find_installation',
        KwargInfo('required', (bool, UserFeatureOption), default=True),
        KwargInfo('disabler', bool, default=False, since='0.49.0'),
        KwargInfo('modules', ContainerTypeInfo(list, str), listify=True, default=[], since='0.51.0'),
        _PURE_KW.evolve(default=True, since='0.64.0'),
    )
    def find_installation(self, state: 'ModuleState', args: T.Tuple[T.Optional[str]],
                          kwargs: 'FindInstallationKw') -> MaybePythonProg:
        feature_check = FeatureNew('Passing "feature" option to find_installation', '0.48.0')
        disabled, required, feature = extract_required_kwarg(kwargs, state.subproject, feature_check)

        # FIXME: this code is *full* of sharp corners. It assumes that it's
        # going to get a string value (or now a list of length 1), of `python2`
        # or `python3` which is completely nonsense.  On windows the value could
        # easily be `['py', '-3']`, or `['py', '-3.7']` to get a very specific
        # version of python. On Linux we might want a python that's not in
        # $PATH, or that uses a wrapper of some kind.
        np: T.List[str] = state.environment.lookup_binary_entry(MachineChoice.HOST, 'python') or []
        fallback = args[0]
        display_name = fallback or 'python'
        if not np and fallback is not None:
            np = [fallback]
        name_or_path = np[0] if np else None

        if disabled:
            mlog.log('Program', name_or_path or 'python', 'found:', mlog.red('NO'), '(disabled by:', mlog.bold(feature), ')')
            return NonExistingExternalProgram()

        python = self.installations.get(name_or_path)
        if not python:
            python = self._find_installation_impl(state, display_name, name_or_path, required)
            self.installations[name_or_path] = python

        want_modules = kwargs['modules']
        found_modules: T.List[str] = []
        missing_modules: T.List[str] = []
        if python.found() and want_modules:
            for mod in want_modules:
                p, *_ = mesonlib.Popen_safe(
                    python.command +
                    ['-c', f'import {mod}'])
                if p.returncode != 0:
                    missing_modules.append(mod)
                else:
                    found_modules.append(mod)

        msg: T.List['mlog.TV_Loggable'] = ['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'))
            return NonExistingExternalProgram(python.name)
        elif missing_modules:
            if required:
                raise mesonlib.MesonException('{} is missing modules: {}'.format(name_or_path or 'python', ', '.join(missing_modules)))
            return NonExistingExternalProgram(python.name)
        else:
            assert isinstance(python, PythonExternalProgram), 'for mypy'
            python = copy.copy(python)
            python.pure = kwargs['pure']
            python.run_bytecompile.setdefault(python.info['version'], False)
            return python

        raise mesonlib.MesonBugException('Unreachable code was reached (PythonModule.find_installation).')


def initialize(interpreter: 'Interpreter') -> PythonModule:
    mod = PythonModule(interpreter)
    mod.interpreter.append_holder_map(PythonExternalProgram, PythonInstallation)
    return mod
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/python3.py0000644000175000017500000000746114562742363020643 0ustar00jpakkanejpakkane# 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.
from __future__ import annotations

import sysconfig
import typing as T

from .. import mesonlib
from . import ExtensionModule, ModuleInfo, ModuleState
from ..build import (
    BuildTarget, CustomTarget, CustomTargetIndex, ExtractedObjects,
    GeneratedList, SharedModule, StructuredSources, known_shmod_kwargs
)
from ..interpreter.type_checking import SHARED_MOD_KWS
from ..interpreterbase import typed_kwargs, typed_pos_args, noPosargs, noKwargs, permittedKwargs
from ..programs import ExternalProgram

if T.TYPE_CHECKING:
    from ..interpreter.interpreter import BuildTargetSource
    from ..interpreter.kwargs import SharedModule as SharedModuleKW


_MOD_KWARGS = [k for k in SHARED_MOD_KWS if k.name not in {'name_prefix', 'name_suffix'}]


class Python3Module(ExtensionModule):

    INFO = ModuleInfo('python3', '0.38.0', deprecated='0.48.0')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.methods.update({
            'extension_module': self.extension_module,
            'find_python': self.find_python,
            'language_version': self.language_version,
            'sysconfig_path': self.sysconfig_path,
        })

    @permittedKwargs(known_shmod_kwargs - {'name_prefix', 'name_suffix'})
    @typed_pos_args('python3.extension_module', str, varargs=(str, mesonlib.File, CustomTarget, CustomTargetIndex, GeneratedList, StructuredSources, ExtractedObjects, BuildTarget))
    @typed_kwargs('python3.extension_module', *_MOD_KWARGS, allow_unknown=True)
    def extension_module(self, state: ModuleState, args: T.Tuple[str, T.List[BuildTargetSource]], kwargs: SharedModuleKW):
        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 self.interpreter.build_target(state.current_node, args, kwargs, SharedModule)

    @noPosargs
    @noKwargs
    def find_python(self, state, args, kwargs):
        command = state.environment.lookup_binary_entry(mesonlib.MachineChoice.HOST, 'python3')
        if command is not None:
            py3 = ExternalProgram.from_entry('python3', command)
        else:
            py3 = ExternalProgram('python3', mesonlib.python_command, silent=True)
        return py3

    @noPosargs
    @noKwargs
    def language_version(self, state, args, kwargs):
        return sysconfig.get_python_version()

    @noKwargs
    @typed_pos_args('python3.sysconfig_path', str)
    def sysconfig_path(self, state, args, kwargs):
        path_name = args[0]
        valid_names = sysconfig.get_path_names()
        if path_name not in valid_names:
            raise mesonlib.MesonException(f'{path_name} is not a valid path name {valid_names}.')

        # Get a relative path without a prefix, e.g. lib/python3.6/site-packages
        return sysconfig.get_path(path_name, vars={'base': '', 'platbase': '', 'installed_base': ''})[1:]


def initialize(*args, **kwargs):
    return Python3Module(*args, **kwargs)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/qt.py0000644000175000017500000007357514562742363017674 0ustar00jpakkanejpakkane# Copyright 2015 The Meson development team
# Copyright Ā© 2021 Intel Corporation

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

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

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

import os
import shutil
import typing as T
import xml.etree.ElementTree as ET

from . import ModuleReturnValue, ExtensionModule
from .. import build
from .. import coredata
from .. import mlog
from ..dependencies import find_external_dependency, Dependency, ExternalLibrary, InternalDependency
from ..mesonlib import MesonException, File, version_compare, Popen_safe
from ..interpreter import extract_required_kwarg
from ..interpreter.type_checking import INSTALL_DIR_KW, INSTALL_KW, NoneType
from ..interpreterbase import ContainerTypeInfo, FeatureDeprecated, KwargInfo, noPosargs, FeatureNew, typed_kwargs
from ..programs import NonExistingExternalProgram

if T.TYPE_CHECKING:
    from . import ModuleState
    from ..dependencies.qt import QtPkgConfigDependency, QmakeQtDependency
    from ..interpreter import Interpreter
    from ..interpreter import kwargs
    from ..mesonlib import FileOrString
    from ..programs import ExternalProgram

    QtDependencyType = T.Union[QtPkgConfigDependency, QmakeQtDependency]

    from typing_extensions import TypedDict

    class ResourceCompilerKwArgs(TypedDict):

        """Keyword arguments for the Resource Compiler method."""

        name: T.Optional[str]
        sources: T.Sequence[T.Union[FileOrString, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList]]
        extra_args: T.List[str]
        method: str

    class UICompilerKwArgs(TypedDict):

        """Keyword arguments for the Ui Compiler method."""

        sources: T.Sequence[T.Union[FileOrString, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList]]
        extra_args: T.List[str]
        method: str

    class MocCompilerKwArgs(TypedDict):

        """Keyword arguments for the Moc Compiler method."""

        sources: T.Sequence[T.Union[FileOrString, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList]]
        headers: T.Sequence[T.Union[FileOrString, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList]]
        extra_args: T.List[str]
        method: str
        include_directories: T.List[T.Union[str, build.IncludeDirs]]
        dependencies: T.List[T.Union[Dependency, ExternalLibrary]]

    class PreprocessKwArgs(TypedDict):

        sources: T.List[FileOrString]
        moc_sources: T.List[T.Union[FileOrString, build.CustomTarget]]
        moc_headers: T.List[T.Union[FileOrString, build.CustomTarget]]
        qresources: T.List[FileOrString]
        ui_files: T.List[T.Union[FileOrString, build.CustomTarget]]
        moc_extra_arguments: T.List[str]
        rcc_extra_arguments: T.List[str]
        uic_extra_arguments: T.List[str]
        include_directories: T.List[T.Union[str, build.IncludeDirs]]
        dependencies: T.List[T.Union[Dependency, ExternalLibrary]]
        method: str

    class HasToolKwArgs(kwargs.ExtractRequired):

        method: str

    class CompileTranslationsKwArgs(TypedDict):

        build_by_default: bool
        install: bool
        install_dir: T.Optional[str]
        method: str
        qresource: T.Optional[str]
        rcc_extra_arguments: T.List[str]
        ts_files: T.List[T.Union[str, File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList]]

class QtBaseModule(ExtensionModule):
    _tools_detected = False
    _rcc_supports_depfiles = False
    _moc_supports_depfiles = False

    def __init__(self, interpreter: 'Interpreter', qt_version: int = 5):
        ExtensionModule.__init__(self, interpreter)
        self.qt_version = qt_version
        # It is important that this list does not change order as the order of
        # the returned ExternalPrograms will change as well
        self.tools: T.Dict[str, T.Union[ExternalProgram, build.Executable]] = {
            'moc': NonExistingExternalProgram('moc'),
            'uic': NonExistingExternalProgram('uic'),
            'rcc': NonExistingExternalProgram('rcc'),
            'lrelease': NonExistingExternalProgram('lrelease'),
        }
        self.methods.update({
            'has_tools': self.has_tools,
            'preprocess': self.preprocess,
            'compile_translations': self.compile_translations,
            'compile_resources': self.compile_resources,
            'compile_ui': self.compile_ui,
            'compile_moc': self.compile_moc,
        })

    def compilers_detect(self, state: 'ModuleState', qt_dep: 'QtDependencyType') -> None:
        """Detect Qt (4 or 5) moc, uic, rcc in the specified bindir or in PATH"""
        wanted = f'== {qt_dep.version}'

        def gen_bins() -> T.Generator[T.Tuple[str, str], None, None]:
            for b in self.tools:
                if qt_dep.bindir:
                    yield os.path.join(qt_dep.bindir, b), b
                if qt_dep.libexecdir:
                    yield os.path.join(qt_dep.libexecdir, b), b
                # prefer the (official)  or (unofficial) -qt
                # of the tool to the plain one, as we
                # don't know what the unsuffixed one points to without calling it.
                yield f'{b}{qt_dep.qtver}', b
                yield f'{b}-qt{qt_dep.qtver}', b
                yield b, b

        for b, name in gen_bins():
            if self.tools[name].found():
                continue

            if name == 'lrelease':
                arg = ['-version']
            elif version_compare(qt_dep.version, '>= 5'):
                arg = ['--version']
            else:
                arg = ['-v']

            # Ensure that the version of qt and each tool are the same
            def get_version(p: T.Union[ExternalProgram, build.Executable]) -> str:
                _, out, err = Popen_safe(p.get_command() + arg)
                if name == 'lrelease' or not qt_dep.version.startswith('4'):
                    care = out
                else:
                    care = err
                return care.rsplit(' ', maxsplit=1)[-1].replace(')', '').strip()

            p = state.find_program(b, required=False,
                                   version_func=get_version,
                                   wanted=wanted)
            if p.found():
                self.tools[name] = p

    def _detect_tools(self, state: 'ModuleState', method: str, required: bool = True) -> None:
        if self._tools_detected:
            return
        self._tools_detected = True
        mlog.log(f'Detecting Qt{self.qt_version} tools')
        kwargs = {'required': required, 'modules': 'Core', 'method': method}
        # Just pick one to make mypy happy
        qt = T.cast('QtPkgConfigDependency', find_external_dependency(f'qt{self.qt_version}', state.environment, kwargs))
        if qt.found():
            # Get all tools and then make sure that they are the right version
            self.compilers_detect(state, qt)
            if version_compare(qt.version, '>=5.15.0'):
                self._moc_supports_depfiles = True
            else:
                mlog.warning('moc dependencies will not work properly until you move to Qt >= 5.15', fatal=False)
            if version_compare(qt.version, '>=5.14.0'):
                self._rcc_supports_depfiles = True
            else:
                mlog.warning('rcc dependencies will not work properly until you move to Qt >= 5.14:',
                             mlog.bold('https://bugreports.qt.io/browse/QTBUG-45460'), fatal=False)
        else:
            suffix = f'-qt{self.qt_version}'
            self.tools['moc'] = NonExistingExternalProgram(name='moc' + suffix)
            self.tools['uic'] = NonExistingExternalProgram(name='uic' + suffix)
            self.tools['rcc'] = NonExistingExternalProgram(name='rcc' + suffix)
            self.tools['lrelease'] = NonExistingExternalProgram(name='lrelease' + suffix)

    @staticmethod
    def _qrc_nodes(state: 'ModuleState', rcc_file: 'FileOrString') -> T.Tuple[str, T.List[str]]:
        abspath: str
        if isinstance(rcc_file, str):
            abspath = os.path.join(state.environment.source_dir, state.subdir, rcc_file)
        else:
            abspath = rcc_file.absolute_path(state.environment.source_dir, state.environment.build_dir)
        rcc_dirname = os.path.dirname(abspath)

        # FIXME: what error are we actually trying to check here? (probably parse errors?)
        try:
            tree = ET.parse(abspath)
            root = tree.getroot()
            result: T.List[str] = []
            for child in root[0]:
                if child.tag != 'file':
                    mlog.warning("malformed rcc file: ", os.path.join(state.subdir, str(rcc_file)))
                    break
                elif child.text is None:
                    raise MesonException(f' element without a path in {os.path.join(state.subdir, str(rcc_file))}')
                else:
                    result.append(child.text)

            return rcc_dirname, result
        except MesonException:
            raise
        except Exception:
            raise MesonException(f'Unable to parse resource file {abspath}')

    def _parse_qrc_deps(self, state: 'ModuleState',
                        rcc_file_: T.Union['FileOrString', build.CustomTarget, build.CustomTargetIndex, build.GeneratedList]) -> T.List[File]:
        result: T.List[File] = []
        inputs: T.Sequence['FileOrString'] = []
        if isinstance(rcc_file_, (str, File)):
            inputs = [rcc_file_]
        else:
            inputs = rcc_file_.get_outputs()

        for rcc_file in inputs:
            rcc_dirname, nodes = self._qrc_nodes(state, rcc_file)
            for resource_path in nodes:
                # 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

    @FeatureNew('qt.has_tools', '0.54.0')
    @noPosargs
    @typed_kwargs(
        'qt.has_tools',
        KwargInfo('required', (bool, coredata.UserFeatureOption), default=False),
        KwargInfo('method', str, default='auto'),
    )
    def has_tools(self, state: 'ModuleState', args: T.Tuple, kwargs: 'HasToolKwArgs') -> bool:
        method = kwargs.get('method', 'auto')
        # We have to cast here because TypedDicts are invariant, even though
        # ExtractRequiredKwArgs is a subset of HasToolKwArgs, type checkers
        # will insist this is wrong
        disabled, required, feature = extract_required_kwarg(kwargs, state.subproject, default=False)
        if disabled:
            mlog.log('qt.has_tools skipped: feature', mlog.bold(feature), 'disabled')
            return False
        self._detect_tools(state, method, required=False)
        for tool in self.tools.values():
            if not tool.found():
                if required:
                    raise MesonException('Qt tools not found')
                return False
        return True

    @FeatureNew('qt.compile_resources', '0.59.0')
    @noPosargs
    @typed_kwargs(
        'qt.compile_resources',
        KwargInfo('name', (str, NoneType)),
        KwargInfo(
            'sources',
            ContainerTypeInfo(list, (File, str, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList), allow_empty=False),
            listify=True,
            required=True,
        ),
        KwargInfo('extra_args', ContainerTypeInfo(list, str), listify=True, default=[]),
        KwargInfo('method', str, default='auto')
    )
    def compile_resources(self, state: 'ModuleState', args: T.Tuple, kwargs: 'ResourceCompilerKwArgs') -> ModuleReturnValue:
        """Compile Qt resources files.

        Uses CustomTargets to generate .cpp files from .qrc files.
        """
        if any(isinstance(s, (build.CustomTarget, build.CustomTargetIndex, build.GeneratedList)) for s in kwargs['sources']):
            FeatureNew.single_use('qt.compile_resources: custom_target or generator for "sources" keyword argument',
                                  '0.60.0', state.subproject, location=state.current_node)
        out = self._compile_resources_impl(state, kwargs)
        return ModuleReturnValue(out, [out])

    def _compile_resources_impl(self, state: 'ModuleState', kwargs: 'ResourceCompilerKwArgs') -> T.List[build.CustomTarget]:
        # Avoid the FeatureNew when dispatching from preprocess
        self._detect_tools(state, kwargs['method'])
        if not self.tools['rcc'].found():
            err_msg = ("{0} sources specified and couldn't find {1}, "
                       "please check your qt{2} installation")
            raise MesonException(err_msg.format('RCC', f'rcc-qt{self.qt_version}', self.qt_version))

        # List of generated CustomTargets
        targets: T.List[build.CustomTarget] = []

        # depfile arguments
        DEPFILE_ARGS: T.List[str] = ['--depfile', '@DEPFILE@'] if self._rcc_supports_depfiles else []

        name = kwargs['name']
        sources: T.List['FileOrString'] = []
        for s in kwargs['sources']:
            if isinstance(s, (str, File)):
                sources.append(s)
            else:
                sources.extend(s.get_outputs())
        extra_args = kwargs['extra_args']

        # If a name was set generate a single .cpp file from all of the qrc
        # files, otherwise generate one .cpp file per qrc file.
        if name:
            qrc_deps: T.List[File] = []
            for s in sources:
                qrc_deps.extend(self._parse_qrc_deps(state, s))

            res_target = build.CustomTarget(
                name,
                state.subdir,
                state.subproject,
                state.environment,
                self.tools['rcc'].get_command() + ['-name', name, '-o', '@OUTPUT@'] + extra_args + ['@INPUT@'] + DEPFILE_ARGS,
                sources,
                [f'{name}.cpp'],
                depend_files=qrc_deps,
                depfile=f'{name}.d',
                description='Compiling Qt resources {}',
            )
            targets.append(res_target)
        else:
            for rcc_file in sources:
                qrc_deps = self._parse_qrc_deps(state, rcc_file)
                if isinstance(rcc_file, str):
                    basename = os.path.basename(rcc_file)
                else:
                    basename = os.path.basename(rcc_file.fname)
                name = f'qt{self.qt_version}-{basename.replace(".", "_")}'
                res_target = build.CustomTarget(
                    name,
                    state.subdir,
                    state.subproject,
                    state.environment,
                    self.tools['rcc'].get_command() + ['-name', '@BASENAME@', '-o', '@OUTPUT@'] + extra_args + ['@INPUT@'] + DEPFILE_ARGS,
                    [rcc_file],
                    [f'{name}.cpp'],
                    depend_files=qrc_deps,
                    depfile=f'{name}.d',
                    description='Compiling Qt resources {}',
                )
                targets.append(res_target)

        return targets

    @FeatureNew('qt.compile_ui', '0.59.0')
    @noPosargs
    @typed_kwargs(
        'qt.compile_ui',
        KwargInfo(
            'sources',
            ContainerTypeInfo(list, (File, str, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList), allow_empty=False),
            listify=True,
            required=True,
        ),
        KwargInfo('extra_args', ContainerTypeInfo(list, str), listify=True, default=[]),
        KwargInfo('method', str, default='auto')
    )
    def compile_ui(self, state: 'ModuleState', args: T.Tuple, kwargs: 'UICompilerKwArgs') -> ModuleReturnValue:
        """Compile UI resources into cpp headers."""
        if any(isinstance(s, (build.CustomTarget, build.CustomTargetIndex, build.GeneratedList)) for s in kwargs['sources']):
            FeatureNew.single_use('qt.compile_ui: custom_target or generator for "sources" keyword argument',
                                  '0.60.0', state.subproject, location=state.current_node)
        out = self._compile_ui_impl(state, kwargs)
        return ModuleReturnValue(out, [out])

    def _compile_ui_impl(self, state: 'ModuleState', kwargs: 'UICompilerKwArgs') -> build.GeneratedList:
        # Avoid the FeatureNew when dispatching from preprocess
        self._detect_tools(state, kwargs['method'])
        if not self.tools['uic'].found():
            err_msg = ("{0} sources specified and couldn't find {1}, "
                       "please check your qt{2} installation")
            raise MesonException(err_msg.format('UIC', f'uic-qt{self.qt_version}', self.qt_version))

        # TODO: This generator isn't added to the generator list in the Interpreter
        gen = build.Generator(
            self.tools['uic'],
            kwargs['extra_args'] + ['-o', '@OUTPUT@', '@INPUT@'],
            ['ui_@BASENAME@.h'],
            name=f'Qt{self.qt_version} ui')
        return gen.process_files(kwargs['sources'], state)

    @FeatureNew('qt.compile_moc', '0.59.0')
    @noPosargs
    @typed_kwargs(
        'qt.compile_moc',
        KwargInfo(
            'sources',
            ContainerTypeInfo(list, (File, str, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList)),
            listify=True,
            default=[],
        ),
        KwargInfo(
            'headers',
            ContainerTypeInfo(list, (File, str, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList)),
            listify=True,
            default=[]
        ),
        KwargInfo('extra_args', ContainerTypeInfo(list, str), listify=True, default=[]),
        KwargInfo('method', str, default='auto'),
        KwargInfo('include_directories', ContainerTypeInfo(list, (build.IncludeDirs, str)), listify=True, default=[]),
        KwargInfo('dependencies', ContainerTypeInfo(list, (Dependency, ExternalLibrary)), listify=True, default=[]),
    )
    def compile_moc(self, state: 'ModuleState', args: T.Tuple, kwargs: 'MocCompilerKwArgs') -> ModuleReturnValue:
        if any(isinstance(s, (build.CustomTarget, build.CustomTargetIndex, build.GeneratedList)) for s in kwargs['headers']):
            FeatureNew.single_use('qt.compile_moc: custom_target or generator for "headers" keyword argument',
                                  '0.60.0', state.subproject, location=state.current_node)
        if any(isinstance(s, (build.CustomTarget, build.CustomTargetIndex, build.GeneratedList)) for s in kwargs['sources']):
            FeatureNew.single_use('qt.compile_moc: custom_target or generator for "sources" keyword argument',
                                  '0.60.0', state.subproject, location=state.current_node)
        out = self._compile_moc_impl(state, kwargs)
        return ModuleReturnValue(out, [out])

    def _compile_moc_impl(self, state: 'ModuleState', kwargs: 'MocCompilerKwArgs') -> T.List[build.GeneratedList]:
        # Avoid the FeatureNew when dispatching from preprocess
        self._detect_tools(state, kwargs['method'])
        if not self.tools['moc'].found():
            err_msg = ("{0} sources specified and couldn't find {1}, "
                       "please check your qt{2} installation")
            raise MesonException(err_msg.format('MOC', f'uic-qt{self.qt_version}', self.qt_version))

        if not (kwargs['headers'] or kwargs['sources']):
            raise build.InvalidArguments('At least one of the "headers" or "sources" keyword arguments must be provided and not empty')

        inc = state.get_include_args(include_dirs=kwargs['include_directories'])
        compile_args: T.List[str] = []
        for dep in kwargs['dependencies']:
            compile_args.extend(a for a in dep.get_all_compile_args() if a.startswith(('-I', '-D')))
            if isinstance(dep, InternalDependency):
                for incl in dep.include_directories:
                    compile_args.extend(f'-I{i}' for i in incl.to_string_list(self.interpreter.source_root, self.interpreter.environment.build_dir))

        output: T.List[build.GeneratedList] = []

        # depfile arguments (defaults to .d)
        DEPFILE_ARGS: T.List[str] = ['--output-dep-file'] if self._moc_supports_depfiles else []

        arguments = kwargs['extra_args'] + DEPFILE_ARGS + inc + compile_args + ['@INPUT@', '-o', '@OUTPUT@']
        if kwargs['headers']:
            moc_gen = build.Generator(
                self.tools['moc'], arguments, ['moc_@BASENAME@.cpp'],
                depfile='moc_@BASENAME@.cpp.d',
                name=f'Qt{self.qt_version} moc header')
            output.append(moc_gen.process_files(kwargs['headers'], state))
        if kwargs['sources']:
            moc_gen = build.Generator(
                self.tools['moc'], arguments, ['@BASENAME@.moc'],
                depfile='@BASENAME@.moc.d',
                name=f'Qt{self.qt_version} moc source')
            output.append(moc_gen.process_files(kwargs['sources'], state))

        return output

    # We can't use typed_pos_args here, the signature is ambiguous
    @typed_kwargs(
        'qt.preprocess',
        KwargInfo('sources', ContainerTypeInfo(list, (File, str)), listify=True, default=[], deprecated='0.59.0'),
        KwargInfo('qresources', ContainerTypeInfo(list, (File, str)), listify=True, default=[]),
        KwargInfo('ui_files', ContainerTypeInfo(list, (File, str, build.CustomTarget)), listify=True, default=[]),
        KwargInfo('moc_sources', ContainerTypeInfo(list, (File, str, build.CustomTarget)), listify=True, default=[]),
        KwargInfo('moc_headers', ContainerTypeInfo(list, (File, str, build.CustomTarget)), listify=True, default=[]),
        KwargInfo('moc_extra_arguments', ContainerTypeInfo(list, str), listify=True, default=[], since='0.44.0'),
        KwargInfo('rcc_extra_arguments', ContainerTypeInfo(list, str), listify=True, default=[], since='0.49.0'),
        KwargInfo('uic_extra_arguments', ContainerTypeInfo(list, str), listify=True, default=[], since='0.49.0'),
        KwargInfo('method', str, default='auto'),
        KwargInfo('include_directories', ContainerTypeInfo(list, (build.IncludeDirs, str)), listify=True, default=[]),
        KwargInfo('dependencies', ContainerTypeInfo(list, (Dependency, ExternalLibrary)), listify=True, default=[]),
    )
    def preprocess(self, state: 'ModuleState', args: T.List[T.Union[str, File]], kwargs: 'PreprocessKwArgs') -> ModuleReturnValue:
        _sources = args[1:]
        if _sources:
            FeatureDeprecated.single_use('qt.preprocess positional sources', '0.59', state.subproject, location=state.current_node)
        # List is invariant, os we have to cast...
        sources = T.cast('T.List[T.Union[str, File, build.GeneratedList, build.CustomTarget]]',
                         _sources + kwargs['sources'])
        for s in sources:
            if not isinstance(s, (str, File)):
                raise build.InvalidArguments('Variadic arguments to qt.preprocess must be Strings or Files')
        method = kwargs['method']

        if kwargs['qresources']:
            # custom output name set? -> one output file, multiple otherwise
            rcc_kwargs: 'ResourceCompilerKwArgs' = {'name': '', 'sources': kwargs['qresources'], 'extra_args': kwargs['rcc_extra_arguments'], 'method': method}
            if args:
                name = args[0]
                if not isinstance(name, str):
                    raise build.InvalidArguments('First argument to qt.preprocess must be a string')
                rcc_kwargs['name'] = name
            sources.extend(self._compile_resources_impl(state, rcc_kwargs))

        if kwargs['ui_files']:
            ui_kwargs: 'UICompilerKwArgs' = {'sources': kwargs['ui_files'], 'extra_args': kwargs['uic_extra_arguments'], 'method': method}
            sources.append(self._compile_ui_impl(state, ui_kwargs))

        if kwargs['moc_headers'] or kwargs['moc_sources']:
            moc_kwargs: 'MocCompilerKwArgs' = {
                'extra_args': kwargs['moc_extra_arguments'],
                'sources': kwargs['moc_sources'],
                'headers': kwargs['moc_headers'],
                'include_directories': kwargs['include_directories'],
                'dependencies': kwargs['dependencies'],
                'method': method,
            }
            sources.extend(self._compile_moc_impl(state, moc_kwargs))

        return ModuleReturnValue(sources, [sources])

    @FeatureNew('qt.compile_translations', '0.44.0')
    @noPosargs
    @typed_kwargs(
        'qt.compile_translations',
        KwargInfo('build_by_default', bool, default=False),
        INSTALL_KW,
        INSTALL_DIR_KW,
        KwargInfo('method', str, default='auto'),
        KwargInfo('qresource', (str, NoneType), since='0.56.0'),
        KwargInfo('rcc_extra_arguments', ContainerTypeInfo(list, str), listify=True, default=[], since='0.56.0'),
        KwargInfo('ts_files', ContainerTypeInfo(list, (str, File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList)), listify=True, default=[]),
    )
    def compile_translations(self, state: 'ModuleState', args: T.Tuple, kwargs: 'CompileTranslationsKwArgs') -> ModuleReturnValue:
        ts_files = kwargs['ts_files']
        if any(isinstance(s, (build.CustomTarget, build.CustomTargetIndex, build.GeneratedList)) for s in ts_files):
            FeatureNew.single_use('qt.compile_translations: custom_target or generator for "ts_files" keyword argument',
                                  '0.60.0', state.subproject, location=state.current_node)
        if kwargs['install'] and not kwargs['install_dir']:
            raise MesonException('qt.compile_translations: "install_dir" keyword argument must be set when "install" is true.')
        qresource = kwargs['qresource']
        if qresource:
            if ts_files:
                raise MesonException('qt.compile_translations: Cannot specify both ts_files and qresource')
            if os.path.dirname(qresource) != '':
                raise MesonException('qt.compile_translations: qresource file name must not contain a subdirectory.')
            qresource_file = File.from_built_file(state.subdir, qresource)
            infile_abs = os.path.join(state.environment.source_dir, qresource_file.relative_name())
            outfile_abs = os.path.join(state.environment.build_dir, qresource_file.relative_name())
            os.makedirs(os.path.dirname(outfile_abs), exist_ok=True)
            shutil.copy2(infile_abs, outfile_abs)
            self.interpreter.add_build_def_file(infile_abs)

            _, nodes = self._qrc_nodes(state, qresource_file)
            for c in nodes:
                if c.endswith('.qm'):
                    ts_files.append(c.rstrip('.qm') + '.ts')
                else:
                    raise MesonException(f'qt.compile_translations: qresource can only contain qm files, found {c}')
            results = self.preprocess(state, [], {'qresources': qresource_file, 'rcc_extra_arguments': kwargs['rcc_extra_arguments']})
        self._detect_tools(state, kwargs['method'])
        translations: T.List[build.CustomTarget] = []
        for ts in ts_files:
            if not self.tools['lrelease'].found():
                raise MesonException('qt.compile_translations: ' +
                                     self.tools['lrelease'].name + ' not found')
            if qresource:
                # In this case we know that ts_files is always a List[str], as
                # it's generated above and no ts_files are passed in. However,
                # mypy can't figure that out so we use assert to assure it that
                # what we're doing is safe
                assert isinstance(ts, str), 'for mypy'
                outdir = os.path.dirname(os.path.normpath(os.path.join(state.subdir, ts)))
                ts = os.path.basename(ts)
            else:
                outdir = state.subdir
            cmd: T.List[T.Union[ExternalProgram, build.Executable, str]] = [self.tools['lrelease'], '@INPUT@', '-qm', '@OUTPUT@']
            lrelease_target = build.CustomTarget(
                f'qt{self.qt_version}-compile-{ts}',
                outdir,
                state.subproject,
                state.environment,
                cmd,
                [ts],
                ['@BASENAME@.qm'],
                install=kwargs['install'],
                install_dir=[kwargs['install_dir']],
                install_tag=['i18n'],
                build_by_default=kwargs['build_by_default'],
                description='Compiling Qt translations {}',
            )
            translations.append(lrelease_target)
        if qresource:
            return ModuleReturnValue(results.return_value[0], [results.new_objects, translations])
        else:
            return ModuleReturnValue(translations, [translations])
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/qt4.py0000644000175000017500000000177214562742363017746 0ustar00jpakkanejpakkane# 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 __future__ import annotations
import typing as T

from .qt import QtBaseModule
from . import ModuleInfo

if T.TYPE_CHECKING:
    from ..interpreter import Interpreter


class Qt4Module(QtBaseModule):

    INFO = ModuleInfo('qt4')

    def __init__(self, interpreter: Interpreter):
        QtBaseModule.__init__(self, interpreter, qt_version=4)


def initialize(interp: Interpreter) -> Qt4Module:
    return Qt4Module(interp)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/qt5.py0000644000175000017500000000177214562742363017747 0ustar00jpakkanejpakkane# 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 __future__ import annotations
import typing as T

from .qt import QtBaseModule
from . import ModuleInfo

if T.TYPE_CHECKING:
    from ..interpreter import Interpreter


class Qt5Module(QtBaseModule):

    INFO = ModuleInfo('qt5')

    def __init__(self, interpreter: Interpreter):
        QtBaseModule.__init__(self, interpreter, qt_version=5)


def initialize(interp: Interpreter) -> Qt5Module:
    return Qt5Module(interp)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/qt6.py0000644000175000017500000000200314562742363017734 0ustar00jpakkanejpakkane# Copyright 2020 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 __future__ import annotations
import typing as T

from .qt import QtBaseModule
from . import ModuleInfo

if T.TYPE_CHECKING:
    from ..interpreter import Interpreter

class Qt6Module(QtBaseModule):

    INFO = ModuleInfo('qt6', '0.57.0')

    def __init__(self, interpreter: Interpreter):
        QtBaseModule.__init__(self, interpreter, qt_version=6)


def initialize(interp: Interpreter) -> Qt6Module:
    return Qt6Module(interp)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0
meson-1.3.2/mesonbuild/modules/rust.py0000644000175000017500000003001514562742373020224 0ustar00jpakkanejpakkane# Copyright Ā© 2020-2023 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.
from __future__ import annotations
import itertools
import os
import typing as T

from mesonbuild.interpreterbase.decorators import FeatureNew

from . import ExtensionModule, ModuleReturnValue, ModuleInfo
from .. import mlog
from ..build import (BothLibraries, BuildTarget, CustomTargetIndex, Executable, ExtractedObjects, GeneratedList,
                     CustomTarget, InvalidArguments, Jar, StructuredSources, SharedLibrary)
from ..compilers.compilers import are_asserts_disabled
from ..interpreter.type_checking import DEPENDENCIES_KW, LINK_WITH_KW, SHARED_LIB_KWS, TEST_KWS, OUTPUT_KW, INCLUDE_DIRECTORIES, SOURCES_VARARGS
from ..interpreterbase import ContainerTypeInfo, InterpreterException, KwargInfo, typed_kwargs, typed_pos_args, noPosargs, permittedKwargs
from ..mesonlib import File

if T.TYPE_CHECKING:
    from . import ModuleState
    from ..build import IncludeDirs, LibTypes
    from ..dependencies import Dependency, ExternalLibrary
    from ..interpreter import Interpreter
    from ..interpreter import kwargs as _kwargs
    from ..interpreter.interpreter import SourceInputs, SourceOutputs
    from ..programs import ExternalProgram, OverrideProgram
    from ..interpreter.type_checking import SourcesVarargsType

    from typing_extensions import TypedDict

    class FuncTest(_kwargs.BaseTest):

        dependencies: T.List[T.Union[Dependency, ExternalLibrary]]
        is_parallel: bool
        link_with: T.List[LibTypes]
        rust_args: T.List[str]

    class FuncBindgen(TypedDict):

        args: T.List[str]
        c_args: T.List[str]
        include_directories: T.List[IncludeDirs]
        input: T.List[SourceInputs]
        output: str
        dependencies: T.List[T.Union[Dependency, ExternalLibrary]]


class RustModule(ExtensionModule):

    """A module that holds helper functions for rust."""

    INFO = ModuleInfo('rust', '0.57.0', stabilized='1.0.0')

    def __init__(self, interpreter: Interpreter) -> None:
        super().__init__(interpreter)
        self._bindgen_bin: T.Optional[T.Union[ExternalProgram, Executable, OverrideProgram]] = None
        self.methods.update({
            'test': self.test,
            'bindgen': self.bindgen,
            'proc_macro': self.proc_macro,
        })

    @typed_pos_args('rust.test', str, BuildTarget)
    @typed_kwargs(
        'rust.test',
        *TEST_KWS,
        DEPENDENCIES_KW,
        LINK_WITH_KW.evolve(since='1.2.0'),
        KwargInfo(
            'rust_args',
            ContainerTypeInfo(list, str),
            listify=True,
            default=[],
            since='1.2.0',
        ),
        KwargInfo('is_parallel', bool, default=False),
    )
    def test(self, state: ModuleState, args: T.Tuple[str, BuildTarget], kwargs: FuncTest) -> ModuleReturnValue:
        """Generate a rust test target from a given rust target.

        Rust puts it's unitests inside it's main source files, unlike most
        languages that put them in external files. This means that normally
        you have to define two separate targets with basically the same
        arguments to get tests:

        ```meson
        rust_lib_sources = [...]
        rust_lib = static_library(
            'rust_lib',
            rust_lib_sources,
        )

        rust_lib_test = executable(
            'rust_lib_test',
            rust_lib_sources,
            rust_args : ['--test'],
        )

        test(
            'rust_lib_test',
            rust_lib_test,
            protocol : 'rust',
        )
        ```

        This is all fine, but not very DRY. This method makes it much easier
        to define rust tests:

        ```meson
        rust = import('unstable-rust')

        rust_lib = static_library(
            'rust_lib',
            [sources],
        )

        rust.test('rust_lib_test', rust_lib)
        ```
        """
        if any(isinstance(t, Jar) for t in kwargs.get('link_with', [])):
            raise InvalidArguments('Rust tests cannot link with Jar targets')

        name = args[0]
        base_target: BuildTarget = args[1]
        if not base_target.uses_rust():
            raise InterpreterException('Second positional argument to rustmod.test() must be a rust based target')
        extra_args = kwargs['args']

        # Delete any arguments we don't want passed
        if '--test' in extra_args:
            mlog.warning('Do not add --test to rustmod.test arguments')
            extra_args.remove('--test')
        if '--format' in extra_args:
            mlog.warning('Do not add --format to rustmod.test arguments')
            i = extra_args.index('--format')
            # Also delete the argument to --format
            del extra_args[i + 1]
            del extra_args[i]
        for i, a in enumerate(extra_args):
            if isinstance(a, str) and a.startswith('--format='):
                del extra_args[i]
                break

        # We need to cast here, as currently these don't have protocol in them, but test itself does.
        tkwargs = T.cast('_kwargs.FuncTest', kwargs.copy())

        tkwargs['args'] = extra_args + ['--test', '--format', 'pretty']
        tkwargs['protocol'] = 'rust'

        new_target_kwargs = base_target.original_kwargs.copy()
        # Don't mutate the shallow copied list, instead replace it with a new
        # one
        new_target_kwargs['install'] = False
        new_target_kwargs['dependencies'] = new_target_kwargs.get('dependencies', []) + kwargs['dependencies']
        new_target_kwargs['link_with'] = new_target_kwargs.get('link_with', []) + kwargs['link_with']
        del new_target_kwargs['rust_crate_type']

        lang_args = base_target.extra_args.copy()
        lang_args['rust'] = base_target.extra_args['rust'] + kwargs['rust_args'] + ['--test']
        new_target_kwargs['language_args'] = lang_args

        sources = T.cast('T.List[SourceOutputs]', base_target.sources.copy())
        sources.extend(base_target.generated)

        new_target = Executable(
            name, base_target.subdir, state.subproject, base_target.for_machine,
            sources, base_target.structured_sources,
            base_target.objects, base_target.environment, base_target.compilers,
            new_target_kwargs
        )

        test = self.interpreter.make_test(
            self.interpreter.current_node, (name, new_target), tkwargs)

        return ModuleReturnValue(None, [new_target, test])

    @noPosargs
    @typed_kwargs(
        'rust.bindgen',
        KwargInfo('c_args', ContainerTypeInfo(list, str), default=[], listify=True),
        KwargInfo('args', ContainerTypeInfo(list, str), default=[], listify=True),
        KwargInfo(
            'input',
            ContainerTypeInfo(list, (File, GeneratedList, BuildTarget, BothLibraries, ExtractedObjects, CustomTargetIndex, CustomTarget, str), allow_empty=False),
            default=[],
            listify=True,
            required=True,
        ),
        INCLUDE_DIRECTORIES.evolve(since_values={ContainerTypeInfo(list, str): '1.0.0'}),
        OUTPUT_KW,
        DEPENDENCIES_KW.evolve(since='1.0.0'),
    )
    def bindgen(self, state: ModuleState, args: T.List, kwargs: FuncBindgen) -> ModuleReturnValue:
        """Wrapper around bindgen to simplify it's use.

        The main thing this simplifies is the use of `include_directory`
        objects, instead of having to pass a plethora of `-I` arguments.
        """
        header, *_deps = self.interpreter.source_strings_to_files(kwargs['input'])

        # Split File and Target dependencies to add pass to CustomTarget
        depends: T.List[SourceOutputs] = []
        depend_files: T.List[File] = []
        for d in _deps:
            if isinstance(d, File):
                depend_files.append(d)
            else:
                depends.append(d)

        # Copy to avoid subsequent calls mutating the original
        # TODO: if we want this to be per-machine we'll need a native kwarg
        clang_args = state.environment.properties.host.get_bindgen_clang_args().copy()

        for i in state.process_include_dirs(kwargs['include_directories']):
            # bindgen always uses clang, so it's safe to hardcode -I here
            clang_args.extend([f'-I{x}' for x in i.to_string_list(
                state.environment.get_source_dir(), state.environment.get_build_dir())])
        if are_asserts_disabled(state.environment.coredata.options):
            clang_args.append('-DNDEBUG')

        for de in kwargs['dependencies']:
            for i in de.get_include_dirs():
                clang_args.extend([f'-I{x}' for x in i.to_string_list(
                    state.environment.get_source_dir(), state.environment.get_build_dir())])
            clang_args.extend(de.get_all_compile_args())
            for s in de.get_sources():
                if isinstance(s, File):
                    depend_files.append(s)
                elif isinstance(s, CustomTarget):
                    depends.append(s)

        # We only want include directories and defines, other things may not be valid
        cargs = state.get_option('args', state.subproject, lang='c')
        assert isinstance(cargs, list), 'for mypy'
        for a in itertools.chain(state.global_args.get('c', []), state.project_args.get('c', []), cargs):
            if a.startswith(('-I', '/I', '-D', '/D', '-U', '/U')):
                clang_args.append(a)

        if self._bindgen_bin is None:
            self._bindgen_bin = state.find_program('bindgen')

        name: str
        if isinstance(header, File):
            name = header.fname
        elif isinstance(header, (BuildTarget, BothLibraries, ExtractedObjects, StructuredSources)):
            raise InterpreterException('bindgen source file must be a C header, not an object or build target')
        else:
            name = header.get_outputs()[0]

        cmd = self._bindgen_bin.get_command() + \
            [
                '@INPUT@', '--output',
                os.path.join(state.environment.build_dir, '@OUTPUT@')
            ] + \
            kwargs['args'] + ['--'] + kwargs['c_args'] + clang_args + \
            ['-MD', '-MQ', '@INPUT@', '-MF', '@DEPFILE@']

        target = CustomTarget(
            f'rustmod-bindgen-{name}'.replace('/', '_'),
            state.subdir,
            state.subproject,
            state.environment,
            cmd,
            [header],
            [kwargs['output']],
            depfile='@PLAINNAME@.d',
            extra_depends=depends,
            depend_files=depend_files,
            backend=state.backend,
            description='Generating bindings for Rust {}',
        )

        return ModuleReturnValue([target], [target])

    # Allow a limited set of kwargs, but still use the full set of typed_kwargs()
    # because it could be setting required default values.
    @FeatureNew('rust.proc_macro', '1.3.0')
    @permittedKwargs({'rust_args', 'rust_dependency_map', 'sources', 'dependencies', 'extra_files',
                      'link_args', 'link_depends', 'link_with', 'override_options'})
    @typed_pos_args('rust.proc_macro', str, varargs=SOURCES_VARARGS)
    @typed_kwargs('rust.proc_macro', *SHARED_LIB_KWS, allow_unknown=True)
    def proc_macro(self, state: ModuleState, args: T.Tuple[str, SourcesVarargsType], kwargs: _kwargs.SharedLibrary) -> SharedLibrary:
        kwargs['native'] = True  # type: ignore
        kwargs['rust_crate_type'] = 'proc-macro'  # type: ignore
        kwargs['rust_args'] = kwargs['rust_args'] + ['--extern', 'proc_macro']
        target = state._interpreter.build_target(state.current_node, args, kwargs, SharedLibrary)
        return target


def initialize(interp: Interpreter) -> RustModule:
    return RustModule(interp)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/simd.py0000644000175000017500000001061014562742363020161 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import typing as T

from .. import mesonlib, mlog
from .. import build
from ..compilers import Compiler
from ..interpreter.type_checking import BT_SOURCES_KW, STATIC_LIB_KWS
from ..interpreterbase.decorators import KwargInfo, permittedKwargs, typed_pos_args, typed_kwargs

from . import ExtensionModule, ModuleInfo

if T.TYPE_CHECKING:
    from . import ModuleState
    from ..interpreter import Interpreter, kwargs as kwtypes
    from ..interpreter.type_checking import SourcesVarargsType

    class CheckKw(kwtypes.StaticLibrary):

        compiler: Compiler
        mmx: SourcesVarargsType
        sse: SourcesVarargsType
        sse2: SourcesVarargsType
        sse3: SourcesVarargsType
        ssse3: SourcesVarargsType
        sse41: SourcesVarargsType
        sse42: SourcesVarargsType
        avx: SourcesVarargsType
        avx2: SourcesVarargsType
        neon: SourcesVarargsType


# FIXME add Altivec and AVX512.
ISETS = (
    'mmx',
    'sse',
    'sse2',
    'sse3',
    'ssse3',
    'sse41',
    'sse42',
    'avx',
    'avx2',
    'neon',
)


class SimdModule(ExtensionModule):

    INFO = ModuleInfo('SIMD', '0.42.0', unstable=True)

    def __init__(self, interpreter: Interpreter):
        super().__init__(interpreter)
        self.methods.update({
            'check': self.check,
        })

    @typed_pos_args('simd.check', str)
    @typed_kwargs('simd.check',
                  KwargInfo('compiler', Compiler, required=True),
                  *[BT_SOURCES_KW.evolve(name=iset, default=None) for iset in ISETS],
                  *[a for a in STATIC_LIB_KWS if a.name != 'sources'],
                  allow_unknown=True) # Because we also accept STATIC_LIB_KWS, but build targets have not been completely ported to typed_pos_args/typed_kwargs.
    @permittedKwargs({'compiler', *ISETS, *build.known_stlib_kwargs}) # Also remove this, per above comment
    def check(self, state: ModuleState, args: T.Tuple[str], kwargs: CheckKw) -> T.List[T.Union[T.List[build.StaticLibrary], build.ConfigurationData]]:
        result: T.List[build.StaticLibrary] = []

        if 'sources' in kwargs:
            raise mesonlib.MesonException('SIMD module does not support the "sources" keyword')

        local_kwargs = set((*ISETS, 'compiler'))
        static_lib_kwargs = T.cast('kwtypes.StaticLibrary', {k: v for k, v in kwargs.items() if k not in local_kwargs})

        prefix = args[0]
        compiler = kwargs['compiler']
        conf = build.ConfigurationData()

        for iset in ISETS:
            sources = kwargs[iset]
            if sources is None:
                continue

            compile_args = compiler.get_instruction_set_args(iset)
            if compile_args is None:
                mlog.log(f'Compiler supports {iset}:', mlog.red('NO'))
                continue

            if not compiler.has_multi_arguments(compile_args, state.environment)[0]:
                mlog.log(f'Compiler supports {iset}:', mlog.red('NO'))
                continue
            mlog.log(f'Compiler supports {iset}:', mlog.green('YES'))
            conf.values['HAVE_' + iset.upper()] = ('1', f'Compiler supports {iset}.')

            libname = prefix + '_' + iset
            lib_kwargs = static_lib_kwargs.copy()
            lib_kwargs['sources'] = sources

            # Add compile args we derived above to those the user provided us
            langarg_key = compiler.get_language() + '_args'
            old_lang_args = mesonlib.extract_as_list(lib_kwargs, langarg_key)
            all_lang_args = old_lang_args + compile_args
            lib_kwargs[langarg_key] = all_lang_args

            lib = self.interpreter.build_target(state.current_node, (libname, []), lib_kwargs, build.StaticLibrary)

            result.append(lib)

        return [result, conf]

def initialize(interp: Interpreter) -> SimdModule:
    return SimdModule(interp)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/sourceset.py0000644000175000017500000002726114562742363021253 0ustar00jpakkanejpakkane# 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 __future__ import annotations
import typing as T

from . import ExtensionModule, ModuleObject, MutableModuleObject, ModuleInfo
from .. import build
from .. import dependencies
from .. import mesonlib
from ..interpreterbase import (
    noPosargs, noKwargs,
    InterpreterException, InvalidArguments, InvalidCode, FeatureNew,
)
from ..interpreterbase.decorators import ContainerTypeInfo, KwargInfo, typed_kwargs, typed_pos_args
from ..mesonlib import OrderedSet

if T.TYPE_CHECKING:
    from typing_extensions import TypedDict

    from . import ModuleState
    from ..interpreter import Interpreter
    from ..interpreterbase import TYPE_var, TYPE_kwargs

    class AddKwargs(TypedDict):

        when: T.List[T.Union[str, dependencies.Dependency]]
        if_true: T.List[T.Union[mesonlib.FileOrString, build.GeneratedTypes, dependencies.Dependency]]
        if_false: T.List[T.Union[mesonlib.FileOrString, build.GeneratedTypes]]

    class AddAllKw(TypedDict):

        when: T.List[T.Union[str, dependencies.Dependency]]
        if_true: T.List[SourceSetImpl]

    class ApplyKw(TypedDict):

        strict: bool


_WHEN_KW: KwargInfo[T.List[T.Union[str, dependencies.Dependency]]] = KwargInfo(
    'when',
    ContainerTypeInfo(list, (str, dependencies.Dependency)),
    listify=True,
    default=[],
)


class SourceSetRule(T.NamedTuple):
    keys: T.List[str]
    """Configuration keys that enable this rule if true"""

    deps: T.List[dependencies.Dependency]
    """Dependencies that enable this rule if true"""

    sources: T.List[T.Union[mesonlib.FileOrString, build.GeneratedTypes]]
    """Source files added when this rule's conditions are true"""

    extra_deps: T.List[dependencies.Dependency]
    """Dependencies added when this rule's conditions are true, but
       that do not make the condition false if they're absent."""

    sourcesets: T.List[SourceSetImpl]
    """Other sourcesets added when this rule's conditions are true"""

    if_false: T.List[T.Union[mesonlib.FileOrString, build.GeneratedTypes]]
    """Source files added when this rule's conditions are false"""


class SourceFiles(T.NamedTuple):
    sources: OrderedSet[T.Union[mesonlib.FileOrString, build.GeneratedTypes]]
    deps: OrderedSet[dependencies.Dependency]


class SourceSet:
    """Base class to avoid circular references.

    Because of error messages, this class is called SourceSet, and the actual
    implementation is an Impl.
    """


class SourceSetImpl(SourceSet, MutableModuleObject):
    def __init__(self, interpreter: Interpreter):
        super().__init__()
        self.rules: T.List[SourceSetRule] = []
        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, args: T.Sequence[T.Union[mesonlib.FileOrString, build.GeneratedTypes, dependencies.Dependency]],
                           ) -> T.Tuple[T.List[T.Union[mesonlib.FileOrString, build.GeneratedTypes]], T.List[dependencies.Dependency]]:
        sources: T.List[T.Union[mesonlib.FileOrString, build.GeneratedTypes]] = []
        deps: T.List[dependencies.Dependency] = []
        for x in args:
            if isinstance(x, dependencies.Dependency):
                deps.append(x)
            else:
                sources.append(x)
        to_check: T.List[str] = []

        # Get the actual output names to check
        for s in sources:
            if isinstance(s, str):
                to_check.append(s)
            elif isinstance(s, mesonlib.File):
                to_check.append(s.fname)
            else:
                to_check.extend(s.get_outputs())
        mesonlib.check_direntry_issues(to_check)
        return sources, deps

    def check_conditions(self, args: T.Sequence[T.Union[str, dependencies.Dependency]]
                         ) -> T.Tuple[T.List[str], T.List[dependencies.Dependency]]:
        keys: T.List[str] = []
        deps: T.List[dependencies.Dependency] = []
        for x in args:
            if isinstance(x, str):
                keys.append(x)
            else:
                deps.append(x)
        return keys, deps

    @typed_pos_args('sourceset.add', varargs=(str, mesonlib.File, build.GeneratedList, build.CustomTarget, build.CustomTargetIndex, dependencies.Dependency))
    @typed_kwargs(
        'sourceset.add',
        _WHEN_KW,
        KwargInfo(
            'if_true',
            ContainerTypeInfo(list, (str, mesonlib.File, build.GeneratedList, build.CustomTarget, build.CustomTargetIndex, dependencies.Dependency)),
            listify=True,
            default=[],
        ),
        KwargInfo(
            'if_false',
            ContainerTypeInfo(list, (str, mesonlib.File, build.GeneratedList, build.CustomTarget, build.CustomTargetIndex)),
            listify=True,
            default=[],
        ),
    )
    def add_method(self, state: ModuleState,
                   args: T.Tuple[T.List[T.Union[mesonlib.FileOrString, build.GeneratedTypes, dependencies.Dependency]]],
                   kwargs: AddKwargs) -> None:
        if self.frozen:
            raise InvalidCode('Tried to use \'add\' after querying the source set')
        when = kwargs['when']
        if_true = kwargs['if_true']
        if_false = kwargs['if_false']
        if not any([when, if_true, if_false]):
            if_true = args[0]
        elif args[0]:
            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)
        if_false, _ = self.check_source_files(if_false)
        self.rules.append(SourceSetRule(keys, dependencies, sources, extra_deps, [], if_false))

    @typed_pos_args('sourceset.add_all', varargs=SourceSet)
    @typed_kwargs(
        'sourceset.add_all',
        _WHEN_KW,
        KwargInfo(
            'if_true',
            ContainerTypeInfo(list, SourceSet),
            listify=True,
            default=[],
        )
    )
    def add_all_method(self, state: ModuleState, args: T.Tuple[T.List[SourceSetImpl]],
                       kwargs: AddAllKw) -> None:
        if self.frozen:
            raise InvalidCode('Tried to use \'add_all\' after querying the source set')
        when = kwargs['when']
        if_true = kwargs['if_true']
        if not when and not if_true:
            if_true = args[0]
        elif args[0]:
            raise InterpreterException('add_all called with both positional and keyword arguments')
        keys, dependencies = self.check_conditions(when)
        for s in if_true:
            s.frozen = True
        self.rules.append(SourceSetRule(keys, dependencies, [], [], if_true, []))

    def collect(self, enabled_fn: T.Callable[[str], bool],
                all_sources: bool,
                into: T.Optional['SourceFiles'] = None) -> SourceFiles:
        if not into:
            into = SourceFiles(OrderedSet(), OrderedSet())
        for entry in self.rules:
            if all(x.found() for x in entry.deps) and \
               all(enabled_fn(key) for key in entry.keys):
                into.sources.update(entry.sources)
                into.deps.update(entry.deps)
                into.deps.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, state: ModuleState, args: T.List[TYPE_var], kwargs: TYPE_kwargs
                           ) -> T.List[T.Union[mesonlib.FileOrString, build.GeneratedTypes]]:
        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, state: ModuleState, args: T.List[TYPE_var], kwargs: TYPE_kwargs
                                ) -> T.List[dependencies.Dependency]:
        self.frozen = True
        files = self.collect(lambda x: True, True)
        return list(files.deps)

    @typed_pos_args('sourceset.apply', (build.ConfigurationData, dict))
    @typed_kwargs('sourceset.apply', KwargInfo('strict', bool, default=True))
    def apply_method(self, state: ModuleState, args: T.Tuple[T.Union[build.ConfigurationData, T.Dict[str, TYPE_var]]], kwargs: ApplyKw) -> SourceFilesObject:
        config_data = args[0]
        self.frozen = True
        strict = kwargs['strict']
        if isinstance(config_data, dict):
            def _get_from_config_data(key: str) -> bool:
                assert isinstance(config_data, dict), 'for mypy'
                if strict and key not in config_data:
                    raise InterpreterException(f'Entry {key} not in configuration dictionary.')
                return bool(config_data.get(key, False))
        else:
            config_cache: T.Dict[str, bool] = {}

            def _get_from_config_data(key: str) -> bool:
                assert isinstance(config_data, build.ConfigurationData), 'for mypy'
                if key not in config_cache:
                    if key in config_data:
                        config_cache[key] = bool(config_data.get(key)[0])
                    elif strict:
                        raise InvalidArguments(f'sourceset.apply: key "{key}" not in passed configuration, and strict set.')
                    else:
                        config_cache[key] = False
                return config_cache[key]

        files = self.collect(_get_from_config_data, False)
        res = SourceFilesObject(files)
        return res

class SourceFilesObject(ModuleObject):
    def __init__(self, files: SourceFiles):
        super().__init__()
        self.files = files
        self.methods.update({
            'sources': self.sources_method,
            'dependencies': self.dependencies_method,
        })

    @noPosargs
    @noKwargs
    def sources_method(self, state: ModuleState, args: T.List[TYPE_var], kwargs: TYPE_kwargs
                       ) -> T.List[T.Union[mesonlib.FileOrString, build.GeneratedTypes]]:
        return list(self.files.sources)

    @noPosargs
    @noKwargs
    def dependencies_method(self, state: ModuleState, args: T.List[TYPE_var], kwargs: TYPE_kwargs
                            ) -> T.List[dependencies.Dependency]:
        return list(self.files.deps)

class SourceSetModule(ExtensionModule):

    INFO = ModuleInfo('sourceset', '0.51.0')

    def __init__(self, interpreter: Interpreter):
        super().__init__(interpreter)
        self.methods.update({
            'source_set': self.source_set,
        })

    @noKwargs
    @noPosargs
    def source_set(self, state: ModuleState, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> SourceSetImpl:
        return SourceSetImpl(self.interpreter)

def initialize(interp: Interpreter) -> SourceSetModule:
    return SourceSetModule(interp)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/wayland.py0000644000175000017500000001376214562742363020677 0ustar00jpakkanejpakkane# Copyright 2022 Mark Bolhuis 

# 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 __future__ import annotations
import os
import typing as T

from . import ExtensionModule, ModuleReturnValue, ModuleInfo
from ..build import CustomTarget
from ..interpreter.type_checking import NoneType, in_set_validator
from ..interpreterbase import typed_pos_args, typed_kwargs, KwargInfo
from ..mesonlib import File, MesonException

if T.TYPE_CHECKING:
    from typing_extensions import Literal, TypedDict

    from . import ModuleState
    from ..build import Executable
    from ..dependencies import Dependency
    from ..interpreter import Interpreter
    from ..programs import ExternalProgram
    from ..mesonlib import FileOrString

    class ScanXML(TypedDict):

        public: bool
        client: bool
        server: bool
        include_core_only: bool

    class FindProtocol(TypedDict):

        state: Literal['stable', 'staging', 'unstable']
        version: T.Optional[int]

class WaylandModule(ExtensionModule):

    INFO = ModuleInfo('wayland', '0.62.0', unstable=True)

    def __init__(self, interpreter: Interpreter) -> None:
        super().__init__(interpreter)

        self.protocols_dep: T.Optional[Dependency] = None
        self.pkgdatadir: T.Optional[str] = None
        self.scanner_bin: T.Optional[T.Union[ExternalProgram, Executable]] = None

        self.methods.update({
            'scan_xml': self.scan_xml,
            'find_protocol': self.find_protocol,
        })

    @typed_pos_args('wayland.scan_xml', varargs=(str, File), min_varargs=1)
    @typed_kwargs(
        'wayland.scan_xml',
        KwargInfo('public', bool, default=False),
        KwargInfo('client', bool, default=True),
        KwargInfo('server', bool, default=False),
        KwargInfo('include_core_only', bool, default=True, since='0.64.0'),
    )
    def scan_xml(self, state: ModuleState, args: T.Tuple[T.List[FileOrString]], kwargs: ScanXML) -> ModuleReturnValue:
        if self.scanner_bin is None:
            # wayland-scanner from BUILD machine must have same version as wayland
            # libraries from HOST machine.
            dep = state.dependency('wayland-client')
            self.scanner_bin = state.find_tool('wayland-scanner', 'wayland-scanner', 'wayland_scanner',
                                               wanted=dep.version)

        scope = 'public' if kwargs['public'] else 'private'
        # We have to cast because mypy can't deduce these are literals
        sides = [i for i in T.cast("T.List[Literal['client', 'server']]", ['client', 'server']) if kwargs[i]]
        if not sides:
            raise MesonException('At least one of client or server keyword argument must be set to true.')

        xml_files = self.interpreter.source_strings_to_files(args[0])
        targets: T.List[CustomTarget] = []
        for xml_file in xml_files:
            name = os.path.splitext(os.path.basename(xml_file.fname))[0]

            code = CustomTarget(
                f'{name}-protocol',
                state.subdir,
                state.subproject,
                state.environment,
                [self.scanner_bin, f'{scope}-code', '@INPUT@', '@OUTPUT@'],
                [xml_file],
                [f'{name}-protocol.c'],
                backend=state.backend,
            )
            targets.append(code)

            for side in sides:
                command = [self.scanner_bin, f'{side}-header', '@INPUT@', '@OUTPUT@']
                if kwargs['include_core_only']:
                    command.append('--include-core-only')

                header = CustomTarget(
                    f'{name}-{side}-protocol',
                    state.subdir,
                    state.subproject,
                    state.environment,
                    command,
                    [xml_file],
                    [f'{name}-{side}-protocol.h'],
                    backend=state.backend,
                )
                targets.append(header)

        return ModuleReturnValue(targets, targets)

    @typed_pos_args('wayland.find_protocol', str)
    @typed_kwargs(
        'wayland.find_protocol',
        KwargInfo('state', str, default='stable', validator=in_set_validator({'stable', 'staging', 'unstable'})),
        KwargInfo('version', (int, NoneType)),
    )
    def find_protocol(self, state: ModuleState, args: T.Tuple[str], kwargs: FindProtocol) -> File:
        base_name = args[0]
        xml_state = kwargs['state']
        version = kwargs['version']

        if xml_state != 'stable' and version is None:
            raise MesonException(f'{xml_state} protocols require a version number.')

        if xml_state == 'stable' and version is not None:
            raise MesonException('stable protocols do not require a version number.')

        if self.protocols_dep is None:
            self.protocols_dep = state.dependency('wayland-protocols')

        if self.pkgdatadir is None:
            self.pkgdatadir = self.protocols_dep.get_variable(pkgconfig='pkgdatadir', internal='pkgdatadir')

        if xml_state == 'stable':
            xml_name = f'{base_name}.xml'
        elif xml_state == 'staging':
            xml_name = f'{base_name}-v{version}.xml'
        else:
            xml_name = f'{base_name}-unstable-v{version}.xml'

        path = os.path.join(self.pkgdatadir, xml_state, base_name, xml_name)

        if not os.path.exists(path):
            raise MesonException(f'The file {path} does not exist.')

        return File.from_absolute_file(path)


def initialize(interpreter: Interpreter) -> WaylandModule:
    return WaylandModule(interpreter)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/modules/windows.py0000644000175000017500000002326214562742363020726 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import enum
import os
import re
import typing as T


from . import ExtensionModule, ModuleInfo
from . import ModuleReturnValue
from .. import mesonlib, build
from .. import mlog
from ..interpreter.type_checking import DEPEND_FILES_KW, DEPENDS_KW, INCLUDE_DIRECTORIES
from ..interpreterbase.decorators import ContainerTypeInfo, FeatureNew, KwargInfo, typed_kwargs, typed_pos_args
from ..mesonlib import MachineChoice, MesonException
from ..programs import ExternalProgram

if T.TYPE_CHECKING:
    from . import ModuleState
    from ..compilers import Compiler
    from ..interpreter import Interpreter

    from typing_extensions import TypedDict

    class CompileResources(TypedDict):

        depend_files: T.List[mesonlib.FileOrString]
        depends: T.List[T.Union[build.BuildTarget, build.CustomTarget]]
        include_directories: T.List[T.Union[str, build.IncludeDirs]]
        args: T.List[str]

    class RcKwargs(TypedDict):
        output: str
        input: T.List[T.Union[mesonlib.FileOrString, build.CustomTargetIndex]]
        depfile: T.Optional[str]
        depend_files: T.List[mesonlib.FileOrString]
        depends: T.List[T.Union[build.BuildTarget, build.CustomTarget]]
        command: T.List[T.Union[str, ExternalProgram]]

class ResourceCompilerType(enum.Enum):
    windres = 1
    rc = 2
    wrc = 3

class WindowsModule(ExtensionModule):

    INFO = ModuleInfo('windows')

    def __init__(self, interpreter: 'Interpreter'):
        super().__init__(interpreter)
        self._rescomp: T.Optional[T.Tuple[ExternalProgram, ResourceCompilerType]] = None
        self.methods.update({
            'compile_resources': self.compile_resources,
        })

    def detect_compiler(self, compilers: T.Dict[str, 'Compiler']) -> 'Compiler':
        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: 'ModuleState') -> T.Tuple[ExternalProgram, ResourceCompilerType]:
        # 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 self._rescomp:
            return self._rescomp

        # Will try cross / native file and then env var
        rescomp = ExternalProgram.from_bin_list(state.environment, 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'} or (comp.linker and comp.linker.id in {'link', 'lld-link'}):
                # Microsoft compilers uses rc irrespective of the frontend
                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),
                ('/?', 'LLVM Resource Converter.*$', ResourceCompilerType.rc),
                ('--version', '^.*GNU windres.*$', ResourceCompilerType.windres),
                ('--version', '^.*Wine Resource Compiler.*$', ResourceCompilerType.wrc),
        ]:
            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

    @typed_pos_args('windows.compile_resources', varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex), min_varargs=1)
    @typed_kwargs(
        'windows.compile_resources',
        DEPEND_FILES_KW.evolve(since='0.47.0'),
        DEPENDS_KW.evolve(since='0.47.0'),
        INCLUDE_DIRECTORIES,
        KwargInfo('args', ContainerTypeInfo(list, str), default=[], listify=True),
    )
    def compile_resources(self, state: 'ModuleState',
                          args: T.Tuple[T.List[T.Union[str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex]]],
                          kwargs: 'CompileResources') -> ModuleReturnValue:
        extra_args = kwargs['args'].copy()
        wrc_depend_files = kwargs['depend_files']
        wrc_depends = kwargs['depends']
        for d in wrc_depends:
            if isinstance(d, build.CustomTarget):
                extra_args += state.get_include_args([
                    build.IncludeDirs('', [], False, [os.path.join('@BUILD_ROOT@', self.interpreter.backend.get_target_dir(d))])
                ])
        extra_args += state.get_include_args(kwargs['include_directories'])

        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@']
        elif rescomp_type == ResourceCompilerType.windres:
            # 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), fatal=False)
        else:
            suffix = 'o'
            res_args = extra_args + ['@INPUT@', '-o', '@OUTPUT@']

        res_targets: T.List[build.CustomTarget] = []

        def get_names() -> T.Iterable[T.Tuple[str, str, T.Union[str, mesonlib.File, build.CustomTargetIndex]]]:
            for src in args[0]:
                if isinstance(src, str):
                    yield os.path.join(state.subdir, src), src, src
                elif isinstance(src, mesonlib.File):
                    yield src.relative_name(), src.fname, src
                elif isinstance(src, build.CustomTargetIndex):
                    FeatureNew.single_use('windows.compile_resource CustomTargetIndex in positional arguments', '0.61.0',
                                          state.subproject, location=state.current_node)
                    # This dance avoids a case where two indexes of the same
                    # target are given as separate arguments.
                    yield (f'{src.get_id()}_{src.target.get_outputs().index(src.output)}',
                           f'windows_compile_resources_{src.get_filename()}', src)
                else:
                    if len(src.get_outputs()) > 1:
                        FeatureNew.single_use('windows.compile_resource CustomTarget with multiple outputs in positional arguments',
                                              '0.61.0', state.subproject, location=state.current_node)
                    for i, out in enumerate(src.get_outputs()):
                        # Chances are that src.get_filename() is already the name of that
                        # target, add a prefix to avoid name clash.
                        yield f'{src.get_id()}_{i}', f'windows_compile_resources_{i}_{out}', src[i]

        for name, name_formatted, src in get_names():
            # Path separators are not allowed in target names
            name = name.replace('/', '_').replace('\\', '_').replace(':', '_')
            name_formatted = name_formatted.replace('/', '_').replace('\\', '_').replace(':', '_')
            output = f'{name}_@BASENAME@.{suffix}'
            command: T.List[T.Union[str, ExternalProgram]] = []
            command.append(rescomp)
            command.extend(res_args)
            depfile: T.Optional[str] = None
            # instruct binutils windres to generate a preprocessor depfile
            if rescomp_type == ResourceCompilerType.windres:
                depfile = f'{output}.d'
                command.extend(['--preprocessor-arg=-MD',
                                '--preprocessor-arg=-MQ@OUTPUT@',
                                '--preprocessor-arg=-MF@DEPFILE@'])

            res_targets.append(build.CustomTarget(
                name_formatted,
                state.subdir,
                state.subproject,
                state.environment,
                command,
                [src],
                [output],
                depfile=depfile,
                depend_files=wrc_depend_files,
                extra_depends=wrc_depends,
                description='Compiling Windows resource {}',
            ))

        return ModuleReturnValue(res_targets, [res_targets])

def initialize(interp: 'Interpreter') -> WindowsModule:
    return WindowsModule(interp)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/mparser.py0000644000175000017500000012111114562742363017225 0ustar00jpakkanejpakkane# 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.
from __future__ import annotations
from dataclasses import dataclass, field
import re
import codecs
import os
import typing as T

from .mesonlib import MesonException
from . import mlog

if T.TYPE_CHECKING:
    from typing_extensions import Literal

    from .ast import AstVisitor

    BaseNodeT = T.TypeVar('BaseNodeT', bound='BaseNode')

# 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)

def decode_match(match: T.Match[str]) -> str:
    return codecs.decode(match.group(0).encode(), 'unicode_escape')

class ParseException(MesonException):

    ast: T.Optional[CodeBlockNode] = None

    def __init__(self, text: str, line: str, lineno: int, colno: int) -> None:
        # Format as error message, followed by the line with the error, followed by a caret to show the error column.
        super().__init__(mlog.code_line(text, line, colno))
        self.lineno = lineno
        self.colno = colno

class BlockParseException(ParseException):
    def __init__(
                self,
                text: str,
                line: str,
                lineno: int,
                colno: int,
                start_line: str,
                start_lineno: int,
                start_colno: int,
            ) -> None:
        # 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.
            MesonException.__init__(self, "{}\n{}\n{}".format(text, line, '{}^{}^'.format(' ' * 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.
            MesonException.__init__(self, "%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

TV_TokenTypes = T.TypeVar('TV_TokenTypes', int, str, bool)

@dataclass(eq=False)
class Token(T.Generic[TV_TokenTypes]):
    tid: str
    filename: str
    line_start: int
    lineno: int
    colno: int
    bytespan: T.Tuple[int, int]
    value: TV_TokenTypes

    def __eq__(self, other: object) -> bool:
        if isinstance(other, str):
            return self.tid == other
        elif isinstance(other, Token):
            return self.tid == other.tid
        return NotImplemented

class Lexer:
    def __init__(self, code: str):
        self.code = code
        self.keywords = {'true', 'false', 'if', 'else', 'elif',
                         'endif', 'and', 'or', 'not', 'foreach', 'endforeach',
                         'in', 'continue', 'break'}
        self.future_keywords = {'return'}
        self.in_unit_test = 'MESON_RUNNING_IN_PROJECT_TESTS' in os.environ
        if self.in_unit_test:
            self.keywords.update({'testcase', 'endtestcase'})
        self.token_specification = [
            # Need to be sorted longest to shortest.
            ('whitespace', re.compile(r'[ \t]+')),
            ('multiline_fstring', re.compile(r"f'''(.|\n)*?'''", re.M)),
            ('fstring', re.compile(r"f'([^'\\]|(\\.))*'")),
            ('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'\\[ \t]*(#.*)?\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: int) -> str:
        return self.code[line_start:self.code.find('\n', line_start)]

    def lex(self, filename: str) -> T.Generator[Token, None, None]:
        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: str = ''
            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)
                    value = mo.group()
                    if 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 in {'string', 'fstring'}:
                        if value.find("\n") != -1:
                            msg = ("Newline character in a string detected, use ''' (three single quotes) "
                                   "for multiline strings instead.\n"
                                   "This will become a hard error in a future Meson release.")
                            mlog.warning(mlog.code_line(msg, self.getline(line_start), col), location=BaseNode(lineno, col, filename))
                        value = value[2 if tid == 'fstring' else 1:-1]
                    elif tid in {'multiline_string', 'multiline_fstring'}:
                        value = value[4 if tid == 'multiline_fstring' else 3:-3]
                        lines = value.split('\n')
                        if len(lines) > 1:
                            lineno += len(lines) - 1
                            line_start = mo.end() - len(lines[-1])
                    elif tid == 'eol_cont':
                        lineno += 1
                        line_start = loc
                        tid = 'whitespace'
                    elif tid == 'eol':
                        lineno += 1
                        line_start = loc
                        if par_count > 0 or bracket_count > 0 or curl_count > 0:
                            tid = 'whitespace'
                    elif tid == 'id':
                        if value in self.keywords:
                            tid = value
                        else:
                            if value in self.future_keywords:
                                mlog.warning(f"Identifier '{value}' will become a reserved keyword in a future release. Please rename it.",
                                             location=BaseNode(lineno, col, filename))
                    yield Token(tid, filename, curline_start, curline, col, bytespan, value)
                    break
            if not matched:
                raise ParseException('lexer', self.getline(line_start), lineno, col)

@dataclass
class BaseNode:
    lineno: int
    colno: int
    filename: str = field(hash=False)
    end_lineno: int = field(hash=False)
    end_colno: int = field(hash=False)
    whitespaces: T.Optional[WhitespaceNode] = field(hash=False)

    def __init__(self, lineno: int, colno: int, filename: str,
                 end_lineno: T.Optional[int] = None, end_colno: T.Optional[int] = None) -> None:
        self.lineno = lineno
        self.colno = colno
        self.filename = filename
        self.end_lineno = end_lineno if end_lineno is not None else lineno
        self.end_colno = end_colno if end_colno is not None else colno
        self.whitespaces = None

        # Attributes for the visitors
        self.level = 0
        self.ast_id = ''
        self.condition_level = 0

    def accept(self, visitor: 'AstVisitor') -> None:
        fname = 'visit_{}'.format(type(self).__name__)
        if hasattr(visitor, fname):
            func = getattr(visitor, fname)
            if callable(func):
                func(self)

    def append_whitespaces(self, token: Token) -> None:
        if self.whitespaces is None:
            self.whitespaces = WhitespaceNode(token)
        else:
            self.whitespaces.append(token)


@dataclass(unsafe_hash=True)
class WhitespaceNode(BaseNode):

    value: str

    def __init__(self, token: Token[str]):
        super().__init__(token.lineno, token.colno, token.filename)
        self.value = ''
        self.append(token)

    def append(self, token: Token[str]) -> None:
        self.value += token.value

@dataclass(unsafe_hash=True)
class ElementaryNode(T.Generic[TV_TokenTypes], BaseNode):

    value: TV_TokenTypes
    bytespan: T.Tuple[int, int] = field(hash=False)

    def __init__(self, token: Token[TV_TokenTypes]):
        super().__init__(token.lineno, token.colno, token.filename)
        self.value = token.value
        self.bytespan = token.bytespan

class BooleanNode(ElementaryNode[bool]):
    pass

class IdNode(ElementaryNode[str]):
    pass

@dataclass(unsafe_hash=True)
class NumberNode(ElementaryNode[int]):

    raw_value: str = field(hash=False)

    def __init__(self, token: Token[str]):
        BaseNode.__init__(self, token.lineno, token.colno, token.filename)
        self.raw_value = token.value
        self.value = int(token.value, base=0)
        self.bytespan = token.bytespan

class BaseStringNode(ElementaryNode[str]):
    pass

@dataclass(unsafe_hash=True)
class StringNode(BaseStringNode):

    raw_value: str = field(hash=False)

    def __init__(self, token: Token[str], escape: bool = True):
        super().__init__(token)
        self.value = ESCAPE_SEQUENCE_SINGLE_RE.sub(decode_match, token.value) if escape else token.value
        self.raw_value = token.value

class FormatStringNode(StringNode):
    pass

@dataclass(unsafe_hash=True)
class MultilineStringNode(BaseStringNode):

    def __init__(self, token: Token[str]):
        super().__init__(token)
        self.value = token.value

class MultilineFormatStringNode(MultilineStringNode):
    pass

class ContinueNode(ElementaryNode):
    pass

class BreakNode(ElementaryNode):
    pass

class SymbolNode(ElementaryNode[str]):
    pass

@dataclass(unsafe_hash=True)
class ArgumentNode(BaseNode):

    arguments: T.List[BaseNode] = field(hash=False)
    commas: T.List[SymbolNode] = field(hash=False)
    columns: T.List[SymbolNode] = field(hash=False)
    kwargs: T.Dict[BaseNode, BaseNode] = field(hash=False)

    def __init__(self, token: Token[TV_TokenTypes]):
        super().__init__(token.lineno, token.colno, token.filename)
        self.arguments = []
        self.commas = []
        self.columns = []
        self.kwargs = {}
        self.order_error = False

    def prepend(self, statement: BaseNode) -> None:
        if self.num_kwargs() > 0:
            self.order_error = True
        if not isinstance(statement, EmptyNode):
            self.arguments = [statement] + self.arguments

    def append(self, statement: BaseNode) -> None:
        if self.num_kwargs() > 0:
            self.order_error = True
        if not isinstance(statement, EmptyNode):
            self.arguments += [statement]

    def set_kwarg(self, name: IdNode, value: BaseNode) -> None:
        if any((isinstance(x, IdNode) and name.value == x.value) for x in self.kwargs):
            mlog.warning(f'Keyword argument "{name.value}" defined multiple times.', location=self)
            mlog.warning('This will be an error in future Meson releases.')
        self.kwargs[name] = value

    def set_kwarg_no_check(self, name: BaseNode, value: BaseNode) -> None:
        self.kwargs[name] = value

    def num_args(self) -> int:
        return len(self.arguments)

    def num_kwargs(self) -> int:
        return len(self.kwargs)

    def incorrect_order(self) -> bool:
        return self.order_error

    def __len__(self) -> int:
        return self.num_args() # Fixme

@dataclass(unsafe_hash=True)
class ArrayNode(BaseNode):

    lbracket: SymbolNode
    args: ArgumentNode
    rbracket: SymbolNode

    def __init__(self, lbracket: SymbolNode, args: ArgumentNode, rbracket: SymbolNode):
        super().__init__(lbracket.lineno, lbracket.colno, args.filename, end_lineno=rbracket.lineno, end_colno=rbracket.colno+1)
        self.lbracket = lbracket
        self.args = args
        self.rbracket = rbracket

@dataclass(unsafe_hash=True)
class DictNode(BaseNode):

    lcurl: SymbolNode
    args: ArgumentNode
    rcurl: SymbolNode

    def __init__(self, lcurl: SymbolNode, args: ArgumentNode, rcurl: SymbolNode):
        super().__init__(lcurl.lineno, lcurl.colno, args.filename, end_lineno=rcurl.lineno, end_colno=rcurl.colno+1)
        self.lcurl = lcurl
        self.args = args
        self.rcurl = rcurl

class EmptyNode(BaseNode):
    pass

@dataclass(unsafe_hash=True)
class BinaryOperatorNode(BaseNode):

    left: BaseNode
    operator: SymbolNode
    right: BaseNode

    def __init__(self, left: BaseNode, operator: SymbolNode, right: BaseNode):
        super().__init__(left.lineno, left.colno, left.filename)
        self.left = left
        self.operator = operator
        self.right = right

class OrNode(BinaryOperatorNode):
    pass

class AndNode(BinaryOperatorNode):
    pass

@dataclass(unsafe_hash=True)
class ComparisonNode(BinaryOperatorNode):

    ctype: COMPARISONS

    def __init__(self, ctype: COMPARISONS, left: BaseNode, operator: SymbolNode, right: BaseNode):
        super().__init__(left, operator, right)
        self.ctype = ctype

@dataclass(unsafe_hash=True)
class ArithmeticNode(BinaryOperatorNode):

    # TODO: use a Literal for operation
    operation: str

    def __init__(self, operation: str, left: BaseNode, operator: SymbolNode, right: BaseNode):
        super().__init__(left, operator, right)
        self.operation = operation

@dataclass(unsafe_hash=True)
class UnaryOperatorNode(BaseNode):

    operator: SymbolNode
    value: BaseNode

    def __init__(self, token: Token[TV_TokenTypes], operator: SymbolNode, value: BaseNode):
        super().__init__(token.lineno, token.colno, token.filename)
        self.operator = operator
        self.value = value

class NotNode(UnaryOperatorNode):
    pass

class UMinusNode(UnaryOperatorNode):
    pass

@dataclass(unsafe_hash=True)
class CodeBlockNode(BaseNode):

    pre_whitespaces: T.Optional[WhitespaceNode] = field(hash=False)
    lines: T.List[BaseNode] = field(hash=False)

    def __init__(self, token: Token[TV_TokenTypes]):
        super().__init__(token.lineno, token.colno, token.filename)
        self.pre_whitespaces = None
        self.lines = []

    def append_whitespaces(self, token: Token) -> None:
        if self.lines:
            self.lines[-1].append_whitespaces(token)
        elif self.pre_whitespaces is None:
            self.pre_whitespaces = WhitespaceNode(token)
        else:
            self.pre_whitespaces.append(token)

@dataclass(unsafe_hash=True)
class IndexNode(BaseNode):

    iobject: BaseNode
    lbracket: SymbolNode
    index: BaseNode
    rbracket: SymbolNode

    def __init__(self, iobject: BaseNode, lbracket: SymbolNode, index: BaseNode, rbracket: SymbolNode):
        super().__init__(iobject.lineno, iobject.colno, iobject.filename)
        self.iobject = iobject
        self.lbracket = lbracket
        self.index = index
        self.rbracket = rbracket

@dataclass(unsafe_hash=True)
class MethodNode(BaseNode):

    source_object: BaseNode
    dot: SymbolNode
    name: IdNode
    lpar: SymbolNode
    args: ArgumentNode
    rpar: SymbolNode

    def __init__(self, source_object: BaseNode, dot: SymbolNode, name: IdNode, lpar: SymbolNode, args: ArgumentNode, rpar: SymbolNode):
        super().__init__(name.lineno, name.colno, name.filename, end_lineno=rpar.lineno, end_colno=rpar.colno+1)
        self.source_object = source_object
        self.dot = dot
        self.name = name
        self.lpar = lpar
        self.args = args
        self.rpar = rpar

@dataclass(unsafe_hash=True)
class FunctionNode(BaseNode):

    func_name: IdNode
    lpar: SymbolNode
    args: ArgumentNode
    rpar: SymbolNode

    def __init__(self, func_name: IdNode, lpar: SymbolNode, args: ArgumentNode, rpar: SymbolNode):
        super().__init__(func_name.lineno, func_name.colno, func_name.filename, end_lineno=rpar.end_lineno, end_colno=rpar.end_colno+1)
        self.func_name = func_name
        self.lpar = lpar
        self.args = args
        self.rpar = rpar

@dataclass(unsafe_hash=True)
class AssignmentNode(BaseNode):

    var_name: IdNode
    operator: SymbolNode
    value: BaseNode

    def __init__(self, var_name: IdNode, operator: SymbolNode, value: BaseNode):
        super().__init__(var_name.lineno, var_name.colno, var_name.filename)
        self.var_name = var_name
        self.operator = operator
        self.value = value

class PlusAssignmentNode(AssignmentNode):
    pass

@dataclass(unsafe_hash=True)
class ForeachClauseNode(BaseNode):

    foreach_: SymbolNode = field(hash=False)
    varnames: T.List[IdNode] = field(hash=False)
    commas: T.List[SymbolNode] = field(hash=False)
    column: SymbolNode = field(hash=False)
    items: BaseNode
    block: CodeBlockNode
    endforeach: SymbolNode = field(hash=False)

    def __init__(self, foreach_: SymbolNode, varnames: T.List[IdNode], commas: T.List[SymbolNode], column: SymbolNode, items: BaseNode, block: CodeBlockNode, endforeach: SymbolNode):
        super().__init__(foreach_.lineno, foreach_.colno, foreach_.filename)
        self.foreach_ = foreach_
        self.varnames = varnames
        self.commas = commas
        self.column = column
        self.items = items
        self.block = block
        self.endforeach = endforeach


@dataclass(unsafe_hash=True)
class IfNode(BaseNode):

    if_: SymbolNode
    condition: BaseNode
    block: CodeBlockNode

    def __init__(self, linenode: BaseNode, if_node: SymbolNode, condition: BaseNode, block: CodeBlockNode):
        super().__init__(linenode.lineno, linenode.colno, linenode.filename)
        self.if_ = if_node
        self.condition = condition
        self.block = block

@dataclass(unsafe_hash=True)
class ElseNode(BaseNode):

    else_: SymbolNode
    block: CodeBlockNode

    def __init__(self, else_: SymbolNode, block: CodeBlockNode):
        super().__init__(block.lineno, block.colno, block.filename)
        self.else_ = else_
        self.block = block

@dataclass(unsafe_hash=True)
class IfClauseNode(BaseNode):

    ifs: T.List[IfNode] = field(hash=False)
    elseblock: T.Union[EmptyNode, ElseNode]
    endif: SymbolNode

    def __init__(self, linenode: BaseNode):
        super().__init__(linenode.lineno, linenode.colno, linenode.filename)
        self.ifs = []
        self.elseblock = EmptyNode(linenode.lineno, linenode.colno, linenode.filename)
        self.endif = None

@dataclass(unsafe_hash=True)
class TestCaseClauseNode(BaseNode):

    testcase: SymbolNode
    condition: BaseNode
    block: CodeBlockNode
    endtestcase: SymbolNode

    def __init__(self, testcase: SymbolNode, condition: BaseNode, block: CodeBlockNode, endtestcase: SymbolNode):
        super().__init__(condition.lineno, condition.colno, condition.filename)
        self.testcase = testcase
        self.condition = condition
        self.block = block
        self.endtestcase = endtestcase

@dataclass(unsafe_hash=True)
class TernaryNode(BaseNode):

    condition: BaseNode
    questionmark: SymbolNode
    trueblock: BaseNode
    column: SymbolNode
    falseblock: BaseNode

    def __init__(self, condition: BaseNode, questionmark: SymbolNode, trueblock: BaseNode, column: SymbolNode, falseblock: BaseNode):
        super().__init__(condition.lineno, condition.colno, condition.filename)
        self.condition = condition
        self.questionmark = questionmark
        self.trueblock = trueblock
        self.column = column
        self.falseblock = falseblock


@dataclass(unsafe_hash=True)
class ParenthesizedNode(BaseNode):

    lpar: SymbolNode = field(hash=False)
    inner: BaseNode
    rpar: SymbolNode = field(hash=False)

    def __init__(self, lpar: SymbolNode, inner: BaseNode, rpar: SymbolNode):
        super().__init__(lpar.lineno, lpar.colno, inner.filename, end_lineno=rpar.lineno, end_colno=rpar.colno+1)
        self.lpar = lpar
        self.inner = inner
        self.rpar = rpar


if T.TYPE_CHECKING:
    COMPARISONS = Literal['==', '!=', '<', '<=', '>=', '>', 'in', 'notin']

comparison_map: T.Mapping[str, COMPARISONS] = {
    'equal': '==',
    'nequal': '!=',
    'lt': '<',
    'le': '<=',
    'gt': '>',
    'ge': '>=',
    'in': 'in',
    'not in': 'notin',
}

# 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: str, filename: str):
        self.lexer = Lexer(code)
        self.stream = self.lexer.lex(filename)
        self.current: Token = Token('eof', '', 0, 0, 0, (0, 0), None)
        self.previous = self.current
        self.current_ws: T.List[Token] = []

        self.getsym()
        self.in_ternary = False

    def create_node(self, node_type: T.Type[BaseNodeT], *args: T.Any, **kwargs: T.Any) -> BaseNodeT:
        node = node_type(*args, **kwargs)
        for ws_token in self.current_ws:
            node.append_whitespaces(ws_token)
        self.current_ws = []
        return node

    def getsym(self) -> None:
        self.previous = self.current
        try:
            self.current = next(self.stream)

            while self.current.tid in {'eol', 'comment', 'whitespace'}:
                self.current_ws.append(self.current)
                if self.current.tid == 'eol':
                    break
                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) -> str:
        return self.lexer.getline(self.current.line_start)

    def accept(self, s: str) -> bool:
        if self.current.tid == s:
            self.getsym()
            return True
        return False

    def accept_any(self, tids: T.Tuple[str, ...]) -> str:
        tid = self.current.tid
        if tid in tids:
            self.getsym()
            return tid
        return ''

    def expect(self, s: str) -> bool:
        if self.accept(s):
            return True
        raise ParseException(f'Expecting {s} got {self.current.tid}.', self.getline(), self.current.lineno, self.current.colno)

    def block_expect(self, s: str, block_start: Token) -> bool:
        if self.accept(s):
            return True
        raise BlockParseException(f'Expecting {s} got {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) -> CodeBlockNode:
        block = self.codeblock()
        try:
            self.expect('eof')
        except ParseException as e:
            e.ast = block
            raise
        return block

    def statement(self) -> BaseNode:
        return self.e1()

    def e1(self) -> BaseNode:
        left = self.e2()
        if self.accept('plusassign'):
            operator = self.create_node(SymbolNode, self.previous)
            value = self.e1()
            if not isinstance(left, IdNode):
                raise ParseException('Plusassignment target must be an id.', self.getline(), left.lineno, left.colno)
            assert isinstance(left.value, str)
            return self.create_node(PlusAssignmentNode, left, operator, value)
        elif self.accept('assign'):
            operator = self.create_node(SymbolNode, self.previous)
            value = self.e1()
            if not isinstance(left, IdNode):
                raise ParseException('Assignment target must be an id.',
                                     self.getline(), left.lineno, left.colno)
            assert isinstance(left.value, str)
            return self.create_node(AssignmentNode, left, operator, value)
        elif self.accept('questionmark'):
            if self.in_ternary:
                raise ParseException('Nested ternary operators are not allowed.',
                                     self.getline(), left.lineno, left.colno)

            qm_node = self.create_node(SymbolNode, self.previous)
            self.in_ternary = True
            trueblock = self.e1()
            self.expect('colon')
            column_node = self.create_node(SymbolNode, self.previous)
            falseblock = self.e1()
            self.in_ternary = False
            return self.create_node(TernaryNode, left, qm_node, trueblock, column_node, falseblock)
        return left

    def e2(self) -> BaseNode:
        left = self.e3()
        while self.accept('or'):
            operator = self.create_node(SymbolNode, self.previous)
            if isinstance(left, EmptyNode):
                raise ParseException('Invalid or clause.',
                                     self.getline(), left.lineno, left.colno)
            left = self.create_node(OrNode, left, operator, self.e3())
        return left

    def e3(self) -> BaseNode:
        left = self.e4()
        while self.accept('and'):
            operator = self.create_node(SymbolNode, self.previous)
            if isinstance(left, EmptyNode):
                raise ParseException('Invalid and clause.',
                                     self.getline(), left.lineno, left.colno)
            left = self.create_node(AndNode, left, operator, self.e4())
        return left

    def e4(self) -> BaseNode:
        left = self.e5()
        for nodename, operator_type in comparison_map.items():
            if self.accept(nodename):
                operator = self.create_node(SymbolNode, self.previous)
                return self.create_node(ComparisonNode, operator_type, left, operator, self.e5())
        if self.accept('not'):
            ws = self.current_ws.copy()
            not_token = self.previous
            if self.accept('in'):
                in_token = self.previous
                self.current_ws = self.current_ws[len(ws):]  # remove whitespaces between not and in
                temp_node = EmptyNode(in_token.lineno, in_token.colno, in_token.filename)
                for w in ws:
                    temp_node.append_whitespaces(w)

                not_token.bytespan = (not_token.bytespan[0], in_token.bytespan[1])
                not_token.value += temp_node.whitespaces.value + in_token.value
                operator = self.create_node(SymbolNode, not_token)
                return self.create_node(ComparisonNode, 'notin', left, operator, self.e5())
        return left

    def e5(self) -> BaseNode:
        return self.e5addsub()

    def e5addsub(self) -> BaseNode:
        op_map = {
            'plus': 'add',
            'dash': 'sub',
        }
        left = self.e5muldiv()
        while True:
            op = self.accept_any(tuple(op_map.keys()))
            if op:
                operator = self.create_node(SymbolNode, self.previous)
                left = self.create_node(ArithmeticNode, op_map[op], left, operator, self.e5muldiv())
            else:
                break
        return left

    def e5muldiv(self) -> BaseNode:
        op_map = {
            'percent': 'mod',
            'star': 'mul',
            'fslash': 'div',
        }
        left = self.e6()
        while True:
            op = self.accept_any(tuple(op_map.keys()))
            if op:
                operator = self.create_node(SymbolNode, self.previous)
                left = self.create_node(ArithmeticNode, op_map[op], left, operator, self.e6())
            else:
                break
        return left

    def e6(self) -> BaseNode:
        if self.accept('not'):
            operator = self.create_node(SymbolNode, self.previous)
            return self.create_node(NotNode, self.current, operator, self.e7())
        if self.accept('dash'):
            operator = self.create_node(SymbolNode, self.previous)
            return self.create_node(UMinusNode, self.current, operator, self.e7())
        return self.e7()

    def e7(self) -> BaseNode:
        left = self.e8()
        block_start = self.current
        if self.accept('lparen'):
            lpar = self.create_node(SymbolNode, block_start)
            args = self.args()
            self.block_expect('rparen', block_start)
            rpar = self.create_node(SymbolNode, self.previous)
            if not isinstance(left, IdNode):
                raise ParseException('Function call must be applied to plain id',
                                     self.getline(), left.lineno, left.colno)
            assert isinstance(left.value, str)
            left = self.create_node(FunctionNode, left, lpar, args, rpar)
        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) -> BaseNode:
        block_start = self.current
        if self.accept('lparen'):
            lpar = self.create_node(SymbolNode, block_start)
            e = self.statement()
            self.block_expect('rparen', block_start)
            rpar = self.create_node(SymbolNode, self.previous)
            return ParenthesizedNode(lpar, e, rpar)
        elif self.accept('lbracket'):
            lbracket = self.create_node(SymbolNode, block_start)
            args = self.args()
            self.block_expect('rbracket', block_start)
            rbracket = self.create_node(SymbolNode, self.previous)
            return self.create_node(ArrayNode, lbracket, args, rbracket)
        elif self.accept('lcurl'):
            lcurl = self.create_node(SymbolNode, block_start)
            key_values = self.key_values()
            self.block_expect('rcurl', block_start)
            rcurl = self.create_node(SymbolNode, self.previous)
            return self.create_node(DictNode, lcurl, key_values, rcurl)
        else:
            return self.e9()

    def e9(self) -> BaseNode:
        t = self.current
        if self.accept('true'):
            t.value = True
            return self.create_node(BooleanNode, t)
        if self.accept('false'):
            t.value = False
            return self.create_node(BooleanNode, t)
        if self.accept('id'):
            return self.create_node(IdNode, t)
        if self.accept('number'):
            return self.create_node(NumberNode, t)
        if self.accept('string'):
            return self.create_node(StringNode, t)
        if self.accept('fstring'):
            return self.create_node(FormatStringNode, t)
        if self.accept('multiline_string'):
            return self.create_node(MultilineStringNode, t)
        if self.accept('multiline_fstring'):
            return self.create_node(MultilineFormatStringNode, t)
        return EmptyNode(self.current.lineno, self.current.colno, self.current.filename)

    def key_values(self) -> ArgumentNode:
        s = self.statement()
        a = self.create_node(ArgumentNode, self.current)

        while not isinstance(s, EmptyNode):
            if self.accept('colon'):
                a.columns.append(self.create_node(SymbolNode, self.previous))
                a.set_kwarg_no_check(s, self.statement())
                if not self.accept('comma'):
                    return a
                a.commas.append(self.create_node(SymbolNode, self.previous))
            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) -> ArgumentNode:
        s = self.statement()
        a = self.create_node(ArgumentNode, self.current)

        while not isinstance(s, EmptyNode):
            if self.accept('comma'):
                a.commas.append(self.create_node(SymbolNode, self.previous))
                a.append(s)
            elif self.accept('colon'):
                a.columns.append(self.create_node(SymbolNode, self.previous))
                if not isinstance(s, IdNode):
                    raise ParseException('Dictionary key must be a plain identifier.',
                                         self.getline(), s.lineno, s.colno)
                a.set_kwarg(s, self.statement())
                if not self.accept('comma'):
                    return a
                a.commas.append(self.create_node(SymbolNode, self.previous))
            else:
                a.append(s)
                return a
            s = self.statement()
        return a

    def method_call(self, source_object: BaseNode) -> MethodNode:
        dot = self.create_node(SymbolNode, self.previous)
        methodname = self.e9()
        if not isinstance(methodname, IdNode):
            if isinstance(source_object, NumberNode) and isinstance(methodname, NumberNode):
                raise ParseException('meson does not support float numbers',
                                     self.getline(), source_object.lineno, source_object.colno)
            raise ParseException('Method name must be plain id',
                                 self.getline(), self.current.lineno, self.current.colno)
        assert isinstance(methodname.value, str)
        self.expect('lparen')
        lpar = self.create_node(SymbolNode, self.previous)
        args = self.args()
        rpar = self.create_node(SymbolNode, self.current)
        self.expect('rparen')
        method = self.create_node(MethodNode, source_object, dot, methodname, lpar, args, rpar)
        if self.accept('dot'):
            return self.method_call(method)
        return method

    def index_call(self, source_object: BaseNode) -> IndexNode:
        lbracket = self.create_node(SymbolNode, self.previous)
        index_statement = self.statement()
        self.expect('rbracket')
        rbracket = self.create_node(SymbolNode, self.previous)
        return self.create_node(IndexNode, source_object, lbracket, index_statement, rbracket)

    def foreachblock(self) -> ForeachClauseNode:
        foreach_ = self.create_node(SymbolNode, self.previous)
        self.expect('id')
        assert isinstance(self.previous.value, str)
        varnames = [self.create_node(IdNode, self.previous)]
        commas = []

        if self.accept('comma'):
            commas.append(self.create_node(SymbolNode, self.previous))
            self.expect('id')
            assert isinstance(self.previous.value, str)
            varnames.append(self.create_node(IdNode, self.previous))

        self.expect('colon')
        column = self.create_node(SymbolNode, self.previous)
        items = self.statement()
        block = self.codeblock()
        endforeach = self.create_node(SymbolNode, self.current)
        return self.create_node(ForeachClauseNode, foreach_, varnames, commas, column, items, block, endforeach)

    def ifblock(self) -> IfClauseNode:
        if_node = self.create_node(SymbolNode, self.previous)
        condition = self.statement()
        clause = self.create_node(IfClauseNode, condition)
        self.expect('eol')
        block = self.codeblock()
        clause.ifs.append(self.create_node(IfNode, clause, if_node, condition, block))
        self.elseifblock(clause)
        clause.elseblock = self.elseblock()
        clause.endif = self.create_node(SymbolNode, self.current)
        return clause

    def elseifblock(self, clause: IfClauseNode) -> None:
        while self.accept('elif'):
            elif_ = self.create_node(SymbolNode, self.previous)
            s = self.statement()
            self.expect('eol')
            b = self.codeblock()
            clause.ifs.append(self.create_node(IfNode, s, elif_, s, b))

    def elseblock(self) -> T.Union[ElseNode, EmptyNode]:
        if self.accept('else'):
            else_ = self.create_node(SymbolNode, self.previous)
            self.expect('eol')
            block = self.codeblock()
            return ElseNode(else_, block)
        return EmptyNode(self.current.lineno, self.current.colno, self.current.filename)

    def testcaseblock(self) -> TestCaseClauseNode:
        testcase = self.create_node(SymbolNode, self.previous)
        condition = self.statement()
        self.expect('eol')
        block = self.codeblock()
        endtestcase = SymbolNode(self.current)
        return self.create_node(TestCaseClauseNode, testcase, condition, block, endtestcase)

    def line(self) -> BaseNode:
        block_start = self.current
        if self.current == 'eol':
            return EmptyNode(self.current.lineno, self.current.colno, self.current.filename)
        if self.accept('if'):
            ifblock = self.ifblock()
            self.block_expect('endif', block_start)
            return ifblock
        if self.accept('foreach'):
            forblock = self.foreachblock()
            self.block_expect('endforeach', block_start)
            return forblock
        if self.accept('continue'):
            return self.create_node(ContinueNode, self.current)
        if self.accept('break'):
            return self.create_node(BreakNode, self.current)
        if self.lexer.in_unit_test and self.accept('testcase'):
            block = self.testcaseblock()
            self.block_expect('endtestcase', block_start)
            return block
        return self.statement()

    def codeblock(self) -> CodeBlockNode:
        block = self.create_node(CodeBlockNode, self.current)
        cond = True

        try:
            while cond:
                for ws_token in self.current_ws:
                    block.append_whitespaces(ws_token)
                self.current_ws = []

                curline = self.line()

                if not isinstance(curline, EmptyNode):
                    block.lines.append(curline)

                cond = self.accept('eol')

        except ParseException as e:
            e.ast = block
            raise

        # Remaining whitespaces will not be catched since there are no more nodes
        for ws_token in self.current_ws:
            block.append_whitespaces(ws_token)
        self.current_ws = []

        return block
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/msetup.py0000644000175000017500000004652614562742363017111 0ustar00jpakkanejpakkane# 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.
from __future__ import annotations

import argparse, datetime, glob, json, os, platform, shutil, sys, tempfile, time
import cProfile as profile
from pathlib import Path
import typing as T

from . import build, coredata, environment, interpreter, mesonlib, mintro, mlog
from .mesonlib import MesonException

git_ignore_file = '''# This file is autogenerated by Meson. If you change or delete it, it won't be recreated.
*
'''

hg_ignore_file = '''# This file is autogenerated by Meson. If you change or delete it, it won't be recreated.
syntax: glob
**/*
'''


# Note: when adding arguments, please also add them to the completion
# scripts in $MESONSRC/data/shell-completions/
def add_arguments(parser: argparse.ArgumentParser) -> None:
    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. ' +
                             'Useful when build directory got corrupted, or when rebuilding with a ' +
                             'newer version of meson.')
    parser.add_argument('--clearcache', action='store_true', default=False,
                        help='Clear cached state (e.g. found dependencies). Since 1.3.0.')
    parser.add_argument('builddir', nargs='?', default=None)
    parser.add_argument('sourcedir', nargs='?', default=None)

class MesonApp:
    def __init__(self, options: argparse.Namespace) -> None:
        self.options = options
        (self.source_dir, self.build_dir) = self.validate_dirs()
        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:
                        # validate_dirs() already verified that build_dir has
                        # a partial build or is empty.
                        pass

                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) and not os.path.islink(l):
                            mesonlib.windows_proof_rmtree(l)
                        else:
                            mesonlib.windows_proof_rm(l)
                finally:
                    self.add_vcs_ignore_files(self.build_dir)
                    for b, f in restore:
                        os.makedirs(os.path.dirname(f), exist_ok=True)
                        shutil.move(b, f)

    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: T.Optional[str], dir2: T.Optional[str]) -> T.Tuple[str, str]:
        invalid_msg_prefix = f'Neither source directory {dir1!r} nor build directory {dir2!r}'
        if dir1 is None:
            if dir2 is None:
                if not self.has_build_file('.') and self.has_build_file('..'):
                    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) and not os.path.exists(ndir2):
            raise MesonException(f'{invalid_msg_prefix} exist.')
        try:
            os.makedirs(ndir1, exist_ok=True)
        except FileExistsError as e:
            raise MesonException(f'{dir1} is not a directory') from e
        try:
            os.makedirs(ndir2, exist_ok=True)
        except FileExistsError as e:
            raise MesonException(f'{dir2} is not a directory') from e
        if os.path.samefile(ndir1, ndir2):
            # Fallback to textual compare if undefined entries found
            has_undefined = any((s.st_ino == 0 and s.st_dev == 0) for s in (os.stat(ndir1), os.stat(ndir2)))
            if not has_undefined or ndir1 == ndir2:
                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(f'Both directories contain a build file {environment.build_filename}.')
            return ndir1, ndir2
        if self.has_build_file(ndir2):
            return ndir2, ndir1
        raise MesonException(f'{invalid_msg_prefix} contain a build file {environment.build_filename}.')

    def add_vcs_ignore_files(self, build_dir: str) -> None:
        with open(os.path.join(build_dir, '.gitignore'), 'w', encoding='utf-8') as ofile:
            ofile.write(git_ignore_file)
        with open(os.path.join(build_dir, '.hgignore'), 'w', encoding='utf-8') as ofile:
            ofile.write(hg_ignore_file)

    def validate_dirs(self) -> T.Tuple[str, str]:
        (src_dir, build_dir) = self.validate_core_dirs(self.options.builddir, self.options.sourcedir)
        if Path(build_dir) in Path(src_dir).parents:
            raise MesonException(f'Build directory {build_dir} cannot be a parent of source directory {src_dir}')
        if not os.listdir(build_dir):
            self.add_vcs_ignore_files(build_dir)
            return src_dir, build_dir
        priv_dir = os.path.join(build_dir, 'meson-private')
        has_valid_build = os.path.exists(os.path.join(priv_dir, 'coredata.dat'))
        has_partial_build = os.path.isdir(priv_dir)
        if has_valid_build:
            if not self.options.reconfigure and not self.options.wipe:
                print('Directory already configured.\n\n'
                      'Just run your build command (e.g. ninja) and Meson will regenerate as necessary.\n'
                      'Run "meson setup --reconfigure to force Meson to regenerate.\n\n'
                      'If build failures persist, run "meson setup --wipe" to rebuild from scratch\n'
                      'using the same options as passed when configuring the build.')
                if self.options.cmd_line_options:
                    from . import mconf
                    raise SystemExit(mconf.run_impl(self.options, build_dir))
                raise SystemExit(0)
        elif not has_partial_build and self.options.wipe:
            raise MesonException(f'Directory is not empty and does not contain a previous build:\n{build_dir}')
        return src_dir, build_dir

    # See class Backend's 'generate' for comments on capture args and returned dictionary.
    def generate(self, capture: bool = False, vslite_ctx: T.Optional[dict] = None) -> T.Optional[dict]:
        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())
        if self.options.clearcache:
            env.coredata.clear_cache()
        with mesonlib.BuildDirLock(self.build_dir):
            return self._generate(env, capture, vslite_ctx)

    def _generate(self, env: environment.Environment, capture: bool, vslite_ctx: T.Optional[dict]) -> T.Optional[dict]:
        # Get all user defined options, including options that have been defined
        # during a previous invocation or using meson configure.
        user_defined_options = argparse.Namespace(**vars(self.options))
        coredata.read_cmd_line_file(self.build_dir, user_defined_options)

        mlog.debug('Build started at', datetime.datetime.now().isoformat())
        mlog.debug('Main binary:', sys.executable)
        mlog.debug('Build Options:', coredata.format_cmd_line_options(user_defined_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, user_defined_options=user_defined_options)
        # Super hack because mlog.log and mlog.debug have different signatures,
        # and there is currently no way to annotate them correctly, unionize them, or
        # even to write `T.Callable[[*mlog.TV_Loggable], None]`
        logger_fun = T.cast('T.Callable[[mlog.TV_Loggable, mlog.TV_Loggable], None]',
                            (mlog.log if env.is_cross_build() else mlog.debug))
        build_machine = intr.builtin['build_machine']
        host_machine = intr.builtin['host_machine']
        target_machine = intr.builtin['target_machine']
        assert isinstance(build_machine, interpreter.MachineHolder)
        assert isinstance(host_machine, interpreter.MachineHolder)
        assert isinstance(target_machine, interpreter.MachineHolder)
        logger_fun('Build machine cpu family:', mlog.bold(build_machine.cpu_family_method([], {})))
        logger_fun('Build machine cpu:', mlog.bold(build_machine.cpu_method([], {})))
        mlog.log('Host machine cpu family:', mlog.bold(host_machine.cpu_family_method([], {})))
        mlog.log('Host machine cpu:', mlog.bold(host_machine.cpu_method([], {})))
        logger_fun('Target machine cpu family:', mlog.bold(target_machine.cpu_family_method([], {})))
        logger_fun('Target machine cpu:', mlog.bold(target_machine.cpu_method([], {})))
        try:
            if self.options.profile:
                fname = os.path.join(self.build_dir, 'meson-logs', '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

        cdf: T.Optional[str] = None
        captured_compile_args: T.Optional[dict] = None
        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()

            self.finalize_postconf_hooks(b, intr)
            if self.options.profile:
                fname = f'profile-{intr.backend.name}-backend.log'
                fname = os.path.join(self.build_dir, 'meson-logs', fname)
                profile.runctx('gen_result = intr.backend.generate(capture, vslite_ctx)', globals(), locals(), filename=fname)
                captured_compile_args = locals()['gen_result']
                assert captured_compile_args is None or isinstance(captured_compile_args, dict)
            else:
                captured_compile_args = intr.backend.generate(capture, vslite_ctx)

            build.save(b, dumpfile)
            if env.first_invocation:
                # Use path resolved by coredata because they could have been
                # read from a pipe and wrote into a private file.
                self.options.cross_file = env.coredata.cross_files
                self.options.native_file = env.coredata.config_files
                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-logs', '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()

            # collect warnings about unsupported build configurations; must be done after full arg processing
            # by Interpreter() init, but this is most visible at the end
            if env.coredata.options[mesonlib.OptionKey('backend')].value == 'xcode':
                mlog.warning('xcode backend is currently unmaintained, patches welcome')
            if env.coredata.options[mesonlib.OptionKey('layout')].value == 'flat':
                mlog.warning('-Dlayout=flat is unsupported and probably broken. It was a failed experiment at '
                             'making Windows build artifacts runnable while uninstalled, due to PATH considerations, '
                             'but was untested by CI and anyways breaks reasonable use of conflicting targets in different subdirs. '
                             'Please consider using `meson devenv` instead. See https://github.com/mesonbuild/meson/pull/9243 '
                             'for details.')

            if self.options.profile:
                fname = os.path.join(self.build_dir, 'meson-logs', 'profile-startup-modules.json')
                mods = set(sys.modules.keys())
                mesonmods = {mod for mod in mods if (mod+'.').startswith('mesonbuild.')}
                stdmods = sorted(mods - mesonmods)
                data = {'stdlib': {'modules': stdmods, 'count': len(stdmods)}, 'meson': {'modules': sorted(mesonmods), 'count': len(mesonmods)}}
                with open(fname, 'w', encoding='utf-8') as f:
                    json.dump(data, f)

                mlog.log("meson setup completed")  # Display timestamp

        except Exception as e:
            mintro.write_meson_info_file(b, [e])
            if cdf is not None:
                old_cdf = cdf + '.prev'
                if os.path.exists(old_cdf):
                    os.replace(old_cdf, cdf)
                else:
                    os.unlink(cdf)
            raise

        return captured_compile_args

    def finalize_postconf_hooks(self, b: build.Build, intr: interpreter.Interpreter) -> None:
        b.devenv.append(intr.backend.get_devenv())
        for mod in intr.modules.values():
            mod.postconf_hook(b)

def run_genvslite_setup(options: argparse.Namespace) -> None:
    # With --genvslite, we essentially want to invoke multiple 'setup' iterations. I.e. -
    #    meson setup ... builddirprefix_debug
    #    meson setup ... builddirprefix_debugoptimized
    #    meson setup ... builddirprefix_release
    # along with also setting up a new, thin/lite visual studio solution and projects with the multiple debug/opt/release configurations that
    # invoke the appropriate 'meson compile ...' build commands upon the normal visual studio build/rebuild/clean actions, instead of using
    # the native VS/msbuild system.
    builddir_prefix = options.builddir
    genvsliteval = options.cmd_line_options.pop(mesonlib.OptionKey('genvslite'))
    # The command line may specify a '--backend' option, which doesn't make sense in conjunction with
    # '--genvslite', where we always want to use a ninja back end -
    k_backend = mesonlib.OptionKey('backend')
    if k_backend in options.cmd_line_options.keys():
        if options.cmd_line_options[k_backend] != 'ninja':
            raise MesonException('Explicitly specifying a backend option with \'genvslite\' is not necessary '
                                 '(the ninja backend is always used) but specifying a non-ninja backend '
                                 'conflicts with a \'genvslite\' setup')
    else:
        options.cmd_line_options[k_backend] = 'ninja'
    buildtypes_list = coredata.get_genvs_default_buildtype_list()
    vslite_ctx = {}

    for buildtypestr in buildtypes_list:
        options.builddir = f'{builddir_prefix}_{buildtypestr}' # E.g. builddir_release
        options.cmd_line_options[mesonlib.OptionKey('buildtype')] = buildtypestr
        app = MesonApp(options)
        vslite_ctx[buildtypestr] = app.generate(capture=True)
    #Now for generating the 'lite' solution and project files, which will use these builds we've just set up, above.
    options.builddir = f'{builddir_prefix}_vs'
    options.cmd_line_options[mesonlib.OptionKey('genvslite')] = genvsliteval
    app = MesonApp(options)
    app.generate(capture=False, vslite_ctx=vslite_ctx)

def run(options: T.Union[argparse.Namespace, T.List[str]]) -> int:
    if not isinstance(options, argparse.Namespace):
        parser = argparse.ArgumentParser()
        add_arguments(parser)
        options = parser.parse_args(options)
    coredata.parse_cmd_line_options(options)

    if mesonlib.OptionKey('genvslite') in options.cmd_line_options.keys():
        run_genvslite_setup(options)
    else:
        app = MesonApp(options)
        app.generate()

    return 0
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1699814460.0
meson-1.3.2/mesonbuild/msubprojects.py0000755000175000017500000010114714524216074020277 0ustar00jpakkanejpakkanefrom __future__ import annotations

from dataclasses import dataclass, InitVar
import os, subprocess
import argparse
import asyncio
import threading
import copy
import shutil
from concurrent.futures.thread import ThreadPoolExecutor
from pathlib import Path
import typing as T
import tarfile
import zipfile

from . import mlog
from .ast import IntrospectionInterpreter
from .mesonlib import quiet_git, GitException, Popen_safe, MesonException, windows_proof_rmtree
from .wrap.wrap import (Resolver, WrapException, ALL_TYPES,
                        parse_patch_url, update_wrap_file, get_releases)

if T.TYPE_CHECKING:
    from typing_extensions import Protocol

    from .wrap.wrap import PackageDefinition

    SubParsers = argparse._SubParsersAction[argparse.ArgumentParser]

    class Arguments(Protocol):
        sourcedir: str
        num_processes: int
        subprojects: T.List[str]
        types: str
        subprojects_func: T.Callable[[], bool]
        allow_insecure: bool

    class UpdateArguments(Arguments):
        rebase: bool
        reset: bool

    class UpdateWrapDBArguments(Arguments):
        force: bool
        releases: T.Dict[str, T.Any]

    class CheckoutArguments(Arguments):
        b: bool
        branch_name: str

    class ForeachArguments(Arguments):
        command: str
        args: T.List[str]

    class PurgeArguments(Arguments):
        confirm: bool
        include_cache: bool

    class PackagefilesArguments(Arguments):
        apply: bool
        save: bool

ALL_TYPES_STRING = ', '.join(ALL_TYPES)

def read_archive_files(path: Path, base_path: Path) -> T.Set[Path]:
    if path.suffix == '.zip':
        with zipfile.ZipFile(path, 'r') as zip_archive:
            archive_files = {base_path / i.filename for i in zip_archive.infolist()}
    else:
        with tarfile.open(path) as tar_archive: # [ignore encoding]
            archive_files = {base_path / i.name for i in tar_archive}
    return archive_files

class Logger:
    def __init__(self, total_tasks: int) -> None:
        self.lock = threading.Lock()
        self.total_tasks = total_tasks
        self.completed_tasks = 0
        self.running_tasks: T.Set[str] = set()
        self.should_erase_line = ''

    def flush(self) -> None:
        if self.should_erase_line:
            print(self.should_erase_line, end='\r')
            self.should_erase_line = ''

    def print_progress(self) -> None:
        line = f'Progress: {self.completed_tasks} / {self.total_tasks}'
        max_len = shutil.get_terminal_size().columns - len(line)
        running = ', '.join(self.running_tasks)
        if len(running) + 3 > max_len:
            running = running[:max_len - 6] + '...'
        line = line + f' ({running})'
        print(self.should_erase_line, line, sep='', end='\r')
        self.should_erase_line = '\x1b[K'

    def start(self, wrap_name: str) -> None:
        with self.lock:
            self.running_tasks.add(wrap_name)
            self.print_progress()

    def done(self, wrap_name: str, log_queue: T.List[T.Tuple[mlog.TV_LoggableList, T.Any]]) -> None:
        with self.lock:
            self.flush()
            for args, kwargs in log_queue:
                mlog.log(*args, **kwargs)
            self.running_tasks.remove(wrap_name)
            self.completed_tasks += 1
            self.print_progress()


@dataclass(eq=False)
class Runner:
    logger: Logger
    r: InitVar[Resolver]
    wrap: PackageDefinition
    repo_dir: str
    options: 'Arguments'

    def __post_init__(self, r: Resolver) -> None:
        # FIXME: Do a copy because Resolver.resolve() is stateful method that
        # cannot be called from multiple threads.
        self.wrap_resolver = copy.copy(r)
        self.wrap_resolver.dirname = os.path.join(r.subdir_root, self.wrap.directory)
        self.wrap_resolver.wrap = self.wrap
        self.run_method: T.Callable[[], bool] = self.options.subprojects_func.__get__(self)
        self.log_queue: T.List[T.Tuple[mlog.TV_LoggableList, T.Any]] = []

    def log(self, *args: mlog.TV_Loggable, **kwargs: T.Any) -> None:
        self.log_queue.append((list(args), kwargs))

    def run(self) -> bool:
        self.logger.start(self.wrap.name)
        try:
            result = self.run_method()
        except MesonException as e:
            self.log(mlog.red('Error:'), str(e))
            result = False
        self.logger.done(self.wrap.name, self.log_queue)
        return result

    @staticmethod
    def pre_update_wrapdb(options: 'UpdateWrapDBArguments') -> None:
        options.releases = get_releases(options.allow_insecure)

    def update_wrapdb(self) -> bool:
        self.log(f'Checking latest WrapDB version for {self.wrap.name}...')
        options = T.cast('UpdateWrapDBArguments', self.options)

        # Check if this wrap is in WrapDB
        info = options.releases.get(self.wrap.name)
        if not info:
            self.log('  -> Wrap not found in wrapdb')
            return True

        # Determine current version
        try:
            wrapdb_version = self.wrap.get('wrapdb_version')
            branch, revision = wrapdb_version.split('-', 1)
        except ValueError:
            if not options.force:
                self.log('  ->', mlog.red('Malformed wrapdb_version field, use --force to update anyway'))
                return False
            branch = revision = None
        except WrapException:
            # Fallback to parsing the patch URL to determine current version.
            # This won't work for projects that have upstream Meson support.
            try:
                patch_url = self.wrap.get('patch_url')
                branch, revision = parse_patch_url(patch_url)
            except WrapException:
                if not options.force:
                    self.log('  ->', mlog.red('Could not determine current version, use --force to update anyway'))
                    return False
                branch = revision = None

        # Download latest wrap if version differs
        latest_version = info['versions'][0]
        new_branch, new_revision = latest_version.rsplit('-', 1)
        if new_branch != branch or new_revision != revision:
            filename = self.wrap.filename if self.wrap.has_wrap else f'{self.wrap.filename}.wrap'
            update_wrap_file(filename, self.wrap.name,
                             new_branch, new_revision,
                             options.allow_insecure)
            self.log('  -> New version downloaded:', mlog.blue(latest_version))
        else:
            self.log('  -> Already at latest version:', mlog.blue(latest_version))

        return True

    def update_file(self) -> bool:
        options = T.cast('UpdateArguments', self.options)
        if options.reset:
            # Delete existing directory and redownload. It is possible that nothing
            # changed but we have no way to know. Hopefully tarballs are still
            # cached.
            windows_proof_rmtree(self.repo_dir)
            try:
                self.wrap_resolver.resolve(self.wrap.name)
                self.log('  -> New version extracted')
                return True
            except WrapException as e:
                self.log('  ->', mlog.red(str(e)))
                return False
        else:
            # The subproject has not changed, or the new source and/or patch
            # tarballs should be extracted in the same directory than previous
            # version.
            self.log('  -> Subproject has not changed, or the new source/patch needs to be extracted on the same location.')
            self.log('     Pass --reset option to delete directory and redownload.')
            return False

    def git_output(self, cmd: T.List[str]) -> str:
        return quiet_git(cmd, self.repo_dir, check=True)[1]

    def git_verbose(self, cmd: T.List[str]) -> None:
        self.log(self.git_output(cmd))

    def git_stash(self) -> None:
        # That git command return some output when there is something to stash.
        # We don't want to stash when there is nothing to stash because that would
        # print spurious "No local changes to save".
        if quiet_git(['status', '--porcelain', ':!/.meson-subproject-wrap-hash.txt'], self.repo_dir)[1].strip():
            # Don't pipe stdout here because we want the user to see their changes have
            # been saved.
            # Note: `--all` is used, and not `--include-untracked`, to prevent
            # a potential error if `.meson-subproject-wrap-hash.txt` matches a
            # gitignore pattern.
            # We must add the dot in addition to the negation, because older versions of git have a bug.
            self.git_verbose(['stash', 'push', '--all', ':!/.meson-subproject-wrap-hash.txt', '.'])

    def git_show(self) -> None:
        commit_message = self.git_output(['show', '--quiet', '--pretty=format:%h%n%d%n%s%n[%an]'])
        parts = [s.strip() for s in commit_message.split('\n')]
        self.log('  ->', mlog.yellow(parts[0]), mlog.red(parts[1]), parts[2], mlog.blue(parts[3]))

    def git_rebase(self, revision: str) -> bool:
        try:
            self.git_output(['-c', 'rebase.autoStash=true', 'rebase', 'FETCH_HEAD'])
        except GitException as e:
            self.git_output(['-c', 'rebase.autoStash=true', 'rebase', '--abort'])
            self.log('  -> Could not rebase', mlog.bold(self.repo_dir), 'onto', mlog.bold(revision),
                     '-- aborted')
            self.log(mlog.red(e.output))
            self.log(mlog.red(str(e)))
            return False
        return True

    def git_reset(self, revision: str) -> bool:
        try:
            # Stash local changes, commits can always be found back in reflog, to
            # avoid any data lost by mistake.
            self.git_stash()
            self.git_output(['reset', '--hard', 'FETCH_HEAD'])
            self.wrap_resolver.apply_patch()
            self.wrap_resolver.apply_diff_files()
        except GitException as e:
            self.log('  -> Could not reset', mlog.bold(self.repo_dir), 'to', mlog.bold(revision))
            self.log(mlog.red(e.output))
            self.log(mlog.red(str(e)))
            return False
        return True

    def git_checkout(self, revision: str, create: bool = False) -> bool:
        cmd = ['checkout', '--ignore-other-worktrees']
        if create:
            cmd.append('-b')
        cmd += [revision, '--']
        try:
            # Stash local changes, commits can always be found back in reflog, to
            # avoid any data lost by mistake.
            self.git_stash()
            self.git_output(cmd)
        except GitException as e:
            self.log('  -> Could not checkout', mlog.bold(revision), 'in', mlog.bold(self.repo_dir))
            self.log(mlog.red(e.output))
            self.log(mlog.red(str(e)))
            return False
        return True

    def git_checkout_and_reset(self, revision: str) -> bool:
        # revision could be a branch that already exists but is outdated, so we still
        # have to reset after the checkout.
        success = self.git_checkout(revision)
        if success:
            success = self.git_reset(revision)
        return success

    def git_checkout_and_rebase(self, revision: str) -> bool:
        # revision could be a branch that already exists but is outdated, so we still
        # have to rebase after the checkout.
        success = self.git_checkout(revision)
        if success:
            success = self.git_rebase(revision)
        return success

    def git_branch_has_upstream(self, urls: set) -> bool:
        cmd = ['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{upstream}']
        ret, upstream = quiet_git(cmd, self.repo_dir)
        if not ret:
            return False
        try:
            remote = upstream.split('/', maxsplit=1)[0]
        except IndexError:
            return False
        cmd = ['remote', 'get-url', remote]
        ret, remote_url = quiet_git(cmd, self.repo_dir)
        return remote_url.strip() in urls

    def update_git(self) -> bool:
        options = T.cast('UpdateArguments', self.options)
        if not os.path.exists(os.path.join(self.repo_dir, '.git')):
            if options.reset:
                # Delete existing directory and redownload
                windows_proof_rmtree(self.repo_dir)
                try:
                    self.wrap_resolver.resolve(self.wrap.name)
                    self.update_git_done()
                    return True
                except WrapException as e:
                    self.log('  ->', mlog.red(str(e)))
                    return False
            else:
                self.log('  -> Not a git repository.')
                self.log('Pass --reset option to delete directory and redownload.')
                return False
        revision = self.wrap.values.get('revision')
        url = self.wrap.values.get('url')
        push_url = self.wrap.values.get('push-url')
        if not revision or not url:
            # It could be a detached git submodule for example.
            self.log('  -> No revision or URL specified.')
            return True
        try:
            origin_url = self.git_output(['remote', 'get-url', 'origin']).strip()
        except GitException as e:
            self.log('  -> Failed to determine current origin URL in', mlog.bold(self.repo_dir))
            self.log(mlog.red(e.output))
            self.log(mlog.red(str(e)))
            return False
        if options.reset:
            try:
                self.git_output(['remote', 'set-url', 'origin', url])
                if push_url:
                    self.git_output(['remote', 'set-url', '--push', 'origin', push_url])
            except GitException as e:
                self.log('  -> Failed to reset origin URL in', mlog.bold(self.repo_dir))
                self.log(mlog.red(e.output))
                self.log(mlog.red(str(e)))
                return False
        elif url != origin_url:
            self.log(f'  -> URL changed from {origin_url!r} to {url!r}')
            return False
        try:
            # Same as `git branch --show-current` but compatible with older git version
            branch = self.git_output(['rev-parse', '--abbrev-ref', 'HEAD']).strip()
            branch = branch if branch != 'HEAD' else ''
        except GitException as e:
            self.log('  -> Failed to determine current branch in', mlog.bold(self.repo_dir))
            self.log(mlog.red(e.output))
            self.log(mlog.red(str(e)))
            return False
        if self.wrap_resolver.is_git_full_commit_id(revision) and \
                quiet_git(['rev-parse', '--verify', revision + '^{commit}'], self.repo_dir)[0]:
            # The revision we need is both a commit and available. So we do not
            # need to fetch it because it cannot be updated.  Instead, trick
            # git into setting FETCH_HEAD just in case, from the local commit.
            self.git_output(['fetch', '.', revision])
        else:
            try:
                # Fetch only the revision we need, this avoids fetching useless branches.
                # revision can be either a branch, tag or commit id. In all cases we want
                # FETCH_HEAD to be set to the desired commit and "git checkout "
                # to to either switch to existing/new branch, or detach to tag/commit.
                # It is more complicated than it first appear, see discussion there:
                # https://github.com/mesonbuild/meson/pull/7723#discussion_r488816189.
                heads_refmap = '+refs/heads/*:refs/remotes/origin/*'
                tags_refmap = '+refs/tags/*:refs/tags/*'
                self.git_output(['fetch', '--refmap', heads_refmap, '--refmap', tags_refmap, 'origin', revision])
            except GitException as e:
                self.log('  -> Could not fetch revision', mlog.bold(revision), 'in', mlog.bold(self.repo_dir))
                self.log(mlog.red(e.output))
                self.log(mlog.red(str(e)))
                return False

        if branch == '':
            # We are currently in detached mode
            if options.reset:
                success = self.git_checkout_and_reset(revision)
            else:
                success = self.git_checkout_and_rebase(revision)
        elif branch == revision:
            # We are in the same branch. A reset could still be needed in the case
            # a force push happened on remote repository.
            if options.reset:
                success = self.git_reset(revision)
            else:
                success = self.git_rebase(revision)
        else:
            # We are in another branch, either the user created their own branch and
            # we should rebase it, or revision changed in the wrap file (we
            # know this when the current branch has an upstream) and we need to
            # checkout the new branch.
            if options.reset:
                success = self.git_checkout_and_reset(revision)
            else:
                if self.git_branch_has_upstream({url, push_url}):
                    success = self.git_checkout_and_rebase(revision)
                else:
                    success = self.git_rebase(revision)
        if success:
            self.update_git_done()
        return success

    def update_git_done(self) -> None:
        self.git_output(['submodule', 'update', '--checkout', '--recursive'])
        self.git_show()

    def update_hg(self) -> bool:
        revno = self.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=self.repo_dir)
        else:
            if subprocess.call(['hg', 'checkout', revno], cwd=self.repo_dir) != 0:
                subprocess.check_call(['hg', 'pull'], cwd=self.repo_dir)
                subprocess.check_call(['hg', 'checkout', revno], cwd=self.repo_dir)
        return True

    def update_svn(self) -> bool:
        revno = self.wrap.get('revision')
        _, out, _ = Popen_safe(['svn', 'info', '--show-item', 'revision', self.repo_dir])
        current_revno = out
        if current_revno == revno:
            return True
        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=self.repo_dir)
        else:
            subprocess.check_call(['svn', 'update', '-r', revno], cwd=self.repo_dir)
        return True

    def update(self) -> bool:
        self.log(f'Updating {self.wrap.name}...')
        success = False
        if not os.path.isdir(self.repo_dir):
            self.log('  -> Not used.')
            # It is not an error if we are updating all subprojects.
            success = not self.options.subprojects
        elif self.wrap.type == 'file':
            success = self.update_file()
        elif self.wrap.type == 'git':
            success = self.update_git()
        elif self.wrap.type == 'hg':
            success = self.update_hg()
        elif self.wrap.type == 'svn':
            success = self.update_svn()
        elif self.wrap.type is None:
            self.log('  -> Cannot update subproject with no wrap file')
            # It is not an error if we are updating all subprojects.
            success = not self.options.subprojects
        else:
            self.log('  -> Cannot update', self.wrap.type, 'subproject')
        if success and os.path.isdir(self.repo_dir):
            self.wrap.update_hash_cache(self.repo_dir)
        return success

    def checkout(self) -> bool:
        options = T.cast('CheckoutArguments', self.options)

        if self.wrap.type != 'git' or not os.path.isdir(self.repo_dir):
            return True
        branch_name = options.branch_name if options.branch_name else self.wrap.get('revision')
        if not branch_name:
            # It could be a detached git submodule for example.
            return True
        self.log(f'Checkout {branch_name} in {self.wrap.name}...')
        if self.git_checkout(branch_name, create=options.b):
            self.git_show()
            return True
        return False

    def download(self) -> bool:
        self.log(f'Download {self.wrap.name}...')
        if os.path.isdir(self.repo_dir):
            self.log('  -> Already downloaded')
            return True
        try:
            self.wrap_resolver.resolve(self.wrap.name)
            self.log('  -> done')
        except WrapException as e:
            self.log('  ->', mlog.red(str(e)))
            return False
        return True

    def foreach(self) -> bool:
        options = T.cast('ForeachArguments', self.options)

        self.log(f'Executing command in {self.repo_dir}')
        if not os.path.isdir(self.repo_dir):
            self.log('  -> Not downloaded yet')
            return True
        cmd = [options.command] + options.args
        p, out, _ = Popen_safe(cmd, stderr=subprocess.STDOUT, cwd=self.repo_dir)
        if p.returncode != 0:
            err_message = "Command '{}' returned non-zero exit status {}.".format(" ".join(cmd), p.returncode)
            self.log('  -> ', mlog.red(err_message))
            self.log(out, end='')
            return False

        self.log(out, end='')
        return True

    def purge(self) -> bool:
        options = T.cast('PurgeArguments', self.options)

        # if subproject is not wrap-based, then don't remove it
        if not self.wrap.type:
            return True

        if self.wrap.redirected:
            redirect_file = Path(self.wrap.original_filename).resolve()
            if options.confirm:
                redirect_file.unlink()
            mlog.log(f'Deleting {redirect_file}')

        if self.wrap.type == 'redirect':
            redirect_file = Path(self.wrap.filename).resolve()
            if options.confirm:
                redirect_file.unlink()
            self.log(f'Deleting {redirect_file}')

        if options.include_cache:
            packagecache = Path(self.wrap_resolver.cachedir).resolve()
            try:
                subproject_cache_file = packagecache / self.wrap.get("source_filename")
                if subproject_cache_file.is_file():
                    if options.confirm:
                        subproject_cache_file.unlink()
                    self.log(f'Deleting {subproject_cache_file}')
            except WrapException:
                pass

            try:
                subproject_patch_file = packagecache / self.wrap.get("patch_filename")
                if subproject_patch_file.is_file():
                    if options.confirm:
                        subproject_patch_file.unlink()
                    self.log(f'Deleting {subproject_patch_file}')
            except WrapException:
                pass

            # Don't log that we will remove an empty directory. Since purge is
            # parallelized, another thread could have deleted it already.
            try:
                if not any(packagecache.iterdir()):
                    windows_proof_rmtree(str(packagecache))
            except FileNotFoundError:
                pass

        # NOTE: Do not use .resolve() here; the subproject directory may be a symlink
        subproject_source_dir = Path(self.repo_dir)
        # Resolve just the parent, just to print out the full path
        subproject_source_dir = subproject_source_dir.parent.resolve() / subproject_source_dir.name

        # Don't follow symlink. This is covered by the next if statement, but why
        # not be doubly sure.
        if subproject_source_dir.is_symlink():
            if options.confirm:
                subproject_source_dir.unlink()
            self.log(f'Deleting {subproject_source_dir}')
            return True
        if not subproject_source_dir.is_dir():
            return True

        try:
            if options.confirm:
                windows_proof_rmtree(str(subproject_source_dir))
            self.log(f'Deleting {subproject_source_dir}')
        except OSError as e:
            mlog.error(f'Unable to remove: {subproject_source_dir}: {e}')
            return False

        return True

    @staticmethod
    def post_purge(options: 'PurgeArguments') -> None:
        if not options.confirm:
            mlog.log('')
            mlog.log('Nothing has been deleted, run again with --confirm to apply.')

    def packagefiles(self) -> bool:
        options = T.cast('PackagefilesArguments', self.options)

        if options.apply and options.save:
            # not quite so nice as argparse failure
            print('error: --apply and --save are mutually exclusive')
            return False
        if options.apply:
            self.log(f'Re-applying patchfiles overlay for {self.wrap.name}...')
            if not os.path.isdir(self.repo_dir):
                self.log('  -> Not downloaded yet')
                return True
            self.wrap_resolver.apply_patch()
            return True
        if options.save:
            if 'patch_directory' not in self.wrap.values:
                mlog.error('can only save packagefiles to patch_directory')
                return False
            if 'source_filename' not in self.wrap.values:
                mlog.error('can only save packagefiles from a [wrap-file]')
                return False
            archive_path = Path(self.wrap_resolver.cachedir, self.wrap.values['source_filename'])
            lead_directory_missing = bool(self.wrap.values.get('lead_directory_missing', False))
            directory = Path(self.repo_dir)
            packagefiles = Path(self.wrap.filesdir, self.wrap.values['patch_directory'])

            base_path = directory if lead_directory_missing else directory.parent
            archive_files = read_archive_files(archive_path, base_path)
            directory_files = set(directory.glob('**/*'))

            self.log(f'Saving {self.wrap.name} to {packagefiles}...')
            shutil.rmtree(packagefiles)
            for src_path in directory_files - archive_files:
                if not src_path.is_file():
                    continue
                rel_path = src_path.relative_to(directory)
                dst_path = packagefiles / rel_path
                dst_path.parent.mkdir(parents=True, exist_ok=True)
                shutil.copyfile(src_path, dst_path)
        return True


def add_common_arguments(p: argparse.ArgumentParser) -> None:
    p.add_argument('--sourcedir', default='.',
                   help='Path to source directory')
    p.add_argument('--types', default='',
                   help=f'Comma-separated list of subproject types. Supported types are: {ALL_TYPES_STRING} (default: all)')
    p.add_argument('-j', '--num-processes', default=None, type=int,
                   help='How many parallel processes to use (Since 0.59.0).')
    p.add_argument('--allow-insecure', default=False, action='store_true',
                   help='Allow insecure server connections.')

def add_subprojects_argument(p: argparse.ArgumentParser) -> None:
    p.add_argument('subprojects', nargs='*',
                   help='List of subprojects (default: all)')

def add_wrap_update_parser(subparsers: 'SubParsers') -> argparse.ArgumentParser:
    p = subparsers.add_parser('update', help='Update wrap files from WrapDB (Since 0.63.0)')
    p.add_argument('--force', default=False, action='store_true',
                   help='Update wraps that does not seems to come from WrapDB')
    add_common_arguments(p)
    add_subprojects_argument(p)
    p.set_defaults(subprojects_func=Runner.update_wrapdb)
    p.set_defaults(pre_func=Runner.pre_update_wrapdb)
    return p

# Note: when adding arguments, please also add them to the completion
# scripts in $MESONSRC/data/shell-completions/
def add_arguments(parser: argparse.ArgumentParser) -> None:
    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=True, action='store_true',
                   help='Rebase your branch on top of wrap\'s revision. ' +
                        'Deprecated, it is now the default behaviour. (git only)')
    p.add_argument('--reset', default=False, action='store_true',
                   help='Checkout wrap\'s revision and hard reset to that commit. (git only)')
    add_common_arguments(p)
    add_subprojects_argument(p)
    p.set_defaults(subprojects_func=Runner.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)
    add_subprojects_argument(p)
    p.set_defaults(subprojects_func=Runner.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)
    add_subprojects_argument(p)
    p.set_defaults(subprojects_func=Runner.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)
    add_common_arguments(p)
    p.set_defaults(subprojects=[])
    p.set_defaults(subprojects_func=Runner.foreach)

    p = subparsers.add_parser('purge', help='Remove all wrap-based subproject artifacts')
    add_common_arguments(p)
    add_subprojects_argument(p)
    p.add_argument('--include-cache', action='store_true', default=False, help='Remove the package cache as well')
    p.add_argument('--confirm', action='store_true', default=False, help='Confirm the removal of subproject artifacts')
    p.set_defaults(subprojects_func=Runner.purge)
    p.set_defaults(post_func=Runner.post_purge)

    p = subparsers.add_parser('packagefiles', help='Manage the packagefiles overlay')
    add_common_arguments(p)
    add_subprojects_argument(p)
    p.add_argument('--apply', action='store_true', default=False, help='Apply packagefiles to the subproject')
    p.add_argument('--save', action='store_true', default=False, help='Save packagefiles from the subproject')
    p.set_defaults(subprojects_func=Runner.packagefiles)

def run(options: 'Arguments') -> int:
    source_dir = os.path.relpath(os.path.realpath(options.sourcedir))
    if not os.path.isfile(os.path.join(source_dir, 'meson.build')):
        mlog.error('Directory', mlog.bold(source_dir), 'does not seem to be a Meson source directory.')
        return 1
    with mlog.no_logging():
        intr = IntrospectionInterpreter(source_dir, '', 'none')
        intr.load_root_meson_file()
        subproject_dir = intr.extract_subproject_dir() or 'subprojects'
    if not os.path.isdir(os.path.join(source_dir, subproject_dir)):
        mlog.log('Directory', mlog.bold(source_dir), 'does not seem to have subprojects.')
        return 0
    r = Resolver(source_dir, subproject_dir, wrap_frontend=True, allow_insecure=options.allow_insecure, silent=True)
    if options.subprojects:
        wraps = [wrap for name, wrap in r.wraps.items() if name in options.subprojects]
    else:
        wraps = list(r.wraps.values())
    types = [t.strip() for t in options.types.split(',')] if options.types else []
    for t in types:
        if t not in ALL_TYPES:
            raise MesonException(f'Unknown subproject type {t!r}, supported types are: {ALL_TYPES_STRING}')
    tasks: T.List[T.Awaitable[bool]] = []
    task_names: T.List[str] = []
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    executor = ThreadPoolExecutor(options.num_processes)
    if types:
        wraps = [wrap for wrap in wraps if wrap.type in types]
    pre_func = getattr(options, 'pre_func', None)
    if pre_func:
        pre_func(options)
    logger = Logger(len(wraps))
    for wrap in wraps:
        dirname = Path(source_dir, subproject_dir, wrap.directory).as_posix()
        runner = Runner(logger, r, wrap, dirname, options)
        task = loop.run_in_executor(executor, runner.run)
        tasks.append(task)
        task_names.append(wrap.name)
    results = loop.run_until_complete(asyncio.gather(*tasks))
    logger.flush()
    post_func = getattr(options, 'post_func', None)
    if post_func:
        post_func(options)
    failures = [name for name, success in zip(task_names, results) if not success]
    if failures:
        m = 'Please check logs above as command failed in some subprojects which could have been left in conflict state: '
        m += ', '.join(failures)
        mlog.warning(m)
    return len(failures)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/mtest.py0000644000175000017500000025603614562742363016727 0ustar00jpakkanejpakkane# 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 __future__ import annotations

from pathlib import Path
from collections import deque
from contextlib import suppress
from copy import deepcopy
from fnmatch import fnmatch
import argparse
import asyncio
import datetime
import enum
import json
import multiprocessing
import os
import pickle
import platform
import random
import re
import signal
import subprocess
import shlex
import sys
import textwrap
import time
import typing as T
import unicodedata
import xml.etree.ElementTree as et

from . import build
from . import environment
from . import mlog
from .coredata import MesonVersionMismatchException, major_versions_differ
from .coredata import version as coredata_version
from .mesonlib import (MesonException, OptionKey, OrderedSet, RealPathAction,
                       get_wine_shortpath, join_args, split_args, setup_vsenv)
from .mintro import get_infodir, load_info_file
from .programs import ExternalProgram
from .backend.backends import TestProtocol, TestSerialisation

if T.TYPE_CHECKING:
    TYPE_TAPResult = T.Union['TAPParser.Test',
                             'TAPParser.Error',
                             'TAPParser.Version',
                             'TAPParser.Plan',
                             'TAPParser.UnknownLine',
                             'TAPParser.Bailout']


# 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

# Exit if 3 Ctrl-C's are received within one second
MAX_CTRLC = 3

# Define unencodable xml characters' regex for replacing them with their
# printable representation
UNENCODABLE_XML_UNICHRS: T.List[T.Tuple[int, int]] = [
    (0x00, 0x08), (0x0B, 0x0C), (0x0E, 0x1F), (0x7F, 0x84),
    (0x86, 0x9F), (0xFDD0, 0xFDEF), (0xFFFE, 0xFFFF)]
# Not narrow build
if sys.maxunicode >= 0x10000:
    UNENCODABLE_XML_UNICHRS.extend([
        (0x1FFFE, 0x1FFFF), (0x2FFFE, 0x2FFFF),
        (0x3FFFE, 0x3FFFF), (0x4FFFE, 0x4FFFF),
        (0x5FFFE, 0x5FFFF), (0x6FFFE, 0x6FFFF),
        (0x7FFFE, 0x7FFFF), (0x8FFFE, 0x8FFFF),
        (0x9FFFE, 0x9FFFF), (0xAFFFE, 0xAFFFF),
        (0xBFFFE, 0xBFFFF), (0xCFFFE, 0xCFFFF),
        (0xDFFFE, 0xDFFFF), (0xEFFFE, 0xEFFFF),
        (0xFFFFE, 0xFFFFF), (0x10FFFE, 0x10FFFF)])
UNENCODABLE_XML_CHR_RANGES = [fr'{chr(low)}-{chr(high)}' for (low, high) in UNENCODABLE_XML_UNICHRS]
UNENCODABLE_XML_CHRS_RE = re.compile('([' + ''.join(UNENCODABLE_XML_CHR_RANGES) + '])')


def is_windows() -> bool:
    platname = platform.system().lower()
    return platname == 'windows'

def is_cygwin() -> bool:
    return sys.platform == 'cygwin'

UNIWIDTH_MAPPING = {'F': 2, 'H': 1, 'W': 2, 'Na': 1, 'N': 1, 'A': 1}
def uniwidth(s: str) -> int:
    result = 0
    for c in s:
        w = unicodedata.east_asian_width(c)
        result += UNIWIDTH_MAPPING[w]
    return result

def determine_worker_count() -> int:
    varname = 'MESON_TESTTHREADS'
    if varname in os.environ:
        try:
            num_workers = int(os.environ[varname])
        except ValueError:
            print(f'Invalid value in {varname}, using 1 thread.')
            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

# Note: when adding arguments, please also add them to the completion
# scripts in $MESONSRC/data/shell-completions/
def add_arguments(parser: argparse.ArgumentParser) -> None:
    parser.add_argument('--maxfail', default=0, type=int,
                        help='Number of failing tests before aborting the '
                        'test run. (default: 0, to disable aborting on failure)')
    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', dest='wd', action=RealPathAction,
                        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('-j', '--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. (<= 0 to disable timeout)')
    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 test names to run. "testname" to run all tests with that name, '
                        '"subprojname:testname" to specifically run "testname" from "subprojname", '
                        '"subprojname:" to run all tests defined by "subprojname".')


def print_safe(s: str) -> None:
    end = '' if s[-1] == '\n' else '\n'
    try:
        print(s, end=end)
    except UnicodeEncodeError:
        s = s.encode('ascii', errors='backslashreplace').decode('ascii')
        print(s, end=end)

def join_lines(a: str, b: str) -> str:
    if not a:
        return b
    if not b:
        return a
    return a + '\n' + b

def dashes(s: str, dash: str, cols: int) -> str:
    if not s:
        return dash * cols
    s = ' ' + s + ' '
    width = uniwidth(s)
    first = (cols - width) // 2
    s = dash * first + s
    return s + dash * (cols - first - width)

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 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 f'killed by signal {signum} {signame}'

    if retcode <= 128:
        return f'exit status {retcode}'

    signum = retcode - 128
    try:
        signame = signal.Signals(signum).name
    except ValueError:
        signame = 'SIGinvalid'
    return f'(exit status {retcode} or signal {signum} {signame})'

# TODO for Windows
sh_quote: T.Callable[[str], str] = lambda x: x
if not is_windows():
    sh_quote = shlex.quote

def env_tuple_to_str(env: T.Iterable[T.Tuple[str, str]]) -> str:
    return ''.join(["{}={} ".format(k, sh_quote(v)) for k, v in env])


class TestException(MesonException):
    pass


@enum.unique
class ConsoleUser(enum.Enum):

    # the logger can use the console
    LOGGER = 0

    # the console is used by gdb
    GDB = 1

    # the console is used to write stdout/stderr
    STDOUT = 2


@enum.unique
class TestResult(enum.Enum):

    PENDING = 'PENDING'
    RUNNING = 'RUNNING'
    OK = 'OK'
    TIMEOUT = 'TIMEOUT'
    INTERRUPT = 'INTERRUPT'
    SKIP = 'SKIP'
    FAIL = 'FAIL'
    EXPECTEDFAIL = 'EXPECTEDFAIL'
    UNEXPECTEDPASS = 'UNEXPECTEDPASS'
    ERROR = 'ERROR'

    @staticmethod
    def maxlen() -> int:
        return 14  # len(UNEXPECTEDPASS)

    def is_ok(self) -> bool:
        return self in {TestResult.OK, TestResult.EXPECTEDFAIL}

    def is_bad(self) -> bool:
        return self in {TestResult.FAIL, TestResult.TIMEOUT, TestResult.INTERRUPT,
                        TestResult.UNEXPECTEDPASS, TestResult.ERROR}

    def is_finished(self) -> bool:
        return self not in {TestResult.PENDING, TestResult.RUNNING}

    def was_killed(self) -> bool:
        return self in (TestResult.TIMEOUT, TestResult.INTERRUPT)

    def colorize(self, s: str) -> mlog.AnsiDecorator:
        if self.is_bad():
            decorator = mlog.red
        elif self in (TestResult.SKIP, TestResult.EXPECTEDFAIL):
            decorator = mlog.yellow
        elif self.is_finished():
            decorator = mlog.green
        else:
            decorator = mlog.blue
        return decorator(s)

    def get_text(self, colorize: bool) -> str:
        result_str = '{res:{reslen}}'.format(res=self.value, reslen=self.maxlen())
        return self.colorize(result_str).get_text(colorize)

    def get_command_marker(self) -> str:
        return str(self.colorize('>>> '))


class TAPParser:
    class Plan(T.NamedTuple):
        num_tests: int
        late: bool
        skipped: bool
        explanation: T.Optional[str]

    class Bailout(T.NamedTuple):
        message: str

    class Test(T.NamedTuple):
        number: int
        name: str
        result: TestResult
        explanation: T.Optional[str]

        def __str__(self) -> str:
            return f'{self.number} {self.name}'.strip()

    class Error(T.NamedTuple):
        message: str

    class UnknownLine(T.NamedTuple):
        message: str
        lineno: int

    class Version(T.NamedTuple):
        version: int

    _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*')

    found_late_test = False
    bailed_out = False
    plan: T.Optional[Plan] = None
    lineno = 0
    num_tests = 0
    yaml_lineno: T.Optional[int] = None
    yaml_indent = ''
    state = _MAIN
    version = 12

    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.startswith('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(f'invalid directive "{directive}"')

        yield self.Test(num, name, TestResult.OK if ok else TestResult.FAIL, explanation)

    async def parse_async(self, lines: T.AsyncIterator[str]) -> T.AsyncIterator[TYPE_TAPResult]:
        async for line in lines:
            for event in self.parse_line(line):
                yield event
        for event in self.parse_line(None):
            yield event

    def parse(self, io: T.Iterator[str]) -> T.Iterator[TYPE_TAPResult]:
        for line in io:
            yield from self.parse_line(line)
        yield from self.parse_line(None)

    def parse_line(self, line: T.Optional[str]) -> T.Iterator[TYPE_TAPResult]:
        if line is not None:
            self.lineno += 1
            line = line.rstrip()

            # YAML blocks are only accepted after a test
            if self.state == self._AFTER_TEST:
                if self.version >= 13:
                    m = self._RE_YAML_START.match(line)
                    if m:
                        self.state = self._YAML
                        self.yaml_lineno = self.lineno
                        self.yaml_indent = m.group(1)
                        return
                self.state = self._MAIN

            elif self.state == self._YAML:
                if self._RE_YAML_END.match(line):
                    self.state = self._MAIN
                    return
                if line.startswith(self.yaml_indent):
                    return
                yield self.Error(f'YAML block not terminated (started on line {self.yaml_lineno})')
                self.state = self._MAIN

            assert self.state == self._MAIN
            if not line or line.startswith('#'):
                return

            m = self._RE_TEST.match(line)
            if m:
                if self.plan and self.plan.late and not self.found_late_test:
                    yield self.Error('unexpected test after late plan')
                    self.found_late_test = True
                self.num_tests += 1
                num = self.num_tests if m.group(2) is None else int(m.group(2))
                if num != self.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))
                self.state = self._AFTER_TEST
                return

            m = self._RE_PLAN.match(line)
            if m:
                if self.plan:
                    yield self.Error('more than one plan found')
                else:
                    num_tests = int(m.group(1))
                    skipped = num_tests == 0
                    if m.group(2):
                        if m.group(2).upper().startswith('SKIP'):
                            if num_tests > 0:
                                yield self.Error('invalid SKIP directive for plan')
                            skipped = True
                        else:
                            yield self.Error('invalid directive for plan')
                    self.plan = self.Plan(num_tests=num_tests, late=(self.num_tests > 0),
                                          skipped=skipped, explanation=m.group(3))
                    yield self.plan
                return

            m = self._RE_BAILOUT.match(line)
            if m:
                yield self.Bailout(m.group(1))
                self.bailed_out = True
                return

            m = self._RE_VERSION.match(line)
            if m:
                # The TAP version is only accepted as the first line
                if self.lineno != 1:
                    yield self.Error('version number must be on the first line')
                    return
                self.version = int(m.group(1))
                if self.version < 13:
                    yield self.Error('version number should be at least 13')
                else:
                    yield self.Version(version=self.version)
                return

            # unknown syntax
            yield self.UnknownLine(line, self.lineno)
        else:
            # end of file
            if self.state == self._YAML:
                yield self.Error(f'YAML block not terminated (started on line {self.yaml_lineno})')

            if not self.bailed_out and self.plan and self.num_tests != self.plan.num_tests:
                if self.num_tests < self.plan.num_tests:
                    yield self.Error(f'Too few tests run (expected {self.plan.num_tests}, got {self.num_tests})')
                else:
                    yield self.Error(f'Too many tests run (expected {self.plan.num_tests}, got {self.num_tests})')

class TestLogger:
    def flush(self) -> None:
        pass

    def start(self, harness: 'TestHarness') -> None:
        pass

    def start_test(self, harness: 'TestHarness', test: 'TestRun') -> None:
        pass

    def log_subtest(self, harness: 'TestHarness', test: 'TestRun', s: str, res: TestResult) -> None:
        pass

    def log(self, harness: 'TestHarness', result: 'TestRun') -> None:
        pass

    async def finish(self, harness: 'TestHarness') -> None:
        pass

    def close(self) -> None:
        pass


class TestFileLogger(TestLogger):
    def __init__(self, filename: str, errors: str = 'replace') -> None:
        self.filename = filename
        self.file = open(filename, 'w', encoding='utf-8', errors=errors)

    def close(self) -> None:
        if self.file:
            self.file.close()
            self.file = None


class ConsoleLogger(TestLogger):
    ASCII_SPINNER = ['..', ':.', '.:']
    SPINNER = ["\U0001f311", "\U0001f312", "\U0001f313", "\U0001f314",
               "\U0001f315", "\U0001f316", "\U0001f317", "\U0001f318"]

    SCISSORS = "\u2700 "
    HLINE = "\u2015"
    RTRI = "\u25B6 "

    def __init__(self) -> None:
        self.running_tests: OrderedSet['TestRun'] = OrderedSet()
        self.progress_test: T.Optional['TestRun'] = None
        self.progress_task: T.Optional[asyncio.Future] = None
        self.max_left_width = 0
        self.stop = False
        # TODO: before 3.10 this cannot be created immediately, because
        # it will create a new event loop
        self.update: asyncio.Event
        self.should_erase_line = ''
        self.test_count = 0
        self.started_tests = 0
        self.spinner_index = 0
        try:
            self.cols, _ = os.get_terminal_size(1)
            self.is_tty = True
        except OSError:
            self.cols = 80
            self.is_tty = False

        self.output_start = dashes(self.SCISSORS, self.HLINE, self.cols - 2)
        self.output_end = dashes('', self.HLINE, self.cols - 2)
        self.sub = self.RTRI
        self.spinner = self.SPINNER
        try:
            self.output_start.encode(sys.stdout.encoding or 'ascii')
        except UnicodeEncodeError:
            self.output_start = dashes('8<', '-', self.cols - 2)
            self.output_end = dashes('', '-', self.cols - 2)
            self.sub = '| '
            self.spinner = self.ASCII_SPINNER

    def flush(self) -> None:
        if self.should_erase_line:
            print(self.should_erase_line, end='')
            self.should_erase_line = ''

    def print_progress(self, line: str) -> None:
        print(self.should_erase_line, line, sep='', end='\r')
        self.should_erase_line = '\x1b[K'

    def request_update(self) -> None:
        self.update.set()

    def emit_progress(self, harness: 'TestHarness') -> None:
        if self.progress_test is None:
            self.flush()
            return

        if len(self.running_tests) == 1:
            count = f'{self.started_tests}/{self.test_count}'
        else:
            count = '{}-{}/{}'.format(self.started_tests - len(self.running_tests) + 1,
                                      self.started_tests, self.test_count)

        left = '[{}] {} '.format(count, self.spinner[self.spinner_index])
        self.spinner_index = (self.spinner_index + 1) % len(self.spinner)

        right = '{spaces} {dur:{durlen}}'.format(
            spaces=' ' * TestResult.maxlen(),
            dur=int(time.time() - self.progress_test.starttime),
            durlen=harness.duration_max_len)
        if self.progress_test.timeout:
            right += '/{timeout:{durlen}}'.format(
                timeout=self.progress_test.timeout,
                durlen=harness.duration_max_len)
        right += 's'
        details = self.progress_test.get_details()
        if details:
            right += '   ' + details

        line = harness.format(self.progress_test, colorize=True,
                              max_left_width=self.max_left_width,
                              left=left, right=right)
        self.print_progress(line)

    def start(self, harness: 'TestHarness') -> None:
        async def report_progress() -> None:
            loop = asyncio.get_running_loop()
            next_update = 0.0
            self.request_update()
            while not self.stop:
                await self.update.wait()
                self.update.clear()
                # We may get here simply because the progress line has been
                # overwritten, so do not always switch.  Only do so every
                # second, or if the printed test has finished
                if loop.time() >= next_update:
                    self.progress_test = None
                    next_update = loop.time() + 1
                    loop.call_at(next_update, self.request_update)

                if (self.progress_test and
                        self.progress_test.res is not TestResult.RUNNING):
                    self.progress_test = None

                if not self.progress_test:
                    if not self.running_tests:
                        continue
                    # Pick a test in round robin order
                    self.progress_test = self.running_tests.pop(last=False)
                    self.running_tests.add(self.progress_test)

                self.emit_progress(harness)
            self.flush()

        self.update = asyncio.Event()
        self.test_count = harness.test_count
        self.cols = max(self.cols, harness.max_left_width + 30)

        if self.is_tty and not harness.need_console:
            # Account for "[aa-bb/cc] OO " in the progress report
            self.max_left_width = 3 * len(str(self.test_count)) + 8
            self.progress_task = asyncio.ensure_future(report_progress())

    def start_test(self, harness: 'TestHarness', test: 'TestRun') -> None:
        if test.verbose and test.cmdline:
            self.flush()
            print(harness.format(test, mlog.colorize_console(),
                                 max_left_width=self.max_left_width,
                                 right=test.res.get_text(mlog.colorize_console())))
            print(test.res.get_command_marker() + test.cmdline)
            if test.direct_stdout:
                print(self.output_start, flush=True)
            elif not test.needs_parsing:
                print(flush=True)

        self.started_tests += 1
        self.running_tests.add(test)
        self.running_tests.move_to_end(test, last=False)
        self.request_update()

    def shorten_log(self, harness: 'TestHarness', result: 'TestRun') -> str:
        if not result.verbose and not harness.options.print_errorlogs:
            return ''

        log = result.get_log(mlog.colorize_console(),
                             stderr_only=result.needs_parsing)
        if result.verbose:
            return log

        lines = log.splitlines()
        if len(lines) < 100:
            return log
        else:
            return str(mlog.bold('Listing only the last 100 lines from a long log.\n')) + '\n'.join(lines[-100:])

    def print_log(self, harness: 'TestHarness', result: 'TestRun') -> None:
        if not result.verbose:
            cmdline = result.cmdline
            if not cmdline:
                print(result.res.get_command_marker() + result.stdo)
                return
            print(result.res.get_command_marker() + cmdline)

        log = self.shorten_log(harness, result)
        if log:
            print(self.output_start)
            print_safe(log)
            print(self.output_end)

    def log_subtest(self, harness: 'TestHarness', test: 'TestRun', s: str, result: TestResult) -> None:
        if test.verbose or (harness.options.print_errorlogs and result.is_bad()):
            self.flush()
            print(harness.format(test, mlog.colorize_console(), max_left_width=self.max_left_width,
                                 prefix=self.sub,
                                 middle=s,
                                 right=result.get_text(mlog.colorize_console())), flush=True)

            self.request_update()

    def log(self, harness: 'TestHarness', result: 'TestRun') -> None:
        self.running_tests.remove(result)
        if result.res is TestResult.TIMEOUT and (result.verbose or
                                                 harness.options.print_errorlogs):
            self.flush()
            print(f'{result.name} time out (After {result.timeout} seconds)')

        if not harness.options.quiet or not result.res.is_ok():
            self.flush()
            if result.cmdline and result.direct_stdout:
                print(self.output_end)
                print(harness.format(result, mlog.colorize_console(), max_left_width=self.max_left_width))
            else:
                print(harness.format(result, mlog.colorize_console(), max_left_width=self.max_left_width),
                      flush=True)
                if result.verbose or result.res.is_bad():
                    self.print_log(harness, result)
            if result.warnings:
                print(flush=True)
                for w in result.warnings:
                    print(w, flush=True)
                print(flush=True)
            if result.verbose or result.res.is_bad():
                print(flush=True)

        self.request_update()

    async def finish(self, harness: 'TestHarness') -> None:
        self.stop = True
        self.request_update()
        if self.progress_task:
            await self.progress_task

        if harness.collected_failures and \
                (harness.options.print_errorlogs or harness.options.verbose):
            print("\nSummary of Failures:\n")
            for i, result in enumerate(harness.collected_failures, 1):
                print(harness.format(result, mlog.colorize_console()))

        print(harness.summary())


class TextLogfileBuilder(TestFileLogger):
    def start(self, harness: 'TestHarness') -> None:
        self.file.write(f'Log of Meson test suite run on {datetime.datetime.now().isoformat()}\n\n')
        inherit_env = env_tuple_to_str(os.environ.items())
        self.file.write(f'Inherited environment: {inherit_env}\n\n')

    def log(self, harness: 'TestHarness', result: 'TestRun') -> None:
        title = f'{result.num}/{harness.test_count}'
        self.file.write(dashes(title, '=', 78) + '\n')
        self.file.write('test:         ' + result.name + '\n')
        starttime_str = time.strftime("%H:%M:%S", time.gmtime(result.starttime))
        self.file.write('start time:   ' + starttime_str + '\n')
        self.file.write('duration:     ' + '%.2fs' % result.duration + '\n')
        self.file.write('result:       ' + result.get_exit_status() + '\n')
        if result.cmdline:
            self.file.write('command:      ' + result.cmdline + '\n')
        if result.stdo:
            name = 'stdout' if harness.options.split else 'output'
            self.file.write(dashes(name, '-', 78) + '\n')
            self.file.write(result.stdo)
        if result.stde:
            self.file.write(dashes('stderr', '-', 78) + '\n')
            self.file.write(result.stde)
        self.file.write(dashes('', '=', 78) + '\n\n')

    async def finish(self, harness: 'TestHarness') -> None:
        if harness.collected_failures:
            self.file.write("\nSummary of Failures:\n\n")
            for i, result in enumerate(harness.collected_failures, 1):
                self.file.write(harness.format(result, False) + '\n')
        self.file.write(harness.summary())

        print(f'Full log written to {self.filename}')


class JsonLogfileBuilder(TestFileLogger):
    def log(self, harness: 'TestHarness', result: 'TestRun') -> None:
        jresult: T.Dict[str, T.Any] = {
            'name': result.name,
            'stdout': result.stdo,
            'result': result.res.value,
            'starttime': result.starttime,
            'duration': result.duration,
            'returncode': result.returncode,
            'env': result.env,
            'command': result.cmd,
        }
        if result.stde:
            jresult['stderr'] = result.stde
        self.file.write(json.dumps(jresult) + '\n')


class JunitBuilder(TestLogger):

    """Builder for Junit test results.

    Junit is impossible to stream out, it requires attributes counting the
    total number of tests, failures, skips, and errors in the root element
    and in each test suite. As such, we use a builder class to track each
    test case, and calculate all metadata before writing it out.

    For tests with multiple results (like from a TAP test), we record the
    test as a suite with the project_name.test_name. This allows us to track
    each result separately. For tests with only one result (such as exit-code
    tests) we record each one into a suite with the name project_name. The use
    of the project_name allows us to sort subproject tests separately from
    the root project.
    """

    def __init__(self, filename: str) -> None:
        self.filename = filename
        self.root = et.Element(
            'testsuites', tests='0', errors='0', failures='0')
        self.suites: T.Dict[str, et.Element] = {}

    def log(self, harness: 'TestHarness', test: 'TestRun') -> None:
        """Log a single test case."""
        if test.junit is not None:
            for suite in test.junit.findall('.//testsuite'):
                # Assume that we don't need to merge anything here...
                suite.attrib['name'] = '{}.{}.{}'.format(test.project, test.name, suite.attrib['name'])

                # GTest can inject invalid attributes
                for case in suite.findall('.//testcase[@result]'):
                    del case.attrib['result']
                for case in suite.findall('.//testcase[@timestamp]'):
                    del case.attrib['timestamp']
                for case in suite.findall('.//testcase[@file]'):
                    del case.attrib['file']
                for case in suite.findall('.//testcase[@line]'):
                    del case.attrib['line']
                self.root.append(suite)
            return

        # In this case we have a test binary with multiple results.
        # We want to record this so that each result is recorded
        # separately
        if test.results:
            suitename = f'{test.project}.{test.name}'
            assert suitename not in self.suites or harness.options.repeat > 1, 'duplicate suite'

            suite = self.suites[suitename] = et.Element(
                'testsuite',
                name=suitename,
                tests=str(len(test.results)),
                errors=str(sum(1 for r in test.results if r.result in
                               {TestResult.INTERRUPT, TestResult.ERROR})),
                failures=str(sum(1 for r in test.results if r.result in
                                 {TestResult.FAIL, TestResult.UNEXPECTEDPASS, TestResult.TIMEOUT})),
                skipped=str(sum(1 for r in test.results if r.result is TestResult.SKIP)),
                time=str(test.duration),
            )

            for subtest in test.results:
                # Both name and classname are required. Use the suite name as
                # the class name, so that e.g. GitLab groups testcases correctly.
                testcase = et.SubElement(suite, 'testcase', name=str(subtest), classname=suitename)
                if subtest.result is TestResult.SKIP:
                    et.SubElement(testcase, 'skipped')
                elif subtest.result is TestResult.ERROR:
                    et.SubElement(testcase, 'error')
                elif subtest.result is TestResult.FAIL:
                    et.SubElement(testcase, 'failure')
                elif subtest.result is TestResult.UNEXPECTEDPASS:
                    fail = et.SubElement(testcase, 'failure')
                    fail.text = 'Test unexpected passed.'
                elif subtest.result is TestResult.INTERRUPT:
                    fail = et.SubElement(testcase, 'error')
                    fail.text = 'Test was interrupted by user.'
                elif subtest.result is TestResult.TIMEOUT:
                    fail = et.SubElement(testcase, 'error')
                    fail.text = 'Test did not finish before configured timeout.'
                if subtest.explanation:
                    et.SubElement(testcase, 'system-out').text = subtest.explanation
            if test.stdo:
                out = et.SubElement(suite, 'system-out')
                out.text = replace_unencodable_xml_chars(test.stdo.rstrip())
            if test.stde:
                err = et.SubElement(suite, 'system-err')
                err.text = replace_unencodable_xml_chars(test.stde.rstrip())
        else:
            if test.project not in self.suites:
                suite = self.suites[test.project] = et.Element(
                    'testsuite', name=test.project, tests='1', errors='0',
                    failures='0', skipped='0', time=str(test.duration))
            else:
                suite = self.suites[test.project]
                suite.attrib['tests'] = str(int(suite.attrib['tests']) + 1)

            testcase = et.SubElement(suite, 'testcase', name=test.name,
                                     classname=test.project, time=str(test.duration))
            if test.res is TestResult.SKIP:
                et.SubElement(testcase, 'skipped')
                suite.attrib['skipped'] = str(int(suite.attrib['skipped']) + 1)
            elif test.res is TestResult.ERROR:
                et.SubElement(testcase, 'error')
                suite.attrib['errors'] = str(int(suite.attrib['errors']) + 1)
            elif test.res is TestResult.FAIL:
                et.SubElement(testcase, 'failure')
                suite.attrib['failures'] = str(int(suite.attrib['failures']) + 1)
            if test.stdo:
                out = et.SubElement(testcase, 'system-out')
                out.text = replace_unencodable_xml_chars(test.stdo.rstrip())
            if test.stde:
                err = et.SubElement(testcase, 'system-err')
                err.text = replace_unencodable_xml_chars(test.stde.rstrip())

    async def finish(self, harness: 'TestHarness') -> None:
        """Calculate total test counts and write out the xml result."""
        for suite in self.suites.values():
            self.root.append(suite)
            # Skipped is really not allowed in the "testsuits" element
            for attr in ['tests', 'errors', 'failures']:
                self.root.attrib[attr] = str(int(self.root.attrib[attr]) + int(suite.attrib[attr]))

        tree = et.ElementTree(self.root)
        with open(self.filename, 'wb') as f:
            tree.write(f, encoding='utf-8', xml_declaration=True)


class TestRun:
    TEST_NUM = 0
    PROTOCOL_TO_CLASS: T.Dict[TestProtocol, T.Type['TestRun']] = {}

    def __new__(cls, test: TestSerialisation, *args: T.Any, **kwargs: T.Any) -> T.Any:
        return super().__new__(TestRun.PROTOCOL_TO_CLASS[test.protocol])

    def __init__(self, test: TestSerialisation, test_env: T.Dict[str, str],
                 name: str, timeout: T.Optional[int], is_parallel: bool, verbose: bool):
        self.res = TestResult.PENDING
        self.test = test
        self._num: T.Optional[int] = None
        self.name = name
        self.timeout = timeout
        self.results: T.List[TAPParser.Test] = []
        self.returncode: T.Optional[int] = None
        self.starttime: T.Optional[float] = None
        self.duration: T.Optional[float] = None
        self.stdo = ''
        self.stde = ''
        self.additional_error = ''
        self.cmd: T.Optional[T.List[str]] = None
        self.env = test_env
        self.should_fail = test.should_fail
        self.project = test.project_name
        self.junit: T.Optional[et.ElementTree] = None
        self.is_parallel = is_parallel
        self.verbose = verbose
        self.warnings: T.List[str] = []

    def start(self, cmd: T.List[str]) -> None:
        self.res = TestResult.RUNNING
        self.starttime = time.time()
        self.cmd = cmd

    @property
    def num(self) -> int:
        if self._num is None:
            TestRun.TEST_NUM += 1
            self._num = TestRun.TEST_NUM
        return self._num

    @property
    def direct_stdout(self) -> bool:
        return self.verbose and not self.is_parallel and not self.needs_parsing

    def get_results(self) -> str:
        if self.results:
            # running or succeeded
            passed = sum(x.result.is_ok() for x in self.results)
            ran = sum(x.result is not TestResult.SKIP for x in self.results)
            if passed == ran:
                return f'{passed} subtests passed'
            else:
                return f'{passed}/{ran} subtests passed'
        return ''

    def get_exit_status(self) -> str:
        return returncode_to_status(self.returncode)

    def get_details(self) -> str:
        if self.res is TestResult.PENDING:
            return ''
        if self.returncode:
            return self.get_exit_status()
        return self.get_results()

    def _complete(self) -> None:
        if self.res == TestResult.RUNNING:
            self.res = TestResult.OK
        assert isinstance(self.res, TestResult)
        if self.should_fail and self.res in (TestResult.OK, TestResult.FAIL):
            self.res = TestResult.UNEXPECTEDPASS if self.res is TestResult.OK else TestResult.EXPECTEDFAIL
        if self.stdo and not self.stdo.endswith('\n'):
            self.stdo += '\n'
        if self.stde and not self.stde.endswith('\n'):
            self.stde += '\n'
        self.duration = time.time() - self.starttime

    @property
    def cmdline(self) -> T.Optional[str]:
        if not self.cmd:
            return None
        test_only_env = set(self.env.items()) - set(os.environ.items())
        return env_tuple_to_str(test_only_env) + \
            ' '.join(sh_quote(x) for x in self.cmd)

    def complete_skip(self) -> None:
        self.starttime = time.time()
        self.returncode = GNU_SKIP_RETURNCODE
        self.res = TestResult.SKIP
        self._complete()

    def complete(self) -> None:
        self._complete()

    def get_log(self, colorize: bool = False, stderr_only: bool = False) -> str:
        stdo = '' if stderr_only else self.stdo
        if self.stde or self.additional_error:
            res = ''
            if stdo:
                res += mlog.cyan('stdout:').get_text(colorize) + '\n'
                res += stdo
                if res[-1:] != '\n':
                    res += '\n'
            res += mlog.cyan('stderr:').get_text(colorize) + '\n'
            res += join_lines(self.stde, self.additional_error)
        else:
            res = stdo
        if res and res[-1:] != '\n':
            res += '\n'
        return res

    @property
    def needs_parsing(self) -> bool:
        return False

    async def parse(self, harness: 'TestHarness', lines: T.AsyncIterator[str]) -> None:
        async for l in lines:
            pass


class TestRunExitCode(TestRun):

    def complete(self) -> None:
        if self.res != TestResult.RUNNING:
            pass
        elif self.returncode == GNU_SKIP_RETURNCODE:
            self.res = TestResult.SKIP
        elif self.returncode == GNU_ERROR_RETURNCODE:
            self.res = TestResult.ERROR
        else:
            self.res = TestResult.FAIL if bool(self.returncode) else TestResult.OK
        super().complete()

TestRun.PROTOCOL_TO_CLASS[TestProtocol.EXITCODE] = TestRunExitCode


class TestRunGTest(TestRunExitCode):
    def complete(self) -> None:
        filename = f'{self.test.name}.xml'
        if self.test.workdir:
            filename = os.path.join(self.test.workdir, filename)

        try:
            with open(filename, 'r', encoding='utf8', errors='replace') as f:
                self.junit = et.parse(f)
        except FileNotFoundError:
            # This can happen if the test fails to run or complete for some
            # reason, like the rpath for libgtest isn't properly set. ExitCode
            # will handle the failure, don't generate a stacktrace.
            pass
        except et.ParseError as e:
            # ExitCode will handle the failure, don't generate a stacktrace.
            mlog.error(f'Unable to parse {filename}: {e!s}')

        super().complete()

TestRun.PROTOCOL_TO_CLASS[TestProtocol.GTEST] = TestRunGTest


class TestRunTAP(TestRun):
    @property
    def needs_parsing(self) -> bool:
        return True

    def complete(self) -> None:
        if self.returncode != 0 and not self.res.was_killed():
            self.res = TestResult.ERROR
            self.stde = self.stde or ''
            self.stde += f'\n(test program exited with status code {self.returncode})'
        super().complete()

    async def parse(self, harness: 'TestHarness', lines: T.AsyncIterator[str]) -> None:
        res = None
        warnings: T.List[TAPParser.UnknownLine] = []
        version = 12

        async for i in TAPParser().parse_async(lines):
            if isinstance(i, TAPParser.Version):
                version = i.version
            elif isinstance(i, TAPParser.Bailout):
                res = TestResult.ERROR
                harness.log_subtest(self, i.message, res)
            elif isinstance(i, TAPParser.Test):
                self.results.append(i)
                if i.result.is_bad():
                    res = TestResult.FAIL
                harness.log_subtest(self, i.name or f'subtest {i.number}', i.result)
            elif isinstance(i, TAPParser.UnknownLine):
                warnings.append(i)
            elif isinstance(i, TAPParser.Error):
                self.additional_error += 'TAP parsing error: ' + i.message
                res = TestResult.ERROR

        if warnings:
            unknown = str(mlog.yellow('UNKNOWN'))
            width = len(str(max(i.lineno for i in warnings)))
            for w in warnings:
                self.warnings.append(f'stdout: {w.lineno:{width}}: {unknown}: {w.message}')
            if version > 13:
                self.warnings.append('Unknown TAP output lines have been ignored. Please open a feature request to\n'
                                     'implement them, or prefix them with a # if they are not TAP syntax.')
            else:
                self.warnings.append(str(mlog.red('ERROR')) + ': Unknown TAP output lines for a supported TAP version.\n'
                                     'This is probably a bug in the test; if they are not TAP syntax, prefix them with a #')
        if all(t.result is TestResult.SKIP for t in self.results):
            # This includes the case where self.results is empty
            res = TestResult.SKIP

        if res and self.res == TestResult.RUNNING:
            self.res = res

TestRun.PROTOCOL_TO_CLASS[TestProtocol.TAP] = TestRunTAP


class TestRunRust(TestRun):
    @property
    def needs_parsing(self) -> bool:
        return True

    async def parse(self, harness: 'TestHarness', lines: T.AsyncIterator[str]) -> None:
        def parse_res(n: int, name: str, result: str) -> TAPParser.Test:
            if result == 'ok':
                return TAPParser.Test(n, name, TestResult.OK, None)
            elif result == 'ignored':
                return TAPParser.Test(n, name, TestResult.SKIP, None)
            elif result == 'FAILED':
                return TAPParser.Test(n, name, TestResult.FAIL, None)
            return TAPParser.Test(n, name, TestResult.ERROR,
                                  f'Unsupported output from rust test: {result}')

        n = 1
        async for line in lines:
            if line.startswith('test ') and not line.startswith('test result'):
                _, name, _, result = line.rstrip().split(' ')
                name = name.replace('::', '.')
                t = parse_res(n, name, result)
                self.results.append(t)
                harness.log_subtest(self, name, t.result)
                n += 1

        res = None

        if all(t.result is TestResult.SKIP for t in self.results):
            # This includes the case where self.results is empty
            res = TestResult.SKIP
        elif any(t.result is TestResult.ERROR for t in self.results):
            res = TestResult.ERROR
        elif any(t.result is TestResult.FAIL for t in self.results):
            res = TestResult.FAIL

        if res and self.res == TestResult.RUNNING:
            self.res = res

TestRun.PROTOCOL_TO_CLASS[TestProtocol.RUST] = TestRunRust

# Check unencodable characters in xml output and replace them with
# their printable representation
def replace_unencodable_xml_chars(original_str: str) -> str:
    # [1:-1] is needed for removing `'` characters from both start and end
    # of the string
    replacement_lambda = lambda illegal_chr: repr(illegal_chr.group())[1:-1]
    return UNENCODABLE_XML_CHRS_RE.sub(replacement_lambda, original_str)

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

async def read_decode(reader: asyncio.StreamReader,
                      queue: T.Optional['asyncio.Queue[T.Optional[str]]'],
                      console_mode: ConsoleUser) -> str:
    stdo_lines = []
    try:
        while not reader.at_eof():
            # Prefer splitting by line, as that produces nicer output
            try:
                line_bytes = await reader.readuntil(b'\n')
            except asyncio.IncompleteReadError as e:
                line_bytes = e.partial
            except asyncio.LimitOverrunError as e:
                line_bytes = await reader.readexactly(e.consumed)
            if line_bytes:
                line = decode(line_bytes)
                stdo_lines.append(line)
                if console_mode is ConsoleUser.STDOUT:
                    print(line, end='', flush=True)
                if queue:
                    await queue.put(line)
        return ''.join(stdo_lines)
    except asyncio.CancelledError:
        return ''.join(stdo_lines)
    finally:
        if queue:
            await queue.put(None)

def run_with_mono(fname: str) -> bool:
    return fname.endswith('.exe') and not (is_windows() or is_cygwin())

def check_testdata(objs: T.List[TestSerialisation]) -> T.List[TestSerialisation]:
    if not isinstance(objs, list):
        raise MesonVersionMismatchException('', coredata_version)
    for obj in objs:
        if not isinstance(obj, TestSerialisation):
            raise MesonVersionMismatchException('', coredata_version)
        if not hasattr(obj, 'version'):
            raise MesonVersionMismatchException('', coredata_version)
        if major_versions_differ(obj.version, coredata_version):
            raise MesonVersionMismatchException(obj.version, coredata_version)
    return objs

# Custom waiting primitives for asyncio

async def queue_iter(q: 'asyncio.Queue[T.Optional[str]]') -> T.AsyncIterator[str]:
    while True:
        item = await q.get()
        q.task_done()
        if item is None:
            break
        yield item

async def complete(future: asyncio.Future) -> None:
    """Wait for completion of the given future, ignoring cancellation."""
    try:
        await future
    except asyncio.CancelledError:
        pass

async def complete_all(futures: T.Iterable[asyncio.Future],
                       timeout: T.Optional[T.Union[int, float]] = None) -> None:
    """Wait for completion of all the given futures, ignoring cancellation.
       If timeout is not None, raise an asyncio.TimeoutError after the given
       time has passed.  asyncio.TimeoutError is only raised if some futures
       have not completed and none have raised exceptions, even if timeout
       is zero."""

    def check_futures(futures: T.Iterable[asyncio.Future]) -> None:
        # Raise exceptions if needed
        left = False
        for f in futures:
            if not f.done():
                left = True
            elif not f.cancelled():
                f.result()
        if left:
            raise asyncio.TimeoutError

    # Python is silly and does not have a variant of asyncio.wait with an
    # absolute time as deadline.
    loop = asyncio.get_running_loop()
    deadline = None if timeout is None else loop.time() + timeout
    while futures and (timeout is None or timeout > 0):
        done, futures = await asyncio.wait(futures, timeout=timeout,
                                           return_when=asyncio.FIRST_EXCEPTION)
        check_futures(done)
        if deadline:
            timeout = deadline - loop.time()

    check_futures(futures)


class TestSubprocess:
    def __init__(self, p: asyncio.subprocess.Process,
                 stdout: T.Optional[int], stderr: T.Optional[int],
                 postwait_fn: T.Callable[[], None] = None):
        self._process = p
        self.stdout = stdout
        self.stderr = stderr
        self.stdo_task: T.Optional[asyncio.Task[None]] = None
        self.stde_task: T.Optional[asyncio.Task[None]] = None
        self.postwait_fn = postwait_fn
        self.all_futures: T.List[asyncio.Future] = []
        self.queue: T.Optional[asyncio.Queue[T.Optional[str]]] = None

    def stdout_lines(self) -> T.AsyncIterator[str]:
        self.queue = asyncio.Queue()
        return queue_iter(self.queue)

    def communicate(self,
                    test: 'TestRun',
                    console_mode: ConsoleUser) -> T.Tuple[T.Optional[T.Awaitable[str]],
                                                          T.Optional[T.Awaitable[str]]]:
        async def collect_stdo(test: 'TestRun',
                               reader: asyncio.StreamReader,
                               console_mode: ConsoleUser) -> None:
            test.stdo = await read_decode(reader, self.queue, console_mode)

        async def collect_stde(test: 'TestRun',
                               reader: asyncio.StreamReader,
                               console_mode: ConsoleUser) -> None:
            test.stde = await read_decode(reader, None, console_mode)

        # asyncio.ensure_future ensures that printing can
        # run in the background, even before it is awaited
        if self.stdo_task is None and self.stdout is not None:
            decode_coro = collect_stdo(test, self._process.stdout, console_mode)
            self.stdo_task = asyncio.ensure_future(decode_coro)
            self.all_futures.append(self.stdo_task)
        if self.stderr is not None and self.stderr != asyncio.subprocess.STDOUT:
            decode_coro = collect_stde(test, self._process.stderr, console_mode)
            self.stde_task = asyncio.ensure_future(decode_coro)
            self.all_futures.append(self.stde_task)

        return self.stdo_task, self.stde_task

    async def _kill(self) -> T.Optional[str]:
        # Python does not provide multiplatform support for
        # killing a process and all its children so we need
        # to roll our own.
        p = self._process
        try:
            if is_windows():
                subprocess.run(['taskkill', '/F', '/T', '/PID', str(p.pid)])
            else:
                # Send a termination signal to the process group that setsid()
                # created - giving it a chance to perform any cleanup.
                os.killpg(p.pid, signal.SIGTERM)

                # Make sure the termination signal actually kills the process
                # group, otherwise retry with a SIGKILL.
                with suppress(asyncio.TimeoutError):
                    await asyncio.wait_for(p.wait(), timeout=0.5)
                if p.returncode is not None:
                    return None

                os.killpg(p.pid, signal.SIGKILL)

            with suppress(asyncio.TimeoutError):
                await asyncio.wait_for(p.wait(), timeout=1)
            if p.returncode is not None:
                return None

            # 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()
            with suppress(asyncio.TimeoutError):
                await asyncio.wait_for(p.wait(), timeout=1)
            if p.returncode is not None:
                return None
            return 'Test process could not be killed.'
        except ProcessLookupError:
            # Sometimes (e.g. with Wine) this happens.  There's nothing
            # we can do, probably the process already died so just wait
            # for the event loop to pick that up.
            await p.wait()
            return None
        finally:
            if self.stdo_task:
                self.stdo_task.cancel()
            if self.stde_task:
                self.stde_task.cancel()

    async def wait(self, test: 'TestRun') -> None:
        p = self._process

        self.all_futures.append(asyncio.ensure_future(p.wait()))
        try:
            await complete_all(self.all_futures, timeout=test.timeout)
        except asyncio.TimeoutError:
            test.additional_error += await self._kill() or ''
            test.res = TestResult.TIMEOUT
        except asyncio.CancelledError:
            # The main loop must have seen Ctrl-C.
            test.additional_error += await self._kill() or ''
            test.res = TestResult.INTERRUPT
        finally:
            if self.postwait_fn:
                self.postwait_fn()

        test.returncode = p.returncode or 0

class SingleTestRunner:

    def __init__(self, test: TestSerialisation, env: T.Dict[str, str], name: str,
                 options: argparse.Namespace):
        self.test = test
        self.options = options
        self.cmd = self._get_cmd()

        if self.cmd and self.test.extra_paths:
            env['PATH'] = os.pathsep.join(self.test.extra_paths + ['']) + env['PATH']
            winecmd = []
            for c in self.cmd:
                winecmd.append(c)
                if os.path.basename(c).startswith('wine'):
                    env['WINEPATH'] = get_wine_shortpath(
                        winecmd,
                        ['Z:' + p for p in self.test.extra_paths] + env.get('WINEPATH', '').split(';'),
                        self.test.workdir
                    )
                    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 env or not env['MALLOC_PERTURB_']) and not options.benchmark:
            env['MALLOC_PERTURB_'] = str(random.randint(1, 255))

        # Sanitizers do not default to aborting on error. This is counter to
        # expectations when using -Db_sanitize and has led to confusion in the wild
        # in CI. Set our own values of {ASAN,UBSAN}_OPTOINS to rectify this, but
        # only if the user has not defined them.
        if ('ASAN_OPTIONS' not in env or not env['ASAN_OPTIONS']):
            env['ASAN_OPTIONS'] = 'halt_on_error=1:abort_on_error=1:print_summary=1'
        if ('UBSAN_OPTIONS' not in env or not env['UBSAN_OPTIONS']):
            env['UBSAN_OPTIONS'] = 'halt_on_error=1:abort_on_error=1:print_summary=1:print_stacktrace=1'

        if self.options.gdb or self.test.timeout is None or self.test.timeout <= 0:
            timeout = None
        elif self.options.timeout_multiplier is None:
            timeout = self.test.timeout
        elif self.options.timeout_multiplier <= 0:
            timeout = None
        else:
            timeout = self.test.timeout * self.options.timeout_multiplier

        is_parallel = test.is_parallel and self.options.num_processes > 1 and not self.options.gdb
        verbose = (test.verbose or self.options.verbose) and not self.options.quiet
        self.runobj = TestRun(test, env, name, timeout, is_parallel, verbose)

        if self.options.gdb:
            self.console_mode = ConsoleUser.GDB
        elif self.runobj.direct_stdout:
            self.console_mode = ConsoleUser.STDOUT
        else:
            self.console_mode = ConsoleUser.LOGGER

    def _get_test_cmd(self) -> T.Optional[T.List[str]]:
        testentry = self.test.fname[0]
        if self.options.no_rebuild and self.test.cmd_is_built and not os.path.isfile(testentry):
            raise TestException(f'The test program {testentry!r} does not exist. Cannot run tests before building them.')
        if testentry.endswith('.jar'):
            return ['java', '-jar'] + self.test.fname
        elif not self.test.is_cross_built and run_with_mono(testentry):
            return ['mono'] + self.test.fname
        elif self.test.cmd_is_exe and self.test.is_cross_built and self.test.needs_exe_wrapper:
            if self.test.exe_wrapper is None:
                # Can not run test on cross compiled executable
                # because there is no execute wrapper.
                return None
            elif self.test.cmd_is_exe:
                # If the command is not built (ie, its a python script),
                # then we don't check for the exe-wrapper
                if not self.test.exe_wrapper.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_wrapper.name))
                return self.test.exe_wrapper.get_command() + self.test.fname
        return self.test.fname

    def _get_cmd(self) -> T.Optional[T.List[str]]:
        test_cmd = self._get_test_cmd()
        if not test_cmd:
            return None
        return TestHarness.get_wrapper(self.options) + test_cmd

    @property
    def is_parallel(self) -> bool:
        return self.runobj.is_parallel

    @property
    def visible_name(self) -> str:
        return self.runobj.name

    @property
    def timeout(self) -> T.Optional[int]:
        return self.runobj.timeout

    async def run(self, harness: 'TestHarness') -> TestRun:
        if self.cmd is None:
            self.stdo = 'Not run because cannot execute cross compiled binaries.'
            harness.log_start_test(self.runobj)
            self.runobj.complete_skip()
        else:
            cmd = self.cmd + self.test.cmd_args + self.options.test_args
            self.runobj.start(cmd)
            harness.log_start_test(self.runobj)
            await self._run_cmd(harness, cmd)
        return self.runobj

    async def _run_subprocess(self, args: T.List[str], *,
                              stdout: T.Optional[int], stderr: T.Optional[int],
                              env: T.Dict[str, str], cwd: T.Optional[str]) -> TestSubprocess:
        # 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()

        def postwait_fn() -> None:
            if self.options.gdb:
                # Let us accept ^C again
                signal.signal(signal.SIGINT, previous_sigint_handler)

        p = await asyncio.create_subprocess_exec(*args,
                                                 stdout=stdout,
                                                 stderr=stderr,
                                                 env=env,
                                                 cwd=cwd,
                                                 preexec_fn=preexec_fn if not is_windows() else None)
        return TestSubprocess(p, stdout=stdout, stderr=stderr,
                              postwait_fn=postwait_fn if not is_windows() else None)

    async def _run_cmd(self, harness: 'TestHarness', cmd: T.List[str]) -> None:
        if self.console_mode is ConsoleUser.GDB:
            stdout = None
            stderr = None
        else:
            stdout = asyncio.subprocess.PIPE
            stderr = asyncio.subprocess.STDOUT \
                if not self.options.split and not self.runobj.needs_parsing \
                else asyncio.subprocess.PIPE

        extra_cmd: T.List[str] = []
        if self.test.protocol is TestProtocol.GTEST:
            gtestname = self.test.name
            if self.test.workdir:
                gtestname = os.path.join(self.test.workdir, self.test.name)
            extra_cmd.append(f'--gtest_output=xml:{gtestname}.xml')

        p = await self._run_subprocess(cmd + extra_cmd,
                                       stdout=stdout,
                                       stderr=stderr,
                                       env=self.runobj.env,
                                       cwd=self.test.workdir)

        if self.runobj.needs_parsing:
            parse_coro = self.runobj.parse(harness, p.stdout_lines())
            parse_task = asyncio.ensure_future(parse_coro)
        else:
            parse_task = None

        stdo_task, stde_task = p.communicate(self.runobj, self.console_mode)
        await p.wait(self.runobj)

        if parse_task:
            await parse_task
        if stdo_task:
            await stdo_task
        if stde_task:
            await stde_task

        self.runobj.complete()


class TestHarness:
    def __init__(self, options: argparse.Namespace):
        self.options = options
        self.collected_failures: T.List[TestRun] = []
        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.test_count = 0
        self.name_max_len = 0
        self.is_run = False
        self.loggers: T.List[TestLogger] = []
        self.console_logger = ConsoleLogger()
        self.loggers.append(self.console_logger)
        self.need_console = False
        self.ninja: T.List[str] = None

        self.logfile_base: T.Optional[str] = None
        if self.options.logbase and not self.options.gdb:
            namebase = None
            self.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:
                self.logfile_base += '-' + namebase.replace(' ', '_')

        self.prepare_build()
        self.load_metadata()

        ss = set()
        for t in self.tests:
            for s in t.suite:
                ss.add(s)
        self.suites = list(ss)

    def get_console_logger(self) -> 'ConsoleLogger':
        assert self.console_logger
        return self.console_logger

    def prepare_build(self) -> None:
        if self.options.no_rebuild:
            return

        self.ninja = environment.detect_ninja()
        if not self.ninja:
            print("Can't find ninja, can't rebuild test.")
            # If ninja can't be found return exit code 127, indicating command
            # not found for shell, which seems appropriate here. This works
            # nicely for `git bisect run`, telling it to abort - no point in
            # continuing if there's no ninja.
            sys.exit(127)

    def load_metadata(self) -> None:
        startdir = os.getcwd()
        try:
            os.chdir(self.options.wd)

            # Before loading build / test data, make sure that the build
            # configuration does not need to be regenerated. This needs to
            # happen before rebuild_deps(), because we need the correct list of
            # tests and their dependencies to compute
            if not self.options.no_rebuild:
                teststdo = subprocess.run(self.ninja + ['-n', 'build.ninja'], capture_output=True).stdout
                if b'ninja: no work to do.' not in teststdo and b'samu: nothing to do' not in teststdo:
                    stdo = sys.stderr if self.options.list else sys.stdout
                    ret = subprocess.run(self.ninja + ['build.ninja'], stdout=stdo.fileno())
                    if ret.returncode != 0:
                        raise TestException(f'Could not configure {self.options.wd!r}')

            self.build_data = build.load(os.getcwd())
            if not self.options.setup:
                self.options.setup = self.build_data.test_setup_default_name
            if self.options.benchmark:
                self.tests = self.load_tests('meson_benchmark_setup.dat')
            else:
                self.tests = self.load_tests('meson_test_setup.dat')
        finally:
            os.chdir(startdir)

    def load_tests(self, file_name: str) -> T.List[TestSerialisation]:
        datafile = Path('meson-private') / file_name
        if not datafile.is_file():
            raise TestException(f'Directory {self.options.wd!r} does not seem to be a Meson build directory.')
        with datafile.open('rb') as f:
            objs = check_testdata(pickle.load(f))
        return objs

    def __enter__(self) -> 'TestHarness':
        return self

    def __exit__(self, exc_type: T.Any, exc_value: T.Any, traceback: T.Any) -> None:
        self.close_logfiles()

    def close_logfiles(self) -> None:
        for l in self.loggers:
            l.close()
        self.console_logger = None

    def get_test_setup(self, test: T.Optional[TestSerialisation]) -> build.TestSetup:
        if ':' in self.options.setup:
            if self.options.setup not in self.build_data.test_setups:
                sys.exit(f"Unknown test setup '{self.options.setup}'.")
            return self.build_data.test_setups[self.options.setup]
        else:
            full_name = test.project_name + ":" + self.options.setup
            if full_name not in self.build_data.test_setups:
                sys.exit(f"Test setup '{self.options.setup}' not found from project '{test.project_name}'.")
            return self.build_data.test_setups[full_name]

    def merge_setup_options(self, options: argparse.Namespace, test: TestSerialisation) -> T.Dict[str, str]:
        current = self.get_test_setup(test)
        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 None:
            options.wrapper = current.exe_wrapper
        elif current.exe_wrapper:
            sys.exit('Conflict: both test setup and command line specify an exe wrapper.')
        return current.env.get_env(os.environ.copy())

    def get_test_runner(self, test: TestSerialisation) -> SingleTestRunner:
        name = self.get_pretty_suite(test)
        options = deepcopy(self.options)
        if self.options.setup:
            env = self.merge_setup_options(options, test)
        else:
            env = os.environ.copy()
        test_env = test.env.get_env(env)
        env.update(test_env)
        if (test.is_cross_built and test.needs_exe_wrapper and
                test.exe_wrapper and test.exe_wrapper.found()):
            env['MESON_EXE_WRAPPER'] = join_args(test.exe_wrapper.get_command())
        return SingleTestRunner(test, env, name, 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 in {TestResult.FAIL, TestResult.ERROR, TestResult.INTERRUPT}:
            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(f'Unknown test result encountered: {result.res}')

        if result.res.is_bad():
            self.collected_failures.append(result)
        for l in self.loggers:
            l.log(self, result)

    @property
    def numlen(self) -> int:
        return len(str(self.test_count))

    @property
    def max_left_width(self) -> int:
        return 2 * self.numlen + 2

    def get_test_num_prefix(self, num: int) -> str:
        return '{num:{numlen}}/{testcount} '.format(numlen=self.numlen,
                                                    num=num,
                                                    testcount=self.test_count)

    def format(self, result: TestRun, colorize: bool,
               max_left_width: int = 0,
               prefix: str = '',
               left: T.Optional[str] = None,
               middle: T.Optional[str] = None,
               right: T.Optional[str] = None) -> str:
        if left is None:
            left = self.get_test_num_prefix(result.num)

        # A non-default max_left_width lets the logger print more stuff before the
        # name, while ensuring that the rightmost columns remain aligned.
        max_left_width = max(max_left_width, self.max_left_width)

        if middle is None:
            middle = result.name
        extra_mid_width = max_left_width + self.name_max_len + 1 - uniwidth(middle) - uniwidth(left) - uniwidth(prefix)
        middle += ' ' * max(1, extra_mid_width)

        if right is None:
            right = '{res} {dur:{durlen}.2f}s'.format(
                res=result.res.get_text(colorize),
                dur=result.duration,
                durlen=self.duration_max_len + 3)
            details = result.get_details()
            if details:
                right += '   ' + details
        return prefix + left + middle + right

    def summary(self) -> str:
        return textwrap.dedent('''
            Ok:                 {:<4}
            Expected Fail:      {:<4}
            Fail:               {:<4}
            Unexpected Pass:    {:<4}
            Skipped:            {:<4}
            Timeout:            {:<4}
            ''').format(self.success_count, self.expectedfail_count, self.fail_count,
                        self.unexpectedpass_count, self.skip_count, self.timeout_count)

    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
        if not self.options.no_rebuild and not rebuild_deps(self.ninja, self.options.wd, tests):
            # 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.
            sys.exit(125)

        self.name_max_len = max(uniwidth(self.get_pretty_suite(test)) for test in tests)
        self.options.num_processes = min(self.options.num_processes,
                                         len(tests) * self.options.repeat)
        startdir = os.getcwd()
        try:
            os.chdir(self.options.wd)
            runners: T.List[SingleTestRunner] = []
            for i in range(self.options.repeat):
                runners.extend(self.get_test_runner(test) for test in tests)
                if i == 0:
                    self.duration_max_len = max(len(str(int(runner.timeout or 99)))
                                                for runner in runners)
                    # Disable the progress report if it gets in the way
                    self.need_console = any(runner.console_mode is not ConsoleUser.LOGGER
                                            for runner in runners)

            self.test_count = len(runners)
            self.run_tests(runners)
        finally:
            os.chdir(startdir)
        return self.total_failure_count()

    @staticmethod
    def split_suite_string(suite: str) -> T.Tuple[str, str]:
        if ':' in suite:
            split = suite.split(':', 1)
            assert len(split) == 2
            return split[0], 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:
        if TestHarness.test_in_suites(test, self.options.exclude_suites):
            return False

        if self.options.include_suites:
            # Both force inclusion (overriding add_test_setup) and exclude
            # everything else
            return TestHarness.test_in_suites(test, self.options.include_suites)

        if self.options.setup:
            setup = self.get_test_setup(test)
            if TestHarness.test_in_suites(test, setup.exclude_suites):
                return False

        return True

    def tests_from_args(self, tests: T.List[TestSerialisation]) -> T.Generator[TestSerialisation, None, None]:
        '''
        Allow specifying test names like "meson test foo1 foo2", where test('foo1', ...)

        Also support specifying the subproject to run tests from like
        "meson test subproj:" (all tests inside subproj) or "meson test subproj:foo1"
        to run foo1 inside subproj. Coincidentally also "meson test :foo1" to
        run all tests with that name across all subprojects, which is
        identical to "meson test foo1"
        '''
        patterns: T.Dict[T.Tuple[str, str], bool] = {}
        for arg in self.options.args:
            # Replace empty components by wildcards:
            # '' -> '*:*'
            # 'name' -> '*:name'
            # ':name' -> '*:name'
            # 'proj:' -> 'proj:*'
            if ':' in arg:
                subproj, name = arg.split(':', maxsplit=1)
                if name == '':
                    name = '*'
                if subproj == '':  # in case arg was ':'
                    subproj = '*'
            else:
                subproj, name = '*', arg
            patterns[(subproj, name)] = False

        for t in tests:
            # For each test, find the first matching pattern
            # and mark it as used. yield the matching tests.
            for subproj, name in list(patterns):
                if fnmatch(t.project_name, subproj) and fnmatch(t.name, name):
                    patterns[(subproj, name)] = True
                    yield t
                    break

        for (subproj, name), was_used in patterns.items():
            if not was_used:
                # For each unused pattern...
                arg = f'{subproj}:{name}'
                for t in tests:
                    # ... if it matches a test, then it wasn't used because another
                    # pattern matched the same test before.
                    # Report it as a warning.
                    if fnmatch(t.project_name, subproj) and fnmatch(t.name, name):
                        mlog.warning(f'{arg} test name is redundant and was not used')
                        break
                else:
                    # If the pattern doesn't match any test,
                    # report it as an error. We don't want the `test` command to
                    # succeed on an invalid pattern.
                    raise MesonException(f'{arg} test name does not match any test')

    def get_tests(self, errorfile: T.Optional[T.IO] = None) -> T.List[TestSerialisation]:
        if not self.tests:
            print('No tests defined.', file=errorfile)
            return []

        tests = [t for t in self.tests if self.test_suitable(t)]
        if self.options.args:
            tests = list(self.tests_from_args(tests))

        if not tests:
            print('No suitable tests defined.', file=errorfile)
            return []

        return tests

    def flush_logfiles(self) -> None:
        for l in self.loggers:
            l.flush()

    def open_logfiles(self) -> None:
        if not self.logfile_base:
            return

        self.loggers.append(JunitBuilder(self.logfile_base + '.junit.xml'))
        self.loggers.append(JsonLogfileBuilder(self.logfile_base + '.json'))
        self.loggers.append(TextLogfileBuilder(self.logfile_base + '.txt', errors='surrogateescape'))

    @staticmethod
    def get_wrapper(options: argparse.Namespace) -> T.List[str]:
        wrap: T.List[str] = []
        if options.gdb:
            wrap = [options.gdb_path, '--quiet']
            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 s:
                rv += ":"
            return rv + s + " / " + test.name
        else:
            return test.name

    def run_tests(self, runners: T.List[SingleTestRunner]) -> None:
        try:
            self.open_logfiles()

            # TODO: this is the default for python 3.8
            if sys.platform == 'win32':
                asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())

            asyncio.run(self._run_tests(runners))
        finally:
            self.close_logfiles()

    def log_subtest(self, test: TestRun, s: str, res: TestResult) -> None:
        for l in self.loggers:
            l.log_subtest(self, test, s, res)

    def log_start_test(self, test: TestRun) -> None:
        for l in self.loggers:
            l.start_test(self, test)

    async def _run_tests(self, runners: T.List[SingleTestRunner]) -> None:
        semaphore = asyncio.Semaphore(self.options.num_processes)
        futures: T.Deque[asyncio.Future] = deque()
        running_tests: T.Dict[asyncio.Future, str] = {}
        interrupted = False
        ctrlc_times: T.Deque[float] = deque(maxlen=MAX_CTRLC)
        loop = asyncio.get_running_loop()

        async def run_test(test: SingleTestRunner) -> None:
            async with semaphore:
                if interrupted or (self.options.repeat > 1 and self.fail_count):
                    return
                res = await test.run(self)
                self.process_test_result(res)
                maxfail = self.options.maxfail
                if maxfail and self.fail_count >= maxfail and res.res.is_bad():
                    cancel_all_tests()

        def test_done(f: asyncio.Future) -> None:
            if not f.cancelled():
                f.result()
            futures.remove(f)
            try:
                del running_tests[f]
            except KeyError:
                pass

        def cancel_one_test(warn: bool) -> None:
            future = futures.popleft()
            futures.append(future)
            if warn:
                self.flush_logfiles()
                mlog.warning('CTRL-C detected, interrupting {}'.format(running_tests[future]))
            del running_tests[future]
            future.cancel()

        def cancel_all_tests() -> None:
            nonlocal interrupted
            interrupted = True
            while running_tests:
                cancel_one_test(False)

        def sigterm_handler() -> None:
            if interrupted:
                return
            self.flush_logfiles()
            mlog.warning('Received SIGTERM, exiting')
            cancel_all_tests()

        def sigint_handler() -> None:
            # We always pick the longest-running future that has not been cancelled
            # If all the tests have been CTRL-C'ed, just stop
            nonlocal interrupted
            if interrupted:
                return
            ctrlc_times.append(loop.time())
            if len(ctrlc_times) == MAX_CTRLC and ctrlc_times[-1] - ctrlc_times[0] < 1:
                self.flush_logfiles()
                mlog.warning('CTRL-C detected, exiting')
                cancel_all_tests()
            elif running_tests:
                cancel_one_test(True)
            else:
                self.flush_logfiles()
                mlog.warning('CTRL-C detected, exiting')
                interrupted = True

        for l in self.loggers:
            l.start(self)

        if sys.platform != 'win32':
            if os.getpgid(0) == os.getpid():
                loop.add_signal_handler(signal.SIGINT, sigint_handler)
            else:
                loop.add_signal_handler(signal.SIGINT, sigterm_handler)
            loop.add_signal_handler(signal.SIGTERM, sigterm_handler)
        try:
            for runner in runners:
                if not runner.is_parallel:
                    await complete_all(futures)
                future = asyncio.ensure_future(run_test(runner))
                futures.append(future)
                running_tests[future] = runner.visible_name
                future.add_done_callback(test_done)
                if not runner.is_parallel:
                    await complete(future)
                if self.options.repeat > 1 and self.fail_count:
                    break

            await complete_all(futures)
        finally:
            if sys.platform != 'win32':
                loop.remove_signal_handler(signal.SIGINT)
                loop.remove_signal_handler(signal.SIGTERM)
            for l in self.loggers:
                await l.finish(self)

def list_tests(th: TestHarness) -> bool:
    tests = th.get_tests(errorfile=sys.stderr)
    for t in tests:
        print(th.get_pretty_suite(t))
    return not tests

def rebuild_deps(ninja: T.List[str], wd: str, tests: T.List[TestSerialisation]) -> bool:
    def convert_path_to_target(path: str) -> str:
        path = os.path.relpath(path, wd)
        if os.sep != '/':
            path = path.replace(os.sep, '/')
        return path

    assert len(ninja) > 0

    depends: T.Set[str] = set()
    targets: T.Set[str] = set()
    intro_targets: T.Dict[str, T.List[str]] = {}
    for target in load_info_file(get_infodir(wd), kind='targets'):
        intro_targets[target['id']] = [
            convert_path_to_target(f)
            for f in target['filename']]
    for t in tests:
        for d in t.depends:
            if d in depends:
                continue
            depends.update(d)
            targets.update(intro_targets[d])

    ret = subprocess.run(ninja + ['-C', wd] + sorted(targets)).returncode
    if ret != 0:
        print(f'Could not rebuild {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(f'Could not find requested program: {check_bin!r}')
            return 1

    b = build.load(options.wd)
    need_vsenv = T.cast('bool', b.environment.coredata.get_option(OptionKey('vsenv')))
    setup_vsenv(need_vsenv)

    if not options.no_rebuild:
        backend = b.environment.coredata.get_option(OptionKey('backend'))
        if backend == 'none':
            # nothing to build...
            options.no_rebuild = True
        elif backend != 'ninja':
            print('Only ninja backend is supported to rebuild tests before running them.')
            # Disable, no point in trying to build anything later
            options.no_rebuild = True

    with TestHarness(options) as th:
        try:
            if options.list:
                return list_tests(th)
            return th.doit()
        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)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/munstable_coredata.py0000644000175000017500000001120314562742363021410 0ustar00jpakkanejpakkane# 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 __future__ import annotations


from . import coredata as cdata
from .mesonlib import MachineChoice, OptionKey

import os.path
import pprint
import textwrap

# Note: when adding arguments, please also add them to the completion
# scripts in $MESONSRC/data/shell-completions/
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_option(OptionKey('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 == '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][1] + ": ")
                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 = sorted(v[for_machine].items())
                if items_list:
                    print(f'Cached dependencies for {for_machine.get_lower_case_name()} machine')
                    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), '  '))
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/optinterpreter.py0000644000175000017500000002724314562742363020655 0ustar00jpakkanejpakkane# 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.
from __future__ import annotations

import re
import typing as T

from . import coredata
from . import mesonlib
from . import mparser
from . import mlog
from .interpreterbase import FeatureNew, FeatureDeprecated, typed_pos_args, typed_kwargs, ContainerTypeInfo, KwargInfo
from .interpreter.type_checking import NoneType, in_set_validator

if T.TYPE_CHECKING:
    from .interpreterbase import TYPE_var, TYPE_kwargs
    from .interpreterbase import SubProject
    from typing_extensions import TypedDict, Literal

    _DEPRECATED_ARGS = T.Union[bool, str, T.Dict[str, str], T.List[str]]

    FuncOptionArgs = TypedDict('FuncOptionArgs', {
        'type': str,
        'description': str,
        'yield': bool,
        'choices': T.Optional[T.List[str]],
        'value': object,
        'min': T.Optional[int],
        'max': T.Optional[int],
        'deprecated': _DEPRECATED_ARGS,
        })

    class StringArgs(TypedDict):
        value: str

    class BooleanArgs(TypedDict):
        value: bool

    class ComboArgs(TypedDict):
        value: str
        choices: T.List[str]

    class IntegerArgs(TypedDict):
        value: int
        min: T.Optional[int]
        max: T.Optional[int]

    class StringArrayArgs(TypedDict):
        value: T.Optional[T.Union[str, T.List[str]]]
        choices: T.List[str]

    class FeatureArgs(TypedDict):
        value: Literal['enabled', 'disabled', 'auto']
        choices: T.List[str]


class OptionException(mesonlib.MesonException):
    pass


optname_regex = re.compile('[^a-zA-Z0-9_-]')


class OptionInterpreter:
    def __init__(self, subproject: 'SubProject') -> None:
        self.options: 'coredata.MutableKeyedOptionDictType' = {}
        self.subproject = subproject
        self.option_types: T.Dict[str, T.Callable[..., coredata.UserOption]] = {
            'string': self.string_parser,
            'boolean': self.boolean_parser,
            'combo': self.combo_parser,
            'integer': self.integer_parser,
            'array': self.string_array_parser,
            'feature': self.feature_parser,
        }

    def process(self, option_file: str) -> None:
        try:
            with open(option_file, encoding='utf-8') as f:
                ast = mparser.Parser(f.read(), option_file).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()
            e.file = option_file
            raise e
        for cur in ast.lines:
            try:
                self.current_node = cur
                self.evaluate_statement(cur)
            except mesonlib.MesonException as e:
                e.lineno = cur.lineno
                e.colno = cur.colno
                e.file = option_file
                raise e
            except Exception as e:
                raise mesonlib.MesonException(
                    str(e), lineno=cur.lineno, colno=cur.colno, file=option_file)

    def reduce_single(self, arg: T.Union[str, mparser.BaseNode]) -> 'TYPE_var':
        if isinstance(arg, str):
            return arg
        if isinstance(arg, mparser.ParenthesizedNode):
            return self.reduce_single(arg.inner)
        elif isinstance(arg, (mparser.BaseStringNode, mparser.BooleanNode,
                              mparser.NumberNode)):
            return arg.value
        elif isinstance(arg, mparser.ArrayNode):
            return [self.reduce_single(curarg) for curarg in arg.args.arguments]
        elif isinstance(arg, mparser.DictNode):
            d = {}
            for k, v in arg.args.kwargs.items():
                if not isinstance(k, mparser.BaseStringNode):
                    raise OptionException('Dictionary keys must be a string literal')
                d[k.value] = self.reduce_single(v)
            return d
        elif isinstance(arg, mparser.UMinusNode):
            res = self.reduce_single(arg.value)
            if not isinstance(res, (int, float)):
                raise OptionException('Token after "-" is not a number')
            FeatureNew.single_use('negative numbers in meson_options.txt', '0.54.1', self.subproject)
            return -res
        elif isinstance(arg, mparser.NotNode):
            res = self.reduce_single(arg.value)
            if not isinstance(res, bool):
                raise OptionException('Token after "not" is not a a boolean')
            FeatureNew.single_use('negation ("not") in meson_options.txt', '0.54.1', self.subproject)
            return not res
        elif isinstance(arg, mparser.ArithmeticNode):
            l = self.reduce_single(arg.left)
            r = self.reduce_single(arg.right)
            if not (arg.operation == 'add' and isinstance(l, str) and isinstance(r, str)):
                raise OptionException('Only string concatenation with the "+" operator is allowed')
            FeatureNew.single_use('string concatenation in meson_options.txt', '0.55.0', self.subproject)
            return l + r
        else:
            raise OptionException('Arguments may only be string, int, bool, or array of those.')

    def reduce_arguments(self, args: mparser.ArgumentNode) -> T.Tuple['TYPE_var', 'TYPE_kwargs']:
        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, mparser.IdNode):
                raise OptionException('Keyword argument name is not a string.')
            a = args.kwargs[key]
            reduced_kw[key.value] = self.reduce_single(a)
        return reduced_pos, reduced_kw

    def evaluate_statement(self, node: mparser.BaseNode) -> None:
        if not isinstance(node, mparser.FunctionNode):
            raise OptionException('Option file may only contain option definitions')
        func_name = node.func_name.value
        if func_name != 'option':
            raise OptionException('Only calls to option() are allowed in option files.')
        (posargs, kwargs) = self.reduce_arguments(node.args)
        self.func_option(posargs, kwargs)

    @typed_kwargs(
        'option',
        KwargInfo(
            'type',
            str,
            required=True,
            validator=in_set_validator({'string', 'boolean', 'integer', 'combo', 'array', 'feature'})
        ),
        KwargInfo('description', str, default=''),
        KwargInfo(
            'deprecated',
            (bool, str, ContainerTypeInfo(dict, str), ContainerTypeInfo(list, str)),
            default=False,
            since='0.60.0',
            since_values={str: '0.63.0'},
        ),
        KwargInfo('yield', bool, default=coredata.DEFAULT_YIELDING, since='0.45.0'),
        allow_unknown=True,
    )
    @typed_pos_args('option', str)
    def func_option(self, args: T.Tuple[str], kwargs: 'FuncOptionArgs') -> None:
        opt_name = args[0]
        if optname_regex.search(opt_name) is not None:
            raise OptionException('Option names can only contain letters, numbers or dashes.')
        key = mesonlib.OptionKey.from_string(opt_name).evolve(subproject=self.subproject)
        if not key.is_project():
            raise OptionException('Option name %s is reserved.' % opt_name)

        opt_type = kwargs['type']
        parser = self.option_types[opt_type]
        description = kwargs['description'] or opt_name

        # Drop the arguments we've already consumed
        n_kwargs = {k: v for k, v in kwargs.items()
                    if k not in {'type', 'description', 'deprecated', 'yield'}}

        opt = parser(description, (kwargs['yield'], kwargs['deprecated']), n_kwargs)
        if key in self.options:
            mlog.deprecation(f'Option {opt_name} already exists.')
        self.options[key] = opt

    @typed_kwargs(
        'string option',
        KwargInfo('value', str, default=''),
    )
    def string_parser(self, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: StringArgs) -> coredata.UserOption:
        return coredata.UserStringOption(description, kwargs['value'], *args)

    @typed_kwargs(
        'boolean option',
        KwargInfo(
            'value',
            (bool, str),
            default=True,
            validator=lambda x: None if isinstance(x, bool) or x in {'true', 'false'} else 'boolean options must have boolean values',
            deprecated_values={str: ('1.1.0', 'use a boolean, not a string')},
        ),
    )
    def boolean_parser(self, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: BooleanArgs) -> coredata.UserOption:
        return coredata.UserBooleanOption(description, kwargs['value'], *args)

    @typed_kwargs(
        'combo option',
        KwargInfo('value', (str, NoneType)),
        KwargInfo('choices', ContainerTypeInfo(list, str, allow_empty=False), required=True),
    )
    def combo_parser(self, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: ComboArgs) -> coredata.UserOption:
        choices = kwargs['choices']
        value = kwargs['value']
        if value is None:
            value = kwargs['choices'][0]
        return coredata.UserComboOption(description, choices, value, *args)

    @typed_kwargs(
        'integer option',
        KwargInfo(
            'value',
            (int, str),
            default=True,
            deprecated_values={str: ('1.1.0', 'use an integer, not a string')},
            convertor=int,
        ),
        KwargInfo('min', (int, NoneType)),
        KwargInfo('max', (int, NoneType)),
    )
    def integer_parser(self, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: IntegerArgs) -> coredata.UserOption:
        value = kwargs['value']
        inttuple = (kwargs['min'], kwargs['max'], value)
        return coredata.UserIntegerOption(description, inttuple, *args)

    @typed_kwargs(
        'string array option',
        KwargInfo('value', (ContainerTypeInfo(list, str), str, NoneType)),
        KwargInfo('choices', ContainerTypeInfo(list, str), default=[]),
    )
    def string_array_parser(self, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: StringArrayArgs) -> coredata.UserOption:
        choices = kwargs['choices']
        value = kwargs['value'] if kwargs['value'] is not None else choices
        if isinstance(value, str):
            if value.startswith('['):
                FeatureDeprecated('String value for array option', '1.3.0').use(self.subproject)
            else:
                raise mesonlib.MesonException('Value does not define an array: ' + value)
        return coredata.UserArrayOption(description, value,
                                        choices=choices,
                                        yielding=args[0],
                                        deprecated=args[1])

    @typed_kwargs(
        'feature option',
        KwargInfo('value', str, default='auto', validator=in_set_validator({'auto', 'enabled', 'disabled'})),
    )
    def feature_parser(self, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: FeatureArgs) -> coredata.UserOption:
        return coredata.UserFeatureOption(description, kwargs['value'], *args)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/programs.py0000644000175000017500000004124014562742363017412 0ustar00jpakkanejpakkane# Copyright 2013-2020 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 __future__ import annotations

"""Representations and logic for External and Internal Programs."""

import functools
import os
import shutil
import stat
import sys
import re
import typing as T
from pathlib import Path

from . import mesonlib
from . import mlog
from .mesonlib import MachineChoice, OrderedSet

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


class ExternalProgram(mesonlib.HoldableObject):

    """A program that is found on the system."""

    windows_exts = ('exe', 'msc', 'com', 'bat', 'cmd')
    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
        self.path: T.Optional[str] = None
        self.cached_version: T.Optional[str] = None
        if command is not None:
            self.command = mesonlib.listify(command)
            if mesonlib.is_windows():
                cmd = self.command[0]
                args = self.command[1:]
                # Check whether the specified cmd is a path to a script, in
                # which case we need to insert the interpreter. If not, try to
                # use it as-is.
                ret = self._shebang_to_cmd(cmd)
                if ret:
                    self.command = ret + args
                else:
                    self.command = [cmd] + args
        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

        if self.found():
            # 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.
            for arg in reversed(self.command):
                if arg is not None and os.path.isfile(arg):
                    self.path = arg
                    break
            else:
                self.path = self.command[-1]

        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 summary_value(self) -> T.Union[str, mlog.AnsiDecorator]:
        if not self.found():
            return mlog.red('NO')
        return self.path

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

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

    def get_version(self, interpreter: T.Optional['Interpreter'] = None) -> str:
        if not self.cached_version:
            raw_cmd = self.get_command() + ['--version']
            if interpreter:
                res = interpreter.run_command_impl((self, ['--version']),
                                                   {'capture': True,
                                                    'check': True,
                                                    'env': mesonlib.EnvironmentVariables()},
                                                   True)
                o, e = res.stdout, res.stderr
            else:
                p, o, e = mesonlib.Popen_safe(raw_cmd)
                if p.returncode != 0:
                    cmd_str = mesonlib.join_args(raw_cmd)
                    raise mesonlib.MesonException(f'Command {cmd_str!r} failed with status {p.returncode}.')
            output = o.strip()
            if not output:
                output = e.strip()
            match = re.search(r'([0-9][0-9\.]+)', output)
            if not match:
                raise mesonlib.MesonException(f'Could not find a version number in output of {raw_cmd!r}')
            self.cached_version = match.group(1)
        return self.cached_version

    @classmethod
    def from_bin_list(cls, env: 'Environment', for_machine: MachineChoice, name: str) -> 'ExternalProgram':
        # There is a static `for_machine` for this class because the binary
        # always runs on the build platform. (It's host platform is our build
        # platform.) But some external programs have a target platform, so this
        # is what we are specifying here.
        command = env.lookup_binary_entry(for_machine, 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
        # The WindowsApps directory is a bit of a problem. It contains
        # some zero-sized .exe files which have "reparse points", that
        # might either launch an installed application, or might open
        # a page in the Windows Store to download the application.
        #
        # To handle the case where the python interpreter we're
        # running on came from the Windows Store, if we see the
        # WindowsApps path in the search path, replace it with
        # dirname(sys.executable).
        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)
            elif 'WindowsApps' in sys.executable:
                paths.append(os.path.dirname(sys.executable))
        return os.pathsep.join(paths)

    @staticmethod
    def from_entry(name: str, command: T.Union[str, T.List[str]]) -> 'ExternalProgram':
        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):
            if isinstance(command, str):
                command = [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: str) -> T.Optional[T.List[str]]:
        """
        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, encoding='utf-8') 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(str(e))
        mlog.debug(f'Unusable script {script!r}')
        return None

    def _is_executable(self, path: str) -> bool:
        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: str, search_dir: T.Optional[str]) -> T.Optional[list]:
        if search_dir is None:
            return None
        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 = f'{trial}.{ext}'
                    if os.path.exists(trial_ext):
                        return [trial_ext]
        return None

    def _search_windows_special_cases(self, name: str, command: str) -> T.List[T.Optional[str]]:
        '''
        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 = f'{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: str, search_dir: T.Optional[str]) -> T.List[T.Optional[str]]:
        '''
        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
        # If there is a directory component, do not look in PATH
        if os.path.dirname(name) and not os.path.isabs(name):
            return [None]
        # 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) -> T.List[str]:
        return self.command[:]

    def get_path(self) -> T.Optional[str]:
        return self.path

    def get_name(self) -> str:
        return self.name


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

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

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

    def found(self) -> bool:
        return False


class OverrideProgram(ExternalProgram):

    """A script overriding a program."""


def find_external_program(env: 'Environment', for_machine: MachineChoice, name: str,
                          display_name: str, default_names: T.List[str],
                          allow_default_for_cross: bool = True) -> T.Generator['ExternalProgram', None, None]:
    """Find an external program, checking the cross file plus any default options."""
    potential_names = OrderedSet(default_names)
    potential_names.add(name)
    # Lookup in cross or machine file.
    for potential_name in potential_names:
        potential_cmd = env.lookup_binary_entry(for_machine, potential_name)
        if potential_cmd is not None:
            mlog.debug(f'{display_name} binary for {for_machine} specified from cross file, native file, '
                       f'or env var as {potential_cmd}')
            yield ExternalProgram.from_entry(potential_name, potential_cmd)
            # We never fallback if the user-specified option is no good, so
            # stop returning options.
            return
    mlog.debug(f'{display_name} binary missing from cross or native file, or env var undefined.')
    # Fallback on hard-coded defaults, if a default binary is allowed for use
    # with cross targets, or if this is not a cross target
    if allow_default_for_cross or not (for_machine is MachineChoice.HOST and env.is_cross_build(for_machine)):
        for potential_path in default_names:
            mlog.debug(f'Trying a default {display_name} fallback at', potential_path)
            yield ExternalProgram(potential_path, silent=True)
    else:
        mlog.debug('Default target is not allowed for cross use')
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/rewriter.py0000644000175000017500000012571314562742363017433 0ustar00jpakkanejpakkane# 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 __future__ import annotations

from .ast import IntrospectionInterpreter, BUILD_TARGET_FUNCTIONS, AstConditionLevel, AstIDGenerator, AstIndentationGenerator, AstPrinter
from mesonbuild.mesonlib import MesonException, setup_vsenv
from . import mlog, environment
from functools import wraps
from .mparser import Token, ArrayNode, ArgumentNode, AssignmentNode, BaseStringNode, BooleanNode, ElementaryNode, IdNode, FunctionNode, StringNode, SymbolNode
import json, os, re, sys
import typing as T

if T.TYPE_CHECKING:
    from .mparser import BaseNode

class RewriterException(MesonException):
    pass

# Note: when adding arguments, please also add them to the completion
# scripts in $MESONSRC/data/shell-completions/
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', aliases=['tgt'], 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', 'add_extra_files', 'rm_extra_files', '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', aliases=['def'], 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', aliases=['cmd'], 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

def _symbol(val: str) -> SymbolNode:
    return SymbolNode(Token('', '', 0, 0, 0, (0, 0), val))

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
        raise RewriterException('Internal error: _new_node of MTypeBase was called')

    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 BooleanNode(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 IdNode(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(_symbol('['), ArgumentNode(Token('', '', 0, 0, 0, None, '')), _symbol(']'))

    def _new_element_node(self, value):
        # Overwrite in derived class
        raise RewriterException('Internal error: _new_element_node of MTypeList was called')

    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, BaseStringNode):
            return node.value == value
        return False

    def _check_regex_matches(self, node, regex: str) -> bool:
        if isinstance(node, BaseStringNode):
            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, BaseStringNode):
            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', 'extra_files_add', 'extra_files_rm', '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.modified_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 in {i['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]
            if isinstance(node, FunctionNode):
                if node.func_name.value in {'executable', 'jar', 'library', 'shared_library', 'shared_module', 'static_library', 'both_libraries'}:
                    tgt = self.interpreter.assign_vals[target]

        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]
            if isinstance(node, FunctionNode):
                if node.func_name.value == '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': [f'{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 = {
            **{str(k): v for k, v in cdata.options.items()},
            **{str(k): v for k, v in cdata.options.items()},
            **{str(k): v for k, v in cdata.options.items()},
            **{str(k): v for k, v in cdata.options.items()},
            **{str(k): v for k, v in cdata.options.items()},
        }

        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'] += [f'{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':
            # msys bash may expand '/' to a path. It will mangle '//' to '/'
            # but in order to keep usage shell-agnostic, also allow `//` as
            # the function ID such that it will work in both msys bash and
            # other shells.
            if {'/', '//'}.isdisjoint({cmd['id']}):
                mlog.error('The ID for the function type project must be "/" or "//" not "' + cmd['id'] + '"', *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)
        # Transform the key nodes to plain strings
        arg_node.kwargs = {k.value: v for k, v in arg_node.kwargs.items()}

        # 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
            modifier = kwargs_def[key](arg_node.kwargs[key])
            if not modifier.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))
                modifier.set_value(val)
            elif cmd['operation'] == 'add':
                mlog.log('  -- Adding', mlog.yellow(val_str), 'to', mlog.bold(key))
                modifier.add_value(val)
            elif cmd['operation'] == 'remove':
                mlog.log('  -- Removing', mlog.yellow(val_str), 'from', mlog.bold(key))
                modifier.remove_value(val)
            elif cmd['operation'] == 'remove_regex':
                mlog.log('  -- Removing all values matching', mlog.yellow(val_str), 'from', mlog.bold(key))
                modifier.remove_regex(val)

            # Write back the result
            arg_node.kwargs[key] = modifier.get_node()
            num_changed += 1

        # Convert the keys back to IdNode's
        arg_node.kwargs = {IdNode(Token('', '', 0, 0, 0, None, k)): v for k, v in arg_node.kwargs.items()}
        for k, v in arg_node.kwargs.items():
            k.level = v.level
        if num_changed > 0 and node not in self.modified_nodes:
            self.modified_nodes += [node]

    def find_assignment_node(self, node: BaseNode) -> AssignmentNode:
        if 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.value 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, BaseStringNode):
                        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(f'{node.filename}:{node.lineno}'))
                token = Token('string', node.filename, 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.modified_nodes:
                self.modified_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, BaseStringNode):
                            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(f'{string_node.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.modified_nodes:
                    self.modified_nodes += [root]

        elif cmd['operation'] == 'extra_files_add':
            tgt_function: FunctionNode = target['node']
            mark_array = True
            try:
                node = target['extra_files'][0]
            except IndexError:
                # Specifying `extra_files` with a list that flattens to empty gives an empty
                # target['extra_files'] list, account for that.
                try:
                    extra_files_key = next(k for k in tgt_function.args.kwargs.keys() if isinstance(k, IdNode) and k.value == 'extra_files')
                    node = tgt_function.args.kwargs[extra_files_key]
                except StopIteration:
                    # Target has no extra_files kwarg, create one
                    node = ArrayNode(_symbol('['), ArgumentNode(Token('', tgt_function.filename, 0, 0, 0, None, '[]')), _symbol(']'))
                    tgt_function.args.kwargs[IdNode(Token('string', tgt_function.filename, 0, 0, 0, None, 'extra_files'))] = node
                    mark_array = False
                    if tgt_function not in self.modified_nodes:
                        self.modified_nodes += [tgt_function]
                target['extra_files'] = [node]
            if isinstance(node, IdNode):
                node = self.interpreter.assignments[node.value]
                target['extra_files'] = [node]
            if not isinstance(node, ArrayNode):
                mlog.error('Target', mlog.bold(cmd['target']), 'extra_files argument must be a list', *self.on_error())
                return self.handle_error()

            # Generate the current extra files list
            extra_files_list = []
            for i in target['extra_files']:
                for j in arg_list_from_node(i):
                    if isinstance(j, BaseStringNode):
                        extra_files_list += [j.value]

            # Generate the new String nodes
            to_append = []
            for i in sorted(set(cmd['sources'])):
                if i in extra_files_list:
                    mlog.log('  -- Extra file', mlog.green(i), 'is already defined for the target --> skipping')
                    continue
                mlog.log('  -- Adding extra file', mlog.green(i), 'at',
                         mlog.yellow(f'{node.filename}:{node.lineno}'))
                token = Token('string', node.filename, 0, 0, 0, None, i)
                to_append += [StringNode(token)]

            # Append to the AST at the right place
            arg_node = node.args
            arg_node.arguments += to_append

            # Mark the node as modified
            if arg_node not in to_sort_nodes:
                to_sort_nodes += [arg_node]
            # If the extra_files array is newly created, don't mark it as its parent function node already is,
            # otherwise this would cause double modification.
            if mark_array and node not in self.modified_nodes:
                self.modified_nodes += [node]

        elif cmd['operation'] == 'extra_files_rm':
            # Helper to find the exact string node and its parent
            def find_node(src):
                for i in target['extra_files']:
                    for j in arg_list_from_node(i):
                        if isinstance(j, BaseStringNode):
                            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 extra file', mlog.green(i), 'in the target')
                    continue

                # Remove the found string node from the argument list
                arg_node = root.args
                mlog.log('  -- Removing extra file', mlog.green(i), 'from',
                         mlog.yellow(f'{string_node.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.modified_nodes:
                    self.modified_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'
            filename = os.path.join(cmd['subdir'], environment.build_filename)

            # Build src list
            src_arg_node = ArgumentNode(Token('string', filename, 0, 0, 0, None, ''))
            src_arr_node = ArrayNode(_symbol('['), src_arg_node, _symbol(']'))
            src_far_node = ArgumentNode(Token('string', filename, 0, 0, 0, None, ''))
            src_fun_node = FunctionNode(IdNode(Token('id', filename, 0, 0, 0, (0, 0), 'files')), _symbol('('), src_far_node, _symbol(')'))
            src_ass_node = AssignmentNode(IdNode(Token('id', filename, 0, 0, 0, (0, 0), source_id)), _symbol('='), src_fun_node)
            src_arg_node.arguments = [StringNode(Token('string', filename, 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', filename, 0, 0, 0, None, ''))
            tgt_fun_node = FunctionNode(IdNode(Token('id', filename, 0, 0, 0, (0, 0), cmd['target_type'])), _symbol('('), tgt_arg_node, _symbol(')'))
            tgt_ass_node = AssignmentNode(IdNode(Token('id', filename, 0, 0, 0, (0, 0), target_id)), _symbol('='), tgt_fun_node)
            tgt_arg_node.arguments = [
                StringNode(Token('string', filename, 0, 0, 0, None, cmd['target'])),
                IdNode(Token('string', filename, 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(f'{to_remove.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, BaseStringNode):
                        src_list += [j.value]
            extra_files_list = []
            for i in target['extra_files']:
                for j in arg_list_from_node(i):
                    if isinstance(j, BaseStringNode):
                        extra_files_list += [j.value]
            test_data = {
                'name': target['name'],
                'sources': src_list,
                'extra_files': extra_files_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, BaseStringNode)]
            sources = [x for x in i.arguments if isinstance(x, BaseStringNode)]
            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, 'filename') for x in self.modified_nodes)
        assert all(hasattr(x, 'lineno') and hasattr(x, 'colno') and hasattr(x, 'filename') for x in self.to_remove_nodes)
        assert all(isinstance(x, (ArrayNode, FunctionNode)) for x in self.modified_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.modified_nodes]
        work_nodes += [{'node': x, 'action': 'rm'} for x in self.to_remove_nodes]
        work_nodes = 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': i['node'].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', encoding='utf-8'):
                    pass
            with open(fpath, encoding='utf-8') 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'] == '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', encoding='utf-8') as fp:
                fp.write(val['raw'])

target_operation_map = {
    'add': 'src_add',
    'rm': 'src_rm',
    'add_target': 'target_add',
    'rm_target': 'target_rm',
    'add_extra_files': 'extra_files_add',
    'rm_extra_files': 'extra_files_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 generate_cmd(options) -> T.List[dict]:
    if os.path.exists(options.json):
        with open(options.json, encoding='utf-8') 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': generate_cmd,
    'cmd': generate_cmd,
}

def run(options):
    if not options.verbose:
        mlog.set_quiet()

    try:
        setup_vsenv()
        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()
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.7546396
meson-1.3.2/mesonbuild/scripts/0000755000175000017500000000000014562742414016671 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/__init__.py0000644000175000017500000000145014562742363021005 0ustar00jpakkanejpakkane# 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 pathlib import PurePath

def destdir_join(d1: str, d2: str) -> str:
    if not d1:
        return d2
    # c:\destdir + c:\prefix must produce c:\destdir\prefix
    return str(PurePath(d1, *PurePath(d2).parts[1:]))
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/clangformat.py0000644000175000017500000000446014562742363021547 0ustar00jpakkanejpakkane# 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.
from __future__ import annotations

import argparse
import subprocess
from pathlib import Path

from .run_tool import run_tool
from ..environment import detect_clangformat
from ..mesonlib import version_compare
from ..programs import ExternalProgram
import typing as T

def run_clang_format(fname: Path, exelist: T.List[str], check: bool, cformat_ver: T.Optional[str]) -> subprocess.CompletedProcess:
    clangformat_10 = False
    if check and cformat_ver:
        if version_compare(cformat_ver, '>=10'):
            clangformat_10 = True
            exelist = exelist + ['--dry-run', '--Werror']
        else:
            original = fname.read_bytes()
    before = fname.stat().st_mtime
    ret = subprocess.run(exelist + ['-style=file', '-i', str(fname)])
    after = fname.stat().st_mtime
    if before != after:
        print('File reformatted: ', fname)
        if check and not clangformat_10:
            # Restore the original if only checking.
            fname.write_bytes(original)
            ret.returncode = 1
    return ret

def run(args: T.List[str]) -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument('--check', action='store_true')
    parser.add_argument('sourcedir')
    parser.add_argument('builddir')
    options = parser.parse_args(args)

    srcdir = Path(options.sourcedir)
    builddir = Path(options.builddir)

    exelist = detect_clangformat()
    if not exelist:
        print('Could not execute clang-format "%s"' % ' '.join(exelist))
        return 1

    if options.check:
        cformat_ver = ExternalProgram('clang-format', exelist, silent=True).get_version()
    else:
        cformat_ver = None

    return run_tool('clang-format', srcdir, builddir, run_clang_format, exelist, options.check, cformat_ver)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/clangtidy.py0000644000175000017500000000300414562742363021221 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import argparse
import subprocess
from pathlib import Path

from .run_tool import run_tool
import typing as T

def run_clang_tidy(fname: Path, builddir: Path) -> subprocess.CompletedProcess:
    return subprocess.run(['clang-tidy', '-p', str(builddir), str(fname)])

def run_clang_tidy_fix(fname: Path, builddir: Path) -> subprocess.CompletedProcess:
    return subprocess.run(['run-clang-tidy', '-fix', '-format', '-quiet', '-p', str(builddir), str(fname)])

def run(args: T.List[str]) -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument('--fix', action='store_true')
    parser.add_argument('sourcedir')
    parser.add_argument('builddir')
    options = parser.parse_args(args)

    srcdir = Path(options.sourcedir)
    builddir = Path(options.builddir)

    run_func = run_clang_tidy_fix if options.fix else run_clang_tidy
    return run_tool('clang-tidy', srcdir, builddir, run_func, builddir)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/cleantrees.py0000644000175000017500000000274414562742363021402 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import os
import sys
import shutil
import pickle
import typing as T

def rmtrees(build_dir: str, trees: T.List[str]) -> None:
    for t in trees:
        # Never delete trees outside of the builddir
        if os.path.isabs(t):
            print(f'Cannot delete dir with absolute path {t!r}')
            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: T.List[str]) -> int:
    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:])
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336264.0
meson-1.3.2/mesonbuild/scripts/cmake_run_ctgt.py0000755000175000017500000000630014516507010022220 0ustar00jpakkanejpakkane#!/usr/bin/env python3
from __future__ import annotations

import argparse
import subprocess
import shutil
import sys
from pathlib import Path
import typing as T

def run(argsv: T.List[str]) -> int:
    commands: T.List[T.List[str]] = [[]]
    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=f'A "{SEPARATOR}" separated list of commands')

    # Parse
    args = parser.parse_args(argsv)
    directory = Path(args.directory)

    dummy_target = None
    if len(args.outputs) == 1 and len(args.original_outputs) == 0:
        dummy_target = Path(args.outputs[0])
    elif len(args.outputs) != len(args.original_outputs):
        print('Length of output list and original output list differ')
        return 1

    for i in args.commands:
        if i == SEPARATOR:
            commands += [[]]
            continue

        i = i.replace('"', '')  # Remove leftover quotes
        commands[-1] += [i]

    # Execute
    for i in commands:
        # Skip empty lists
        if not i:
            continue

        cmd = []
        stdout = None
        stderr = None
        capture_file = ''

        for j in i:
            if j in {'>', '>>'}:
                stdout = subprocess.PIPE
                continue
            elif j in {'&>', '&>>'}:
                stdout = subprocess.PIPE
                stderr = subprocess.STDOUT
                continue

            if stdout is not None or stderr is not None:
                capture_file += j
            else:
                cmd += [j]

        try:
            directory.mkdir(parents=True, exist_ok=True)

            res = subprocess.run(cmd, stdout=stdout, stderr=stderr, cwd=str(directory), check=True)
            if capture_file:
                out_file = directory / capture_file
                out_file.write_bytes(res.stdout)
        except subprocess.CalledProcessError:
            return 1

    if dummy_target:
        dummy_target.touch()
        return 0

    # Copy outputs
    zipped_outputs = zip([Path(x) for x in args.outputs], [Path(x) for x in args.original_outputs])
    for expected, generated in zipped_outputs:
        do_copy = False
        if not expected.exists():
            if not generated.exists():
                print('Unable to find generated file. This can cause the build to fail:')
                print(generated)
                do_copy = False
            else:
                do_copy = True
        elif generated.exists():
            if generated.stat().st_mtime > expected.stat().st_mtime:
                do_copy = True

        if do_copy:
            if expected.exists():
                expected.unlink()
            shutil.copyfile(str(generated), str(expected))

    return 0

if __name__ == '__main__':
    sys.exit(run(sys.argv[1:]))
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0
meson-1.3.2/mesonbuild/scripts/cmd_or_ps.ps10000644000175000017500000000077614316400150021256 0ustar00jpakkanejpakkane# Copied from GStreamer project
# Author: Seungha Yang 
#         Xavier Claessens 

$i=1
$ppid=$PID
do {
  $ppid=(Get-CimInstance Win32_Process -Filter "ProcessId=$ppid").parentprocessid
  $pname=(Get-Process -id $ppid).Name
  if($pname -eq "cmd" -Or $pname -eq "powershell" -Or $pname -eq "pwsh") {
    Write-Host ("{0}.exe" -f $pname)
    Break
  }
  # not found yet, find grand parent
  # 10 times iteration seems to be sufficient
  $i++
} while ($i -lt 10)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/copy.py0000644000175000017500000000063614562742363020225 0ustar00jpakkanejpakkane# SPDX-License-Identifer: Apache-2.0
# Copyright Ā© 2021 Intel Corporation
from __future__ import annotations

"""Helper script to copy files at build time.

This is easier than trying to detect whether to use copy, cp, or something else.
"""

import shutil
import typing as T


def run(args: T.List[str]) -> int:
    try:
        shutil.copy2(args[0], args[1])
    except Exception:
        return 1
    return 0
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/coverage.py0000644000175000017500000002440314562742363021044 0ustar00jpakkanejpakkane# 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 __future__ import annotations

from mesonbuild import environment, mesonlib

import argparse, re, sys, os, subprocess, pathlib, stat
import typing as T

def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build_root: str, log_dir: str, use_llvm_cov: bool) -> int:
    outfiles = []
    exitcode = 0

    (gcovr_exe, gcovr_version, lcov_exe, lcov_version, genhtml_exe, llvm_cov_exe) = environment.find_coverage_tools()

    # load config files for tools if available in the source tree
    # - lcov requires manually specifying a per-project config
    # - gcovr picks up the per-project config, and also supports filtering files
    #   so don't exclude subprojects ourselves, if the project has a config,
    #   because they either don't want that, or should set it themselves
    lcovrc = os.path.join(source_root, '.lcovrc')
    if os.path.exists(lcovrc):
        lcov_config = ['--config-file', lcovrc]
    else:
        lcov_config = []

    if lcov_exe and mesonlib.version_compare(lcov_version, '>=2.0'):
        lcov_exe_rc_branch_coverage = ['--rc', 'branch_coverage=1']
    else:
        lcov_exe_rc_branch_coverage = ['--rc', 'lcov_branch_coverage=1']

    gcovr_config = ['-e', re.escape(subproject_root)]

    # gcovr >= 4.2 requires a different syntax for out of source builds
    if gcovr_exe and mesonlib.version_compare(gcovr_version, '>=4.2'):
        gcovr_base_cmd = [gcovr_exe, '-r', source_root, build_root]
        # it also started supporting the config file
        if os.path.exists(os.path.join(source_root, 'gcovr.cfg')):
            gcovr_config = []
    else:
        gcovr_base_cmd = [gcovr_exe, '-r', build_root]

    if use_llvm_cov:
        gcov_exe_args = ['--gcov-executable', llvm_cov_exe + ' gcov']
    else:
        gcov_exe_args = []

    if not outputs or 'xml' in outputs:
        if gcovr_exe and mesonlib.version_compare(gcovr_version, '>=3.3'):
            subprocess.check_call(gcovr_base_cmd + gcovr_config +
                                  ['-x',
                                   '-o', os.path.join(log_dir, 'coverage.xml')
                                   ] + gcov_exe_args)
            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 'sonarqube' in outputs:
        if gcovr_exe and mesonlib.version_compare(gcovr_version, '>=4.2'):
            subprocess.check_call(gcovr_base_cmd + gcovr_config +
                                  ['--sonarqube',
                                   '-o', os.path.join(log_dir, 'sonarqube.xml'),
                                   ] + gcov_exe_args)
            outfiles.append(('Sonarqube', pathlib.Path(log_dir, 'sonarqube.xml')))
        elif outputs:
            print('gcovr >= 4.2 needed to generate Xml coverage report')
            exitcode = 1

    if not outputs or 'text' in outputs:
        if gcovr_exe and mesonlib.version_compare(gcovr_version, '>=3.3'):
            subprocess.check_call(gcovr_base_cmd + gcovr_config +
                                  ['-o', os.path.join(log_dir, 'coverage.txt')] +
                                  gcov_exe_args)
            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'
            lcov_subpoject_exclude = []
            if os.path.exists(subproject_root):
                lcov_subpoject_exclude.append(os.path.join(subproject_root, '*'))
            if use_llvm_cov:
                # Create a shim to allow using llvm-cov as a gcov tool.
                if mesonlib.is_windows():
                    llvm_cov_shim_path = os.path.join(log_dir, 'llvm-cov.bat')
                    with open(llvm_cov_shim_path, 'w', encoding='utf-8') as llvm_cov_bat:
                        llvm_cov_bat.write(f'@"{llvm_cov_exe}" gcov %*')
                else:
                    llvm_cov_shim_path = os.path.join(log_dir, 'llvm-cov.sh')
                    with open(llvm_cov_shim_path, 'w', encoding='utf-8') as llvm_cov_sh:
                        llvm_cov_sh.write(f'#!/usr/bin/env sh\nexec "{llvm_cov_exe}" gcov $@')
                    os.chmod(llvm_cov_shim_path, os.stat(llvm_cov_shim_path).st_mode | stat.S_IEXEC)
                gcov_tool_args = ['--gcov-tool', llvm_cov_shim_path]
            else:
                gcov_tool_args = []
            subprocess.check_call([lcov_exe,
                                   '--directory', build_root,
                                   '--capture',
                                   '--initial',
                                   '--output-file',
                                   initial_tracefile] +
                                  lcov_config +
                                  gcov_tool_args)
            subprocess.check_call([lcov_exe,
                                   '--directory', build_root,
                                   '--capture',
                                   '--output-file', run_tracefile,
                                   '--no-checksum',
                                   *lcov_exe_rc_branch_coverage] +
                                  lcov_config +
                                  gcov_tool_args)
            # Join initial and test results.
            subprocess.check_call([lcov_exe,
                                   '-a', initial_tracefile,
                                   '-a', run_tracefile,
                                   *lcov_exe_rc_branch_coverage,
                                   '-o', raw_tracefile] + lcov_config)
            # Remove all directories outside the source_root from the covinfo
            subprocess.check_call([lcov_exe,
                                   '--extract', raw_tracefile,
                                   os.path.join(source_root, '*'),
                                   *lcov_exe_rc_branch_coverage,
                                   '--output-file', covinfo] + lcov_config)
            # Remove all directories inside subproject dir
            subprocess.check_call([lcov_exe,
                                   '--remove', covinfo,
                                   *lcov_subpoject_exclude,
                                   *lcov_exe_rc_branch_coverage,
                                   '--ignore-errors', 'unused',
                                   '--output-file', covinfo] + lcov_config)
            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 and mesonlib.version_compare(gcovr_version, '>=3.3'):
            htmloutdir = os.path.join(log_dir, 'coveragereport')
            if not os.path.isdir(htmloutdir):
                os.mkdir(htmloutdir)
            subprocess.check_call(gcovr_base_cmd + gcovr_config +
                                  ['--html',
                                   '--html-details',
                                   '--print-summary',
                                   '-o', os.path.join(htmloutdir, 'index.html'),
                                   ] + gcov_exe_args)
            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: T.List[str]) -> int:
    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('--sonarqube', dest='outputs', action='append_const',
                        const='sonarqube', help='generate Sonarqube Xml report')
    parser.add_argument('--html', dest='outputs', action='append_const',
                        const='html', help='generate Html report')
    parser.add_argument('--use_llvm_cov', action='store_true',
                        help='use llvm-cov')
    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, options.use_llvm_cov)

if __name__ == '__main__':
    sys.exit(run(sys.argv[1:]))
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/delwithsuffix.py0000644000175000017500000000222014562742363022127 0ustar00jpakkanejpakkane# 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.
from __future__ import annotations

import os, sys
import typing as T

def run(args: T.List[str]) -> int:
    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:])
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/depfixer.py0000644000175000017500000004770714562742363021073 0ustar00jpakkanejpakkane# 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.
from __future__ import annotations


import sys
import os
import stat
import struct
import shutil
import subprocess
import typing as T

from ..mesonlib import OrderedSet, generate_list, Popen_safe

SHT_STRTAB = 3
DT_NEEDED = 1
DT_RPATH = 15
DT_RUNPATH = 29
DT_STRTAB = 5
DT_SONAME = 14
DT_MIPS_RLD_MAP_REL = 1879048245

# Global cache for tools
INSTALL_NAME_TOOL = False

class DataSizes:
    def __init__(self, ptrsize: int, is_le: bool) -> None:
        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: T.BinaryIO, ptrsize: int, is_le: bool) -> None:
        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: T.BinaryIO) -> None:
        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: T.BinaryIO, ptrsize: int, is_le: bool) -> None:
        super().__init__(ptrsize, is_le)
        is_64 = ptrsize == 64

# 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: str, verbose: bool = True) -> None:
        self.bfile = bfile
        self.verbose = verbose
        self.sections: T.List[SectionHeader] = []
        self.dynamic: T.List[DynamicEntry] = []
        self.open_bf(bfile)
        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.close_bf()
            raise

    def open_bf(self, bfile: str) -> None:
        self.bf = None
        self.bf_perms = None
        try:
            self.bf = open(bfile, 'r+b')
        except PermissionError as e:
            self.bf_perms = stat.S_IMODE(os.lstat(bfile).st_mode)
            os.chmod(bfile, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
            try:
                self.bf = open(bfile, 'r+b')
            except Exception:
                os.chmod(bfile, self.bf_perms)
                self.bf_perms = None
                raise e

    def close_bf(self) -> None:
        if self.bf is not None:
            if self.bf_perms is not None:
                os.chmod(self.bf.fileno(), self.bf_perms)
                self.bf_perms = None
            self.bf.close()
            self.bf = None

    def __enter__(self) -> 'Elf':
        return self

    def __del__(self) -> None:
        self.close_bf()

    def __exit__(self, exc_type: T.Any, exc_value: T.Any, traceback: T.Any) -> None:
        self.close_bf()

    def detect_elf_type(self) -> T.Tuple[int, bool]:
        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(f'File {self.bfile!r} is not an ELF file.')
            sys.exit(0)
        if data[4] == 1:
            ptrsize = 32
        elif data[4] == 2:
            ptrsize = 64
        else:
            sys.exit(f'File {self.bfile!r} has unknown ELF class.')
        if data[5] == 1:
            is_le = True
        elif data[5] == 2:
            is_le = False
        else:
            sys.exit(f'File {self.bfile!r} has unknown ELF endianness.')
        return ptrsize, is_le

    def parse_header(self) -> None:
        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) -> None:
        self.bf.seek(self.e_shoff)
        for _ in range(self.e_shnum):
            self.sections.append(SectionHeader(self.bf, self.ptrsize, self.is_le))

    def read_str(self) -> bytes:
        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: bytes) -> T.Optional[SectionHeader]:
        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
        return None

    def parse_dynamic(self) -> None:
        sec = self.find_section(b'.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

    @generate_list
    def get_section_names(self) -> T.Generator[str, None, None]:
        section_names = self.sections[self.e_shstrndx]
        for i in self.sections:
            self.bf.seek(section_names.sh_offset + i.sh_name)
            yield self.read_str().decode()

    def get_soname(self) -> T.Optional[str]:
        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:
            return None
        self.bf.seek(strtab.val + soname.val)
        return self.read_str().decode()

    def get_entry_offset(self, entrynum: int) -> T.Optional[int]:
        sec = self.find_section(b'.dynstr')
        for i in self.dynamic:
            if i.d_tag == entrynum:
                res = sec.sh_offset + i.val
                assert isinstance(res, int)
                return res
        return None

    def get_rpath(self) -> T.Optional[str]:
        offset = self.get_entry_offset(DT_RPATH)
        if offset is None:
            return None
        self.bf.seek(offset)
        return self.read_str().decode()

    def get_runpath(self) -> T.Optional[str]:
        offset = self.get_entry_offset(DT_RUNPATH)
        if offset is None:
            return None
        self.bf.seek(offset)
        return self.read_str().decode()

    @generate_list
    def get_deps(self) -> T.Generator[str, None, None]:
        sec = self.find_section(b'.dynstr')
        for i in self.dynamic:
            if i.d_tag == DT_NEEDED:
                offset = sec.sh_offset + i.val
                self.bf.seek(offset)
                yield self.read_str().decode()

    def fix_deps(self, prefix: bytes) -> None:
        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.rsplit(b'/', maxsplit=1)[-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, fname: str, rpath_dirs_to_remove: T.Set[bytes], new_rpath: bytes) -> None:
        # The path to search for can be either rpath or runpath.
        # Fix both of them to be sure.
        self.fix_rpathtype_entry(fname, rpath_dirs_to_remove, new_rpath, DT_RPATH)
        self.fix_rpathtype_entry(fname, rpath_dirs_to_remove, new_rpath, DT_RUNPATH)

    def fix_rpathtype_entry(self, fname: str, rpath_dirs_to_remove: T.Set[bytes], new_rpath: bytes, entrynum: int) -> None:
        rp_off = self.get_entry_offset(entrynum)
        if rp_off is None:
            if self.verbose:
                print(f'File {fname!r} does not have an rpath. It should be a fully static executable.')
            return
        self.bf.seek(rp_off)

        old_rpath = self.read_str()
        # Some rpath entries may come from multiple sources.
        # Only add each one once.
        new_rpaths: OrderedSet[bytes] = OrderedSet()
        if new_rpath:
            new_rpaths.update(new_rpath.split(b':'))
        if old_rpath:
            # Filter out build-only rpath entries
            # added by get_link_dep_subdirs() or
            # specified by user with build_rpath.
            for rpath_dir in old_rpath.split(b':'):
                if not (rpath_dir in rpath_dirs_to_remove or
                        rpath_dir == (b'X' * len(rpath_dir))):
                    if rpath_dir:
                        new_rpaths.add(rpath_dir)

        # Prepend user-specified new entries while preserving the ones that came from pkgconfig etc.
        new_rpath = b':'.join(new_rpaths)

        if len(old_rpath) < len(new_rpath):
            msg = "New rpath must not be longer than the old one.\n Old: {}\n New: {}".format(old_rpath.decode('utf-8'), new_rpath.decode('utf-8'))
            sys.exit(msg)
        # The linker does read-only string deduplication. If there is a
        # string that shares a suffix with the rpath, they might get
        # deduped. 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: int) -> None:
        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: str, rpath_dirs_to_remove: T.Set[bytes], new_rpath: T.Optional[bytes], verbose: bool = True) -> None:
    if new_rpath is not None:
        with Elf(fname, verbose) as e:
            # note: e.get_rpath() and e.get_runpath() may be useful
            e.fix_rpath(fname, rpath_dirs_to_remove, new_rpath)

def get_darwin_rpaths_to_remove(fname: str) -> T.List[str]:
    p, out, _ = Popen_safe(['otool', '-l', fname], stderr=subprocess.DEVNULL)
    if p.returncode != 0:
        raise subprocess.CalledProcessError(p.returncode, p.args, out)
    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: str, new_rpath: str, final_path: str, install_name_mappings: T.Dict[str, str]) -> None:
    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: str) -> None:
    subprocess.check_call(['jar', 'xf', fname, 'META-INF/MANIFEST.MF'])
    with open('META-INF/MANIFEST.MF', 'r+', encoding='utf-8') as f:
        lines = f.readlines()
        f.seek(0)
        for line in lines:
            if not line.startswith('Class-Path:'):
                f.write(line)
        f.truncate()
    # jar -um doesn't allow removing existing attributes.  Use -uM instead,
    # which a) removes the existing manifest from the jar and b) disables
    # special-casing for the manifest file, so we can re-add it as a normal
    # archive member.  This puts the manifest at the end of the jar rather
    # than the beginning, but the spec doesn't forbid that.
    subprocess.check_call(['jar', 'ufM', fname, 'META-INF/MANIFEST.MF'])

def fix_rpath(fname: str, rpath_dirs_to_remove: T.Set[bytes], new_rpath: T.Union[str, bytes], final_path: str, install_name_mappings: T.Dict[str, str], verbose: bool = True) -> None:
    global INSTALL_NAME_TOOL  # pylint: disable=global-statement
    # Static libraries, import libraries, debug information, headers, etc
    # never have rpaths
    # DLLs and EXE currently do not need runtime path fixing
    if fname.endswith(('.a', '.lib', '.pdb', '.h', '.hpp', '.dll', '.exe')):
        return
    try:
        if fname.endswith('.jar'):
            fix_jar(fname)
            return
        if isinstance(new_rpath, str):
            new_rpath = new_rpath.encode('utf8')
        fix_elf(fname, rpath_dirs_to_remove, new_rpath, verbose)
        return
    except SystemExit as e:
        if isinstance(e.code, int) and e.code == 0:
            pass
        else:
            raise
    # We don't look for this on import because it will do a useless PATH lookup
    # on non-mac platforms. That can be expensive on some Windows machines
    # (up to 30ms), which is significant with --only-changed. For details, see:
    # https://github.com/mesonbuild/meson/pull/6612#discussion_r378581401
    if INSTALL_NAME_TOOL is False:
        INSTALL_NAME_TOOL = bool(shutil.which('install_name_tool'))
    if INSTALL_NAME_TOOL:
        if isinstance(new_rpath, bytes):
            new_rpath = new_rpath.decode('utf8')
        fix_darwin(fname, new_rpath, final_path, install_name_mappings)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/depscan.py0000644000175000017500000002266614562742363020677 0ustar00jpakkanejpakkane# Copyright 2020 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 __future__ import annotations

import json
import os
import pathlib
import pickle
import re
import sys
import typing as T

from ..backend.ninjabackend import ninja_quote
from ..compilers.compilers import lang_suffixes

if T.TYPE_CHECKING:
    from ..backend.ninjabackend import TargetDependencyScannerInfo

CPP_IMPORT_RE = re.compile(r'\w*import ([a-zA-Z0-9]+);')
CPP_EXPORT_RE = re.compile(r'\w*export module ([a-zA-Z0-9]+);')

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+)"

FORTRAN_MODULE_RE = re.compile(FORTRAN_MODULE_PAT, re.IGNORECASE)
FORTRAN_SUBMOD_RE = re.compile(FORTRAN_SUBMOD_PAT, re.IGNORECASE)
FORTRAN_USE_RE = re.compile(FORTRAN_USE_PAT, re.IGNORECASE)

class DependencyScanner:
    def __init__(self, pickle_file: str, outfile: str, sources: T.List[str]):
        with open(pickle_file, 'rb') as pf:
            self.target_data: TargetDependencyScannerInfo = pickle.load(pf)
        self.outfile = outfile
        self.sources = sources
        self.provided_by: T.Dict[str, str] = {}
        self.exports: T.Dict[str, str] = {}
        self.needs: T.Dict[str, T.List[str]] = {}
        self.sources_with_exports: T.List[str] = []

    def scan_file(self, fname: str) -> None:
        suffix = os.path.splitext(fname)[1][1:]
        if suffix != 'C':
            suffix = suffix.lower()
        if suffix in lang_suffixes['fortran']:
            self.scan_fortran_file(fname)
        elif suffix in lang_suffixes['cpp']:
            self.scan_cpp_file(fname)
        else:
            sys.exit(f'Can not scan files with suffix .{suffix}.')

    def scan_fortran_file(self, fname: str) -> None:
        fpath = pathlib.Path(fname)
        modules_in_this_file = set()
        for line in fpath.read_text(encoding='utf-8', errors='ignore').split('\n'):
            import_match = FORTRAN_USE_RE.match(line)
            export_match = FORTRAN_MODULE_RE.match(line)
            submodule_export_match = FORTRAN_SUBMOD_RE.match(line)
            if import_match:
                needed = import_match.group(1).lower()
                # In Fortran you have an using declaration also for the module
                # you define in the same file. Prevent circular dependencies.
                if needed not in modules_in_this_file:
                    if fname in self.needs:
                        self.needs[fname].append(needed)
                    else:
                        self.needs[fname] = [needed]
            if export_match:
                exported_module = export_match.group(1).lower()
                assert exported_module not in modules_in_this_file
                modules_in_this_file.add(exported_module)
                if exported_module in self.provided_by:
                    raise RuntimeError(f'Multiple files provide module {exported_module}.')
                self.sources_with_exports.append(fname)
                self.provided_by[exported_module] = fname
                self.exports[fname] = exported_module
            if submodule_export_match:
                # Store submodule "Foo" "Bar" as "foo:bar".
                # A submodule declaration can be both an import and an export declaration:
                #
                # submodule (a1:a2) a3
                #  - requires a1@a2.smod
                #  - produces a1@a3.smod
                parent_module_name_full = submodule_export_match.group(1).lower()
                parent_module_name = parent_module_name_full.split(':')[0]
                submodule_name = submodule_export_match.group(2).lower()
                concat_name = f'{parent_module_name}:{submodule_name}'
                self.sources_with_exports.append(fname)
                self.provided_by[concat_name] = fname
                self.exports[fname] = concat_name
                # Fortran requires that the immediate parent module must be built
                # before the current one. Thus:
                #
                # submodule (parent) parent   <- requires parent.mod (really parent.smod, but they are created at the same time)
                # submodule (a1:a2) a3        <- requires a1@a2.smod
                #
                # a3 does not depend on the a1 parent module directly, only transitively.
                if fname in self.needs:
                    self.needs[fname].append(parent_module_name_full)
                else:
                    self.needs[fname] = [parent_module_name_full]

    def scan_cpp_file(self, fname: str) -> None:
        fpath = pathlib.Path(fname)
        for line in fpath.read_text(encoding='utf-8', errors='ignore').split('\n'):
            import_match = CPP_IMPORT_RE.match(line)
            export_match = CPP_EXPORT_RE.match(line)
            if import_match:
                needed = import_match.group(1)
                if fname in self.needs:
                    self.needs[fname].append(needed)
                else:
                    self.needs[fname] = [needed]
            if export_match:
                exported_module = export_match.group(1)
                if exported_module in self.provided_by:
                    raise RuntimeError(f'Multiple files provide module {exported_module}.')
                self.sources_with_exports.append(fname)
                self.provided_by[exported_module] = fname
                self.exports[fname] = exported_module

    def objname_for(self, src: str) -> str:
        objname = self.target_data.source2object[src]
        assert isinstance(objname, str)
        return objname

    def module_name_for(self, src: str) -> str:
        suffix = os.path.splitext(src)[1][1:].lower()
        if suffix in lang_suffixes['fortran']:
            exported = self.exports[src]
            # Module foo:bar goes to a file name foo@bar.smod
            # Module Foo goes to a file name foo.mod
            namebase = exported.replace(':', '@')
            if ':' in exported:
                extension = 'smod'
            else:
                extension = 'mod'
            return os.path.join(self.target_data.private_dir, f'{namebase}.{extension}')
        elif suffix in lang_suffixes['cpp']:
            return '{}.ifc'.format(self.exports[src])
        else:
            raise RuntimeError('Unreachable code.')

    def scan(self) -> int:
        for s in self.sources:
            self.scan_file(s)
        with open(self.outfile, 'w', encoding='utf-8') as ofile:
            ofile.write('ninja_dyndep_version = 1\n')
            for src in self.sources:
                objfilename = self.objname_for(src)
                mods_and_submods_needed = []
                module_files_generated = []
                module_files_needed = []
                if src in self.sources_with_exports:
                    module_files_generated.append(self.module_name_for(src))
                if src in self.needs:
                    for modname in self.needs[src]:
                        if modname not in self.provided_by:
                            # Nothing provides this module, we assume that it
                            # comes from a dependency library somewhere and is
                            # already built by the time this compilation starts.
                            pass
                        else:
                            mods_and_submods_needed.append(modname)

                for modname in mods_and_submods_needed:
                    provider_src = self.provided_by[modname]
                    provider_modfile = self.module_name_for(provider_src)
                    # Prune self-dependencies
                    if provider_src != src:
                        module_files_needed.append(provider_modfile)

                quoted_objfilename = ninja_quote(objfilename, True)
                quoted_module_files_generated = [ninja_quote(x, True) for x in module_files_generated]
                quoted_module_files_needed = [ninja_quote(x, True) for x in module_files_needed]
                if quoted_module_files_generated:
                    mod_gen = '| ' + ' '.join(quoted_module_files_generated)
                else:
                    mod_gen = ''
                if quoted_module_files_needed:
                    mod_dep = '| ' + ' '.join(quoted_module_files_needed)
                else:
                    mod_dep = ''
                build_line = 'build {} {}: dyndep {}'.format(quoted_objfilename,
                                                             mod_gen,
                                                             mod_dep)
                ofile.write(build_line + '\n')
        return 0

def run(args: T.List[str]) -> int:
    assert len(args) == 3, 'got wrong number of arguments!'
    pickle_file, outfile, jsonfile = args
    with open(jsonfile, encoding='utf-8') as f:
        sources = json.load(f)
    scanner = DependencyScanner(pickle_file, outfile, sources)
    return scanner.scan()
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/dirchanger.py0000644000175000017500000000172114562742363021355 0ustar00jpakkanejpakkane# 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.
from __future__ import annotations

'''CD into dir given as first argument and execute
the command given in the rest of the arguments.'''

import os, subprocess, sys
import typing as T

def run(args: T.List[str]) -> int:
    dirname = args[0]
    command = args[1:]

    os.chdir(dirname)
    return subprocess.call(command)

if __name__ == '__main__':
    sys.exit(run(sys.argv[1:]))
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/env2mfile.py0000755000175000017500000003766014562742363021154 0ustar00jpakkanejpakkane# Copyright 2022 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 __future__ import annotations

import sys, os, subprocess, shutil
import shlex
import typing as T

from .. import envconfig
from .. import mlog
from ..compilers import compilers
from ..compilers.detect import defaults as compiler_names

if T.TYPE_CHECKING:
    import argparse

def has_for_build() -> bool:
    for cenv in envconfig.ENV_VAR_COMPILER_MAP.values():
        if os.environ.get(cenv + '_FOR_BUILD'):
            return True
    return False

# Note: when adding arguments, please also add them to the completion
# scripts in $MESONSRC/data/shell-completions/
def add_arguments(parser: 'argparse.ArgumentParser') -> None:
    parser.add_argument('--debarch', default=None,
                        help='The dpkg architecture to generate.')
    parser.add_argument('--gccsuffix', default="",
                        help='A particular gcc version suffix if necessary.')
    parser.add_argument('-o', required=True, dest='outfile',
                        help='The output file.')
    parser.add_argument('--cross', default=False, action='store_true',
                        help='Generate a cross compilation file.')
    parser.add_argument('--native', default=False, action='store_true',
                        help='Generate a native compilation file.')
    parser.add_argument('--system', default=None,
                        help='Define system for cross compilation.')
    parser.add_argument('--subsystem', default=None,
                        help='Define subsystem for cross compilation.')
    parser.add_argument('--kernel', default=None,
                        help='Define kernel for cross compilation.')
    parser.add_argument('--cpu', default=None,
                        help='Define cpu for cross compilation.')
    parser.add_argument('--cpu-family', default=None,
                        help='Define cpu family for cross compilation.')
    parser.add_argument('--endian', default='little', choices=['big', 'little'],
                        help='Define endianness for cross compilation.')

class MachineInfo:
    def __init__(self) -> None:
        self.compilers: T.Dict[str, T.List[str]] = {}
        self.binaries: T.Dict[str, T.List[str]] = {}
        self.properties: T.Dict[str, T.Union[str, T.List[str]]] = {}
        self.compile_args: T.Dict[str, T.List[str]] = {}
        self.link_args: T.Dict[str, T.List[str]] = {}
        self.cmake: T.Dict[str, T.Union[str, T.List[str]]] = {}

        self.system: T.Optional[str] = None
        self.subsystem: T.Optional[str] = None
        self.kernel: T.Optional[str] = None
        self.cpu: T.Optional[str] = None
        self.cpu_family: T.Optional[str] = None
        self.endian: T.Optional[str] = None

#parser = argparse.ArgumentParser(description='''Generate cross compilation definition file for the Meson build system.
#
#If you do not specify the --arch argument, Meson assumes that running
#plain 'dpkg-architecture' will return correct information for the
#host system.
#
#This script must be run in an environment where CPPFLAGS et al are set to the
#same values used in the actual compilation.
#'''
#)

def locate_path(program: str) -> T.List[str]:
    if os.path.isabs(program):
        return [program]
    for d in os.get_exec_path():
        f = os.path.join(d, program)
        if os.access(f, os.X_OK):
            return [f]
    raise ValueError("%s not found on $PATH" % program)

def write_args_line(ofile: T.TextIO, name: str, args: T.Union[str, T.List[str]]) -> None:
    if len(args) == 0:
        return
    if isinstance(args, str):
        ostr = name + "= '" + args + "'\n"
    else:
        ostr = name + ' = ['
        ostr += ', '.join("'" + i + "'" for i in args)
        ostr += ']\n'
    ofile.write(ostr)

def get_args_from_envvars(infos: MachineInfo) -> None:
    cppflags = shlex.split(os.environ.get('CPPFLAGS', ''))
    cflags = shlex.split(os.environ.get('CFLAGS', ''))
    cxxflags = shlex.split(os.environ.get('CXXFLAGS', ''))
    objcflags = shlex.split(os.environ.get('OBJCFLAGS', ''))
    objcxxflags = shlex.split(os.environ.get('OBJCXXFLAGS', ''))
    ldflags = shlex.split(os.environ.get('LDFLAGS', ''))

    c_args = cppflags + cflags
    cpp_args = cppflags + cxxflags
    c_link_args = cflags + ldflags
    cpp_link_args = cxxflags + ldflags

    objc_args = cppflags + objcflags
    objcpp_args = cppflags + objcxxflags
    objc_link_args = objcflags + ldflags
    objcpp_link_args = objcxxflags + ldflags

    if c_args:
        infos.compile_args['c'] = c_args
    if c_link_args:
        infos.link_args['c'] = c_link_args
    if cpp_args:
        infos.compile_args['cpp'] = cpp_args
    if cpp_link_args:
        infos.link_args['cpp'] = cpp_link_args
    if objc_args:
        infos.compile_args['objc'] = objc_args
    if objc_link_args:
        infos.link_args['objc'] = objc_link_args
    if objcpp_args:
        infos.compile_args['objcpp'] = objcpp_args
    if objcpp_link_args:
        infos.link_args['objcpp'] = objcpp_link_args

deb_cpu_family_map = {
    'mips64el': 'mips64',
    'i686': 'x86',
    'powerpc64le': 'ppc64',
}

deb_cpu_map = {
    'armhf': 'arm7hlf',
    'mips64el': 'mips64',
    'powerpc64le': 'ppc64',
}

def deb_detect_cmake(infos: MachineInfo, data: T.Dict[str, str]) -> None:
    system_name_map = {'linux': 'Linux', 'kfreebsd': 'kFreeBSD', 'hurd': 'GNU'}
    system_processor_map = {'arm': 'armv7l', 'mips64el': 'mips64', 'powerpc64le': 'ppc64le'}

    infos.cmake["CMAKE_C_COMPILER"] = infos.compilers['c']
    try:
        infos.cmake["CMAKE_CXX_COMPILER"] = infos.compilers['cpp']
    except KeyError:
        pass
    infos.cmake["CMAKE_SYSTEM_NAME"] = system_name_map[data['DEB_HOST_ARCH_OS']]
    infos.cmake["CMAKE_SYSTEM_PROCESSOR"] = system_processor_map.get(data['DEB_HOST_GNU_CPU'],
                                                                     data['DEB_HOST_GNU_CPU'])

def deb_compiler_lookup(infos: MachineInfo, compilerstems: T.List[T.Tuple[str, str]], host_arch: str, gccsuffix: str) -> None:
    for langname, stem in compilerstems:
        compilername = f'{host_arch}-{stem}{gccsuffix}'
        try:
            p = locate_path(compilername)
            infos.compilers[langname] = p
        except ValueError:
            pass

def detect_cross_debianlike(options: T.Any) -> MachineInfo:
    if options.debarch == 'auto':
        cmd = ['dpkg-architecture']
    else:
        cmd = ['dpkg-architecture', '-a' + options.debarch]
    output = subprocess.check_output(cmd, universal_newlines=True,
                                     stderr=subprocess.DEVNULL)
    data = {}
    for line in output.split('\n'):
        line = line.strip()
        if line == '':
            continue
        k, v = line.split('=', 1)
        data[k] = v
    host_arch = data['DEB_HOST_GNU_TYPE']
    host_os = data['DEB_HOST_ARCH_OS']
    host_subsystem = host_os
    host_kernel = 'linux'
    host_cpu_family = deb_cpu_family_map.get(data['DEB_HOST_GNU_CPU'],
                                             data['DEB_HOST_GNU_CPU'])
    host_cpu = deb_cpu_map.get(data['DEB_HOST_ARCH'],
                               data['DEB_HOST_ARCH'])
    host_endian = data['DEB_HOST_ARCH_ENDIAN']

    compilerstems = [('c', 'gcc'),
                     ('cpp', 'g++'),
                     ('objc', 'gobjc'),
                     ('objcpp', 'gobjc++')]
    infos = MachineInfo()
    deb_compiler_lookup(infos, compilerstems, host_arch, options.gccsuffix)
    if len(infos.compilers) == 0:
        print('Warning: no compilers were detected.')
    infos.binaries['ar'] = locate_path("%s-ar" % host_arch)
    infos.binaries['strip'] = locate_path("%s-strip" % host_arch)
    infos.binaries['objcopy'] = locate_path("%s-objcopy" % host_arch)
    infos.binaries['ld'] = locate_path("%s-ld" % host_arch)
    try:
        infos.binaries['cmake'] = locate_path("cmake")
        deb_detect_cmake(infos, data)
    except ValueError:
        pass
    try:
        infos.binaries['pkg-config'] = locate_path("%s-pkg-config" % host_arch)
    except ValueError:
        pass # pkg-config is optional
    try:
        infos.binaries['cups-config'] = locate_path("cups-config")
    except ValueError:
        pass
    infos.system = host_os
    infos.subsystem = host_subsystem
    infos.kernel = host_kernel
    infos.cpu_family = host_cpu_family
    infos.cpu = host_cpu
    infos.endian = host_endian

    get_args_from_envvars(infos)
    return infos

def write_machine_file(infos: MachineInfo, ofilename: str, write_system_info: bool) -> None:
    tmpfilename = ofilename + '~'
    with open(tmpfilename, 'w', encoding='utf-8') as ofile:
        ofile.write('[binaries]\n')
        ofile.write('# Compilers\n')
        for langname in sorted(infos.compilers.keys()):
            compiler = infos.compilers[langname]
            write_args_line(ofile, langname, compiler)
        ofile.write('\n')

        ofile.write('# Other binaries\n')
        for exename in sorted(infos.binaries.keys()):
            exe = infos.binaries[exename]
            write_args_line(ofile, exename, exe)
        ofile.write('\n')

        ofile.write('[properties]\n')
        all_langs = list(set(infos.compile_args.keys()).union(set(infos.link_args.keys())))
        all_langs.sort()
        for lang in all_langs:
            if lang in infos.compile_args:
                write_args_line(ofile, lang + '_args', infos.compile_args[lang])
            if lang in infos.link_args:
                write_args_line(ofile, lang + '_link_args', infos.link_args[lang])
        for k, v in infos.properties.items():
            write_args_line(ofile, k, v)
        ofile.write('\n')

        if infos.cmake:
            ofile.write('[cmake]\n\n')
            for k, v in infos.cmake.items():
                write_args_line(ofile, k, v)
            ofile.write('\n')

        if write_system_info:
            ofile.write('[host_machine]\n')
            ofile.write(f"cpu = '{infos.cpu}'\n")
            ofile.write(f"cpu_family = '{infos.cpu_family}'\n")
            ofile.write(f"endian = '{infos.endian}'\n")
            ofile.write(f"system = '{infos.system}'\n")
            if infos.subsystem:
                ofile.write(f"subsystem = '{infos.subsystem}'\n")
            if infos.kernel:
                ofile.write(f"kernel = '{infos.kernel}'\n")

    os.replace(tmpfilename, ofilename)

def detect_language_args_from_envvars(langname: str, envvar_suffix: str = '') -> T.Tuple[T.List[str], T.List[str]]:
    ldflags = tuple(shlex.split(os.environ.get('LDFLAGS' + envvar_suffix, '')))
    compile_args = []
    if langname in compilers.CFLAGS_MAPPING:
        compile_args = shlex.split(os.environ.get(compilers.CFLAGS_MAPPING[langname] + envvar_suffix, ''))
    if langname in compilers.LANGUAGES_USING_CPPFLAGS:
        cppflags = tuple(shlex.split(os.environ.get('CPPFLAGS' + envvar_suffix, '')))
        lang_compile_args = list(cppflags) + compile_args
    else:
        lang_compile_args = compile_args
    lang_link_args = list(ldflags) + compile_args
    return (lang_compile_args, lang_link_args)

def detect_compilers_from_envvars(envvar_suffix: str = '') -> MachineInfo:
    infos = MachineInfo()
    for langname, envvarname in envconfig.ENV_VAR_COMPILER_MAP.items():
        compilerstr = os.environ.get(envvarname + envvar_suffix)
        if not compilerstr:
            continue
        if os.path.exists(compilerstr):
            compiler = [compilerstr]
        else:
            compiler = shlex.split(compilerstr)
        infos.compilers[langname] = compiler
        lang_compile_args, lang_link_args = detect_language_args_from_envvars(langname, envvar_suffix)
        if lang_compile_args:
            infos.compile_args[langname] = lang_compile_args
        if lang_link_args:
            infos.link_args[langname] = lang_link_args
    return infos

def detect_binaries_from_envvars(infos: MachineInfo, envvar_suffix: str = '') -> None:
    for binname, envvar_base in envconfig.ENV_VAR_TOOL_MAP.items():
        envvar = envvar_base + envvar_suffix
        binstr = os.environ.get(envvar)
        if binstr:
            infos.binaries[binname] = shlex.split(binstr)

def detect_properties_from_envvars(infos: MachineInfo, envvar_suffix: str = '') -> None:
    var = os.environ.get('PKG_CONFIG_LIBDIR' + envvar_suffix)
    if var is not None:
        infos.properties['pkg_config_libdir'] = var
    var = os.environ.get('PKG_CONFIG_SYSROOT_DIR' + envvar_suffix)
    if var is not None:
        infos.properties['sys_root'] = var

def detect_cross_system(infos: MachineInfo, options: T.Any) -> None:
    for optname in ('system', 'subsystem', 'kernel', 'cpu', 'cpu_family', 'endian'):
        v = getattr(options, optname)
        if not v:
            mlog.error(f'Cross property "{optname}" missing, set it with --{optname.replace("_", "-")}.')
            sys.exit(1)
        setattr(infos, optname, v)

def detect_cross_env(options: T.Any) -> MachineInfo:
    if options.debarch:
        print('Detecting cross environment via dpkg-reconfigure.')
        infos = detect_cross_debianlike(options)
    else:
        print('Detecting cross environment via environment variables.')
        infos = detect_compilers_from_envvars()
        detect_cross_system(infos, options)
    detect_binaries_from_envvars(infos)
    detect_properties_from_envvars(infos)
    return infos

def add_compiler_if_missing(infos: MachineInfo, langname: str, exe_names: T.List[str]) -> None:
    if langname in infos.compilers:
        return
    for exe_name in exe_names:
        lookup = shutil.which(exe_name)
        if not lookup:
            continue
        compflags, linkflags = detect_language_args_from_envvars(langname)
        infos.compilers[langname] = [lookup]
        if compflags:
            infos.compile_args[langname] = compflags
        if linkflags:
            infos.link_args[langname] = linkflags
        return

def detect_missing_native_compilers(infos: MachineInfo) -> None:
    # T.Any per-platform special detection should go here.
    for langname, exes in compiler_names.items():
        if langname not in envconfig.ENV_VAR_COMPILER_MAP:
            continue
        add_compiler_if_missing(infos, langname, exes)

def detect_missing_native_binaries(infos: MachineInfo) -> None:
    # T.Any per-platform special detection should go here.
    for toolname in sorted(envconfig.ENV_VAR_TOOL_MAP.keys()):
        if toolname in infos.binaries:
            continue
        exe = shutil.which(toolname)
        if exe:
            infos.binaries[toolname] = [exe]

def detect_native_env(options: T.Any) -> MachineInfo:
    use_for_build = has_for_build()
    if use_for_build:
        mlog.log('Using FOR_BUILD envvars for detection')
        esuffix = '_FOR_BUILD'
    else:
        mlog.log('Using regular envvars for detection.')
        esuffix = ''
    infos = detect_compilers_from_envvars(esuffix)
    detect_missing_native_compilers(infos)
    detect_binaries_from_envvars(infos, esuffix)
    detect_missing_native_binaries(infos)
    detect_properties_from_envvars(infos, esuffix)
    return infos

def run(options: T.Any) -> None:
    if options.cross and options.native:
        sys.exit('You can only specify either --cross or --native, not both.')
    if not options.cross and not options.native:
        sys.exit('You must specify --cross or --native.')
    mlog.notice('This functionality is experimental and subject to change.')
    detect_cross = options.cross
    if detect_cross:
        infos = detect_cross_env(options)
        write_system_info = True
    else:
        infos = detect_native_env(options)
        write_system_info = False
    write_machine_file(infos, options.outfile, write_system_info)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/externalproject.py0000644000175000017500000001010114562742363022450 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import os
import argparse
import multiprocessing
import subprocess
from pathlib import Path
import typing as T

from ..mesonlib import Popen_safe, split_args

class ExternalProject:
    def __init__(self, options: argparse.Namespace):
        self.name = options.name
        self.src_dir = options.srcdir
        self.build_dir = options.builddir
        self.install_dir = options.installdir
        self.log_dir = options.logdir
        self.verbose = options.verbose
        self.stampfile = options.stampfile
        self.depfile = options.depfile
        self.make = split_args(options.make)

    def write_depfile(self) -> None:
        with open(self.depfile, 'w', encoding='utf-8') as f:
            f.write(f'{self.stampfile}: \\\n')
            for dirpath, dirnames, filenames in os.walk(self.src_dir):
                dirnames[:] = [d for d in dirnames if not d.startswith('.')]
                for fname in filenames:
                    if fname.startswith('.'):
                        continue
                    path = Path(dirpath, fname)
                    f.write('  {} \\\n'.format(path.as_posix().replace(' ', '\\ ')))

    def write_stampfile(self) -> None:
        with open(self.stampfile, 'w', encoding='utf-8'):
            pass

    def supports_jobs_flag(self) -> bool:
        p, o, e = Popen_safe(self.make + ['--version'])
        if p.returncode == 0 and ('GNU Make' in o or 'waf' in o):
            return True
        return False

    def build(self) -> int:
        make_cmd = self.make.copy()
        if self.supports_jobs_flag():
            make_cmd.append(f'-j{multiprocessing.cpu_count()}')
        rc = self._run('build', make_cmd)
        if rc != 0:
            return rc

        install_cmd = self.make.copy()
        install_env = {}
        install_env['DESTDIR'] = self.install_dir
        install_cmd.append('install')
        rc = self._run('install', install_cmd, install_env)
        if rc != 0:
            return rc

        self.write_depfile()
        self.write_stampfile()

        return 0

    def _run(self, step: str, command: T.List[str], env: T.Optional[T.Dict[str, str]] = None) -> int:
        m = 'Running command ' + str(command) + ' in directory ' + str(self.build_dir) + '\n'
        log_filename = Path(self.log_dir, f'{self.name}-{step}.log')
        output = None
        if not self.verbose:
            output = open(log_filename, 'w', encoding='utf-8')
            output.write(m + '\n')
            output.flush()
        else:
            print(m)
        run_env = os.environ.copy()
        if env:
            run_env.update(env)
        p, o, e = Popen_safe(command, stderr=subprocess.STDOUT, stdout=output,
                             cwd=self.build_dir,
                             env=run_env)
        if p.returncode != 0:
            m = f'{step} step returned error code {p.returncode}.'
            if not self.verbose:
                m += '\nSee logs: ' + str(log_filename)
            print(m)
        return p.returncode

def run(args: T.List[str]) -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument('--name')
    parser.add_argument('--srcdir')
    parser.add_argument('--builddir')
    parser.add_argument('--installdir')
    parser.add_argument('--logdir')
    parser.add_argument('--make')
    parser.add_argument('--verbose', action='store_true')
    parser.add_argument('stampfile')
    parser.add_argument('depfile')

    options = parser.parse_args(args)
    ep = ExternalProject(options)
    return ep.build()
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/gettext.py0000644000175000017500000000756514562742363020747 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import os
import argparse
import subprocess
import typing as T

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('--source-root', default='')
parser.add_argument('--subdir', default='')
parser.add_argument('--xgettext', default='xgettext')
parser.add_argument('--msgmerge', default='msgmerge')
parser.add_argument('--msginit', default='msginit')
parser.add_argument('--extra-args', default='')

def read_linguas(src_sub: str) -> T.List[str]:
    # 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, encoding='utf-8') as f:
            for line in f:
                line = line.strip()
                if line and not line.startswith('#'):
                    langs += line.split()
        return langs
    except (FileNotFoundError, PermissionError):
        print(f'Could not find file LINGUAS in {src_sub}')
        return []

def run_potgen(src_sub: str, xgettext: str, pkgname: str, datadirs: str, args: T.List[str], source_root: str) -> int:
    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', source_root, '-k_', '-o', ofile] + args,
                           env=child_env)

def update_po(src_sub: str, msgmerge: str, msginit: str, pkgname: str, langs: T.List[str]) -> int:
    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 run(args: T.List[str]) -> int:
    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 = options.subdir
    src_sub = os.path.join(options.source_root, subdir)

    if not langs:
        langs = read_linguas(src_sub)

    if subcmd == 'pot':
        return run_potgen(src_sub, options.xgettext, options.pkgname, options.datadirs, extra_args, options.source_root)
    elif subcmd == 'update_po':
        if run_potgen(src_sub, options.xgettext, options.pkgname, options.datadirs, extra_args, options.source_root) != 0:
            return 1
        return update_po(src_sub, options.msgmerge, options.msginit, options.pkgname, langs)
    else:
        print('Unknown subcommand.')
        return 1
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/gtkdochelper.py0000644000175000017500000002655214562742363021733 0ustar00jpakkanejpakkane# 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.
from __future__ import annotations

import sys, os
import subprocess
import shutil
import argparse
from ..mesonlib import MesonException, Popen_safe, is_windows, is_cygwin, split_args
from . import destdir_join
import typing as T

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: T.List[str], cwd: str, library_paths: T.Optional[T.List[str]] = None) -> None:
    if library_paths is None:
        library_paths = []

    env = dict(os.environ)
    if is_windows() or is_cygwin():
        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)

    if is_windows():
        cmd.insert(0, sys.executable)

    # 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 = [f"{cmd!r} failed with status {p.returncode:d}"]
        if out:
            err_msg.append(out)
        raise MesonException('\n'.join(err_msg))
    elif out:
        # Unfortunately Windows cmd.exe consoles may be using a codepage
        # that might choke print() with a UnicodeEncodeError, so let's
        # ignore such errors for now, as a compromise as we are outputting
        # console output here...
        try:
            print(out)
        except UnicodeEncodeError:
            pass

def build_gtkdoc(source_root: str, build_root: str, doc_subdir: str, src_subdirs: T.List[str],
                 main_file: str, module: str, module_version: str,
                 html_args: T.List[str], scan_args: T.List[str], fixxref_args: T.List[str], mkdb_args: T.List[str],
                 gobject_typesfile: str, scanobjs_args: T.List[str], run: str, ld: str, cc: str, ldflags: str, cflags: str,
                 html_assets: T.List[str], content_files: T.List[str], ignore_headers: T.List[str], namespace: str,
                 expand_content_files: T.List[str], mode: str, options: argparse.Namespace) -> None:
    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=' + os.pathsep.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, f'{module}.devhelp2'),
                    os.path.join(htmldir, f'{module}-{module_version}.devhelp2'))

def install_gtkdoc(build_root: str, doc_subdir: str, install_prefix: str, datadir: str, module: str) -> None:
    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: T.List[str]) -> int:
    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:]))
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0
meson-1.3.2/mesonbuild/scripts/hotdochelper.py0000644000175000017500000000212714433154642021722 0ustar00jpakkanejpakkanefrom __future__ import annotations

import os
import shutil
import subprocess

from . import destdir_join

import argparse
import typing as T

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')
parser.add_argument('--docdir')


def run(argv: T.List[str]) -> int:
    options, args = parser.parse_known_args(argv)
    subenv = os.environ.copy()

    val = subenv.get('PYTHONPATH')
    paths = [val] if val else []
    subenv['PYTHONPATH'] = os.pathsep.join(paths + options.extra_extension_path)

    res = subprocess.call(args, cwd=options.builddir, env=subenv)
    if res != 0:
        return res

    if options.install:
        source_dir = os.path.join(options.builddir, options.install)
        destdir = os.environ.get('DESTDIR', '')
        installdir = destdir_join(destdir, options.docdir)

        shutil.rmtree(installdir, ignore_errors=True)
        shutil.copytree(source_dir, installdir)
    return 0
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/itstool.py0000644000175000017500000000605614562742363020752 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import os
import argparse
import subprocess
import tempfile
import shlex
import shutil
import typing as T

parser = argparse.ArgumentParser()
parser.add_argument('command')
parser.add_argument('--build-dir', default='')
parser.add_argument('-i', '--input', default='')
parser.add_argument('-o', '--output', default='')
parser.add_argument('--itstool', default='itstool')
parser.add_argument('--its', action='append', default=[])
parser.add_argument('mo_files', nargs='+')


def run_join(build_dir: str, itstool: str, its_files: T.List[str], mo_files: T.List[str],
             in_fname: str, out_fname: str) -> int:
    if not mo_files:
        print('No mo files specified to use for translation.')
        return 1

    with tempfile.TemporaryDirectory(prefix=os.path.basename(in_fname), dir=build_dir) as tmp_dir:
        # copy mo files to have the right names so itstool can infer their locale
        locale_mo_files = []
        for mo_file in mo_files:
            if not os.path.exists(mo_file):
                print(f'Could not find mo file {mo_file}')
                return 1
            if not mo_file.endswith('.mo'):
                print(f'File is not a mo file: {mo_file}')
                return 1
            # determine locale of this mo file
            parts = mo_file.partition('LC_MESSAGES')
            if parts[0].endswith((os.sep, '/')):
                locale = os.path.basename(parts[0][:-1])
            else:
                locale = os.path.basename(parts[0])
            tmp_mo_fname = os.path.join(tmp_dir, locale + '.mo')
            shutil.copy(mo_file, tmp_mo_fname)
            locale_mo_files.append(tmp_mo_fname)

        cmd = shlex.split(itstool)
        if its_files:
            for fname in its_files:
                cmd.extend(['-i', fname])
        cmd.extend(['-j', in_fname,
                    '-o', out_fname])
        cmd.extend(locale_mo_files)

        return subprocess.call(cmd)


def run(args: T.List[str]) -> int:
    options = parser.parse_args(args)
    command = options.command
    build_dir = os.environ.get('MESON_BUILD_ROOT', os.getcwd())
    if options.build_dir:
        build_dir = options.build_dir

    if command == 'join':
        return run_join(build_dir,
                        options.itstool,
                        options.its,
                        options.mo_files,
                        options.input,
                        options.output)
    else:
        print('Unknown subcommand.')
        return 1
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/meson_exe.py0000644000175000017500000001106714562742363021235 0ustar00jpakkanejpakkane# 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.
from __future__ import annotations

import os
import sys
import argparse
import pickle
import subprocess
import typing as T
import locale

from ..utils.core import ExecutableSerialisation

def buildparser() -> argparse.ArgumentParser:
    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')
    parser.add_argument('--feed')
    return parser

def run_exe(exe: ExecutableSerialisation, extra_env: T.Optional[T.Dict[str, str]] = None) -> int:
    if exe.exe_wrapper:
        if not exe.exe_wrapper.found():
            raise AssertionError('BUG: Can\'t run cross-compiled exe {!r} with not-found '
                                 'wrapper {!r}'.format(exe.cmd_args[0], exe.exe_wrapper.get_path()))
        cmd_args = exe.exe_wrapper.get_command() + exe.cmd_args
    else:
        cmd_args = exe.cmd_args
    child_env = os.environ.copy()
    if extra_env:
        child_env.update(extra_env)
    if exe.env:
        child_env = exe.env.get_env(child_env)
    if exe.extra_paths:
        child_env['PATH'] = (os.pathsep.join(exe.extra_paths + ['']) +
                             child_env['PATH'])
        if exe.exe_wrapper and any('wine' in i for i in exe.exe_wrapper.get_command()):
            from .. import mesonlib
            child_env['WINEPATH'] = mesonlib.get_wine_shortpath(
                exe.exe_wrapper.get_command(),
                ['Z:' + p for p in exe.extra_paths] + child_env.get('WINEPATH', '').split(';'),
                exe.workdir
            )

    stdin = None
    if exe.feed:
        stdin = open(exe.feed, 'rb')

    pipe = subprocess.PIPE
    if exe.verbose:
        assert not exe.capture, 'Cannot capture and print to console at the same time'
        pipe = None

    p = subprocess.Popen(cmd_args, env=child_env, cwd=exe.workdir,
                         close_fds=False, stdin=stdin, stdout=pipe, stderr=pipe)
    stdout, stderr = p.communicate()

    if stdin is not None:
        stdin.close()

    if p.returncode == 0xc0000135:
        # STATUS_DLL_NOT_FOUND on Windows indicating a common problem that is otherwise hard to diagnose
        strerror = 'Failed to run due to missing DLLs, with path: ' + child_env['PATH']
        raise FileNotFoundError(p.returncode, strerror, cmd_args)

    if p.returncode != 0:
        if exe.pickled:
            print(f'while executing {cmd_args!r}')
        if exe.verbose:
            return p.returncode
        encoding = locale.getpreferredencoding()
        if not exe.capture:
            print('--- stdout ---')
            print(stdout.decode(encoding=encoding, errors='replace'))
        print('--- stderr ---')
        print(stderr.decode(encoding=encoding, errors='replace'))
        return p.returncode

    if exe.capture:
        skip_write = False
        try:
            with open(exe.capture, 'rb') as cur:
                skip_write = cur.read() == stdout
        except OSError:
            pass
        if not skip_write:
            with open(exe.capture, 'wb') as output:
                output.write(stdout)

    return 0

def run(args: T.List[str]) -> int:
    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 or options.feed:
            parser.error('no other arguments can be used with --unpickle')
        with open(options.unpickle, 'rb') as f:
            exe = pickle.load(f)
            exe.pickled = True
    else:
        exe = ExecutableSerialisation(cmd_args, capture=options.capture, feed=options.feed)

    return run_exe(exe)

if __name__ == '__main__':
    sys.exit(run(sys.argv[1:]))
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/msgfmthelper.py0000644000175000017500000000264114562742363021746 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import argparse
import subprocess
import os
import typing as T

parser = argparse.ArgumentParser()
parser.add_argument('input')
parser.add_argument('output')
parser.add_argument('type')
parser.add_argument('podir')
parser.add_argument('--msgfmt', default='msgfmt')
parser.add_argument('--datadirs', default='')
parser.add_argument('args', default=[], metavar='extra msgfmt argument', nargs='*')


def run(args: T.List[str]) -> int:
    options = parser.parse_args(args)
    env = None
    if options.datadirs:
        env = os.environ.copy()
        env.update({'GETTEXTDATADIRS': options.datadirs})
    return subprocess.call([options.msgfmt, '--' + options.type, '-d', options.podir,
                            '--template', options.input,  '-o', options.output] + options.args,
                           env=env)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0
meson-1.3.2/mesonbuild/scripts/pycompile.py0000644000175000017500000000441614562742373021255 0ustar00jpakkanejpakkane# 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.

# ignore all lints for this file, since it is run by python2 as well

# type: ignore
# pylint: disable=deprecated-module

import json, os, subprocess, sys
from compileall import compile_file

quiet = int(os.environ.get('MESON_INSTALL_QUIET', 0))

def compileall(files):
    for f in files:
        # f is prefixed by {py_xxxxlib}, both variants are 12 chars
        # the key is the middle 10 chars of the prefix
        key = f[1:11].upper()
        f = f[12:]

        ddir = None
        fullpath = absf = os.environ['MESON_INSTALL_DESTDIR_'+key] + f
        f = os.environ['MESON_INSTALL_'+key] + f

        if absf != f:
            ddir = os.path.dirname(f)

        if os.path.isdir(absf):
            for root, _, files in os.walk(absf):
                if ddir is not None:
                    ddir = root.replace(absf, f, 1)
                for dirf in files:
                    if dirf.endswith('.py'):
                        fullpath = os.path.join(root, dirf)
                        compile_file(fullpath, ddir, force=True, quiet=quiet)
        else:
            compile_file(fullpath, ddir, force=True, quiet=quiet)

def run(manifest):
    data_file = os.path.join(os.path.dirname(__file__), manifest)
    with open(data_file, 'rb') as f:
        dat = json.load(f)
    compileall(dat)

if __name__ == '__main__':
    manifest = sys.argv[1]
    run(manifest)
    if len(sys.argv) > 2:
        optlevel = int(sys.argv[2])
        # python2 only needs one or the other
        if optlevel == 1 or (sys.version_info >= (3,) and optlevel > 0):
            subprocess.check_call([sys.executable, '-O'] + sys.argv[:2])
        if optlevel == 2:
            subprocess.check_call([sys.executable, '-OO'] + sys.argv[:2])
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336264.0
meson-1.3.2/mesonbuild/scripts/python_info.py0000755000175000017500000001021514516507010021567 0ustar00jpakkanejpakkane#!/usr/bin/env python

# ignore all lints for this file, since it is run by python2 as well

# type: ignore
# pylint: disable=deprecated-module

import sys

# do not inject mesonbuild.scripts
# python -P would work too, but is exclusive to >=3.11
if sys.path[0].endswith('scripts'):
    del sys.path[0]

import json, os, sysconfig

def get_distutils_paths(scheme=None, prefix=None):
    import distutils.dist
    distribution = distutils.dist.Distribution()
    install_cmd = distribution.get_command_obj('install')
    if prefix is not None:
        install_cmd.prefix = prefix
    if scheme:
        install_cmd.select_scheme(scheme)
    install_cmd.finalize_options()
    return {
        'data': install_cmd.install_data,
        'include': os.path.dirname(install_cmd.install_headers),
        'platlib': install_cmd.install_platlib,
        'purelib': install_cmd.install_purelib,
        'scripts': install_cmd.install_scripts,
    }

# On Debian derivatives, the Python interpreter shipped by the distribution uses
# a custom install scheme, deb_system, for the system install, and changes the
# default scheme to a custom one pointing to /usr/local and replacing
# site-packages with dist-packages.
# See https://github.com/mesonbuild/meson/issues/8739.
#
# We should be using sysconfig, but before 3.10.3, Debian only patches distutils.
# So we may end up falling back.

def get_install_paths():
    if sys.version_info >= (3, 10):
        scheme = sysconfig.get_default_scheme()
    else:
        scheme = sysconfig._get_default_scheme()

    if sys.version_info >= (3, 10, 3):
        if 'deb_system' in sysconfig.get_scheme_names():
            scheme = 'deb_system'
    else:
        import distutils.command.install
        if 'deb_system' in distutils.command.install.INSTALL_SCHEMES:
            paths = get_distutils_paths(scheme='deb_system')
            install_paths = get_distutils_paths(scheme='deb_system', prefix='')
            return paths, install_paths

    paths = sysconfig.get_paths(scheme=scheme)
    empty_vars = {'base': '', 'platbase': '', 'installed_base': ''}
    install_paths = sysconfig.get_paths(scheme=scheme, vars=empty_vars)
    return paths, install_paths

paths, install_paths = get_install_paths()

def links_against_libpython():
    # on versions supporting python-embed.pc, this is the non-embed lib
    #
    # PyPy is not yet up to 3.12 and work is still pending to export the
    # relevant information (it doesn't automatically provide arbitrary
    # Makefile vars)
    if sys.version_info >= (3, 8) and not is_pypy:
        variables = sysconfig.get_config_vars()
        return bool(variables.get('LIBPYTHON', 'yes'))
    else:
        from distutils.core import Distribution, Extension
        cmd = Distribution().get_command_obj('build_ext')
        cmd.ensure_finalized()
        return bool(cmd.get_libraries(Extension('dummy', [])))

variables = sysconfig.get_config_vars()
variables.update({'base_prefix': getattr(sys, 'base_prefix', sys.prefix)})

is_pypy = '__pypy__' in sys.builtin_module_names

if sys.version_info < (3, 0):
    suffix = variables.get('SO')
elif sys.version_info < (3, 8, 7):
    # https://bugs.python.org/issue?@action=redirect&bpo=39825
    from distutils.sysconfig import get_config_var
    suffix = get_config_var('EXT_SUFFIX')
else:
    suffix = variables.get('EXT_SUFFIX')

limited_api_suffix = None
if sys.version_info >= (3, 2):
    try:
        from importlib.machinery import EXTENSION_SUFFIXES
        limited_api_suffix = EXTENSION_SUFFIXES[1]
    except Exception:
        pass

# pypy supports modules targetting the limited api but
# does not use a special suffix to distinguish them:
# https://doc.pypy.org/en/latest/cpython_differences.html#permitted-abi-tags-in-extensions
if is_pypy:
    limited_api_suffix = suffix

print(json.dumps({
  'variables': variables,
  'paths': paths,
  'sysconfig_paths': sysconfig.get_paths(),
  'install_paths': install_paths,
  'version': sysconfig.get_python_version(),
  'platform': sysconfig.get_platform(),
  'is_pypy': is_pypy,
  'is_venv': sys.prefix != variables['base_prefix'],
  'link_libpython': links_against_libpython(),
  'suffix': suffix,
  'limited_api_suffix': limited_api_suffix,
}))
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/regen_checker.py0000644000175000017500000000513314562742363022034 0ustar00jpakkanejpakkane# 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.
from __future__ import annotations

import sys, os
import pickle, subprocess
import typing as T
from ..coredata import CoreData
from ..backend.backends import RegenInfo
from ..mesonlib import OptionKey

# This could also be used for XCode.

def need_regen(regeninfo: RegenInfo, regen_timestamp: float) -> bool:
    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: RegenInfo, meson_command: T.List[str], backend: str) -> None:
    cmd = meson_command + ['--internal',
                           'regenerate',
                           regeninfo.build_dir,
                           regeninfo.source_dir,
                           '--backend=' + backend]
    subprocess.check_call(cmd)

def run(args: T.List[str]) -> int:
    private_dir = args[0]
    dumpfile = os.path.join(private_dir, 'regeninfo.dump')
    coredata_file = os.path.join(private_dir, 'coredata.dat')
    with open(dumpfile, 'rb') as f:
        regeninfo = pickle.load(f)
        assert isinstance(regeninfo, RegenInfo)
    with open(coredata_file, 'rb') as f:
        coredata = pickle.load(f)
        assert isinstance(coredata, CoreData)
    backend = coredata.get_option(OptionKey('backend'))
    assert isinstance(backend, str)
    regen_timestamp = os.stat(dumpfile).st_mtime
    if need_regen(regeninfo, regen_timestamp):
        regen(regeninfo, coredata.meson_command, backend)
    return 0

if __name__ == '__main__':
    sys.exit(run(sys.argv[1:]))
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/run_tool.py0000644000175000017500000000470114562742363021111 0ustar00jpakkanejpakkane# 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.
from __future__ import annotations

import itertools
import fnmatch
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor

from ..compilers import lang_suffixes
from ..mesonlib import quiet_git
import typing as T

if T.TYPE_CHECKING:
    import subprocess

def parse_pattern_file(fname: Path) -> T.List[str]:
    patterns = []
    try:
        with fname.open(encoding='utf-8') as f:
            for line in f:
                pattern = line.strip()
                if pattern and not pattern.startswith('#'):
                    patterns.append(pattern)
    except FileNotFoundError:
        pass
    return patterns

def run_tool(name: str, srcdir: Path, builddir: Path, fn: T.Callable[..., subprocess.CompletedProcess], *args: T.Any) -> int:
    patterns = parse_pattern_file(srcdir / f'.{name}-include')
    globs: T.Union[T.List[T.List[Path]], T.List[T.Generator[Path, None, None]]]
    if patterns:
        globs = [srcdir.glob(p) for p in patterns]
    else:
        r, o = quiet_git(['ls-files'], srcdir)
        if r:
            globs = [[Path(srcdir, f) for f in o.splitlines()]]
        else:
            globs = [srcdir.glob('**/*')]
    patterns = parse_pattern_file(srcdir / f'.{name}-ignore')
    ignore = [str(builddir / '*')]
    ignore.extend([str(srcdir / p) for p in patterns])
    suffixes = set(lang_suffixes['c']).union(set(lang_suffixes['cpp']))
    suffixes.add('h')
    suffixes = {f'.{s}' for s in suffixes}
    futures = []
    returncode = 0
    with ThreadPoolExecutor() as e:
        for f in itertools.chain(*globs):
            strf = str(f)
            if f.is_dir() or f.suffix not in suffixes or \
                    any(fnmatch.fnmatch(strf, i) for i in ignore):
                continue
            futures.append(e.submit(fn, f, *args))
        if futures:
            returncode = max(x.result().returncode for x in futures)
    return returncode
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/scanbuild.py0000644000175000017500000000500714562742363021214 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import subprocess
import shutil
import tempfile
from ..environment import detect_ninja, detect_scanbuild
from ..coredata import get_cmd_line_file, CmdLineFileParser
from ..mesonlib import windows_proof_rmtree
from pathlib import Path
import typing as T
from ast import literal_eval
import os

def scanbuild(exelist: T.List[str], srcdir: Path, blddir: Path, privdir: Path, logdir: Path, subprojdir: Path, args: T.List[str]) -> int:
    # In case of problems leave the temp directory around
    # so it can be debugged.
    scandir = tempfile.mkdtemp(dir=str(privdir))
    meson_cmd = exelist + args
    build_cmd = exelist + ['--exclude', str(subprojdir), '-o', str(logdir)] + detect_ninja() + ['-C', scandir]
    rc = subprocess.call(meson_cmd + [str(srcdir), scandir])
    if rc != 0:
        return rc
    rc = subprocess.call(build_cmd)
    if rc == 0:
        windows_proof_rmtree(scandir)
    return rc

def run(args: T.List[str]) -> int:
    srcdir = Path(args[0])
    bldpath = Path(args[1])
    subprojdir = srcdir / Path(args[2])
    blddir = args[1]
    meson_cmd = args[3:]
    privdir = bldpath / 'meson-private'
    logdir = bldpath / 'meson-logs' / 'scanbuild'
    shutil.rmtree(str(logdir), ignore_errors=True)

    # if any cross or native files are specified we should use them
    cmd = get_cmd_line_file(blddir)
    data = CmdLineFileParser()
    data.read(cmd)

    if 'cross_file' in data['properties']:
        meson_cmd.extend([f'--cross-file={os.path.abspath(f)}' for f in literal_eval(data['properties']['cross_file'])])

    if 'native_file' in data['properties']:
        meson_cmd.extend([f'--native-file={os.path.abspath(f)}' for f in literal_eval(data['properties']['native_file'])])

    exelist = detect_scanbuild()
    if not exelist:
        print('Could not execute scan-build "%s"' % ' '.join(exelist))
        return 1

    return scanbuild(exelist, srcdir, bldpath, privdir, logdir, subprojdir, meson_cmd)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/symbolextractor.py0000644000175000017500000003136614562742363022520 0ustar00jpakkanejpakkane# 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
from __future__ import annotations

import typing as T
import os, sys
from .. import mesonlib
from .. import mlog
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='+')

TOOL_WARNING_FILE = None
RELINKING_WARNING = 'Relinking will always happen on source changes.'

def dummy_syms(outfilename: str) -> None:
    """Just touch it so relinking happens always."""
    with open(outfilename, 'w', encoding='utf-8'):
        pass

def write_if_changed(text: str, outfilename: str) -> None:
    try:
        with open(outfilename, encoding='utf-8') as f:
            oldtext = f.read()
        if text == oldtext:
            return
    except FileNotFoundError:
        pass
    with open(outfilename, 'w', encoding='utf-8') as f:
        f.write(text)

def print_tool_warning(tools: T.List[str], msg: str, stderr: T.Optional[str] = None) -> None:
    if os.path.exists(TOOL_WARNING_FILE):
        return
    m = f'{tools!r} {msg}. {RELINKING_WARNING}'
    if stderr:
        m += '\n' + stderr
    mlog.warning(m)
    # Write it out so we don't warn again
    with open(TOOL_WARNING_FILE, 'w', encoding='utf-8'):
        pass

def get_tool(name: str) -> T.List[str]:
    evar = name.upper()
    if evar in os.environ:
        import shlex
        return shlex.split(os.environ[evar])
    return [name]

def call_tool(name: str, args: T.List[str], **kwargs: T.Any) -> str:
    tool = get_tool(name)
    try:
        p, output, e = Popen_safe(tool + args, **kwargs)
    except FileNotFoundError:
        print_tool_warning(tool, 'not found')
        return None
    except PermissionError:
        print_tool_warning(tool, 'not usable')
        return None
    if p.returncode != 0:
        print_tool_warning(tool, 'does not work', e)
        return None
    return output

def call_tool_nowarn(tool: T.List[str], **kwargs: T.Any) -> T.Tuple[str, str]:
    try:
        p, output, e = Popen_safe(tool, **kwargs)
    except FileNotFoundError:
        return None, '{!r} not found\n'.format(tool[0])
    except PermissionError:
        return None, '{!r} not usable\n'.format(tool[0])
    if p.returncode != 0:
        return None, e
    return output, None

def gnu_syms(libfilename: str, outfilename: str) -> None:
    # Get the name of the library
    output = call_tool('readelf', ['-d', libfilename])
    if not output:
        dummy_syms(outfilename)
        return
    result = [x for x in output.split('\n') if 'SONAME' in x]
    assert len(result) <= 1
    # Get a list of all symbols exported
    output = call_tool('nm', ['--dynamic', '--extern-only', '--defined-only',
                              '--format=posix', libfilename])
    if not output:
        dummy_syms(outfilename)
        return
    for line in output.split('\n'):
        if not line:
            continue
        line_split = line.split()
        entry = line_split[0:2]
        # Store the size of symbols pointing to data objects so we relink
        # when those change, which is needed because of copy relocations
        # https://github.com/mesonbuild/meson/pull/7132#issuecomment-628353702
        if line_split[1].upper() in {'B', 'G', 'D'} and len(line_split) >= 4:
            entry += [line_split[3]]
        result += [' '.join(entry)]
    write_if_changed('\n'.join(result) + '\n', outfilename)

def solaris_syms(libfilename: str, outfilename: str) -> None:
    # gnu_syms() works with GNU nm & readelf, not Solaris nm & elfdump
    origpath = os.environ['PATH']
    try:
        os.environ['PATH'] = '/usr/gnu/bin:' + origpath
        gnu_syms(libfilename, outfilename)
    finally:
        os.environ['PATH'] = origpath

def osx_syms(libfilename: str, outfilename: str) -> None:
    # Get the name of the library
    output = call_tool('otool', ['-l', libfilename])
    if not output:
        dummy_syms(outfilename)
        return
    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.
    # Get a list of all symbols exported
    output = call_tool('nm', ['--extern-only', '--defined-only',
                              '--format=posix', libfilename])
    if not output:
        dummy_syms(outfilename)
        return
    result += [' '.join(x.split()[0:2]) for x in output.split('\n')]
    write_if_changed('\n'.join(result) + '\n', outfilename)

def openbsd_syms(libfilename: str, outfilename: str) -> None:
    # Get the name of the library
    output = call_tool('readelf', ['-d', libfilename])
    if not output:
        dummy_syms(outfilename)
        return
    result = [x for x in output.split('\n') if 'SONAME' in x]
    assert len(result) <= 1
    # Get a list of all symbols exported
    output = call_tool('nm', ['-D', '-P', '-g', libfilename])
    if not output:
        dummy_syms(outfilename)
        return
    # U = undefined (cope with the lack of --defined-only option)
    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 freebsd_syms(libfilename: str, outfilename: str) -> None:
    # Get the name of the library
    output = call_tool('readelf', ['-d', libfilename])
    if not output:
        dummy_syms(outfilename)
        return
    result = [x for x in output.split('\n') if 'SONAME' in x]
    assert len(result) <= 1
    # Get a list of all symbols exported
    output = call_tool('nm', ['--dynamic', '--extern-only', '--defined-only',
                              '--format=posix', libfilename])
    if not output:
        dummy_syms(outfilename)
        return

    result += [' '.join(x.split()[0:2]) for x in output.split('\n')]
    write_if_changed('\n'.join(result) + '\n', outfilename)

def cygwin_syms(impfilename: str, outfilename: str) -> None:
    # Get the name of the library
    output = call_tool('dlltool', ['-I', impfilename])
    if not output:
        dummy_syms(outfilename)
        return
    result = [output]
    # Get the list of all symbols exported
    output = call_tool('nm', ['--extern-only', '--defined-only',
                              '--format=posix', impfilename])
    if not output:
        dummy_syms(outfilename)
        return
    for line in output.split('\n'):
        if ' T ' not in line:
            continue
        result.append(line.split(maxsplit=1)[0])
    write_if_changed('\n'.join(result) + '\n', outfilename)

def _get_implib_dllname(impfilename: str) -> T.Tuple[T.List[str], str]:
    all_stderr = ''
    # First try lib.exe, which is provided by MSVC. Then llvm-lib.exe, by LLVM
    # for clang-cl.
    #
    # We cannot call get_tool on `lib` because it will look at the `LIB` env
    # var which is the list of library paths MSVC will search for import
    # libraries while linking.
    for lib in (['lib'], get_tool('llvm-lib')):
        output, e = call_tool_nowarn(lib + ['-list', impfilename])
        if output:
            # The output is a list of DLLs that each symbol exported by the import
            # library is available in. We only build import libraries that point to
            # a single DLL, so we can pick any of these. Pick the last one for
            # simplicity. Also skip the last line, which is empty.
            return output.split('\n')[-2:-1], None
        all_stderr += e
    # Next, try dlltool.exe which is provided by MinGW
    output, e = call_tool_nowarn(get_tool('dlltool') + ['-I', impfilename])
    if output:
        return [output], None
    all_stderr += e
    return ([], all_stderr)

def _get_implib_exports(impfilename: str) -> T.Tuple[T.List[str], str]:
    all_stderr = ''
    # Force dumpbin.exe to use en-US so we can parse its output
    env = os.environ.copy()
    env['VSLANG'] = '1033'
    output, e = call_tool_nowarn(get_tool('dumpbin') + ['-exports', impfilename], env=env)
    if output:
        lines = output.split('\n')
        start = lines.index('File Type: LIBRARY')
        end = lines.index('  Summary')
        return lines[start:end], None
    all_stderr += e
    # Next, try llvm-nm.exe provided by LLVM, then nm.exe provided by MinGW
    for nm in ('llvm-nm', 'nm'):
        output, e = call_tool_nowarn(get_tool(nm) + ['--extern-only', '--defined-only',
                                                     '--format=posix', impfilename])
        if output:
            result = []
            for line in output.split('\n'):
                if ' T ' not in line or line.startswith('.text'):
                    continue
                result.append(line.split(maxsplit=1)[0])
            return result, None
        all_stderr += e
    return ([], all_stderr)

def windows_syms(impfilename: str, outfilename: str) -> None:
    # Get the name of the library
    result, e = _get_implib_dllname(impfilename)
    if not result:
        print_tool_warning(['lib', 'llvm-lib', 'dlltool'], 'do not work or were not found', e)
        dummy_syms(outfilename)
        return
    # Get a list of all symbols exported
    symbols, e = _get_implib_exports(impfilename)
    if not symbols:
        print_tool_warning(['dumpbin', 'llvm-nm', 'nm'], 'do not work or were not found', e)
        dummy_syms(outfilename)
        return
    result += symbols
    write_if_changed('\n'.join(result) + '\n', outfilename)

def gen_symbols(libfilename: str, impfilename: str, outfilename: str, cross_host: str) -> None:
    if cross_host is not None:
        # In case of cross builds just always relink. In theory we could
        # determine the correct toolset, but we would need to use the correct
        # `nm`, `readelf`, etc, from the cross info which requires refactoring.
        dummy_syms(outfilename)
    elif mesonlib.is_linux() or mesonlib.is_hurd():
        gnu_syms(libfilename, outfilename)
    elif mesonlib.is_osx():
        osx_syms(libfilename, outfilename)
    elif mesonlib.is_openbsd():
        openbsd_syms(libfilename, outfilename)
    elif mesonlib.is_freebsd():
        freebsd_syms(libfilename, outfilename)
    elif mesonlib.is_netbsd():
        freebsd_syms(libfilename, outfilename)
    elif mesonlib.is_windows():
        if os.path.isfile(impfilename):
            windows_syms(impfilename, outfilename)
        else:
            # No import library. Not sure how the DLL is being used, so just
            # rebuild everything that links to it every time.
            dummy_syms(outfilename)
    elif mesonlib.is_cygwin():
        if os.path.isfile(impfilename):
            cygwin_syms(impfilename, outfilename)
        else:
            # No import library. Not sure how the DLL is being used, so just
            # rebuild everything that links to it every time.
            dummy_syms(outfilename)
    elif mesonlib.is_sunos():
        solaris_syms(libfilename, outfilename)
    else:
        if not os.path.exists(TOOL_WARNING_FILE):
            mlog.warning('Symbol extracting has not been implemented for this '
                         'platform. ' + RELINKING_WARNING)
            # Write it out so we don't warn again
            with open(TOOL_WARNING_FILE, 'w', encoding='utf-8'):
                pass
        dummy_syms(outfilename)

def run(args: T.List[str]) -> int:
    global TOOL_WARNING_FILE  # pylint: disable=global-statement
    options = parser.parse_args(args)
    if len(options.args) != 4:
        print('symbolextractor.py   ')
        sys.exit(1)
    privdir = os.path.join(options.args[0], 'meson-private')
    TOOL_WARNING_FILE = os.path.join(privdir, 'symbolextractor_tool_warning_printed')
    libfile = options.args[1]
    impfile = options.args[2] # Only used on Windows
    outfile = options.args[3]
    gen_symbols(libfile, impfile, outfile, options.cross_host)
    return 0

if __name__ == '__main__':
    sys.exit(run(sys.argv[1:]))
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/tags.py0000644000175000017500000000331714562742363020210 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import os
import subprocess
from pathlib import Path
import typing as T

def ls_as_bytestream() -> bytes:
    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() -> int:
    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() -> int:
    ls = ls_as_bytestream()
    return subprocess.run(['ctags', '-L-'], input=ls).returncode


def etags() -> int:
    ls = ls_as_bytestream()
    return subprocess.run(['etags', '-'], input=ls).returncode


def run(args: T.List[str]) -> int:
    tool_name = args[0]
    srcdir_name = args[1]
    os.chdir(srcdir_name)
    assert tool_name in {'cscope', 'ctags', 'etags'}
    res = globals()[tool_name]()
    assert isinstance(res, int)
    return res
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336271.0
meson-1.3.2/mesonbuild/scripts/test_loaded_modules.py0000644000175000017500000000052714516507017023263 0ustar00jpakkanejpakkanefrom __future__ import annotations

import sys
import json
import typing as T

from . import meson_exe

# This script is used by run_unittests.py to verify we don't load too many
# modules when executing a wrapped command.
def run(args: T.List[str]) -> int:
    meson_exe.run(args)
    print(json.dumps(list(sys.modules.keys())))
    return 0
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/uninstall.py0000644000175000017500000000321314562742363021256 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import os
import typing as T

logfile = 'meson-logs/install-log.txt'

def do_uninstall(log: str) -> None:
    failures = 0
    successes = 0
    for line in open(log, encoding='utf-8'):
        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(f'Could not delete {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: T.List[str]) -> int:
    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
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/scripts/vcstagger.py0000644000175000017500000000330714562742363021236 0ustar00jpakkanejpakkane# 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.
from __future__ import annotations

import sys, os, subprocess, re
import typing as T

def config_vcs_tag(infile: str, outfile: str, fallback: str, source_dir: str, replace_string: str, regex_selector: str, cmd: T.List[str]) -> None:
    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='utf-8') as f:
        new_data = f.read().replace(replace_string, new_string)
    if os.path.exists(outfile):
        with open(outfile, encoding='utf-8') as f:
            needs_update = f.read() != new_data
    else:
        needs_update = True
    if needs_update:
        with open(outfile, 'w', encoding='utf-8') as f:
            f.write(new_data)


def run(args: T.List[str]) -> int:
    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:]))
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336271.0
meson-1.3.2/mesonbuild/scripts/yasm.py0000644000175000017500000000113414516507017020210 0ustar00jpakkanejpakkanefrom __future__ import annotations

import argparse
import subprocess
import typing as T

def run(args: T.List[str]) -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument('--depfile')
    options, yasm_cmd = parser.parse_known_args(args)

    # Compile
    returncode = subprocess.call(yasm_cmd)
    if returncode != 0:
        return returncode

    # Capture and write depfile
    ret = subprocess.run(yasm_cmd + ['-M'], capture_output=True)
    if ret.returncode != 0:
        return ret.returncode
    with open(options.depfile, 'wb') as f:
        f.write(ret.stdout)

    return 0
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.7666397
meson-1.3.2/mesonbuild/templates/0000755000175000017500000000000014562742414017200 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1650551419.0
meson-1.3.2/mesonbuild/templates/__init__.py0000644000175000017500000000000014230265173021271 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/templates/cpptemplates.py0000644000175000017500000000707714562742363022271 0ustar00jpakkanejpakkane# 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 __future__ import annotations

from mesonbuild.templates.sampleimpl import FileHeaderImpl


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}',
)
'''


class CppProject(FileHeaderImpl):

    source_ext = 'cpp'
    header_ext = 'hpp'
    exe_template = hello_cpp_template
    exe_meson_template = hello_cpp_meson_template
    lib_template = lib_cpp_template
    lib_header_template = lib_hpp_template
    lib_test_template = lib_cpp_test_template
    lib_meson_template = lib_cpp_meson_template
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/templates/cstemplates.py0000644000175000017500000000504514562742363022105 0ustar00jpakkanejpakkane# 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 __future__ import annotations

from mesonbuild.templates.sampleimpl import ClassImpl


hello_cs_template = '''using System;

public class {class_name} {{
    const String PROJECT_NAME = "{project_name}";

    static int Main(String[] args) {{
      if (args.Length > 0) {{
          System.Console.WriteLine(String.Format("{project_name} takes no arguments.."));
          return 1;
      }}
      Console.WriteLine(String.Format("This is project {{0}}.", PROJECT_NAME));
      return 0;
    }}
}}

'''

hello_cs_meson_template = '''project('{project_name}', 'cs',
  version : '{version}',
  default_options : ['warning_level=3'])

exe = executable('{exe_name}', '{source_name}',
  install : true)

test('basic', exe)
'''

lib_cs_template = '''
public class {class_name} {{
    private const int number = 6;

    public int get_number() {{
      return number;
    }}
}}

'''

lib_cs_test_template = '''using System;

public class {class_test} {{
    static int Main(String[] args) {{
      if (args.Length > 0) {{
          System.Console.WriteLine("{project_name} takes no arguments..");
          return 1;
      }}
      {class_name} c = new {class_name}();
      Boolean result = true;
      return result.CompareTo(c.get_number() != 6);
    }}
}}

'''

lib_cs_meson_template = '''project('{project_name}', 'cs',
  version : '{version}',
  default_options : ['warning_level=3'])

stlib = shared_library('{lib_name}', '{source_file}',
  install : true,
)

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)

'''


class CSharpProject(ClassImpl):

    source_ext = 'cs'
    exe_template = hello_cs_template
    exe_meson_template = hello_cs_meson_template
    lib_template = lib_cs_template
    lib_test_template = lib_cs_test_template
    lib_meson_template = lib_cs_meson_template
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/templates/ctemplates.py0000644000175000017500000000657114562742363021727 0ustar00jpakkanejpakkane# 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 __future__ import annotations

from mesonbuild.templates.sampleimpl import FileHeaderImpl


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


class CProject(FileHeaderImpl):

    source_ext = 'c'
    header_ext = 'h'
    exe_template = hello_c_template
    exe_meson_template = hello_c_meson_template
    lib_template = lib_c_template
    lib_header_template = lib_h_template
    lib_test_template = lib_c_test_template
    lib_meson_template = lib_c_meson_template
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/templates/cudatemplates.py0000644000175000017500000000710614562742363022414 0ustar00jpakkanejpakkane# 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 __future__ import annotations

from mesonbuild.templates.sampleimpl import FileHeaderImpl


hello_cuda_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_cuda_meson_template = '''project('{project_name}', ['cuda', 'cpp'],
  version : '{version}',
  default_options : ['warning_level=3',
                     'cpp_std=c++14'])

exe = executable('{exe_name}', '{source_name}',
  install : true)

test('basic', exe)
'''

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

namespace {namespace} {{

class {utoken}_PUBLIC {class_name} {{

public:
  {class_name}();
  int get_number() const;

private:

  int number;

}};

}}

'''

lib_cuda_template = '''#include <{header_file}>

namespace {namespace} {{

{class_name}::{class_name}() {{
    number = 6;
}}

int {class_name}::get_number() const {{
  return number;
}}

}}
'''

lib_cuda_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_cuda_meson_template = '''project('{project_name}', ['cuda', 'cpp'],
  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,
  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}',
)
'''


class CudaProject(FileHeaderImpl):

    source_ext = 'cu'
    header_ext = 'h'
    exe_template = hello_cuda_template
    exe_meson_template = hello_cuda_meson_template
    lib_template = lib_cuda_template
    lib_header_template = lib_h_template
    lib_test_template = lib_cuda_test_template
    lib_meson_template = lib_cuda_meson_template
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/templates/dlangtemplates.py0000644000175000017500000000601014562742363022556 0ustar00jpakkanejpakkane# 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 __future__ import annotations

from mesonbuild.templates.sampleimpl import FileImpl

import typing as T


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


class DlangProject(FileImpl):

    source_ext = 'd'
    exe_template = hello_d_template
    exe_meson_template = hello_d_meson_template
    lib_template = lib_d_template
    lib_test_template = lib_d_test_template
    lib_meson_template = lib_d_meson_template

    def lib_kwargs(self) -> T.Dict[str, str]:
        kwargs = super().lib_kwargs()
        kwargs['module_file'] = self.lowercase_token
        return kwargs
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/templates/fortrantemplates.py0000644000175000017500000000534114562742363023152 0ustar00jpakkanejpakkane# 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 __future__ import annotations

from mesonbuild.templates.sampleimpl import FileImpl

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


class FortranProject(FileImpl):

    source_ext = 'f90'
    exe_template = hello_fortran_template
    exe_meson_template = hello_fortran_meson_template
    lib_template = lib_fortran_template
    lib_meson_template = lib_fortran_meson_template
    lib_test_template = lib_fortran_test_template
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/templates/javatemplates.py0000644000175000017500000000520014562742363022412 0ustar00jpakkanejpakkane# 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 __future__ import annotations

from mesonbuild.templates.sampleimpl import ClassImpl


hello_java_template = '''

public class {class_name} {{
    final static String PROJECT_NAME = "{project_name}";

    public static void main (String args[]) {{
        if(args.length != 0) {{
            System.out.println(args + " takes no arguments.");
            System.exit(0);
        }}
        System.out.println("This is project " + PROJECT_NAME + ".");
        System.exit(0);
    }}
}}

'''

hello_java_meson_template = '''project('{project_name}', 'java',
  version : '{version}',
  default_options : ['warning_level=3'])

exe = jar('{exe_name}', '{source_name}',
  main_class : '{exe_name}',
  install : true)

test('basic', exe)
'''

lib_java_template = '''

public class {class_name} {{
    final static int number = 6;

    public final int get_number() {{
      return number;
    }}
}}

'''

lib_java_test_template = '''

public class {class_test} {{
    public static void main (String args[]) {{
        if(args.length != 0) {{
            System.out.println(args + " takes no arguments.");
            System.exit(1);
        }}

        {class_name} c = new {class_name}();
        Boolean result = true;
        System.exit(result.compareTo(c.get_number() != 6));
    }}
}}

'''

lib_java_meson_template = '''project('{project_name}', 'java',
  version : '{version}',
  default_options : ['warning_level=3'])

jarlib = jar('{class_name}', '{source_file}',
  main_class : '{class_name}',
  install : true,
)

test_jar = jar('{class_test}', '{test_source_file}',
  main_class : '{class_test}',
  link_with : jarlib)
test('{test_name}', test_jar)

# Make this library usable as a Meson subproject.
{ltoken}_dep = declare_dependency(
  include_directories: include_directories('.'),
  link_with : jarlib)
'''


class JavaProject(ClassImpl):

    source_ext = 'java'
    exe_template = hello_java_template
    exe_meson_template = hello_java_meson_template
    lib_template = lib_java_template
    lib_test_template = lib_java_test_template
    lib_meson_template = lib_java_meson_template
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/templates/mesontemplates.py0000644000175000017500000000677014562742363022627 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import typing as T

if T.TYPE_CHECKING:
    from ..minit import Arguments

meson_executable_template = '''project('{project_name}', {language},
  version : '{version}',
  default_options : [{default_options}])

executable('{executable}',
           {sourcespec},{depspec}
           install : true)
'''


meson_jar_template = '''project('{project_name}', '{language}',
  version : '{version}',
  default_options : [{default_options}])

jar('{executable}',
    {sourcespec},{depspec}
    main_class: '{main_class}',
    install : true)
'''


def create_meson_build(options: Arguments) -> None:
    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(f"'{x}'" for x in default_options)
    sourcespec = ',\n           '.join(f"'{x}'" for x in options.srcfiles)
    depspec = ''
    if options.deps:
        depspec = '\n           dependencies : [\n              '
        depspec += ',\n              '.join(f"dependency('{x}')"
                                            for x in options.deps.split(','))
        depspec += '],'
    if options.language != 'java':
        language = f"'{options.language}'" if options.language != 'vala' else ['c', 'vala']
        content = meson_executable_template.format(project_name=options.name,
                                                   language=language,
                                                   version=options.version,
                                                   executable=options.executable,
                                                   sourcespec=sourcespec,
                                                   depspec=depspec,
                                                   default_options=formatted_default_options)
    else:
        content = meson_jar_template.format(project_name=options.name,
                                            language=options.language,
                                            version=options.version,
                                            executable=options.executable,
                                            main_class=options.name,
                                            sourcespec=sourcespec,
                                            depspec=depspec,
                                            default_options=formatted_default_options)
    open('meson.build', 'w', encoding='utf-8').write(content)
    print('Generated meson.build file:\n\n' + content)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/templates/objcpptemplates.py0000644000175000017500000000676114562742363022763 0ustar00jpakkanejpakkane# 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 __future__ import annotations

from mesonbuild.templates.sampleimpl import FileHeaderImpl


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_objcpp_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_objcpp_test_template = '''#import <{header_file}>
#import 

int main(int argc, char **argv) {{
    if(argc != 1) {{
        std::cout << argv[0] << " takes no arguments." << std::endl;
        return 1;
    }}
    return {function_name}();
}}
'''

lib_objcpp_meson_template = '''project('{project_name}', 'objcpp',
  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,
  objcpp_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_objcpp_template = '''#import 

#define PROJECT_NAME "{project_name}"

int main(int argc, char **argv) {{
    if(argc != 1) {{
        std::cout << argv[0] << " takes no arguments." << std::endl;
        return 1;
    }}
    std::cout << "This is project " << PROJECT_NAME << "." << std::endl;
    return 0;
}}
'''

hello_objcpp_meson_template = '''project('{project_name}', 'objcpp',
  version : '{version}',
  default_options : ['warning_level=3'])

exe = executable('{exe_name}', '{source_name}',
  install : true)

test('basic', exe)
'''


class ObjCppProject(FileHeaderImpl):

    source_ext = 'mm'
    header_ext = 'h'
    exe_template = hello_objcpp_template
    exe_meson_template = hello_objcpp_meson_template
    lib_template = lib_objcpp_template
    lib_header_template = lib_h_template
    lib_test_template = lib_objcpp_test_template
    lib_meson_template = lib_objcpp_meson_template
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/templates/objctemplates.py0000644000175000017500000000663714562742363022425 0ustar00jpakkanejpakkane# 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 __future__ import annotations

from mesonbuild.templates.sampleimpl import FileHeaderImpl


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


class ObjCProject(FileHeaderImpl):

    source_ext = 'm'
    header_ext = 'h'
    exe_template = hello_objc_template
    exe_meson_template = hello_objc_meson_template
    lib_template = lib_objc_template
    lib_header_template = lib_h_template
    lib_test_template = lib_objc_test_template
    lib_meson_template = lib_objc_meson_template
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/templates/rusttemplates.py0000644000175000017500000000454114562742363022475 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import typing as T

from mesonbuild.templates.sampleimpl import FileImpl


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


class RustProject(FileImpl):

    source_ext = 'rs'
    exe_template = hello_rust_template
    exe_meson_template = hello_rust_meson_template
    lib_template = lib_rust_template
    lib_test_template = lib_rust_test_template
    lib_meson_template = lib_rust_meson_template

    def lib_kwargs(self) -> T.Dict[str, str]:
        kwargs = super().lib_kwargs()
        kwargs['crate_file'] = self.lowercase_token
        return kwargs
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/templates/samplefactory.py0000644000175000017500000000356014562742363022432 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import typing as T

from mesonbuild.templates.valatemplates import ValaProject
from mesonbuild.templates.fortrantemplates import FortranProject
from mesonbuild.templates.objcpptemplates import ObjCppProject
from mesonbuild.templates.dlangtemplates import DlangProject
from mesonbuild.templates.rusttemplates import RustProject
from mesonbuild.templates.javatemplates import JavaProject
from mesonbuild.templates.cudatemplates import CudaProject
from mesonbuild.templates.objctemplates import ObjCProject
from mesonbuild.templates.cpptemplates import CppProject
from mesonbuild.templates.cstemplates import CSharpProject
from mesonbuild.templates.ctemplates import CProject

if T.TYPE_CHECKING:
    from ..minit import Arguments
    from .sampleimpl import ClassImpl, FileHeaderImpl, FileImpl, SampleImpl


_IMPL: T.Mapping[str, T.Union[T.Type[ClassImpl], T.Type[FileHeaderImpl], T.Type[FileImpl]]] = {
    'c': CProject,
    'cpp': CppProject,
    'cs': CSharpProject,
    'cuda': CudaProject,
    'objc': ObjCProject,
    'objcpp': ObjCppProject,
    'java': JavaProject,
    'd': DlangProject,
    'rust': RustProject,
    'fortran': FortranProject,
    'vala': ValaProject,
}


def sample_generator(options: Arguments) -> SampleImpl:
    return _IMPL[options.language](options)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/templates/sampleimpl.py0000644000175000017500000001426214562742363021725 0ustar00jpakkanejpakkane# 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 __future__ import annotations

import abc
import re
import typing as T

if T.TYPE_CHECKING:
    from ..minit import Arguments


class SampleImpl(metaclass=abc.ABCMeta):

    def __init__(self, args: Arguments):
        self.name = args.name
        self.version = args.version
        self.lowercase_token = re.sub(r'[^a-z0-9]', '_', self.name.lower())
        self.uppercase_token = self.lowercase_token.upper()
        self.capitalized_token = self.lowercase_token.capitalize()

    @abc.abstractmethod
    def create_executable(self) -> None:
        pass

    @abc.abstractmethod
    def create_library(self) -> None:
        pass

    @abc.abstractproperty
    def exe_template(self) -> str:
        pass

    @abc.abstractproperty
    def exe_meson_template(self) -> str:
        pass

    @abc.abstractproperty
    def lib_template(self) -> str:
        pass

    @abc.abstractproperty
    def lib_test_template(self) -> str:
        pass

    @abc.abstractproperty
    def lib_meson_template(self) -> str:
        pass

    @abc.abstractproperty
    def source_ext(self) -> str:
        pass


class ClassImpl(SampleImpl):

    """For Class based languages, like Java and C#"""

    def create_executable(self) -> None:
        source_name = f'{self.capitalized_token}.{self.source_ext}'
        with open(source_name, 'w', encoding='utf-8') as f:
            f.write(self.exe_template.format(project_name=self.name,
                                             class_name=self.capitalized_token))
        with open('meson.build', 'w', encoding='utf-8') as f:
            f.write(self.exe_meson_template.format(project_name=self.name,
                                                   exe_name=self.name,
                                                   source_name=source_name,
                                                   version=self.version))

    def create_library(self) -> None:
        lib_name = f'{self.capitalized_token}.{self.source_ext}'
        test_name = f'{self.capitalized_token}_test.{self.source_ext}'
        kwargs = {'utoken': self.uppercase_token,
                  'ltoken': self.lowercase_token,
                  'class_test': f'{self.capitalized_token}_test',
                  'class_name': self.capitalized_token,
                  'source_file': lib_name,
                  'test_source_file': test_name,
                  'test_exe_name': f'{self.lowercase_token}_test',
                  'project_name': self.name,
                  'lib_name': self.lowercase_token,
                  'test_name': self.lowercase_token,
                  'version': self.version,
                  }
        with open(lib_name, 'w', encoding='utf-8') as f:
            f.write(self.lib_template.format(**kwargs))
        with open(test_name, 'w', encoding='utf-8') as f:
            f.write(self.lib_test_template.format(**kwargs))
        with open('meson.build', 'w', encoding='utf-8') as f:
            f.write(self.lib_meson_template.format(**kwargs))


class FileImpl(SampleImpl):

    """File based languages without headers"""

    def create_executable(self) -> None:
        source_name = f'{self.lowercase_token}.{self.source_ext}'
        with open(source_name, 'w', encoding='utf-8') as f:
            f.write(self.exe_template.format(project_name=self.name))
        with open('meson.build', 'w', encoding='utf-8') as f:
            f.write(self.exe_meson_template.format(project_name=self.name,
                                                   exe_name=self.name,
                                                   source_name=source_name,
                                                   version=self.version))

    def lib_kwargs(self) -> T.Dict[str, str]:
        """Get Language specific keyword arguments

        :return: A dictionary of key: values to fill in the templates
        """
        return {
            'utoken': self.uppercase_token,
            'ltoken': self.lowercase_token,
            'header_dir': self.lowercase_token,
            'class_name': self.capitalized_token,
            'function_name': f'{self.lowercase_token[0:3]}_func',
            'namespace': self.lowercase_token,
            'source_file': f'{self.lowercase_token}.{self.source_ext}',
            'test_source_file': f'{self.lowercase_token}_test.{self.source_ext}',
            'test_exe_name': f'{self.lowercase_token}_test',
            'project_name': self.name,
            'lib_name': self.lowercase_token,
            'test_name': self.lowercase_token,
            'version': self.version,
        }

    def create_library(self) -> None:
        lib_name = f'{self.lowercase_token}.{self.source_ext}'
        test_name = f'{self.lowercase_token}_test.{self.source_ext}'
        kwargs = self.lib_kwargs()
        with open(lib_name, 'w', encoding='utf-8') as f:
            f.write(self.lib_template.format(**kwargs))
        with open(test_name, 'w', encoding='utf-8') as f:
            f.write(self.lib_test_template.format(**kwargs))
        with open('meson.build', 'w', encoding='utf-8') as f:
            f.write(self.lib_meson_template.format(**kwargs))


class FileHeaderImpl(FileImpl):

    @abc.abstractproperty
    def header_ext(self) -> str:
        pass

    @abc.abstractproperty
    def lib_header_template(self) -> str:
        pass

    def lib_kwargs(self) -> T.Dict[str, str]:
        kwargs = super().lib_kwargs()
        kwargs['header_file'] = f'{self.lowercase_token}.{self.header_ext}'
        return kwargs

    def create_library(self) -> None:
        super().create_library()
        kwargs = self.lib_kwargs()
        with open(kwargs['header_file'], 'w', encoding='utf-8') as f:
            f.write(self.lib_header_template.format_map(kwargs))
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/templates/valatemplates.py0000644000175000017500000000473214562742363022425 0ustar00jpakkanejpakkane# 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 __future__ import annotations

from mesonbuild.templates.sampleimpl import FileImpl


hello_vala_template = '''void main (string[] args) {{
    stdout.printf ("Hello {project_name}!\\n");
}}
'''

hello_vala_meson_template = '''project('{project_name}', ['c', 'vala'],
  version : '{version}')

dependencies = [
    dependency('glib-2.0'),
    dependency('gobject-2.0'),
]

exe = executable('{exe_name}', '{source_name}', dependencies : dependencies,
  install : true)

test('basic', exe)
'''


lib_vala_template = '''namespace {namespace} {{
    public int sum(int a, int b) {{
        return(a + b);
    }}

    public int square(int a) {{
        return(a * a);
    }}
}}
'''

lib_vala_test_template = '''using {namespace};

public void main() {{
    stdout.printf("\nTesting shlib");
    stdout.printf("\n\t2 + 3 is %d", sum(2, 3));
    stdout.printf("\n\t8 squared is %d\\n", square(8));
}}
'''

lib_vala_meson_template = '''project('{project_name}', ['c', 'vala'],
  version : '{version}')

dependencies = [
    dependency('glib-2.0'),
    dependency('gobject-2.0'),
]

# These arguments are only used to build the shared library
# not the executables that use the library.
shlib = shared_library('foo', '{source_file}',
               dependencies: dependencies,
               install: true,
               install_dir: [true, true, true])

test_exe = executable('{test_exe_name}', '{test_source_file}', dependencies : dependencies,
  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)
'''


class ValaProject(FileImpl):

    source_ext = 'vala'
    exe_template = hello_vala_template
    exe_meson_template = hello_vala_meson_template
    lib_template = lib_vala_template
    lib_test_template = lib_vala_test_template
    lib_meson_template = lib_vala_meson_template
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.7746398
meson-1.3.2/mesonbuild/utils/0000755000175000017500000000000014562742414016342 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1666639513.0
meson-1.3.2/mesonbuild/utils/__init__.py0000644000175000017500000000000014325563231020434 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/utils/core.py0000644000175000017500000001426114562742363017653 0ustar00jpakkanejpakkane# Copyright 2012-2022 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.

"""
Contains the strict minimum to run scripts.

When the backend needs to call back into Meson during compilation for running
scripts or wrapping commands, it is important to load as little python modules
as possible for performance reasons.
"""

from __future__ import annotations
from dataclasses import dataclass
import os
import abc
import typing as T

if T.TYPE_CHECKING:
    from hashlib import _Hash
    from typing_extensions import Literal
    from ..mparser import BaseNode
    from .. import programs

    EnvironOrDict = T.Union[T.Dict[str, str], os._Environ[str]]

    EnvInitValueType = T.Dict[str, T.Union[str, T.List[str]]]


class MesonException(Exception):
    '''Exceptions thrown by Meson'''

    def __init__(self, *args: object, file: T.Optional[str] = None,
                 lineno: T.Optional[int] = None, colno: T.Optional[int] = None):
        super().__init__(*args)
        self.file = file
        self.lineno = lineno
        self.colno = colno

    @classmethod
    def from_node(cls, *args: object, node: BaseNode) -> MesonException:
        """Create a MesonException with location data from a BaseNode

        :param node: A BaseNode to set location data from
        :return: A Meson Exception instance
        """
        return cls(*args, file=node.filename, lineno=node.lineno, colno=node.colno)

class MesonBugException(MesonException):
    '''Exceptions thrown when there is a clear Meson bug that should be reported'''

    def __init__(self, msg: str, file: T.Optional[str] = None,
                 lineno: T.Optional[int] = None, colno: T.Optional[int] = None):
        super().__init__(msg + '\n\n    This is a Meson bug and should be reported!',
                         file=file, lineno=lineno, colno=colno)

class HoldableObject(metaclass=abc.ABCMeta):
    ''' Dummy base class for all objects that can be
        held by an interpreter.baseobjects.ObjectHolder '''

class EnvironmentVariables(HoldableObject):
    def __init__(self, values: T.Optional[EnvInitValueType] = None,
                 init_method: Literal['set', 'prepend', 'append'] = 'set', separator: str = os.pathsep) -> None:
        self.envvars: T.List[T.Tuple[T.Callable[[T.Dict[str, str], str, T.List[str], str, T.Optional[str]], str], str, T.List[str], str]] = []
        # The set of all env vars we have operations for. Only used for self.has_name()
        self.varnames: T.Set[str] = set()

        if values:
            init_func = getattr(self, init_method)
            for name, value in values.items():
                v = value if isinstance(value, list) else [value]
                init_func(name, v, separator)

    def __repr__(self) -> str:
        repr_str = "<{0}: {1}>"
        return repr_str.format(self.__class__.__name__, self.envvars)

    def hash(self, hasher: _Hash) -> None:
        myenv = self.get_env({})
        for key in sorted(myenv.keys()):
            hasher.update(bytes(key, encoding='utf-8'))
            hasher.update(b',')
            hasher.update(bytes(myenv[key], encoding='utf-8'))
            hasher.update(b';')

    def has_name(self, name: str) -> bool:
        return name in self.varnames

    def get_names(self) -> T.Set[str]:
        return self.varnames

    def merge(self, other: EnvironmentVariables) -> None:
        for method, name, values, separator in other.envvars:
            self.varnames.add(name)
            self.envvars.append((method, name, values, separator))

    def set(self, name: str, values: T.List[str], separator: str = os.pathsep) -> None:
        self.varnames.add(name)
        self.envvars.append((self._set, name, values, separator))

    def append(self, name: str, values: T.List[str], separator: str = os.pathsep) -> None:
        self.varnames.add(name)
        self.envvars.append((self._append, name, values, separator))

    def prepend(self, name: str, values: T.List[str], separator: str = os.pathsep) -> None:
        self.varnames.add(name)
        self.envvars.append((self._prepend, name, values, separator))

    @staticmethod
    def _set(env: T.Dict[str, str], name: str, values: T.List[str], separator: str, default_value: T.Optional[str]) -> str:
        return separator.join(values)

    @staticmethod
    def _append(env: T.Dict[str, str], name: str, values: T.List[str], separator: str, default_value: T.Optional[str]) -> str:
        curr = env.get(name, default_value)
        return separator.join(values if curr is None else [curr] + values)

    @staticmethod
    def _prepend(env: T.Dict[str, str], name: str, values: T.List[str], separator: str, default_value: T.Optional[str]) -> str:
        curr = env.get(name, default_value)
        return separator.join(values if curr is None else values + [curr])

    def get_env(self, full_env: EnvironOrDict, default_fmt: T.Optional[str] = None) -> T.Dict[str, str]:
        env = full_env.copy()
        for method, name, values, separator in self.envvars:
            default_value = default_fmt.format(name) if default_fmt else None
            env[name] = method(env, name, values, separator, default_value)
        return env


@dataclass(eq=False)
class ExecutableSerialisation:

    cmd_args: T.List[str]
    env: T.Optional[EnvironmentVariables] = None
    exe_wrapper: T.Optional['programs.ExternalProgram'] = None
    workdir: T.Optional[str] = None
    extra_paths: T.Optional[T.List] = None
    capture: T.Optional[str] = None
    feed: T.Optional[str] = None
    tag: T.Optional[str] = None
    verbose: bool = False
    installdir_map: T.Optional[T.Dict[str, str]] = None

    def __post_init__(self) -> None:
        self.pickled = False
        self.skip_if_destdir = False
        self.subproject = ''
        self.dry_run = False
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/utils/platform.py0000644000175000017500000000231714562742363020546 0ustar00jpakkanejpakkane# SPDX-license-identifier: Apache-2.0
# Copyright 2012-2021 The Meson development team
# Copyright Ā© 2021 Intel Corporation

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

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

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

"""base classes providing no-op functionality.."""

import os
import typing as T

from .. import mlog

__all__ = ['BuildDirLock']

# This needs to be inherited by the specific implementations to make type
# checking happy
class BuildDirLock:

    def __init__(self, builddir: str) -> None:
        self.lockfilename = os.path.join(builddir, 'meson-private/meson.lock')

    def __enter__(self) -> None:
        mlog.debug('Calling the no-op version of BuildDirLock')

    def __exit__(self, *args: T.Any) -> None:
        pass
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/utils/posix.py0000644000175000017500000000311714562742363020063 0ustar00jpakkanejpakkane# SPDX-license-identifier: Apache-2.0
# Copyright 2012-2021 The Meson development team
# Copyright Ā© 2021 Intel Corporation

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

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

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

"""Posix specific implementations of mesonlib functionality."""

import fcntl
import typing as T

from .core import MesonException
from .platform import BuildDirLock as BuildDirLockBase

__all__ = ['BuildDirLock']

class BuildDirLock(BuildDirLockBase):

    def __enter__(self) -> None:
        self.lockfile = open(self.lockfilename, 'w', encoding='utf-8')
        try:
            fcntl.flock(self.lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)
        except (BlockingIOError, PermissionError):
            self.lockfile.close()
            raise MesonException('Some other Meson process is already using this build directory. Exiting.')
        except OSError as e:
            self.lockfile.close()
            raise MesonException(f'Failed to lock the build directory: {e.strerror}')

    def __exit__(self, *args: T.Any) -> None:
        fcntl.flock(self.lockfile, fcntl.LOCK_UN)
        self.lockfile.close()
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/utils/universal.py0000644000175000017500000024641214562742363020740 0ustar00jpakkanejpakkane# Copyright 2012-2020 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 __future__ import annotations
from pathlib import Path
import argparse
import enum
import sys
import stat
import time
import abc
import platform, subprocess, operator, os, shlex, shutil, re
import collections
from functools import lru_cache, wraps, total_ordering
from itertools import tee
from tempfile import TemporaryDirectory, NamedTemporaryFile
import typing as T
import textwrap
import pickle
import errno
import json

from mesonbuild import mlog
from .core import MesonException, HoldableObject

if T.TYPE_CHECKING:
    from typing_extensions import Literal, Protocol

    from .._typing import ImmutableListProtocol
    from ..build import ConfigurationData
    from ..coredata import StrOrBytesPath
    from ..environment import Environment
    from ..compilers.compilers import Compiler
    from ..interpreterbase.baseobjects import SubProject

    class _EnvPickleLoadable(Protocol):

        environment: Environment

    class _VerPickleLoadable(Protocol):

        version: str

    # A generic type for pickle_load. This allows any type that has either a
    # .version or a .environment to be passed.
    _PL = T.TypeVar('_PL', bound=T.Union[_EnvPickleLoadable, _VerPickleLoadable])

FileOrString = T.Union['File', str]

_T = T.TypeVar('_T')
_U = T.TypeVar('_U')

__all__ = [
    'GIT',
    'python_command',
    'project_meson_versions',
    'SecondLevelHolder',
    'File',
    'FileMode',
    'GitException',
    'LibType',
    'MachineChoice',
    'EnvironmentException',
    'FileOrString',
    'GitException',
    'OptionKey',
    'dump_conf_header',
    'OptionType',
    'OrderedSet',
    'PerMachine',
    'PerMachineDefaultable',
    'PerThreeMachine',
    'PerThreeMachineDefaultable',
    'ProgressBar',
    'RealPathAction',
    'TemporaryDirectoryWinProof',
    'Version',
    'check_direntry_issues',
    'classify_unity_sources',
    'current_vs_supports_modules',
    'darwin_get_object_archs',
    'default_libdir',
    'default_libexecdir',
    'default_prefix',
    'default_datadir',
    'default_includedir',
    'default_infodir',
    'default_localedir',
    'default_mandir',
    'default_sbindir',
    'default_sysconfdir',
    'detect_subprojects',
    'detect_vcs',
    'do_conf_file',
    'do_conf_str',
    'do_replacement',
    'exe_exists',
    'expand_arguments',
    'extract_as_list',
    'first',
    'generate_list',
    'get_compiler_for_source',
    'get_filenames_templates_dict',
    'get_variable_regex',
    'get_wine_shortpath',
    'git',
    'has_path_sep',
    'is_aix',
    'is_android',
    'is_ascii_string',
    'is_cygwin',
    'is_debianlike',
    'is_dragonflybsd',
    'is_freebsd',
    'is_haiku',
    'is_hurd',
    'is_irix',
    'is_linux',
    'is_netbsd',
    'is_openbsd',
    'is_osx',
    'is_qnx',
    'is_sunos',
    'is_windows',
    'is_wsl',
    'iter_regexin_iter',
    'join_args',
    'listify',
    'partition',
    'path_is_in_root',
    'pickle_load',
    'Popen_safe',
    'Popen_safe_logged',
    'quiet_git',
    'quote_arg',
    'relative_to_if_possible',
    'relpath',
    'replace_if_different',
    'run_once',
    'get_meson_command',
    'set_meson_command',
    'split_args',
    'stringlistify',
    'substitute_values',
    'substring_is_in_list',
    'typeslistify',
    'verbose_git',
    'version_compare',
    'version_compare_condition_with_min',
    'version_compare_many',
    'search_version',
    'windows_detect_native_arch',
    'windows_proof_rm',
    'windows_proof_rmtree',
]


# TODO: this is such a hack, this really should be either in coredata or in the
# interpreter
# {subproject: project_meson_version}
project_meson_versions: T.DefaultDict[str, str] = collections.defaultdict(str)


from glob import glob

if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'):
    # using a PyInstaller bundle, e.g. the MSI installed executable
    python_command = [sys.executable, 'runpython']
else:
    python_command = [sys.executable]
_meson_command: T.Optional['ImmutableListProtocol[str]'] = None


class EnvironmentException(MesonException):
    '''Exceptions thrown while processing and creating the build environment'''

class GitException(MesonException):
    def __init__(self, msg: str, output: T.Optional[str] = None):
        super().__init__(msg)
        self.output = output.strip() if output else ''

GIT = shutil.which('git')
def git(cmd: T.List[str], workingdir: StrOrBytesPath, check: bool = False, **kwargs: T.Any) -> T.Tuple[subprocess.Popen[str], str, str]:
    assert GIT is not None, 'Callers should make sure it exists'
    cmd = [GIT, *cmd]
    p, o, e = Popen_safe(cmd, cwd=workingdir, **kwargs)
    if check and p.returncode != 0:
        raise GitException('Git command failed: ' + str(cmd), e)
    return p, o, e

def quiet_git(cmd: T.List[str], workingdir: StrOrBytesPath, check: bool = False) -> T.Tuple[bool, str]:
    if not GIT:
        m = 'Git program not found.'
        if check:
            raise GitException(m)
        return False, m
    p, o, e = git(cmd, workingdir, check)
    if p.returncode != 0:
        return False, e
    return True, o

def verbose_git(cmd: T.List[str], workingdir: StrOrBytesPath, check: bool = False) -> bool:
    if not GIT:
        m = 'Git program not found.'
        if check:
            raise GitException(m)
        return False
    p, _, _ = git(cmd, workingdir, check, stdout=None, stderr=None)
    return p.returncode == 0

def set_meson_command(mainfile: str) -> None:
    global _meson_command  # pylint: disable=global-statement
    # 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(f'meson_command is {_meson_command!r}')


def get_meson_command() -> T.Optional['ImmutableListProtocol[str]']:
    return _meson_command


def is_ascii_string(astring: T.Union[str, bytes]) -> 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: T.Union[T.Iterable[T.Union[str, bytes]], str, bytes]) -> None:
    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 isinstance(direntry_array, (str, bytes)):
            direntry_array = [direntry_array]
        for de in direntry_array:
            if is_ascii_string(de):
                continue
            mlog.warning(textwrap.dedent(f'''
                You are using {e!r} which is not a Unicode-compatible
                locale but you are trying to access a file system entry called {de!r} which is
                not pure ASCII. This may cause problems.
                '''))

class SecondLevelHolder(HoldableObject, metaclass=abc.ABCMeta):
    ''' A second level object holder. The primary purpose
        of such objects is to hold multiple objects with one
        default option. '''

    @abc.abstractmethod
    def get_default_object(self) -> HoldableObject: ...

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: T.Optional[str] = None, owner: T.Union[str, int, None] = None,
                 group: T.Union[str, int, None] = None):
        self.perms_s = perms
        self.perms = self.perms_s_to_bits(perms)
        self.owner = owner
        self.group = group

    def __repr__(self) -> str:
        ret = ' int:
        '''
        Does the opposite of stat.filemode(), converts strings of the form
        'rwxr-xr-x' to st_mode enums which can be passed to os.chmod()
        '''
        if perms_s is None:
            # No perms specified, we will not touch the permissions
            return -1
        eg = 'rwxr-xr-x'
        if not isinstance(perms_s, str):
            raise MesonException(f'Install perms must be a string. For example, {eg!r}')
        if len(perms_s) != 9 or not cls.symbolic_perms_regex.match(perms_s):
            raise MesonException(f'File perms {perms_s!r} must be exactly 9 chars. For example, {eg!r}')
        perms = 0
        # Owner perms
        if perms_s[0] == 'r':
            perms |= stat.S_IRUSR
        if perms_s[1] == 'w':
            perms |= stat.S_IWUSR
        if perms_s[2] == 'x':
            perms |= stat.S_IXUSR
        elif perms_s[2] == 'S':
            perms |= stat.S_ISUID
        elif perms_s[2] == 's':
            perms |= stat.S_IXUSR
            perms |= stat.S_ISUID
        # Group perms
        if perms_s[3] == 'r':
            perms |= stat.S_IRGRP
        if perms_s[4] == 'w':
            perms |= stat.S_IWGRP
        if perms_s[5] == 'x':
            perms |= stat.S_IXGRP
        elif perms_s[5] == 'S':
            perms |= stat.S_ISGID
        elif perms_s[5] == 's':
            perms |= stat.S_IXGRP
            perms |= stat.S_ISGID
        # Others perms
        if perms_s[6] == 'r':
            perms |= stat.S_IROTH
        if perms_s[7] == 'w':
            perms |= stat.S_IWOTH
        if perms_s[8] == 'x':
            perms |= stat.S_IXOTH
        elif perms_s[8] == 'T':
            perms |= stat.S_ISVTX
        elif perms_s[8] == 't':
            perms |= stat.S_IXOTH
            perms |= stat.S_ISVTX
        return perms

dot_C_dot_H_warning = """You are using .C or .H files in your project. This is deprecated.
         Currently, Meson treats this as C++ code, but they
            used to be treated as C code.
         Note that the situation is a bit more complex if you are using the
         Visual Studio compiler, as it treats .C files as C code, unless you add
         the /TP compiler flag, but this is unreliable.
         See https://github.com/mesonbuild/meson/pull/8747 for the discussions."""
class File(HoldableObject):
    def __init__(self, is_built: bool, subdir: str, fname: str):
        if fname.endswith(".C") or fname.endswith(".H"):
            mlog.warning(dot_C_dot_H_warning, once=True)
        self.is_built = is_built
        self.subdir = subdir
        self.fname = fname
        self.hash = hash((is_built, subdir, fname))

    def __str__(self) -> str:
        return self.relative_name()

    def __repr__(self) -> str:
        ret = ' 'File':
        if not os.path.isfile(os.path.join(source_root, subdir, fname)):
            raise MesonException(f'File {fname} does not exist.')
        return File(False, subdir, fname)

    @staticmethod
    def from_built_file(subdir: str, fname: str) -> 'File':
        return File(True, subdir, fname)

    @staticmethod
    def from_built_relative(relative: str) -> 'File':
        dirpart, fnamepart = os.path.split(relative)
        return File(True, dirpart, fnamepart)

    @staticmethod
    def from_absolute_file(fname: str) -> 'File':
        return File(False, '', fname)

    @lru_cache(maxsize=None)
    def rel_to_builddir(self, build_to_src: str) -> 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())

    @property
    def suffix(self) -> str:
        return os.path.splitext(self.fname)[1][1:].lower()

    def endswith(self, ending: T.Union[str, T.Tuple[str, ...]]) -> bool:
        return self.fname.endswith(ending)

    def split(self, s: str, maxsplit: int = -1) -> T.List[str]:
        return self.fname.split(s, maxsplit=maxsplit)

    def rsplit(self, s: str, maxsplit: int = -1) -> T.List[str]:
        return self.fname.rsplit(s, maxsplit=maxsplit)

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, File):
            return NotImplemented
        if self.hash != other.hash:
            return False
        return (self.fname, self.subdir, self.is_built) == (other.fname, other.subdir, other.is_built)

    def __hash__(self) -> int:
        return self.hash

    @lru_cache(maxsize=None)
    def relative_name(self) -> str:
        return os.path.join(self.subdir, self.fname)


def get_compiler_for_source(compilers: T.Iterable['Compiler'], src: 'FileOrString') -> 'Compiler':
    """Given a set of compilers and a source, find the compiler for that source type."""
    for comp in compilers:
        if comp.can_compile(src):
            return comp
    raise MesonException(f'No specified compiler can handle file {src!s}')


def classify_unity_sources(compilers: T.Iterable['Compiler'], sources: T.Sequence['FileOrString']) -> T.Dict['Compiler', T.List['FileOrString']]:
    compsrclist: T.Dict['Compiler', T.List['FileOrString']] = {}
    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 MachineChoice(enum.IntEnum):

    """Enum class representing one of the two abstract machine names used in
    most places: the build, and host, machines.
    """

    BUILD = 0
    HOST = 1

    def __str__(self) -> str:
        return f'{self.get_lower_case_name()} machine'

    def get_lower_case_name(self) -> str:
        return PerMachine('build', 'host')[self]

    def get_prefix(self) -> str:
        return PerMachine('build.', '')[self]


class PerMachine(T.Generic[_T]):
    def __init__(self, build: _T, host: _T) -> None:
        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[T.Optional[_T]] = PerMachineDefaultable()
        unfreeze.build = self.build
        unfreeze.host = self.host
        if unfreeze.host == unfreeze.build:
            unfreeze.host = None
        return unfreeze

    def assign(self, build: _T, host: _T) -> None:
        self.build = build
        self.host = host

    def __repr__(self) -> str:
        return f'PerMachine({self.build!r}, {self.host!r})'


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) -> None:
        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[T.Optional[_T]] = PerThreeMachineDefaultable()
        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]

    def __repr__(self) -> str:
        return f'PerThreeMachine({self.build!r}, {self.host!r}, {self.target!r})'


class PerMachineDefaultable(PerMachine[T.Optional[_T]]):
    """Extends `PerMachine` with the ability to default from `None`s.
    """
    def __init__(self, build: T.Optional[_T] = None, host: T.Optional[_T] = None) -> None:
        super().__init__(build, host)

    def default_missing(self) -> "PerMachine[_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

    def __repr__(self) -> str:
        return f'PerMachineDefaultable({self.build!r}, {self.host!r})'

    @classmethod
    def default(cls, is_cross: bool, build: _T, host: _T) -> PerMachine[_T]:
        """Easy way to get a defaulted value

        This allows simplifying the case where you can control whether host and
        build are separate or not with a boolean. If the is_cross value is set
        to true then the optional host value will be used, otherwise the host
        will be set to the build value.
        """
        m = cls(build)
        if is_cross:
            m.host = host
        return m.default_missing()


class PerThreeMachineDefaultable(PerMachineDefaultable[T.Optional[_T]], 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 __repr__(self) -> str:
        return f'PerThreeMachineDefaultable({self.build!r}, {self.host!r}, {self.target!r})'


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'

def is_wsl() -> bool:
    return is_linux() and 'microsoft' in platform.release().lower()

def is_cygwin() -> bool:
    return sys.platform == '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 is_irix() -> bool:
    return platform.system().startswith('irix')

def is_hurd() -> bool:
    return platform.system().lower() == 'gnu'

def is_qnx() -> bool:
    return platform.system().lower() == 'qnx'

def is_aix() -> bool:
    return platform.system().lower() == 'aix'

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: str) -> 'ImmutableListProtocol[str]':
    '''
    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(f'lipo {objpath}: {stderr}')
        return None
    stdo = stdo.rsplit(': ', 1)[1]

    # Convert from lipo-style archs to meson-style CPUs
    map_arch = {
        'i386': 'x86',
        'arm64': 'aarch64',
        'arm64e': 'aarch64',
        'ppc7400': 'ppc',
        'ppc970': 'ppc',
    }
    lipo_archs = stdo.split()
    meson_archs = [map_arch.get(lipo_arch, lipo_arch) for lipo_arch in lipo_archs]

    # Add generic name for armv7 and armv7s
    if 'armv7' in stdo:
        meson_archs.append('arm')

    return meson_archs

def windows_detect_native_arch() -> str:
    """
    The architecture of Windows itself: x86, amd64 or arm64
    """
    if sys.platform != 'win32':
        return ''
    try:
        import ctypes
        process_arch = ctypes.c_ushort()
        native_arch = ctypes.c_ushort()
        kernel32 = ctypes.windll.kernel32
        process = ctypes.c_void_p(kernel32.GetCurrentProcess())
        # This is the only reliable way to detect an arm system if we are an x86/x64 process being emulated
        if kernel32.IsWow64Process2(process, ctypes.byref(process_arch), ctypes.byref(native_arch)):
            # https://docs.microsoft.com/en-us/windows/win32/sysinfo/image-file-machine-constants
            if native_arch.value == 0x8664:
                return 'amd64'
            elif native_arch.value == 0x014C:
                return 'x86'
            elif native_arch.value == 0xAA64:
                return 'arm64'
            elif native_arch.value == 0x01C4:
                return 'arm'
    except (OSError, AttributeError):
        pass
    # 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_vcs(source_dir: T.Union[str, Path]) -> T.Optional[T.Dict[str, str]]:
    vcs_systems = [
        {
            'name': 'git',
            'cmd': 'git',
            'repo_dir': '.git',
            'get_rev': 'git describe --dirty=+ --always',
            'rev_regex': '(.*)',
            'dep': '.git/logs/HEAD'
        },
        {
            'name': 'mercurial',
            'cmd': 'hg',
            'repo_dir': '.hg',
            'get_rev': 'hg id -i',
            'rev_regex': '(.*)',
            'dep': '.hg/dirstate'
        },
        {
            'name': 'subversion',
            'cmd': 'svn',
            'repo_dir': '.svn',
            'get_rev': 'svn info',
            'rev_regex': 'Revision: (.*)',
            'dep': '.svn/wc.db'
        },
        {
            'name': 'bazaar',
            'cmd': 'bzr',
            'repo_dir': '.bzr',
            'get_rev': 'bzr revno',
            'rev_regex': '(.*)',
            'dep': '.bzr'
        },
    ]
    if isinstance(source_dir, str):
        source_dir = Path(source_dir)

    parent_paths_and_self = collections.deque(source_dir.parents)
    # Prepend the source directory to the front so we can check it;
    # source_dir.parents doesn't include source_dir
    parent_paths_and_self.appendleft(source_dir)
    for curdir in parent_paths_and_self:
        for vcs in vcs_systems:
            if Path.is_dir(curdir.joinpath(vcs['repo_dir'])) and shutil.which(vcs['cmd']):
                vcs['wc_dir'] = str(curdir)
                return vcs
    return None

def current_vs_supports_modules() -> bool:
    vsver = os.environ.get('VSCMD_VER', '')
    nums = vsver.split('.', 2)
    major = int(nums[0])
    if major >= 17:
        return True
    if major == 16 and int(nums[1]) >= 10:
        return True
    return vsver.startswith('16.9.0') and '-pre.' in vsver

# a helper class which implements the same version ordering as RPM
class Version:
    def __init__(self, s: str) -> None:
        self._s = s

        # split into numeric, alphabetic and non-alphanumeric sequences
        sequences1 = re.finditer(r'(\d+|[a-zA-Z]+|[^a-zA-Z\d]+)', s)

        # non-alphanumeric separators are discarded
        sequences2 = [m for m in sequences1 if not re.match(r'[^a-zA-Z\d]+', m.group(1))]

        # numeric sequences are converted from strings to ints
        sequences3 = [int(m.group(1)) if m.group(1).isdigit() else m.group(1) for m in sequences2]

        self._v = sequences3

    def __str__(self) -> str:
        return '{} (V={})'.format(self._s, str(self._v))

    def __repr__(self) -> str:
        return f''

    def __lt__(self, other: object) -> bool:
        if isinstance(other, Version):
            return self.__cmp(other, operator.lt)
        return NotImplemented

    def __gt__(self, other: object) -> bool:
        if isinstance(other, Version):
            return self.__cmp(other, operator.gt)
        return NotImplemented

    def __le__(self, other: object) -> bool:
        if isinstance(other, Version):
            return self.__cmp(other, operator.le)
        return NotImplemented

    def __ge__(self, other: object) -> bool:
        if isinstance(other, Version):
            return self.__cmp(other, operator.ge)
        return NotImplemented

    def __eq__(self, other: object) -> bool:
        if isinstance(other, Version):
            return self._v == other._v
        return NotImplemented

    def __ne__(self, other: object) -> bool:
        if isinstance(other, Version):
            return self._v != other._v
        return NotImplemented

    def __cmp(self, other: 'Version', comparator: T.Callable[[T.Any, T.Any], bool]) -> bool:
        # 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: str, conditions: T.Union[str, T.Iterable[str]]) -> T.Tuple[bool, T.List[str], T.List[str]]:
    if isinstance(conditions, str):
        conditions = [conditions]
    found: T.List[str] = []
    not_found: T.List[str] = []
    for req in conditions:
        if not version_compare(vstr1, req):
            not_found.append(req)
        else:
            found.append(req)
    return not 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 T.cast('bool', cmpop(Version(minimum), Version(condition)))

def search_version(text: str) -> str:
    # 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"""
    (? str:
    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() or is_irix():
        return 'lib'
    if os.path.isdir('/usr/lib64') and not os.path.islink('/usr/lib64'):
        return 'lib64'
    return 'lib'


def default_libexecdir() -> str:
    if is_haiku():
        return 'lib'
    # There is no way to auto-detect this, so it must be set at build time
    return 'libexec'


def default_prefix() -> str:
    if is_windows():
        return 'c:/'
    if is_haiku():
        return '/boot/system/non-packaged'
    return '/usr/local'


def default_datadir() -> str:
    if is_haiku():
        return 'data'
    return 'share'


def default_includedir() -> str:
    if is_haiku():
        return 'develop/headers'
    return 'include'


def default_infodir() -> str:
    if is_haiku():
        return 'documentation/info'
    return 'share/info'


def default_localedir() -> str:
    if is_haiku():
        return 'data/locale'
    return 'share/locale'


def default_mandir() -> str:
    if is_haiku():
        return 'documentation/man'
    return 'share/man'


def default_sbindir() -> str:
    if is_haiku():
        return 'bin'
    return 'sbin'


def default_sysconfdir() -> str:
    if is_haiku():
        return 'settings'
    return 'etc'


def has_path_sep(name: str, sep: str = '/\\') -> bool:
    '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(fr'[{_whitespace}"]').search

    def quote_arg(arg: str) -> str:
        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: str) -> T.List[str]:
        result: T.List[str] = []
        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: str) -> str:
        return shlex.quote(arg)

    def split_args(cmd: str) -> T.List[str]:
        return shlex.split(cmd)


def join_args(args: T.Iterable[str]) -> str:
    return ' '.join([quote_arg(x) for x in args])


def do_replacement(regex: T.Pattern[str], line: str,
                   variable_format: Literal['meson', 'cmake', 'cmake@'],
                   confdata: T.Union[T.Dict[str, T.Tuple[str, T.Optional[str]]], 'ConfigurationData']) -> T.Tuple[str, T.Set[str]]:
    missing_variables: T.Set[str] = set()
    if variable_format == 'cmake':
        start_tag = '${'
        backslash_tag = '\\${'
    else:
        start_tag = '@'
        backslash_tag = '\\@'

    def variable_replace(match: T.Match[str]) -> str:
        # 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)
            var_str = ''
            if varname in confdata:
                var, _ = confdata.get(varname)
                if isinstance(var, str):
                    var_str = var
                elif variable_format.startswith("cmake") and isinstance(var, bool):
                    var_str = str(int(var))
                elif isinstance(var, int):
                    var_str = str(var)
                else:
                    msg = f'Tried to replace variable {varname!r} value with ' \
                          f'something other than a string or int: {var!r}'
                    raise MesonException(msg)
            else:
                missing_variables.add(varname)
            return var_str
    return re.sub(regex, variable_replace, line), missing_variables

def do_define(regex: T.Pattern[str], line: str, confdata: 'ConfigurationData',
              variable_format: Literal['meson', 'cmake', 'cmake@'], subproject: T.Optional[SubProject] = None) -> str:
    cmake_bool_define = False
    if variable_format != "meson":
        cmake_bool_define = "cmakedefine01" in line

    def get_cmake_define(line: str, confdata: 'ConfigurationData') -> str:
        arr = line.split()

        if cmake_bool_define:
            (v, desc) = confdata.get(arr[1])
            return str(int(bool(v)))

        define_value: T.List[str] = []
        for token in arr[2:]:
            try:
                v, _ = confdata.get(token)
                define_value += [str(v)]
            except KeyError:
                define_value += [token]
        return ' '.join(define_value)

    arr = line.split()
    if len(arr) != 2:
        if variable_format == 'meson':
            raise MesonException('#mesondefine does not contain exactly two tokens: %s' % line.strip())
        elif subproject is not None:
            from ..interpreterbase.decorators import FeatureNew
            FeatureNew.single_use('cmakedefine without exactly two tokens', '0.54.1', subproject)

    varname = arr[1]
    try:
        v, _ = confdata.get(varname)
    except KeyError:
        if cmake_bool_define:
            return '#define %s 0\n' % varname
        else:
            return '/* #undef %s */\n' % varname

    if isinstance(v, str) or variable_format != "meson":
        if variable_format == 'meson':
            result = v
        else:
            if not cmake_bool_define and not v:
                return '/* #undef %s */\n' % varname

            result = get_cmake_define(line, confdata)
        result = f'#define {varname} {result}'.strip() + '\n'
        result, _ = do_replacement(regex, result, variable_format, confdata)
        return result
    elif 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)
    else:
        raise MesonException('#mesondefine argument "%s" is of unknown type.' % varname)

def get_variable_regex(variable_format: Literal['meson', 'cmake', 'cmake@'] = 'meson') -> T.Pattern[str]:
    # 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_]+)@')
    else:
        regex = re.compile(r'(?:\\\\)+(?=\\?\$)|\\\${|\${([-a-zA-Z0-9_]+)}')
    return regex

def do_conf_str(src: str, data: T.List[str], confdata: 'ConfigurationData',
                variable_format: Literal['meson', 'cmake', 'cmake@'],
                subproject: T.Optional[SubProject] = None) -> T.Tuple[T.List[str], T.Set[str], bool]:
    def line_is_valid(line: str, variable_format: str) -> bool:
        if variable_format == 'meson':
            if '#cmakedefine' in line:
                return False
        else: # cmake format
            if '#mesondefine' in line:
                return False
        return True

    regex = get_variable_regex(variable_format)

    search_token = '#mesondefine'
    if variable_format != 'meson':
        search_token = '#cmakedefine'

    result: T.List[str] = []
    missing_variables: T.Set[str] = 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.lstrip().startswith(search_token):
            confdata_useless = False
            line = do_define(regex, line, confdata, variable_format, subproject)
        else:
            if not line_is_valid(line, variable_format):
                raise MesonException(f'Format error in {src}: saw "{line.strip()}" when format set to "{variable_format}"')
            line, missing = do_replacement(regex, line, variable_format, confdata)
            missing_variables.update(missing)
            if missing:
                confdata_useless = False
        result.append(line)

    return result, missing_variables, confdata_useless

def do_conf_file(src: str, dst: str, confdata: 'ConfigurationData',
                 variable_format: Literal['meson', 'cmake', 'cmake@'],
                 encoding: str = 'utf-8', subproject: T.Optional[SubProject] = None) -> T.Tuple[T.Set[str], bool]:
    try:
        with open(src, encoding=encoding, newline='') as f:
            data = f.readlines()
    except Exception as e:
        raise MesonException(f'Could not read input file {src}: {e!s}')

    (result, missing_variables, confdata_useless) = do_conf_str(src, data, confdata, variable_format, subproject)
    dst_tmp = dst + '~'
    try:
        with open(dst_tmp, 'w', encoding=encoding, newline='') as f:
            f.writelines(result)
    except Exception as e:
        raise MesonException(f'Could not write output file {dst}: {e!s}')
    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.
 */

{}

'''

CONF_NASM_PRELUDE = '''; Autogenerated by the Meson build system.
; Do not edit, your changes will be lost.

'''

def _dump_c_header(ofile: T.TextIO,
                   cdata: ConfigurationData,
                   output_format: Literal['c', 'nasm'],
                   macro_name: T.Optional[str]) -> None:
    format_desc: T.Callable[[str], str]
    if output_format == 'c':
        if macro_name:
            prelude = CONF_C_PRELUDE.format('#ifndef {0}\n#define {0}'.format(macro_name))
        else:
            prelude = CONF_C_PRELUDE.format('#pragma once')
        prefix = '#'
        format_desc = lambda desc: f'/* {desc} */\n'
    else:  # nasm
        prelude = CONF_NASM_PRELUDE
        prefix = '%'
        format_desc = lambda desc: '; ' + '\n; '.join(desc.splitlines()) + '\n'

    ofile.write(prelude)
    for k in sorted(cdata.keys()):
        (v, desc) = cdata.get(k)
        if desc:
            ofile.write(format_desc(desc))
        if isinstance(v, bool):
            if v:
                ofile.write(f'{prefix}define {k}\n\n')
            else:
                ofile.write(f'{prefix}undef {k}\n\n')
        elif isinstance(v, (int, str)):
            ofile.write(f'{prefix}define {k} {v}\n\n')
        else:
            raise MesonException('Unknown data type in configuration file entry: ' + k)
    if output_format == 'c' and macro_name:
        ofile.write('#endif\n')


def dump_conf_header(ofilename: str, cdata: ConfigurationData,
                     output_format: Literal['c', 'nasm', 'json'],
                     macro_name: T.Optional[str]) -> None:
    ofilename_tmp = ofilename + '~'
    with open(ofilename_tmp, 'w', encoding='utf-8') as ofile:
        if output_format == 'json':
            data = {k: v[0] for k, v in cdata.values.items()}
            json.dump(data, ofile, sort_keys=True)
        else:  # c, nasm
            _dump_c_header(ofile, cdata, output_format, macro_name)

    replace_if_different(ofilename, ofilename_tmp)


def replace_if_different(dst: str, dst_tmp: str) -> None:
    # 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) -> 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
    '''
    if not isinstance(item, list):
        return [item]
    result: T.List[T.Any] = []
    for i in item:
        if flatten and isinstance(i, list):
            result += listify(i, flatten=True)
        else:
            result.append(i)
    return result


def extract_as_list(dict_object: T.Dict[_T, _U], key: _T, pop: bool = False) -> T.List[_U]:
    '''
    Extracts all values from given dict_object and listifies them.
    '''
    fetch: T.Callable[[_T], _U] = dict_object.get
    if pop:
        fetch = dict_object.pop
    # If there's only one key, we don't return a list with one element
    return listify(fetch(key) or [], flatten=True)


def typeslistify(item: 'T.Union[_T, T.Sequence[_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}, not {!r}'.format(types, type(item)))
    for i in item:
        if i is not None and not isinstance(i, types):
            raise MesonException('List item must be one of {!r}, not {!r}'.format(types, type(i)))
    return item


def stringlistify(item: T.Union[T.Any, T.Sequence[T.Any]]) -> T.List[str]:
    return typeslistify(item, str)


def expand_arguments(args: T.Iterable[str]) -> T.Optional[T.List[str]]:
    expended_args: T.List[str] = []
    for arg in args:
        if not arg.startswith('@'):
            expended_args.append(arg)
            continue

        args_file = arg[1:]
        try:
            with open(args_file, encoding='utf-8') as f:
                extended_args = f.read().split()
            expended_args += extended_args
        except Exception as e:
            mlog.error('Expanding command line arguments:',  args_file, 'not found')
            mlog.exception(e)
            return None
    return expended_args


def partition(pred: T.Callable[[_T], object], iterable: T.Iterable[_T]) -> T.Tuple[T.Iterator[_T], T.Iterator[_T]]:
    """Use a predicate to partition entries into false entries and true
    entries.

    >>> x, y = partition(is_odd, range(10))
    >>> (list(x), list(y))
    ([0, 2, 4, 6, 8], [1, 3, 5, 7, 9])
    """
    t1, t2 = tee(iterable)
    return (t for t in t1 if not pred(t)), (t for t in t2 if pred(t))


def Popen_safe(args: T.List[str], write: T.Optional[str] = None,
               stdin: T.Union[T.TextIO, T.BinaryIO, int] = subprocess.DEVNULL,
               stdout: T.Union[T.TextIO, T.BinaryIO, int] = subprocess.PIPE,
               stderr: T.Union[T.TextIO, T.BinaryIO, int] = subprocess.PIPE,
               **kwargs: T.Any) -> T.Tuple['subprocess.Popen[str]', str, str]:
    import locale
    encoding = locale.getpreferredencoding()
    # Stdin defaults to DEVNULL otherwise the command run by us here might mess
    # up the console and ANSI colors will stop working on Windows.
    # If write is not None, set stdin to PIPE so data can be sent.
    if write is not None:
        stdin = subprocess.PIPE

    try:
        if not sys.stdout.encoding or encoding.upper() != 'UTF-8':
            p, o, e = Popen_safe_legacy(args, write=write, stdin=stdin, stdout=stdout, stderr=stderr, **kwargs)
        else:
            p = subprocess.Popen(args, universal_newlines=True, encoding=encoding, close_fds=False,
                                 stdin=stdin, stdout=stdout, stderr=stderr, **kwargs)
            o, e = p.communicate(write)
    except OSError as oserr:
        if oserr.errno == errno.ENOEXEC:
            raise MesonException(f'Failed running {args[0]!r}, binary or interpreter not executable.\n'
                                 'Possibly wrong architecture or the executable bit is not set.')
        raise
    # 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,
                      stdin: T.Union[T.TextIO, T.BinaryIO, int] = subprocess.DEVNULL,
                      stdout: T.Union[T.TextIO, T.BinaryIO, int] = subprocess.PIPE,
                      stderr: T.Union[T.TextIO, T.BinaryIO, int] = subprocess.PIPE,
                      **kwargs: T.Any) -> T.Tuple['subprocess.Popen[str]', str, str]:
    p = subprocess.Popen(args, universal_newlines=False, close_fds=False,
                         stdin=stdin, stdout=stdout, stderr=stderr, **kwargs)
    input_: T.Optional[bytes] = None
    if write is not None:
        input_ = write.encode('utf-8')
    o, e = p.communicate(input_)
    if o is not None:
        if sys.stdout.encoding is not None:
            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 is not None and 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 Popen_safe_logged(args: T.List[str], msg: str = 'Called', **kwargs: T.Any) -> T.Tuple['subprocess.Popen[str]', str, str]:
    '''
    Wrapper around Popen_safe that assumes standard piped o/e and logs this to the meson log.
    '''
    try:
        p, o, e = Popen_safe(args, **kwargs)
    except Exception as excp:
        mlog.debug('-----------')
        mlog.debug(f'{msg}: `{join_args(args)}` -> {excp}')
        raise

    rc, out, err = p.returncode, o.strip(), e.strip()
    mlog.debug('-----------')
    mlog.debug(f'{msg}: `{join_args(args)}` -> {rc}')
    if out:
        mlog.debug(f'stdout:\n{out}\n-----------')
    if err:
        mlog.debug(f'stderr:\n{err}\n-----------')
    return p, o, e


def iter_regexin_iter(regexiter: T.Iterable[str], initer: T.Iterable[str]) -> T.Optional[str]:
    '''
    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 None


def _substitute_values_check_errors(command: T.List[str], values: T.Dict[str, T.Union[str, T.List[str]]]) -> None:
    # Error checking
    inregex: T.List[str] = ['@INPUT([0-9]+)?@', '@PLAINNAME@', '@BASENAME@']
    outregex: T.List[str] = ['@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:
            raise MesonException(f'Command cannot have {match!r}, since no input files were specified')
    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(f'Command cannot have {match!r} when there is '
                                     'more than one input file')
        # Error out if an invalid @INPUTnn@ template was specified
        for each in command:
            if not isinstance(each, str):
                continue
            match2 = re.search(inregex[0], each)
            if match2 and match2.group() not in values:
                m = 'Command cannot have {!r} since there are only {!r} inputs'
                raise MesonException(m.format(match2.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:
            raise MesonException(f'Command cannot have {match!r} since there are no outputs')
    else:
        # Error out if an invalid @OUTPUTnn@ template was specified
        for each in command:
            if not isinstance(each, str):
                continue
            match2 = re.search(outregex[0], each)
            if match2 and match2.group() not in values:
                m = 'Command cannot have {!r} since there are only {!r} outputs'
                raise MesonException(m.format(match2.group(), len(values['@OUTPUT@'])))


def substitute_values(command: T.List[str], values: T.Dict[str, T.Union[str, T.List[str]]]) -> T.List[str]:
    '''
    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.

    The typing of this function is difficult, as only @OUTPUT@ and @INPUT@ can
    be lists, everything else is a string. However, TypeDict cannot represent
    this, as you can have optional keys, but not extra keys. We end up just
    having to us asserts to convince type checkers that this is okay.

    https://github.com/python/mypy/issues/4617
    '''

    def replace(m: T.Match[str]) -> str:
        v = values[m.group(0)]
        assert isinstance(v, str), 'for mypy'
        return v

    # Error checking
    _substitute_values_check_errors(command, values)

    # Substitution
    outcmd: T.List[str] = []
    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:
        more: T.Optional[str] = None
        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:
            o = values[vv]
            assert isinstance(o, str), 'for mypy'
            more = o
        # Substitute everything else with replacement
        elif value_rx:
            more = value_rx.sub(replace, vv)
        else:
            more = vv

        if more is not None:
            outcmd.append(more)

    return outcmd


def get_filenames_templates_dict(inputs: T.List[str], outputs: T.List[str]) -> T.Dict[str, T.Union[str, T.List[str]]]:
    '''
    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: T.Dict[str, T.Union[str, T.List[str]]] = {}
    # 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[f'@INPUT{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[f'@OUTPUT{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: str) -> None:
    # 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: str) -> None:
    # 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]
    writable = False
    for d in delays:
        try:
            # Start by making the tree writable.
            if not writable:
                _make_tree_writable(f)
                writable = True
        except PermissionError:
            time.sleep(d)
            continue
        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: str) -> None:
    """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)


class TemporaryDirectoryWinProof(TemporaryDirectory):
    """
    Like TemporaryDirectory, but cleans things up using
    windows_proof_rmtree()
    """

    def __exit__(self, exc: T.Any, value: T.Any, tb: T.Any) -> None:
        try:
            super().__exit__(exc, value, tb)
        except OSError:
            windows_proof_rmtree(self.name)

    def cleanup(self) -> None:
        try:
            super().cleanup()
        except OSError:
            windows_proof_rmtree(self.name)


def detect_subprojects(spdir_name: str, current_dir: str = '',
                       result: T.Optional[T.Dict[str, T.List[str]]] = None) -> T.Dict[str, T.List[str]]:
    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


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(T.MutableSet[_T]):
    """A set that preserves the order in which items are added, by first
    insertion.
    """
    def __init__(self, iterable: T.Optional[T.Iterable[_T]] = None):
        self.__container: T.OrderedDict[_T, None] = collections.OrderedDict()
        if iterable:
            self.update(iterable)

    def __contains__(self, value: object) -> bool:
        return value in self.__container

    def __iter__(self) -> T.Iterator[_T]:
        return iter(self.__container.keys())

    def __len__(self) -> int:
        return len(self.__container)

    def __repr__(self) -> str:
        # 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) -> T.Iterator[_T]:
        return reversed(self.__container.keys())

    def add(self, value: _T) -> None:
        self.__container[value] = None

    def discard(self, value: _T) -> None:
        if value in self.__container:
            del self.__container[value]

    def move_to_end(self, value: _T, last: bool = True) -> None:
        self.__container.move_to_end(value, last)

    def pop(self, last: bool = True) -> _T:
        item, _ = self.__container.popitem(last)
        return item

    def update(self, iterable: T.Iterable[_T]) -> None:
        for item in iterable:
            self.__container[item] = None

    def difference(self, set_: T.Iterable[_T]) -> 'OrderedSet[_T]':
        return type(self)(e for e in self if e not in set_)

    def difference_update(self, iterable: T.Iterable[_T]) -> None:
        for item in iterable:
            self.discard(item)

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

def path_is_in_root(path: Path, root: Path, resolve: bool = False) -> bool:
    # Check whether a path is within the root directory root
    try:
        if resolve:
            path.resolve().relative_to(root.resolve())
        else:
            path.relative_to(root)
    except ValueError:
        return False
    return True

def relative_to_if_possible(path: Path, root: Path, resolve: bool = False) -> Path:
    try:
        if resolve:
            return path.resolve().relative_to(root.resolve())
        else:
            return path.relative_to(root)
    except ValueError:
        return path

class LibType(enum.IntEnum):

    """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: T.Optional[T.Iterable[str]] = None, total: T.Optional[int] = None,
                 bar_type: T.Optional[str] = None, desc: T.Optional[str] = None,
                 disable: T.Optional[bool] = None):
        if iterable is not None:
            self.iterable = iter(iterable)
            return
        self.total = total
        self.done = 0
        self.printed_dots = 0
        self.disable = not mlog.colorize_console() if disable is None else disable
        if not self.disable:
            if self.total and bar_type == 'download':
                print('Download size:', self.total)
            if desc:
                print(f'{desc}: ', end='')

    # Pretend to be an iterator when called as one and don't print any
    # progress
    def __iter__(self) -> T.Iterator[str]:
        return self.iterable

    def __next__(self) -> str:
        return next(self.iterable)

    def print_dot(self) -> None:
        if not self.disable:
            print('.', end='')
            sys.stdout.flush()
        self.printed_dots += 1

    def update(self, progress: int) -> None:
        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) -> None:
        if not self.disable:
            print()

try:
    from tqdm import tqdm
except ImportError:
    # ideally we would use a typing.Protocol here, but it's part of typing_extensions until 3.8
    ProgressBar: T.Union[T.Type[ProgressBarFallback], T.Type[ProgressBarTqdm]] = ProgressBarFallback
else:
    class ProgressBarTqdm(tqdm):
        def __init__(self, *args: T.Any, bar_type: T.Optional[str] = None, **kwargs: T.Any) -> None:
            if bar_type == 'download':
                kwargs.update({'unit': 'B',
                               'unit_scale': True,
                               'unit_divisor': 1024,
                               'leave': True,
                               'bar_format': '{l_bar}{bar}| {n_fmt}/{total_fmt} {rate_fmt} eta {remaining}',
                               })

            else:
                kwargs.update({'leave': False,
                               'bar_format': '{l_bar}{bar}| {n_fmt}/{total_fmt} eta {remaining}',
                               })
            super().__init__(*args, **kwargs)

    ProgressBar = ProgressBarTqdm


class RealPathAction(argparse.Action):
    def __init__(self, option_strings: T.List[str], dest: str, default: str = '.', **kwargs: T.Any):
        default = os.path.abspath(os.path.realpath(default))
        super().__init__(option_strings, dest, nargs=None, default=default, **kwargs)

    def __call__(self, parser: argparse.ArgumentParser, namespace: argparse.Namespace,
                 values: T.Union[str, T.Sequence[T.Any], None], option_string: T.Optional[str] = None) -> None:
        assert isinstance(values, str)
        setattr(namespace, self.dest, os.path.abspath(os.path.realpath(values)))


def get_wine_shortpath(winecmd: T.List[str], wine_paths: T.List[str],
                       workdir: T.Optional[str] = None) -> str:
    '''
    WINEPATH size is limited to 1024 bytes which can easily be exceeded when
    adding the path to every dll inside build directory. See
    https://bugs.winehq.org/show_bug.cgi?id=45810.

    To shorten it as much as possible we use path relative to `workdir`
    where possible and convert absolute paths to Windows shortpath (e.g.
    "/usr/x86_64-w64-mingw32/lib" to "Z:\\usr\\X86_~FWL\\lib").

    This limitation reportedly has been fixed with wine >= 6.4
    '''

    # Remove duplicates
    wine_paths = list(OrderedSet(wine_paths))

    # Check if it's already short enough
    wine_path = ';'.join(wine_paths)
    if len(wine_path) <= 1024:
        return wine_path

    # Check if we have wine >= 6.4
    from ..programs import ExternalProgram
    wine = ExternalProgram('wine', winecmd, silent=True)
    if version_compare(wine.get_version(), '>=6.4'):
        return wine_path

    # Check paths that can be reduced by making them relative to workdir.
    rel_paths: T.List[str] = []
    if workdir:
        abs_paths: T.List[str] = []
        for p in wine_paths:
            try:
                rel = Path(p).relative_to(workdir)
                rel_paths.append(str(rel))
            except ValueError:
                abs_paths.append(p)
        wine_paths = abs_paths

    if wine_paths:
        # BAT script that takes a list of paths in argv and prints semi-colon separated shortpaths
        with NamedTemporaryFile('w', suffix='.bat', encoding='utf-8', delete=False) as bat_file:
            bat_file.write('''
            @ECHO OFF
            for %%x in (%*) do (
                echo|set /p=;%~sx
            )
            ''')
        try:
            stdout = subprocess.check_output(winecmd + ['cmd', '/C', bat_file.name] + wine_paths,
                                             encoding='utf-8', stderr=subprocess.DEVNULL)
            stdout = stdout.strip(';')
            if stdout:
                wine_paths = stdout.split(';')
            else:
                mlog.warning('Could not shorten WINEPATH: empty stdout')
        except subprocess.CalledProcessError as e:
            mlog.warning(f'Could not shorten WINEPATH: {str(e)}')
        finally:
            os.unlink(bat_file.name)
    wine_path = ';'.join(rel_paths + wine_paths)
    if len(wine_path) > 1024:
        mlog.warning('WINEPATH exceeds 1024 characters which could cause issues')
    return wine_path


def run_once(func: T.Callable[..., _T]) -> T.Callable[..., _T]:
    ret: T.List[_T] = []

    @wraps(func)
    def wrapper(*args: T.Any, **kwargs: T.Any) -> _T:
        if ret:
            return ret[0]

        val = func(*args, **kwargs)
        ret.append(val)
        return val

    return wrapper


def generate_list(func: T.Callable[..., T.Generator[_T, None, None]]) -> T.Callable[..., T.List[_T]]:
    @wraps(func)
    def wrapper(*args: T.Any, **kwargs: T.Any) -> T.List[_T]:
        return list(func(*args, **kwargs))

    return wrapper


class OptionType(enum.IntEnum):

    """Enum used to specify what kind of argument a thing is."""

    BUILTIN = 0
    BACKEND = 1
    BASE = 2
    COMPILER = 3
    PROJECT = 4

# This is copied from coredata. There is no way to share this, because this
# is used in the OptionKey constructor, and the coredata lists are
# OptionKeys...
_BUILTIN_NAMES = {
    'prefix',
    'bindir',
    'datadir',
    'includedir',
    'infodir',
    'libdir',
    'licensedir',
    'libexecdir',
    'localedir',
    'localstatedir',
    'mandir',
    'sbindir',
    'sharedstatedir',
    'sysconfdir',
    'auto_features',
    'backend',
    'buildtype',
    'debug',
    'default_library',
    'errorlogs',
    'genvslite',
    'install_umask',
    'layout',
    'optimization',
    'prefer_static',
    'stdsplit',
    'strip',
    'unity',
    'unity_size',
    'warning_level',
    'werror',
    'wrap_mode',
    'force_fallback_for',
    'pkg_config_path',
    'cmake_prefix_path',
    'vsenv',
}


def _classify_argument(key: 'OptionKey') -> OptionType:
    """Classify arguments into groups so we know which dict to assign them to."""

    if key.name.startswith('b_'):
        return OptionType.BASE
    elif key.lang is not None:
        return OptionType.COMPILER
    elif key.name in _BUILTIN_NAMES or key.module:
        return OptionType.BUILTIN
    elif key.name.startswith('backend_'):
        assert key.machine is MachineChoice.HOST, str(key)
        return OptionType.BACKEND
    else:
        assert key.machine is MachineChoice.HOST, str(key)
        return OptionType.PROJECT


@total_ordering
class OptionKey:

    """Represents an option key in the various option dictionaries.

    This provides a flexible, powerful way to map option names from their
    external form (things like subproject:build.option) to something that
    internally easier to reason about and produce.
    """

    __slots__ = ['name', 'subproject', 'machine', 'lang', '_hash', 'type', 'module']

    name: str
    subproject: str
    machine: MachineChoice
    lang: T.Optional[str]
    _hash: int
    type: OptionType
    module: T.Optional[str]

    def __init__(self, name: str, subproject: str = '',
                 machine: MachineChoice = MachineChoice.HOST,
                 lang: T.Optional[str] = None,
                 module: T.Optional[str] = None,
                 _type: T.Optional[OptionType] = None):
        # the _type option to the constructor is kinda private. We want to be
        # able tos ave the state and avoid the lookup function when
        # pickling/unpickling, but we need to be able to calculate it when
        # constructing a new OptionKey
        object.__setattr__(self, 'name', name)
        object.__setattr__(self, 'subproject', subproject)
        object.__setattr__(self, 'machine', machine)
        object.__setattr__(self, 'lang', lang)
        object.__setattr__(self, 'module', module)
        object.__setattr__(self, '_hash', hash((name, subproject, machine, lang, module)))
        if _type is None:
            _type = _classify_argument(self)
        object.__setattr__(self, 'type', _type)

    def __setattr__(self, key: str, value: T.Any) -> None:
        raise AttributeError('OptionKey instances do not support mutation.')

    def __getstate__(self) -> T.Dict[str, T.Any]:
        return {
            'name': self.name,
            'subproject': self.subproject,
            'machine': self.machine,
            'lang': self.lang,
            '_type': self.type,
            'module': self.module,
        }

    def __setstate__(self, state: T.Dict[str, T.Any]) -> None:
        """De-serialize the state of a pickle.

        This is very clever. __init__ is not a constructor, it's an
        initializer, therefore it's safe to call more than once. We create a
        state in the custom __getstate__ method, which is valid to pass
        splatted to the initializer.
        """
        # Mypy doesn't like this, because it's so clever.
        self.__init__(**state)  # type: ignore

    def __hash__(self) -> int:
        return self._hash

    def _to_tuple(self) -> T.Tuple[str, OptionType, str, str, MachineChoice, str]:
        return (self.subproject, self.type, self.lang or '', self.module or '', self.machine, self.name)

    def __eq__(self, other: object) -> bool:
        if isinstance(other, OptionKey):
            return self._to_tuple() == other._to_tuple()
        return NotImplemented

    def __lt__(self, other: object) -> bool:
        if isinstance(other, OptionKey):
            return self._to_tuple() < other._to_tuple()
        return NotImplemented

    def __str__(self) -> str:
        out = self.name
        if self.lang:
            out = f'{self.lang}_{out}'
        if self.machine is MachineChoice.BUILD:
            out = f'build.{out}'
        if self.module:
            out = f'{self.module}.{out}'
        if self.subproject:
            out = f'{self.subproject}:{out}'
        return out

    def __repr__(self) -> str:
        return f'OptionKey({self.name!r}, {self.subproject!r}, {self.machine!r}, {self.lang!r}, {self.module!r}, {self.type!r})'

    @classmethod
    def from_string(cls, raw: str) -> 'OptionKey':
        """Parse the raw command line format into a three part tuple.

        This takes strings like `mysubproject:build.myoption` and Creates an
        OptionKey out of them.
        """
        try:
            subproject, raw2 = raw.split(':')
        except ValueError:
            subproject, raw2 = '', raw

        module = None
        for_machine = MachineChoice.HOST
        try:
            prefix, raw3 = raw2.split('.')
            if prefix == 'build':
                for_machine = MachineChoice.BUILD
            else:
                module = prefix
        except ValueError:
            raw3 = raw2

        from ..compilers import all_languages
        if any(raw3.startswith(f'{l}_') for l in all_languages):
            lang, opt = raw3.split('_', 1)
        else:
            lang, opt = None, raw3
        assert ':' not in opt
        assert '.' not in opt

        return cls(opt, subproject, for_machine, lang, module)

    def evolve(self, name: T.Optional[str] = None, subproject: T.Optional[str] = None,
               machine: T.Optional[MachineChoice] = None, lang: T.Optional[str] = '',
               module: T.Optional[str] = '') -> 'OptionKey':
        """Create a new copy of this key, but with altered members.

        For example:
        >>> a = OptionKey('foo', '', MachineChoice.Host)
        >>> b = OptionKey('foo', 'bar', MachineChoice.Host)
        >>> b == a.evolve(subproject='bar')
        True
        """
        # We have to be a little clever with lang here, because lang is valid
        # as None, for non-compiler options
        return OptionKey(
            name if name is not None else self.name,
            subproject if subproject is not None else self.subproject,
            machine if machine is not None else self.machine,
            lang if lang != '' else self.lang,
            module if module != '' else self.module
        )

    def as_root(self) -> 'OptionKey':
        """Convenience method for key.evolve(subproject='')."""
        return self.evolve(subproject='')

    def as_build(self) -> 'OptionKey':
        """Convenience method for key.evolve(machine=MachineChoice.BUILD)."""
        return self.evolve(machine=MachineChoice.BUILD)

    def as_host(self) -> 'OptionKey':
        """Convenience method for key.evolve(machine=MachineChoice.HOST)."""
        return self.evolve(machine=MachineChoice.HOST)

    def is_backend(self) -> bool:
        """Convenience method to check if this is a backend option."""
        return self.type is OptionType.BACKEND

    def is_builtin(self) -> bool:
        """Convenience method to check if this is a builtin option."""
        return self.type is OptionType.BUILTIN

    def is_compiler(self) -> bool:
        """Convenience method to check if this is a builtin option."""
        return self.type is OptionType.COMPILER

    def is_project(self) -> bool:
        """Convenience method to check if this is a project option."""
        return self.type is OptionType.PROJECT

    def is_base(self) -> bool:
        """Convenience method to check if this is a base option."""
        return self.type is OptionType.BASE


def pickle_load(filename: str, object_name: str, object_type: T.Type[_PL], suggest_reconfigure: bool = True) -> _PL:
    load_fail_msg = f'{object_name} file {filename!r} is corrupted.'
    extra_msg = ' Consider reconfiguring the directory with "meson setup --reconfigure".' if suggest_reconfigure else ''
    try:
        with open(filename, 'rb') as f:
            obj = pickle.load(f)
    except (pickle.UnpicklingError, EOFError):
        raise MesonException(load_fail_msg + extra_msg)
    except (TypeError, ModuleNotFoundError, AttributeError):
        raise MesonException(
            f"{object_name} file {filename!r} references functions or classes that don't "
            "exist. This probably means that it was generated with an old "
            "version of meson." + extra_msg)

    if not isinstance(obj, object_type):
        raise MesonException(load_fail_msg + extra_msg)

    # Because these Protocols are not available at runtime (and cannot be made
    # available at runtime until we drop support for Python < 3.8), we have to
    # do a bit of hackery so that mypy understands what's going on here
    version: str
    if hasattr(obj, 'version'):
        version = T.cast('_VerPickleLoadable', obj).version
    else:
        version = T.cast('_EnvPickleLoadable', obj).environment.coredata.version

    from ..coredata import version as coredata_version
    from ..coredata import major_versions_differ, MesonVersionMismatchException
    if major_versions_differ(version, coredata_version):
        raise MesonVersionMismatchException(version, coredata_version, extra_msg)
    return obj


def first(iter: T.Iterable[_T], predicate: T.Callable[[_T], bool]) -> T.Optional[_T]:
    """Find the first entry in an iterable where the given predicate is true

    :param iter: The iterable to search
    :param predicate: A finding function that takes an element from the iterable
        and returns True if found, otherwise False
    :return: The first found element, or None if it is not found
    """
    for i in iter:
        if predicate(i):
            return i
    return None
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336264.0
meson-1.3.2/mesonbuild/utils/vsenv.py0000644000175000017500000000773314516507010020055 0ustar00jpakkanejpakkanefrom __future__ import annotations

import os
import subprocess
import json
import pathlib
import shutil
import tempfile
import locale

from .. import mlog
from .core import MesonException
from .universal import is_windows, windows_detect_native_arch


__all__ = [
    'setup_vsenv',
]


bat_template = '''@ECHO OFF

call "{}"

ECHO {}
SET
'''

# If on Windows and VS is installed but not set up in the environment,
# set it to be runnable. In this way Meson can be directly invoked
# from any shell, VS Code etc.
def _setup_vsenv(force: bool) -> bool:
    if not is_windows():
        return False
    if os.environ.get('OSTYPE') == 'cygwin':
        return False
    if 'MESON_FORCE_VSENV_FOR_UNITTEST' not in os.environ:
        # VSINSTALL is set when running setvars from a Visual Studio installation
        # Tested with Visual Studio 2012 and 2017
        if 'VSINSTALLDIR' in os.environ:
            return False
        # Check explicitly for cl when on Windows
        if shutil.which('cl.exe'):
            return False
    if not force:
        if shutil.which('cc'):
            return False
        if shutil.which('gcc'):
            return False
        if shutil.which('clang'):
            return False
        if shutil.which('clang-cl'):
            return False

    root = os.environ.get("ProgramFiles(x86)") or os.environ.get("ProgramFiles")
    bat_locator_bin = pathlib.Path(root, 'Microsoft Visual Studio/Installer/vswhere.exe')
    if not bat_locator_bin.exists():
        raise MesonException(f'Could not find {bat_locator_bin}')
    bat_json = subprocess.check_output(
        [
            str(bat_locator_bin),
            '-latest',
            '-prerelease',
            '-requiresAny',
            '-requires', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
            '-requires', 'Microsoft.VisualStudio.Workload.WDExpress',
            '-products', '*',
            '-utf8',
            '-format',
            'json'
        ]
    )
    bat_info = json.loads(bat_json)
    if not bat_info:
        # VS installer installed but not VS itself maybe?
        raise MesonException('Could not parse vswhere.exe output')
    bat_root = pathlib.Path(bat_info[0]['installationPath'])
    if windows_detect_native_arch() == 'arm64':
        bat_path = bat_root / 'VC/Auxiliary/Build/vcvarsarm64.bat'
        if not bat_path.exists():
            bat_path = bat_root / 'VC/Auxiliary/Build/vcvarsx86_arm64.bat'
    else:
        bat_path = bat_root / 'VC/Auxiliary/Build/vcvars64.bat'
        # if VS is not found try VS Express
        if not bat_path.exists():
            bat_path = bat_root / 'VC/Auxiliary/Build/vcvarsx86_amd64.bat'
    if not bat_path.exists():
        raise MesonException(f'Could not find {bat_path}')

    mlog.log('Activating VS', bat_info[0]['catalog']['productDisplayVersion'])
    bat_separator = '---SPLIT---'
    bat_contents = bat_template.format(bat_path, bat_separator)
    bat_file = tempfile.NamedTemporaryFile('w', suffix='.bat', encoding='utf-8', delete=False)
    bat_file.write(bat_contents)
    bat_file.flush()
    bat_file.close()
    bat_output = subprocess.check_output(bat_file.name, universal_newlines=True,
                                         encoding=locale.getpreferredencoding(False))
    os.unlink(bat_file.name)
    bat_lines = bat_output.split('\n')
    bat_separator_seen = False
    for bat_line in bat_lines:
        if bat_line == bat_separator:
            bat_separator_seen = True
            continue
        if not bat_separator_seen:
            continue
        if not bat_line:
            continue
        try:
            k, v = bat_line.split('=', 1)
        except ValueError:
            # there is no "=", ignore junk data
            pass
        else:
            os.environ[k] = v
    return True

def setup_vsenv(force: bool = False) -> bool:
    try:
        return _setup_vsenv(force)
    except MesonException as e:
        if force:
            raise
        mlog.warning('Failed to activate VS environment:', str(e))
        return False
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/utils/win32.py0000644000175000017500000000271714562742363017670 0ustar00jpakkanejpakkane# SPDX-license-identifier: Apache-2.0
# Copyright 2012-2021 The Meson development team
# Copyright Ā© 2021 Intel Corporation

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

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

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

"""Windows specific implementations of mesonlib functionality."""

import msvcrt
import typing as T

from .core import MesonException
from .platform import BuildDirLock as BuildDirLockBase

__all__ = ['BuildDirLock']

class BuildDirLock(BuildDirLockBase):

    def __enter__(self) -> None:
        self.lockfile = open(self.lockfilename, 'w', encoding='utf-8')
        try:
            msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_NBLCK, 1)
        except (BlockingIOError, PermissionError):
            self.lockfile.close()
            raise MesonException('Some other Meson process is already using this build directory. Exiting.')

    def __exit__(self, *args: T.Any) -> None:
        msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_UNLCK, 1)
        self.lockfile.close()
././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1707853067.77864
meson-1.3.2/mesonbuild/wrap/0000755000175000017500000000000014562742414016153 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1650551419.0
meson-1.3.2/mesonbuild/wrap/__init__.py0000644000175000017500000000402614230265173020260 0ustar00jpakkanejpakkanefrom 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,
                   'nopromote': 5,
                   }

class WrapMode(Enum):
    default = 1
    nofallback = 2
    nodownload = 3
    forcefallback = 4
    nopromote = 5

    def __str__(self) -> str:
        return self.name

    @staticmethod
    def from_string(mode_name: str) -> 'WrapMode':
        g = string_to_value[mode_name]
        return WrapMode(g)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0
meson-1.3.2/mesonbuild/wrap/wrap.py0000644000175000017500000011432214562742373017505 0ustar00jpakkanejpakkane# 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 __future__ import annotations

from .. import mlog
import contextlib
from dataclasses import dataclass
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 time
import typing as T
import textwrap
import json

from base64 import b64encode
from netrc import netrc
from pathlib import Path, PurePath

from . import WrapMode
from .. import coredata
from ..mesonlib import quiet_git, GIT, ProgressBar, MesonException, windows_proof_rmtree, Popen_safe
from ..interpreterbase import FeatureNew
from ..interpreterbase import SubProject
from .. import mesonlib

if T.TYPE_CHECKING:
    import http.client
    from typing_extensions import Literal

    Method = Literal['meson', 'cmake', 'cargo']

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
except ImportError:
    has_ssl = False

REQ_TIMEOUT = 30.0
WHITELIST_SUBDOMAIN = 'wrapdb.mesonbuild.com'

ALL_TYPES = ['file', 'git', 'hg', 'svn']

PATCH = shutil.which('patch')

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(f'{urlstr} is not a valid URL')
    if not url.hostname.endswith(WHITELIST_SUBDOMAIN):
        raise WrapException(f'{urlstr} is not a whitelisted WrapDB URL')
    if has_ssl and not url.scheme == 'https':
        raise WrapException(f'WrapDB did not have expected SSL https url, instead got {urlstr}')
    return url

def open_wrapdburl(urlstring: str, allow_insecure: bool = False, have_opt: bool = False) -> 'http.client.HTTPResponse':
    if have_opt:
        insecure_msg = '\n\n    To allow connecting anyway, pass `--allow-insecure`.'
    else:
        insecure_msg = ''

    url = whitelist_wrapdb(urlstring)
    if has_ssl:
        try:
            return T.cast('http.client.HTTPResponse', urllib.request.urlopen(urllib.parse.urlunparse(url), timeout=REQ_TIMEOUT))
        except urllib.error.URLError as excp:
            msg = f'WrapDB connection failed to {urlstring} with error {excp}.'
            if isinstance(excp.reason, ssl.SSLCertVerificationError):
                if allow_insecure:
                    mlog.warning(f'{msg}\n\n    Proceeding without authentication.')
                else:
                    raise WrapException(f'{msg}{insecure_msg}')
            else:
                raise WrapException(msg)
    elif not allow_insecure:
        raise WrapException(f'SSL module not available in {sys.executable}: Cannot contact the WrapDB.{insecure_msg}')
    else:
        # following code is only for those without Python SSL
        mlog.warning(f'SSL module not available in {sys.executable}: WrapDB traffic not authenticated.', once=True)

    # If we got this far, allow_insecure was manually passed
    nossl_url = url._replace(scheme='http')
    try:
        return T.cast('http.client.HTTPResponse', urllib.request.urlopen(urllib.parse.urlunparse(nossl_url), timeout=REQ_TIMEOUT))
    except urllib.error.URLError as excp:
        raise WrapException(f'WrapDB connection failed to {urlstring} with error {excp}')

def get_releases_data(allow_insecure: bool) -> bytes:
    url = open_wrapdburl('https://wrapdb.mesonbuild.com/v2/releases.json', allow_insecure, True)
    return url.read()

def get_releases(allow_insecure: bool) -> T.Dict[str, T.Any]:
    data = get_releases_data(allow_insecure)
    return T.cast('T.Dict[str, T.Any]', json.loads(data.decode()))

def update_wrap_file(wrapfile: str, name: str, new_version: str, new_revision: str, allow_insecure: bool) -> None:
    url = open_wrapdburl(f'https://wrapdb.mesonbuild.com/v2/{name}_{new_version}-{new_revision}/{name}.wrap',
                         allow_insecure, True)
    with open(wrapfile, 'wb') as f:
        f.write(url.read())

def parse_patch_url(patch_url: str) -> T.Tuple[str, str]:
    u = urllib.parse.urlparse(patch_url)
    if u.netloc != 'wrapdb.mesonbuild.com':
        raise WrapException(f'URL {patch_url} does not seems to be a wrapdb patch')
    arr = u.path.strip('/').split('/')
    if arr[0] == 'v1':
        # e.g. https://wrapdb.mesonbuild.com/v1/projects/zlib/1.2.11/5/get_zip
        return arr[-3], arr[-2]
    elif arr[0] == 'v2':
        # e.g. https://wrapdb.mesonbuild.com/v2/zlib_1.2.11-5/get_patch
        tag = arr[-2]
        _, version = tag.rsplit('_', 1)
        version, revision = version.rsplit('-', 1)
        return version, revision
    else:
        raise WrapException(f'Invalid wrapdb URL {patch_url}')

class WrapException(MesonException):
    pass

class WrapNotFoundException(WrapException):
    pass

class PackageDefinition:
    def __init__(self, fname: str, subproject: str = ''):
        self.filename = fname
        self.subproject = SubProject(subproject)
        self.type: T.Optional[str] = None
        self.values: T.Dict[str, str] = {}
        self.provided_deps: T.Dict[str, T.Optional[str]] = {}
        self.provided_programs: T.List[str] = []
        self.diff_files: T.List[Path] = []
        self.basename = os.path.basename(fname)
        self.has_wrap = self.basename.endswith('.wrap')
        self.name = self.basename[:-5] if self.has_wrap else self.basename
        # must be lowercase for consistency with dep=variable assignment
        self.provided_deps[self.name.lower()] = None
        # What the original file name was before redirection
        self.original_filename = fname
        self.redirected = False
        if self.has_wrap:
            self.parse_wrap()
            with open(fname, 'r', encoding='utf-8') as file:
                self.wrapfile_hash = hashlib.sha256(file.read().encode('utf-8')).hexdigest()
        self.directory = self.values.get('directory', self.name)
        if os.path.dirname(self.directory):
            raise WrapException('Directory key must be a name and not a path')
        if self.type and self.type not in ALL_TYPES:
            raise WrapException(f'Unknown wrap type {self.type!r}')
        self.filesdir = os.path.join(os.path.dirname(self.filename), 'packagefiles')

    def parse_wrap(self) -> None:
        try:
            config = configparser.ConfigParser(interpolation=None)
            config.read(self.filename, encoding='utf-8')
        except configparser.Error as e:
            raise WrapException(f'Failed to parse {self.basename}: {e!s}')
        self.parse_wrap_section(config)
        if self.type == 'redirect':
            # [wrap-redirect] have a `filename` value pointing to the real wrap
            # file we should parse instead. It must be relative to the current
            # wrap file location and must be in the form foo/subprojects/bar.wrap.
            dirname = Path(self.filename).parent
            fname = Path(self.values['filename'])
            for i, p in enumerate(fname.parts):
                if i % 2 == 0:
                    if p == '..':
                        raise WrapException('wrap-redirect filename cannot contain ".."')
                else:
                    if p != 'subprojects':
                        raise WrapException('wrap-redirect filename must be in the form foo/subprojects/bar.wrap')
            if fname.suffix != '.wrap':
                raise WrapException('wrap-redirect filename must be a .wrap file')
            fname = dirname / fname
            if not fname.is_file():
                raise WrapException(f'wrap-redirect {fname} filename does not exist')
            self.filename = str(fname)
            self.parse_wrap()
            self.redirected = True
        else:
            self.parse_provide_section(config)
        if 'patch_directory' in self.values:
            FeatureNew('Wrap files with patch_directory', '0.55.0').use(self.subproject)
        for what in ['patch', 'source']:
            if f'{what}_filename' in self.values and f'{what}_url' not in self.values:
                FeatureNew(f'Local wrap patch files without {what}_url', '0.55.0').use(self.subproject)

    def parse_wrap_section(self, config: configparser.ConfigParser) -> None:
        if len(config.sections()) < 1:
            raise WrapException(f'Missing sections in {self.basename}')
        self.wrap_section = config.sections()[0]
        if not self.wrap_section.startswith('wrap-'):
            raise WrapException(f'{self.wrap_section!r} is not a valid first section in {self.basename}')
        self.type = self.wrap_section[5:]
        self.values = dict(config[self.wrap_section])
        if 'diff_files' in self.values:
            FeatureNew('Wrap files with diff_files', '0.63.0').use(self.subproject)
            for s in self.values['diff_files'].split(','):
                path = Path(s.strip())
                if path.is_absolute():
                    raise WrapException('diff_files paths cannot be absolute')
                if '..' in path.parts:
                    raise WrapException('diff_files paths cannot contain ".."')
                self.diff_files.append(path)

    def parse_provide_section(self, config: configparser.ConfigParser) -> None:
        if config.has_section('provides'):
            raise WrapException('Unexpected "[provides]" section, did you mean "[provide]"?')
        if config.has_section('provide'):
            for k, v in config['provide'].items():
                if k == 'dependency_names':
                    # A comma separated list of dependency names that does not
                    # need a variable name; must be lowercase for consistency with
                    # dep=variable assignment
                    names_dict = {n.strip().lower(): None for n in v.split(',')}
                    self.provided_deps.update(names_dict)
                    continue
                if k == 'program_names':
                    # A comma separated list of program names
                    names_list = [n.strip() for n in v.split(',')]
                    self.provided_programs += names_list
                    continue
                if not v:
                    m = (f'Empty dependency variable name for {k!r} in {self.basename}. '
                         'If the subproject uses meson.override_dependency() '
                         'it can be added in the "dependency_names" special key.')
                    raise WrapException(m)
                self.provided_deps[k] = v

    def get(self, key: str) -> str:
        try:
            return self.values[key]
        except KeyError:
            raise WrapException(f'Missing key {key!r} in {self.basename}')

    def get_hashfile(self, subproject_directory: str) -> str:
        return os.path.join(subproject_directory, '.meson-subproject-wrap-hash.txt')

    def update_hash_cache(self, subproject_directory: str) -> None:
        if self.has_wrap:
            with open(self.get_hashfile(subproject_directory), 'w', encoding='utf-8') as file:
                file.write(self.wrapfile_hash + '\n')

def get_directory(subdir_root: str, packagename: str) -> str:
    fname = os.path.join(subdir_root, packagename + '.wrap')
    if os.path.isfile(fname):
        wrap = PackageDefinition(fname)
        return wrap.directory
    return packagename

def verbose_git(cmd: T.List[str], workingdir: str, check: bool = False) -> bool:
    '''
    Wrapper to convert GitException to WrapException caught in interpreter.
    '''
    try:
        return mesonlib.verbose_git(cmd, workingdir, check=check)
    except mesonlib.GitException as e:
        raise WrapException(str(e))

@dataclass(eq=False)
class Resolver:
    source_dir: str
    subdir: str
    subproject: str = ''
    wrap_mode: WrapMode = WrapMode.default
    wrap_frontend: bool = False
    allow_insecure: bool = False
    silent: bool = False

    def __post_init__(self) -> None:
        self.subdir_root = os.path.join(self.source_dir, self.subdir)
        self.cachedir = os.environ.get('MESON_PACKAGE_CACHE_DIR') or os.path.join(self.subdir_root, 'packagecache')
        self.wraps: T.Dict[str, PackageDefinition] = {}
        self.netrc: T.Optional[netrc] = None
        self.provided_deps: T.Dict[str, PackageDefinition] = {}
        self.provided_programs: T.Dict[str, PackageDefinition] = {}
        self.wrapdb: T.Dict[str, T.Any] = {}
        self.wrapdb_provided_deps: T.Dict[str, str] = {}
        self.wrapdb_provided_programs: T.Dict[str, str] = {}
        self.load_wraps()
        self.load_netrc()
        self.load_wrapdb()

    def load_netrc(self) -> None:
        try:
            self.netrc = netrc()
        except FileNotFoundError:
            return
        except Exception as e:
            mlog.warning(f'failed to process netrc file: {e}.', fatal=False)

    def load_wraps(self) -> None:
        if not os.path.isdir(self.subdir_root):
            return
        root, dirs, files = next(os.walk(self.subdir_root))
        ignore_dirs = {'packagecache', 'packagefiles'}
        for i in files:
            if not i.endswith('.wrap'):
                continue
            fname = os.path.join(self.subdir_root, i)
            wrap = PackageDefinition(fname, self.subproject)
            self.wraps[wrap.name] = wrap
            ignore_dirs |= {wrap.directory, wrap.name}
        # Add dummy package definition for directories not associated with a wrap file.
        for i in dirs:
            if i in ignore_dirs:
                continue
            fname = os.path.join(self.subdir_root, i)
            wrap = PackageDefinition(fname, self.subproject)
            self.wraps[wrap.name] = wrap

        for wrap in self.wraps.values():
            self.add_wrap(wrap)

    def add_wrap(self, wrap: PackageDefinition) -> None:
        for k in wrap.provided_deps.keys():
            if k in self.provided_deps:
                prev_wrap = self.provided_deps[k]
                m = f'Multiple wrap files provide {k!r} dependency: {wrap.basename} and {prev_wrap.basename}'
                raise WrapException(m)
            self.provided_deps[k] = wrap
        for k in wrap.provided_programs:
            if k in self.provided_programs:
                prev_wrap = self.provided_programs[k]
                m = f'Multiple wrap files provide {k!r} program: {wrap.basename} and {prev_wrap.basename}'
                raise WrapException(m)
            self.provided_programs[k] = wrap

    def load_wrapdb(self) -> None:
        try:
            with Path(self.subdir_root, 'wrapdb.json').open('r', encoding='utf-8') as f:
                self.wrapdb = json.load(f)
        except FileNotFoundError:
            return
        for name, info in self.wrapdb.items():
            self.wrapdb_provided_deps.update({i: name for i in info.get('dependency_names', [])})
            self.wrapdb_provided_programs.update({i: name for i in info.get('program_names', [])})

    def get_from_wrapdb(self, subp_name: str) -> PackageDefinition:
        info = self.wrapdb.get(subp_name)
        if not info:
            return None
        self.check_can_download()
        latest_version = info['versions'][0]
        version, revision = latest_version.rsplit('-', 1)
        url = urllib.request.urlopen(f'https://wrapdb.mesonbuild.com/v2/{subp_name}_{version}-{revision}/{subp_name}.wrap')
        fname = Path(self.subdir_root, f'{subp_name}.wrap')
        with fname.open('wb') as f:
            f.write(url.read())
        mlog.log(f'Installed {subp_name} version {version} revision {revision}')
        wrap = PackageDefinition(str(fname))
        self.wraps[wrap.name] = wrap
        self.add_wrap(wrap)
        return wrap

    def merge_wraps(self, other_resolver: 'Resolver') -> None:
        for k, v in other_resolver.wraps.items():
            self.wraps.setdefault(k, v)
        for k, v in other_resolver.provided_deps.items():
            self.provided_deps.setdefault(k, v)
        for k, v in other_resolver.provided_programs.items():
            self.provided_programs.setdefault(k, v)

    def find_dep_provider(self, packagename: str) -> T.Tuple[T.Optional[str], T.Optional[str]]:
        # Python's ini parser converts all key values to lowercase.
        # Thus the query name must also be in lower case.
        packagename = packagename.lower()
        wrap = self.provided_deps.get(packagename)
        if wrap:
            dep_var = wrap.provided_deps.get(packagename)
            return wrap.name, dep_var
        wrap_name = self.wrapdb_provided_deps.get(packagename)
        return wrap_name, None

    def get_varname(self, subp_name: str, depname: str) -> T.Optional[str]:
        wrap = self.wraps.get(subp_name)
        return wrap.provided_deps.get(depname) if wrap else None

    def find_program_provider(self, names: T.List[str]) -> T.Optional[str]:
        for name in names:
            wrap = self.provided_programs.get(name)
            if wrap:
                return wrap.name
            wrap_name = self.wrapdb_provided_programs.get(name)
            if wrap_name:
                return wrap_name
        return None

    def resolve(self, packagename: str, force_method: T.Optional[Method] = None) -> T.Tuple[str, Method]:
        self.packagename = packagename
        self.directory = packagename
        self.wrap = self.wraps.get(packagename)
        if not self.wrap:
            self.wrap = self.get_from_wrapdb(packagename)
        if not self.wrap:
            m = f'Neither a subproject directory nor a {self.packagename}.wrap file was found.'
            raise WrapNotFoundException(m)
        self.directory = self.wrap.directory

        if self.wrap.has_wrap:
            # We have a .wrap file, use directory relative to the location of
            # the wrap file if it exists, otherwise source code will be placed
            # into main project's subproject_dir even if the wrap file comes
            # from another subproject.
            self.dirname = os.path.join(os.path.dirname(self.wrap.filename), self.wrap.directory)
            if not os.path.exists(self.dirname):
                self.dirname = os.path.join(self.subdir_root, self.directory)
            # Check if the wrap comes from the main project.
            main_fname = os.path.join(self.subdir_root, self.wrap.basename)
            if self.wrap.filename != main_fname:
                rel = os.path.relpath(self.wrap.filename, self.source_dir)
                mlog.log('Using', mlog.bold(rel))
                # Write a dummy wrap file in main project that redirect to the
                # wrap we picked.
                with open(main_fname, 'w', encoding='utf-8') as f:
                    f.write(textwrap.dedent(f'''\
                        [wrap-redirect]
                        filename = {PurePath(os.path.relpath(self.wrap.filename, self.subdir_root)).as_posix()}
                        '''))
        else:
            # No wrap file, it's a dummy package definition for an existing
            # directory. Use the source code in place.
            self.dirname = self.wrap.filename
        rel_path = os.path.relpath(self.dirname, self.source_dir)

        # Map each supported method to a file that must exist at the root of source tree.
        methods_map: T.Dict[Method, str] = {
            'meson': 'meson.build',
            'cmake': 'CMakeLists.txt',
            'cargo': 'Cargo.toml',
        }

        # Check if this wrap forces a specific method, use meson otherwise.
        method = T.cast('T.Optional[Method]', self.wrap.values.get('method', force_method))
        if method and method not in methods_map:
            allowed_methods = ', '.join(methods_map.keys())
            raise WrapException(f'Wrap method {method!r} is not supported, must be one of: {allowed_methods}')
        if force_method and method != force_method:
            raise WrapException(f'Wrap method is {method!r} but we are trying to configure it with {force_method}')
        method = method or 'meson'

        def has_buildfile() -> bool:
            return os.path.exists(os.path.join(self.dirname, methods_map[method]))

        # The directory is there and has meson.build? Great, use it.
        if has_buildfile():
            self.validate()
            return rel_path, method

        # 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:
            # Check first if we have the extracted directory in our cache. This can
            # happen for example when MESON_PACKAGE_CACHE_DIR=/usr/share/cargo/registry
            # on distros that ships Rust source code.
            # TODO: We don't currently clone git repositories into the cache
            # directory, but we should to avoid cloning multiple times the same
            # repository. In that case, we could do something smarter than
            # copy_tree() here.
            cached_directory = os.path.join(self.cachedir, self.directory)
            if os.path.isdir(cached_directory):
                self.copy_tree(cached_directory, self.dirname)
            elif 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(f'Unknown wrap type {self.wrap.type!r}')
            try:
                self.apply_patch()
                self.apply_diff_files()
            except Exception:
                windows_proof_rmtree(self.dirname)
                raise

        if not has_buildfile():
            raise WrapException(f'Subproject exists but has no {methods_map[method]} file.')

        # At this point, the subproject has been successfully resolved for the
        # first time so save off the hash of the entire wrap file for future
        # reference.
        self.wrap.update_hash_cache(self.dirname)
        return rel_path, method

    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:
        # Is git installed? If not, we're probably not in a git repository and
        # definitely cannot try to conveniently set up a submodule.
        if not GIT:
            return False
        # Does the directory exist? Even uninitialised submodules checkout an
        # empty directory to work in
        if not os.path.isdir(self.dirname):
            return False
        # Are we in a git repository?
        ret, out = quiet_git(['rev-parse'], Path(self.dirname).parent)
        if not ret:
            return False
        # Is `dirname` a submodule?
        ret, out = quiet_git(['submodule', 'status', '.'], self.dirname)
        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):
                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(['submodule', 'update', '.'], self.dirname)
            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
        raise WrapException(f'Unknown git submodule output: {out!r}')

    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
        try:
            shutil.unpack_archive(path, extract_dir)
        except OSError as e:
            raise WrapException(f'failed to unpack archive with error: {str(e)}') from e

    def get_git(self) -> None:
        if not GIT:
            raise WrapException(f'Git program not found, cannot download {self.packagename}.wrap via git.')
        revno = self.wrap.get('revision')
        checkout_cmd = ['-c', 'advice.detachedHead=false', 'checkout', revno, '--']
        is_shallow = False
        depth_option: 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(['-c', 'init.defaultBranch=meson-dummy-branch', '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_cmd, 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_cmd, self.dirname):
                        verbose_git(['fetch', self.wrap.get('url'), revno], self.dirname, check=True)
                        verbose_git(checkout_cmd, self.dirname, check=True)
            else:
                args = ['-c', 'advice.detachedHead=false', 'clone', *depth_option]
                if revno.lower() != 'head':
                    args += ['--branch', revno]
                args += [self.wrap.get('url'), self.directory]
                verbose_git(args, 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 validate(self) -> None:
        # This check is only for subprojects with wraps.
        if not self.wrap.has_wrap:
            return

        # Retrieve original hash, if it exists.
        hashfile = self.wrap.get_hashfile(self.dirname)
        if os.path.isfile(hashfile):
            with open(hashfile, 'r', encoding='utf-8') as file:
                expected_hash = file.read().strip()
        else:
            # If stored hash doesn't exist then don't warn.
            return

        actual_hash = self.wrap.wrapfile_hash

        # Compare hashes and warn the user if they don't match.
        if expected_hash != actual_hash:
            mlog.warning(f'Subproject {self.wrap.name}\'s revision may be out of date; its wrap file has changed since it was first configured')

    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_netrc_credentials(self, netloc: str) -> T.Optional[T.Tuple[str, str]]:
        if self.netrc is None or netloc not in self.netrc.hosts:
            return None

        login, account, password = self.netrc.authenticators(netloc)
        if account is not None:
            login = account

        return login, password

    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, allow_insecure=self.allow_insecure, have_opt=self.wrap_frontend)
        elif WHITELIST_SUBDOMAIN in urlstring:
            raise WrapException(f'{urlstring} may be a WrapDB-impersonating URL')
        else:
            headers = {'User-Agent': f'mesonbuild/{coredata.version}'}
            creds = self.get_netrc_credentials(url.netloc)

            if creds is not None and '@' not in url.netloc:
                login, password = creds
                if url.scheme == 'https':
                    enc_creds = b64encode(f'{login}:{password}'.encode()).decode()
                    headers.update({'Authorization': f'Basic {enc_creds}'})
                elif url.scheme == 'ftp':
                    urlstring = urllib.parse.urlunparse(url._replace(netloc=f'{login}:{password}@{url.netloc}'))
                else:
                    mlog.warning('Meson is not going to use netrc credentials for protocols other than https/ftp',
                                 fatal=False)

            try:
                req = urllib.request.Request(urlstring, headers=headers)
                resp = urllib.request.urlopen(req, timeout=REQ_TIMEOUT)
            except urllib.error.URLError as e:
                mlog.log(str(e))
                raise WrapException(f'could not get {urlstring} is the internet available?')
        with contextlib.closing(resp) as resp, tmpfile as tmpfile:
            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',
                                       disable=(self.silent or None))
            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, hash_required: bool = True) -> None:
        if what + '_hash' not in self.wrap.values and not hash_required:
            return
        expected = self.wrap.get(what + '_hash').lower()
        h = hashlib.sha256()
        with open(path, 'rb') as f:
            h.update(f.read())
        dhash = h.hexdigest()
        if dhash != expected:
            raise WrapException(f'Incorrect hash for {what}:\n {expected} expected\n {dhash} actual.')

    def get_data_with_backoff(self, urlstring: str) -> T.Tuple[str, str]:
        delays = [1, 2, 4, 8, 16]
        for d in delays:
            try:
                return self.get_data(urlstring)
            except Exception as e:
                mlog.warning(f'failed to download with error: {e}. Trying after a delay...', fatal=False)
                time.sleep(d)
        return self.get_data(urlstring)

    def download(self, what: str, ofname: str, fallback: bool = False) -> None:
        self.check_can_download()
        srcurl = self.wrap.get(what + ('_fallback_url' if fallback else '_url'))
        mlog.log('Downloading', mlog.bold(self.packagename), what, 'from', mlog.bold(srcurl))
        try:
            dhash, tmpfile = self.get_data_with_backoff(srcurl)
            expected = self.wrap.get(what + '_hash').lower()
            if dhash != expected:
                os.remove(tmpfile)
                raise WrapException(f'Incorrect hash for {what}:\n {expected} expected\n {dhash} actual.')
        except WrapException:
            if not fallback:
                if what + '_fallback_url' in self.wrap.values:
                    return self.download(what, ofname, fallback=True)
                mlog.log('A fallback URL could be specified using',
                         mlog.bold(what + '_fallback_url'), 'key in the wrap file')
            raise
        os.rename(tmpfile, ofname)

    def get_file_internal(self, what: str) -> str:
        filename = self.wrap.get(what + '_filename')
        if what + '_url' in self.wrap.values:
            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

            os.makedirs(self.cachedir, exist_ok=True)
            self.download(what, cache_path)
            return cache_path
        else:
            path = Path(self.wrap.filesdir) / filename

            if not path.exists():
                raise WrapException(f'File "{path}" does not exist')
            self.check_hash(what, path.as_posix(), hash_required=False)

            return path.as_posix()

    def apply_patch(self) -> None:
        if 'patch_filename' in self.wrap.values and 'patch_directory' in self.wrap.values:
            m = f'Wrap file {self.wrap.basename!r} must not have both "patch_filename" and "patch_directory"'
            raise WrapException(m)
        if 'patch_filename' in self.wrap.values:
            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)
        elif 'patch_directory' in self.wrap.values:
            patch_dir = self.wrap.values['patch_directory']
            src_dir = os.path.join(self.wrap.filesdir, patch_dir)
            if not os.path.isdir(src_dir):
                raise WrapException(f'patch directory does not exist: {patch_dir}')
            self.copy_tree(src_dir, self.dirname)

    def apply_diff_files(self) -> None:
        for filename in self.wrap.diff_files:
            mlog.log(f'Applying diff file "{filename}"')
            path = Path(self.wrap.filesdir) / filename
            if not path.exists():
                raise WrapException(f'Diff file "{path}" does not exist')
            relpath = os.path.relpath(str(path), self.dirname)
            if PATCH:
                # Always pass a POSIX path to patch, because on Windows it's MSYS
                # Ignore whitespace when applying patches to workaround
                # line-ending differences
                cmd = [PATCH, '-l', '-f', '-p1', '-i', str(Path(relpath).as_posix())]
            elif GIT:
                # If the `patch` command is not available, fall back to `git
                # apply`. The `--work-tree` is necessary in case we're inside a
                # Git repository: by default, Git will try to apply the patch to
                # the repository root.
                cmd = [GIT, '--work-tree', '.', 'apply', '--ignore-whitespace', '-p1', relpath]
            else:
                raise WrapException('Missing "patch" or "git" commands to apply diff files')

            p, out, _ = Popen_safe(cmd, cwd=self.dirname, stderr=subprocess.STDOUT)
            if p.returncode != 0:
                mlog.log(out.strip())
                raise WrapException(f'Failed to apply diff file "{filename}"')

    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)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/mesonbuild/wrap/wraptool.py0000644000175000017500000002407414562742363020406 0ustar00jpakkanejpakkane# 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.
from __future__ import annotations

import sys, os
import configparser
import shutil
import typing as T

from glob import glob
from .wrap import (open_wrapdburl, WrapException, get_releases, get_releases_data,
                   update_wrap_file, parse_patch_url)
from pathlib import Path

from .. import mesonlib, msubprojects

if T.TYPE_CHECKING:
    import argparse

# Note: when adding arguments, please also add them to the completion
# scripts in $MESONSRC/data/shell-completions/
def add_arguments(parser: 'argparse.ArgumentParser') -> None:
    subparsers = parser.add_subparsers(title='Commands', dest='command')
    subparsers.required = True

    p = subparsers.add_parser('list', help='show all available projects')
    p.add_argument('--allow-insecure', default=False, action='store_true',
                   help='Allow insecure server connections.')
    p.set_defaults(wrap_func=list_projects)

    p = subparsers.add_parser('search', help='search the db by name')
    p.add_argument('--allow-insecure', default=False, action='store_true',
                   help='Allow insecure server connections.')
    p.add_argument('name')
    p.set_defaults(wrap_func=search)

    p = subparsers.add_parser('install', help='install the specified project')
    p.add_argument('--allow-insecure', default=False, action='store_true',
                   help='Allow insecure server connections.')
    p.add_argument('name')
    p.set_defaults(wrap_func=install)

    p = msubprojects.add_wrap_update_parser(subparsers)
    p.set_defaults(wrap_func=msubprojects.run)

    p = subparsers.add_parser('info', help='show available versions of a project')
    p.add_argument('--allow-insecure', default=False, action='store_true',
                   help='Allow insecure server connections.')
    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.add_argument('--allow-insecure', default=False, action='store_true',
                   help='Allow insecure server connections.')
    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)

    p = subparsers.add_parser('update-db', help='Update list of projects available in WrapDB (Since 0.61.0)')
    p.add_argument('--allow-insecure', default=False, action='store_true',
                   help='Allow insecure server connections.')
    p.set_defaults(wrap_func=update_db)

def list_projects(options: 'argparse.Namespace') -> None:
    releases = get_releases(options.allow_insecure)
    for p in releases.keys():
        print(p)

def search(options: 'argparse.Namespace') -> None:
    name = options.name
    releases = get_releases(options.allow_insecure)
    for p, info in releases.items():
        if p.find(name) != -1:
            print(p)
        else:
            for dep in info.get('dependency_names', []):
                if dep.find(name) != -1:
                    print(f'Dependency {dep} found in wrap {p}')

def get_latest_version(name: str, allow_insecure: bool) -> T.Tuple[str, str]:
    releases = get_releases(allow_insecure)
    info = releases.get(name)
    if not info:
        raise WrapException(f'Wrap {name} not found in wrapdb')
    latest_version = info['versions'][0]
    version, revision = latest_version.rsplit('-', 1)
    return version, revision

def install(options: 'argparse.Namespace') -> None:
    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.')
    (version, revision) = get_latest_version(name, options.allow_insecure)
    url = open_wrapdburl(f'https://wrapdb.mesonbuild.com/v2/{name}_{version}-{revision}/{name}.wrap', options.allow_insecure, True)
    with open(wrapfile, 'wb') as f:
        f.write(url.read())
    print(f'Installed {name} version {version} revision {revision}')

def get_current_version(wrapfile: str) -> T.Tuple[str, str, str, str, T.Optional[str]]:
    cp = configparser.ConfigParser(interpolation=None)
    cp.read(wrapfile)
    try:
        wrap_data = cp['wrap-file']
    except KeyError:
        raise WrapException('Not a wrap-file, cannot have come from the wrapdb')
    try:
        patch_url = wrap_data['patch_url']
    except KeyError:
        # We assume a wrap without a patch_url is probably just an pointer to upstream's
        # build files. The version should be in the tarball filename, even if it isn't
        # purely guaranteed. The wrapdb revision should be 1 because it just needs uploading once.
        branch = mesonlib.search_version(wrap_data['source_filename'])
        revision, patch_filename = '1', None
    else:
        branch, revision = parse_patch_url(patch_url)
        patch_filename = wrap_data['patch_filename']
    return branch, revision, wrap_data['directory'], wrap_data['source_filename'], patch_filename

def update(options: 'argparse.Namespace') -> None:
    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, options.allow_insecure)
    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, options.allow_insecure)
    shutil.rmtree(os.path.join('subprojects', subdir), ignore_errors=True)
    try:
        os.unlink(os.path.join('subprojects/packagecache', src_file))
    except FileNotFoundError:
        pass
    if patch_file is not None:
        try:
            os.unlink(os.path.join('subprojects/packagecache', patch_file))
        except FileNotFoundError:
            pass
    print(f'Updated {name} version {new_branch} revision {new_revision}')

def info(options: 'argparse.Namespace') -> None:
    name = options.name
    releases = get_releases(options.allow_insecure)
    info = releases.get(name)
    if not info:
        raise WrapException(f'Wrap {name} not found in wrapdb')
    print(f'Available versions of {name}:')
    for v in info['versions']:
        print(' ', v)

def do_promotion(from_path: str, spdir_name: str) -> None:
    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(f'Output dir {outputdir} already exists. Will not overwrite.')
        shutil.copytree(from_path, outputdir, ignore=shutil.ignore_patterns('subprojects'))

def promote(options: 'argparse.Namespace') -> None:
    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(f'Subproject {argument} not found in directory tree.')
    matches = sprojs[argument]
    if len(matches) > 1:
        print(f'There is more than one version of {argument} in tree. Please specify which one to promote:\n', file=sys.stderr)
        for s in matches:
            print(s, file=sys.stderr)
        raise SystemExit(1)
    do_promotion(matches[0], spdir_name)

def status(options: 'argparse.Namespace') -> None:
    print('Subproject status')
    for w in glob('subprojects/*.wrap'):
        name = os.path.basename(w)[:-5]
        try:
            (latest_branch, latest_revision) = get_latest_version(name, options.allow_insecure)
        except Exception:
            print('', name, 'not available in wrapdb.', file=sys.stderr)
            continue
        try:
            (current_branch, current_revision, _, _, _) = get_current_version(w)
        except Exception:
            print('', name, 'Wrap file not from wrapdb.', file=sys.stderr)
            continue
        if current_branch == latest_branch and current_revision == latest_revision:
            print('', name, f'up to date. Branch {current_branch}, revision {current_revision}.')
        else:
            print('', name, f'not up to date. Have {current_branch} {current_revision}, but {latest_branch} {latest_revision} is available.')

def update_db(options: 'argparse.Namespace') -> None:
    data = get_releases_data(options.allow_insecure)
    Path('subprojects').mkdir(exist_ok=True)
    with Path('subprojects/wrapdb.json').open('wb') as f:
        f.write(data)

def run(options: 'argparse.Namespace') -> int:
    options.wrap_func(options)
    return 0
././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1707853067.78264
meson-1.3.2/packaging/0000755000175000017500000000000014562742414014765 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311580.0
meson-1.3.2/packaging/License.rtf0000644000175000017500000002553214031433534017062 0ustar00jpakkanejpakkane{\rtf1\ansi\ansicpg1252\deff0{\fonttbl{\f0\fswiss\fprq2\fcharset0 Arial;}}
{\colortbl ;\red0\green0\blue255;}
{\*\generator Msftedit 5.41.21.2510;}\viewkind4\uc1\pard\qc\lang1033\b\f0\fs18 Apache License\par
Version 2.0, January 2004\par
{\field{\*\fldinst{HYPERLINK "http://www.apache.org/licenses/"}}{\fldrslt{\ul\cf1 http://www.apache.org/licenses/}}}\f0\fs18\par
\b0\par
\pard TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\par
\par
\pard\fi-180\li180 1. Definitions.\par
\par
\pard\li180 "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.\par
\par
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.\par
\par
"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.\par
\par
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.\par
\par
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.\par
\par
"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.\par
\par
"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).\par
\par
"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.\par
\par
"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."\par
\par
"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.\par
\pard\par
\pard\fi-180\li180 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.\par
\par
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.\par
\par
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:\par
\pard\par
\pard\fi-270\li450 (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and\par
\par
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and\par
\par
(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\par
\par
(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.\par
\pard\par
\pard\li180 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.\par
\pard\par
\pard\fi-180\li180 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.\par
\par
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.\par
\par
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.\par
\par
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.\par
\par
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.\par
\pard\par
END OF TERMS AND CONDITIONS\par
\par
APPENDIX: How to apply the Apache License to your work.\par
\par
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.\par
\par
\pard\li180 Copyright [yyyy] [name of copyright owner]\par
\par
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\par
\par
\pard\li360{\field{\*\fldinst{HYPERLINK "http://www.apache.org/licenses/LICENSE-2.0"}}{\fldrslt{\ul\cf1 http://www.apache.org/licenses/LICENSE-2.0}}}\f0\fs18\par
\pard\li180\par
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.\par
\pard\par
\par
}
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0
meson-1.3.2/packaging/create_zipapp.py0000755000175000017500000000161114253672217020167 0ustar00jpakkanejpakkane#!/usr/bin/env python3

import argparse
from pathlib import Path
import shutil
import sys
import tempfile
import zipapp

parser = argparse.ArgumentParser()
parser.add_argument('source', nargs='?', default='.', help='Source directory')
parser.add_argument('--outfile', default='meson.pyz', help='Output file for the zipapp')
parser.add_argument('--interpreter', default='/usr/bin/env python3', help='The name of the Python interpreter to use')
parser.add_argument('--compress', action='store_true', default=False, help='Compress files')

options = parser.parse_args(sys.argv[1:])

source = Path(options.source).resolve()

with tempfile.TemporaryDirectory() as d:
    shutil.copy2(source / 'meson.py', Path(d, '__main__.py'))
    shutil.copytree(source / 'mesonbuild', Path(d, 'mesonbuild'))
    zipapp.create_archive(d, interpreter=options.interpreter, target=options.outfile, compressed=options.compress)
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/packaging/createmsi.py0000755000175000017500000003007514562742363017326 0ustar00jpakkanejpakkane#!/usr/bin/env python3

# Copyright 2017-2021 The Meson development team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

'''
This script is for generating MSI packages
for Windows users.
'''

import subprocess
import shutil
import uuid
import sys
import os
from glob import glob
import xml.etree.ElementTree as ET

sys.path.append(os.getcwd())
from mesonbuild import coredata

# Elementtree does not support CDATA. So hack it.
WINVER_CHECK = 'Installed OR (VersionNT64 > 602)>'

def gen_guid():
    '''
       Generate guid
    '''
    return str(uuid.uuid4()).upper()

class Node:
    '''
       Node to hold path and directory values
    '''

    def __init__(self, dirs, files):
        self.check_dirs(dirs)
        self.check_files(files)
        self.dirs = dirs
        self.files = files

    @staticmethod
    def check_dirs(dirs):
        '''
           Check to see if directory is instance of list
        '''
        assert isinstance(dirs, list)

    @staticmethod
    def check_files(files):
        '''
           Check to see if files is instance of list
        '''
        assert isinstance(files, list)


class PackageGenerator:
    '''
       Package generator for MSI packages
    '''

    def __init__(self):
        self.product_name = 'Meson Build System'
        self.manufacturer = 'The Meson Development Team'
        self.version = coredata.version.replace('dev', '')
        self.root = None
        self.guid = '*'
        self.update_guid = '141527EE-E28A-4D14-97A4-92E6075D28B2'
        self.main_xml = 'meson.wxs'
        self.main_o = 'meson.wixobj'
        self.final_output = f'meson-{self.version}-64.msi'
        self.staging_dirs = ['dist', 'dist2']
        self.progfile_dir = 'ProgramFiles64Folder'
        redist_globs = ['C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Redist\\MSVC\\v*\\MergeModules\\Microsoft_VC142_CRT_x64.msm',
                        'C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Redist\\MSVC\\v*\\MergeModules\\Microsoft_VC143_CRT_x64.msm']
        redist_path = None
        for g in redist_globs:
            trials = glob(g)
            if len(trials) > 1:
                sys.exit('MSM glob matched multiple entries:' + '\n'.join(trials))
            if len(trials) == 1:
                redist_path = trials[0]
                break
        if redist_path is None:
            sys.exit('No MSMs found.')
        self.redist_path = redist_path
        self.component_num = 0
        self.feature_properties = {
            self.staging_dirs[0]: {
                'Id': 'MainProgram',
                'Title': 'Meson',
                'Description': 'Meson executables',
                'Level': '1',
                'AllowAbsent': 'no',
            },
            self.staging_dirs[1]: {
                'Id': 'NinjaProgram',
                'Title': 'Ninja',
                'Description': 'Ninja build tool',
                'Level': '1',
            }
        }
        self.feature_components = {}
        for s_d in self.staging_dirs:
            self.feature_components[s_d] = []

    def build_dist(self):
        '''
           Build dist file from PyInstaller info
        '''
        for sdir in self.staging_dirs:
            if os.path.exists(sdir):
                shutil.rmtree(sdir)
        main_stage, ninja_stage = self.staging_dirs

        pyinstaller = shutil.which('pyinstaller')
        if not pyinstaller:
            print("ERROR: This script requires pyinstaller.")
            sys.exit(1)

        pyinstaller_tmpdir = 'pyinst-tmp'
        if os.path.exists(pyinstaller_tmpdir):
            shutil.rmtree(pyinstaller_tmpdir)
        pyinst_cmd = [pyinstaller,
                      '--clean',
                      '--additional-hooks-dir=packaging',
                      '--distpath',
                      pyinstaller_tmpdir]
        pyinst_cmd += ['meson.py']
        subprocess.check_call(pyinst_cmd)
        shutil.move(pyinstaller_tmpdir + '/meson', main_stage)
        self.del_infodirs(main_stage)
        if not os.path.exists(os.path.join(main_stage, 'meson.exe')):
            sys.exit('Meson exe missing from staging dir.')
        os.mkdir(ninja_stage)
        shutil.copy(shutil.which('ninja'), ninja_stage)
        if not os.path.exists(os.path.join(ninja_stage, 'ninja.exe')):
            sys.exit('Ninja exe missing from staging dir.')

    def del_infodirs(self, dirname):
        # Starting with 3.9.something there are some
        # extra metadatadirs that have a hyphen in their
        # file names. This is a forbidden character in WiX
        # filenames so delete them.
        for d in glob(os.path.join(dirname, '*-info')):
            shutil.rmtree(d)

    def generate_files(self):
        '''
           Generate package files for MSI installer package
        '''
        self.root = ET.Element('Wix', {
            'xmlns': 'http://wixtoolset.org/schemas/v4/wxs',
            'xmlns:ui': 'http://wixtoolset.org/schemas/v4/wxs/ui'
        })

        package = ET.SubElement(self.root, 'Package', {
            'Name': self.product_name,
            'Manufacturer': 'The Meson Development Team',
            'UpgradeCode': self.update_guid,
            'Language': '1033',
            'Codepage':  '1252',
            'Version': self.version,
        })

        ET.SubElement(package, 'SummaryInformation', {
            'Keywords': 'Installer',
            'Description': f'Meson {self.version} installer',
            'Manufacturer': 'The Meson Development Team',
        })

        ET.SubElement(package,
                      'Launch',
                      {'Message': 'This application is only supported on Windows 10 or higher.',
                       'Condition': 'X'*len(WINVER_CHECK)})

        ET.SubElement(package, 'MajorUpgrade',
                      {'DowngradeErrorMessage':
                       'A newer version of Meson is already installed.'})

        ET.SubElement(package, 'Media', {
            'Id': '1',
            'Cabinet': 'meson.cab',
            'EmbedCab': 'yes',
        })
        targetdir = ET.SubElement(package, 'StandardDirectory', {
            'Id': 'ProgramFiles64Folder',
        })
        installdir = ET.SubElement(targetdir, 'Directory', {
            'Id': 'INSTALLDIR',
            'Name': 'Meson',
        })
        ET.SubElement(installdir, 'Merge', {
            'Id': 'VCRedist',
            'SourceFile': self.redist_path,
            'DiskId': '1',
            'Language': '0',
        })

        ET.SubElement(package, 'ui:WixUI', {
            'Id': 'WixUI_FeatureTree',
        })
        for s_d in self.staging_dirs:
            assert os.path.isdir(s_d)
        top_feature = ET.SubElement(package, 'Feature', {
            'Id': 'Complete',
            'Title': 'Meson ' + self.version,
            'Description': 'The complete package',
            'Display': 'expand',
            'Level': '1',
            'ConfigurableDirectory': 'INSTALLDIR',
        })
        for s_d in self.staging_dirs:
            nodes = {}
            for root, dirs, files in os.walk(s_d):
                cur_node = Node(dirs, files)
                nodes[root] = cur_node
            self.create_xml(nodes, s_d, installdir, s_d)
            self.build_features(top_feature, s_d)
        vcredist_feature = ET.SubElement(top_feature, 'Feature', {
            'Id': 'VCRedist',
            'Title': 'Visual C++ runtime',
            'AllowAdvertise': 'no',
            'Display': 'hidden',
            'Level': '1',
        })
        ET.SubElement(vcredist_feature, 'MergeRef', {'Id': 'VCRedist'})
        ET.ElementTree(self.root).write(self.main_xml, encoding='utf-8', xml_declaration=True)
        # ElementTree cannot do pretty-printing, so do it manually
        import xml.dom.minidom
        doc = xml.dom.minidom.parse(self.main_xml)
        with open(self.main_xml, 'w') as open_file:
            open_file.write(doc.toprettyxml())
        # One last fix, add CDATA.
        with open(self.main_xml) as open_file:
            data = open_file.read()
        data = data.replace('X'*len(WINVER_CHECK), WINVER_CHECK)
        with open(self.main_xml, 'w') as open_file:
            open_file.write(data)

    def build_features(self, top_feature, staging_dir):
        '''
           Generate build features
        '''
        feature = ET.SubElement(top_feature, 'Feature', self.feature_properties[staging_dir])
        for component_id in self.feature_components[staging_dir]:
            ET.SubElement(feature, 'ComponentRef', {
                'Id': component_id,
            })

    def create_xml(self, nodes, current_dir, parent_xml_node, staging_dir):
        '''
           Create XML file
        '''
        cur_node = nodes[current_dir]
        if cur_node.files:
            component_id = f'ApplicationFiles{self.component_num}'
            comp_xml_node = ET.SubElement(parent_xml_node, 'Component', {
                'Id': component_id,
                'Bitness': 'always64',
                'Guid': gen_guid(),
            })
            self.feature_components[staging_dir].append(component_id)
            if self.component_num == 0:
                ET.SubElement(comp_xml_node, 'Environment', {
                    'Id': 'Environment',
                    'Name': 'PATH',
                    'Part': 'last',
                    'System': 'yes',
                    'Action': 'set',
                    'Value': '[INSTALLDIR]',
                })
            self.component_num += 1
            for f_node in cur_node.files:
                file_id = os.path.join(current_dir, f_node).replace('\\', '_').replace('#', '_').replace('-', '_')
                ET.SubElement(comp_xml_node, 'File', {
                    'Id': file_id,
                    'Name': f_node,
                    'Source': os.path.join(current_dir, f_node),
                })

        for dirname in cur_node.dirs:
            dir_id = os.path.join(current_dir, dirname).replace('\\', '_').replace('/', '_').replace('-', '_')
            dir_node = ET.SubElement(parent_xml_node, 'Directory', {
                'Id': dir_id,
                'Name': dirname,
            })
            self.create_xml(nodes, os.path.join(current_dir, dirname), dir_node, staging_dir)

    def build_package(self):
        '''
           Generate the Meson build MSI package.
        '''
        subprocess.check_call(['wix',
                               'build',
                               '-bindvariable', 'WixUILicenseRtf=packaging\\License.rtf',
                               '-ext', 'WixToolset.UI.wixext',
                               '-culture', 'en-us',
                               '-arch', 'x64',
                               '-o',
                               self.final_output,
                               self.main_xml,
                               ])


def install_wix():
    subprocess.check_call(['dotnet',
                           'nuget',
                           'add',
                           'source',
                           'https://api.nuget.org/v3/index.json'])
    subprocess.check_call(['dotnet',
                           'tool',
                           'install',
                           '--global',
                           'wix'])
    subprocess.check_call(['wix',
                           'extension',
                           'add',
                           'WixToolset.UI.wixext',
                           ])

if __name__ == '__main__':
    if not os.path.exists('meson.py'):
        sys.exit(print('Run me in the top level source dir.'))
    if not shutil.which('wix'):
        install_wix()
    subprocess.check_call(['pip', 'install', '--upgrade', 'pyinstaller'])

    p = PackageGenerator()
    p.build_dist()
    p.generate_files()
    p.build_package()
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0
meson-1.3.2/packaging/createpkg.py0000755000175000017500000001252114562742363017313 0ustar00jpakkanejpakkane#!/usr/bin/env python3

# Copyright 2017-2021 The Meson development team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import subprocess
import shutil, sys, os
from glob import glob

import xml.etree.ElementTree as ET

sys.path.append(os.getcwd())
from mesonbuild import coredata

class PkgGenerator:

    def __init__(self):
        self.pkg_dir = 'macpkg'
        self.sharedir = os.path.join(self.pkg_dir, 'usr/local/share')
        self.bindir = os.path.join(self.pkg_dir, 'usr/local/bin')
        self.product_name = 'Meson Build System'
        self.identifier = 'com.mesonbuild.meson'
        self.version = coredata.version.replace('dev', '')
        self.mesonstashdir = os.path.join(self.sharedir, f'meson-{self.version}')
        self.pkgname = 'meson.pkg'
        self.productname = f'meson-{self.version}.pkg'
        self.distribution_file = 'meson-distribution.xml'
        self.resourcedir = 'packaging/macpages'

    def build_dist(self):
        if os.path.exists(self.pkg_dir):
            shutil.rmtree(self.pkg_dir)
        os.mkdir(self.pkg_dir)
        pyinstaller_bin = glob('/Users/jpakkane/Library/Python/*/bin/pyinstaller')
        if len(pyinstaller_bin) != 1:
            sys.exit('Could not determine unique installer.')
        pyinstaller_bin = pyinstaller_bin[0]
        pyinst_cmd = [pyinstaller_bin,
                      '--clean',
                      '--additional-hooks-dir=packaging',
                      '--distpath',
                      self.pkg_dir]
        pyinst_cmd += ['meson.py']
        subprocess.check_call(pyinst_cmd)
        tmpdir = os.path.join(self.pkg_dir, 'meson')
        shutil.move(tmpdir, self.mesonstashdir)
        os.makedirs(self.bindir)
        ln_base = os.path.relpath(self.mesonstashdir, self.bindir)
        ninja_bin = shutil.which('ninja')
        assert ninja_bin
        shutil.copy(ninja_bin, self.bindir)
        subprocess.check_call(['strip', os.path.join(self.bindir, 'ninja')])
        os.symlink(os.path.join(ln_base, 'meson'), os.path.join(self.bindir, 'meson'))

    def build_package(self):
        subprocess.check_call(['pkgbuild',
                               '--root',
                               self.pkg_dir,
                               '--identifier',
                               self.identifier,
                               self.pkgname])
        self.generate_distribution()
        subprocess.check_call(['productbuild',
                               '--distribution',
                               self.distribution_file,
                               '--resources',
                               self.resourcedir,
                               self.productname])

    def generate_distribution(self):
        root = ET.Element('installer-gui-script', {'minSpecVersion': '1'})
        ET.SubElement(root, 'welcome', {'file': 'welcome.html',
                                        'mime-type': 'text/html'})
        ET.SubElement(root, 'license', {'file': 'license.html',
                                        'mime-type': 'text/html'})
        ET.SubElement(root, 'conclusion', {'file': 'conclusion.html',
                                        'mime-type': 'text/html'})
        ET.SubElement(root, 'pkg-ref', {'id': self.identifier})
        ET.SubElement(root, 'options', {'customize': 'never',
                                        'require-scripts': 'false',
                                        'hostArchitectures': 'x86_64,arm64'})
        choices_outline = ET.SubElement(root, 'choices-outline')
        line = ET.SubElement(choices_outline, 'line', {'choice': 'default'})
        ET.SubElement(line, 'line', {'choice': self.identifier})
        ET.SubElement(root, 'choice', {'id': 'default'})
        choice = ET.SubElement(root, 'choice', {'id': self.identifier, 'visible': 'false'})
        ET.SubElement(choice, 'pkg-ref', {'id': self.identifier})
        ET.SubElement(root, 'pkg-ref', {'id': self.identifier,
                                        'version': '0', # self.version,
                                        'onConclusion': 'none'}).text = self.pkgname
        ET.ElementTree(root).write(self.distribution_file, encoding='utf-8', xml_declaration=True)
        # ElementTree cannot do pretty-printing, so do it manually
        import xml.dom.minidom
        doc = xml.dom.minidom.parse(self.distribution_file)
        with open(self.distribution_file, 'w') as open_file:
            open_file.write(doc.toprettyxml())

    def remove_tempfiles(self):
        shutil.rmtree('macpkg')
        os.unlink('meson-distribution.xml')
        os.unlink('meson.pkg')
        os.unlink('meson.spec')

if __name__ == '__main__':
    if not os.path.exists('meson.py'):
        sys.exit(print('Run me in the top level source dir.'))
    subprocess.check_call(['pip3', 'install', '--user', '--upgrade', 'pyinstaller'])

    pg = PkgGenerator()
    pg.build_dist()
    pg.build_package()
    pg.remove_tempfiles()
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691448864.0
meson-1.3.2/packaging/hook-mesonbuild.py0000644000175000017500000000342714464273040020437 0ustar00jpakkanejpakkane#!hint/python3

"""
PyInstaller hook to make mesonbuild include everything it needs to.
"""

import os
from glob import glob

from PyInstaller.utils.hooks import collect_data_files

datas = []
hiddenimports = []

def get_all_modules_from_dir(dirname):
    '''
    Get all modules required for Meson itself from directories.
    '''
    modname = os.path.basename(dirname)
    modules = [os.path.splitext(os.path.split(x)[1])[0] for x in glob(os.path.join(dirname, '*'))]
    modules = ['mesonbuild.' + modname + '.' + x for x in modules if not x.startswith('_')]
    return modules

datas += collect_data_files('mesonbuild.scripts', include_py_files=True, excludes=['**/__pycache__'])
datas += collect_data_files('mesonbuild.cmake.data')
datas += collect_data_files('mesonbuild.dependencies.data')

# lazy-loaded
hiddenimports += get_all_modules_from_dir('mesonbuild/dependencies')
# imported by meson.build files
hiddenimports += get_all_modules_from_dir('mesonbuild/modules')
# executed when named on CLI
hiddenimports += get_all_modules_from_dir('mesonbuild/scripts')

# Python packagers want to be minimal and only copy the things
# that they can see being used. They are blind to many things.
hiddenimports += [
    # we run distutils as a subprocess via INTROSPECT_COMMAND.
    'distutils.archive_util',
    'distutils.cmd',
    'distutils.config',
    'distutils.core',
    'distutils.debug',
    'distutils.dep_util',
    'distutils.dir_util',
    'distutils.dist',
    'distutils.errors',
    'distutils.extension',
    'distutils.fancy_getopt',
    'distutils.file_util',
    'distutils.spawn',
    'distutils.util',
    'distutils.version',
    'distutils.command.build_ext',
    'distutils.command.build',
    'distutils.command.install',

    # needed for gtk's find_program() scripts
    'filecmp',
]
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7426243
meson-1.3.2/packaging/macpages/0000755000175000017500000000000014562742413016544 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.7866402
meson-1.3.2/packaging/macpages/English.lproj/0000755000175000017500000000000014562742414021263 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1623087322.0
meson-1.3.2/packaging/macpages/English.lproj/conclusion.html0000644000175000017500000000112214057454332024317 0ustar00jpakkanejpakkane
  
  
  

    

Install finished

The Meson build system is now installed. Note that Meson does not provide any GUI applications, it is only usable from the command line. You can verify if your installation of Meson is working by running the following command in a terminal

      $ meson --version
    

If the system reports that the program could not be found you might need to edit your configuration files so that /usr/local/bin is in your path.

././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1623087322.0 meson-1.3.2/packaging/macpages/English.lproj/license.html0000644000175000017500000002525114057454332023576 0ustar00jpakkanejpakkane
                              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.
  
  

././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1623087322.0
meson-1.3.2/packaging/macpages/English.lproj/welcome.html0000644000175000017500000000027214057454332023603 0ustar00jpakkanejpakkane
  
  
  

  

Meson build system installer

This package will install the command line tools of Meson to this computer.

././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/pyproject.toml0000644000175000017500000000013614253672217015755 0ustar00jpakkanejpakkane[build-system] requires = ["setuptools>=42", "wheel"] build-backend = "setuptools.build_meta" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/run_cross_test.py0000755000175000017500000000427314562742363016503 0ustar00jpakkanejpakkane#!/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. This is now just a wrapper around run_project_tests.py with specific arguments ''' import argparse import subprocess from mesonbuild import mesonlib from mesonbuild.coredata import version as meson_version from pathlib import Path import json import os def runtests(cross_file, failfast, cross_only, test_list, env=None): tests = ['--only'] + test_list if not cross_only: tests.append('native') cmd = mesonlib.python_command + ['run_project_tests.py', '--backend', 'ninja'] if failfast: cmd += ['--failfast'] cmd += tests cmd += ['--cross-file', cross_file] if cross_only: cmd += ['--native-file', 'cross/none.txt'] return subprocess.call(cmd, env=env) def main(): parser = argparse.ArgumentParser() parser.add_argument('--failfast', action='store_true') parser.add_argument('--cross-only', action='store_true') parser.add_argument('cross_file') options = parser.parse_args() cf_path = Path(options.cross_file) try: data = json.loads(cf_path.read_text(encoding='utf-8')) real_cf = cf_path.resolve().parent / data['file'] assert real_cf.exists() env = os.environ.copy() env.update(data['env']) return runtests(real_cf.as_posix(), options.failfast, options.cross_only, data['tests'], env=env) except Exception: return runtests(options.cross_file, options.failfast, options.cross_only, ['common']) if __name__ == '__main__': print('Meson build system', meson_version, 'Cross Tests') raise SystemExit(main()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/run_meson_command_tests.py0000755000175000017500000002323414562742363020352 0ustar00jpakkanejpakkane#!/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 os import tempfile import unittest import subprocess import zipapp import sysconfig from pathlib import Path from mesonbuild.mesonlib import windows_proof_rmtree, python_command, is_windows from mesonbuild.coredata import version as meson_version scheme = None def needs_debian_path_hack(): try: import setuptools return int(setuptools.__version__.split('.')[0]) < 65 except ModuleNotFoundError: return False if needs_debian_path_hack(): # Handle the scheme that Debian patches in the as default # This function was renamed and made public in Python 3.10 if hasattr(sysconfig, 'get_default_scheme'): scheme = sysconfig.get_default_scheme() else: scheme = sysconfig._get_default_scheme() if scheme == 'posix_local': scheme = 'posix_prefix' def get_pypath(): if scheme: pypath = sysconfig.get_path('purelib', scheme=scheme, vars={'base': ''}) else: 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(): # 'Scripts' on Windows and 'bin' on other platforms including MSYS if scheme: return sysconfig.get_path('scripts', scheme=scheme, vars={'base': ''}).strip('\\/') 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, env=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=env, text=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, f'meson_command is {cmd!r}') 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') (bindir / 'python3').symlink_to(python_command[0]) os.environ['PATH'] = str(bindir) + os.pathsep + os.environ['PATH'] # use our overridden PATH-compatible python path_resolved_meson_command = [str(bindir / 'meson')] # 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], path_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)]) # Fix importlib-metadata by appending all dirs in pylibdir PYTHONPATHS = [pylibdir] + [x for x in pylibdir.iterdir()] PYTHONPATHS = [os.path.join(str(x), '') for x in PYTHONPATHS] os.environ['PYTHONPATH'] = os.pathsep.join(PYTHONPATHS) # Check that all the files were installed correctly self.assertTrue(bindir.is_dir()) self.assertTrue(pylibdir.is_dir()) # 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.write_text('#!/bin/sh\n\nmeson.real "$@"', encoding='utf-8') 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 target = self.tmpdir / 'meson.pyz' script = source / 'packaging' / 'create_zipapp.py' self._run([script.as_posix(), source, '--outfile', target, '--interpreter', python_command[0]]) self._run([target.as_posix(), '--help']) def test_meson_runpython(self): meson_command = str(self.src_root / 'meson.py') script_file = str(self.src_root / 'foo.py') test_command = 'import sys; print(sys.argv[1])' env = os.environ.copy() del env['MESON_COMMAND_TESTS'] with open(script_file, 'w') as f: f.write('#!/usr/bin/env python3\n\n') f.write(f'{test_command}\n') for cmd in [['-c', test_command, 'fake argument'], [script_file, 'fake argument']]: pyout = self._run(python_command + cmd) mesonout = self._run(python_command + [meson_command, 'runpython'] + cmd, env=env) self.assertEqual(pyout, mesonout) if __name__ == '__main__': print('Meson build system', meson_version, 'Command Tests') raise SystemExit(unittest.main(buffer=True)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0 meson-1.3.2/run_project_tests.py0000755000175000017500000020275714562742373017213 0ustar00jpakkanejpakkane#!/usr/bin/env python3 # Copyright 2012-2021 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import annotations # Work around some pathlib bugs... from mesonbuild import _pathlib import sys sys.modules['pathlib'] = _pathlib from concurrent.futures import ProcessPoolExecutor, CancelledError from enum import Enum from io import StringIO from pathlib import Path, PurePath import argparse import functools import itertools import json import multiprocessing import os import re import shlex import shutil import signal import subprocess import tempfile import time import typing as T import xml.etree.ElementTree as ET import collections import importlib.util 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.compilers import compiler_from_language, detect_objc_compiler, detect_objcpp_compiler from mesonbuild.build import ConfigurationData from mesonbuild.mesonlib import MachineChoice, Popen_safe, TemporaryDirectoryWinProof, setup_vsenv from mesonbuild.mlog import blue, bold, cyan, green, red, yellow, normal_green from mesonbuild.coredata import backendlist, version as meson_version from mesonbuild.modules.python import PythonExternalProgram from run_tests import ( get_fake_options, run_configure, get_meson_script, get_backend_commands, get_backend_args_for_dir, Backend, ensure_backend_detects_changes, guess_backend, handle_meson_skip_test, ) if T.TYPE_CHECKING: from types import FrameType from mesonbuild.environment import Environment from mesonbuild._typing import Protocol from concurrent.futures import Future class CompilerArgumentType(Protocol): cross_file: str native_file: str use_tmpdir: bool class ArgumentType(CompilerArgumentType): """Typing information for command line arguments.""" extra_args: T.List[str] backend: str num_workers: int failfast: bool no_unittests: bool only: T.List[str] ALL_TESTS = ['cmake', 'common', 'native', 'warning-meson', 'failing-meson', 'failing-build', 'failing-test', 'keyval', 'platform-osx', 'platform-windows', 'platform-linux', 'java', 'C#', 'vala', 'cython', 'rust', 'd', 'objective c', 'objective c++', 'fortran', 'swift', 'cuda', 'python3', 'python', 'fpga', 'frameworks', 'nasm', 'wasm', 'wayland' ] class BuildStep(Enum): configure = 1 build = 2 test = 3 install = 4 clean = 5 validate = 6 class TestResult(BaseException): def __init__(self, cicmds: T.List[str]) -> None: self.msg = '' # empty msg indicates test success self.stdo = '' self.stde = '' self.mlog = '' self.cicmds = cicmds self.conftime: float = 0 self.buildtime: float = 0 self.testtime: float = 0 def add_step(self, step: BuildStep, stdo: str, stde: str, mlog: str = '', time: float = 0) -> None: self.step = step self.stdo += stdo self.stde += stde self.mlog += mlog if step == BuildStep.configure: self.conftime = time elif step == BuildStep.build: self.buildtime = time elif step == BuildStep.test: self.testtime = time def fail(self, msg: str) -> None: self.msg = msg python = PythonExternalProgram(sys.executable) python.sanity() class InstalledFile: def __init__(self, raw: T.Dict[str, str]): self.path = raw['file'] self.typ = raw['type'] self.platform = raw.get('platform', None) self.language = raw.get('language', 'c') version = raw.get('version', '') if version: self.version = version.split('.') else: # split on '' will return [''], we want an empty list though self.version = [] def get_path(self, compiler: str, env: environment.Environment) -> T.Optional[Path]: p = Path(self.path) canonical_compiler = compiler if ((compiler in ['clang-cl', 'intel-cl']) or (env.machines.host.is_windows() and compiler in {'pgi', 'dmd', 'ldc'})): canonical_compiler = 'msvc' python_suffix = python.info['suffix'] python_limited_suffix = python.info['limited_api_suffix'] has_pdb = False if self.language in {'c', 'cpp'}: has_pdb = canonical_compiler == 'msvc' elif self.language == 'd': # dmd's optlink does not generate pdb files has_pdb = env.coredata.compilers.host['d'].linker.id in {'link', 'lld-link'} # Abort if the platform does not match matches = { 'msvc': canonical_compiler == 'msvc', 'gcc': canonical_compiler != 'msvc', 'cygwin': env.machines.host.is_cygwin(), '!cygwin': not env.machines.host.is_cygwin(), }.get(self.platform or '', True) if not matches: return None # Handle the different types if self.typ in {'py_implib', 'py_limited_implib', 'python_lib', 'python_limited_lib', 'python_file', 'python_bytecode'}: val = p.as_posix() val = val.replace('@PYTHON_PLATLIB@', python.platlib) val = val.replace('@PYTHON_PURELIB@', python.purelib) p = Path(val) if self.typ == 'python_file': return p if self.typ == 'python_lib': return p.with_suffix(python_suffix) if self.typ == 'python_limited_lib': return p.with_suffix(python_limited_suffix) if self.typ == 'py_implib': p = p.with_suffix(python_suffix) if env.machines.host.is_windows() and canonical_compiler == 'msvc': return p.with_suffix('.lib') elif env.machines.host.is_windows() or env.machines.host.is_cygwin(): return p.with_suffix('.dll.a') else: return None if self.typ == 'py_limited_implib': p = p.with_suffix(python_limited_suffix) if env.machines.host.is_windows() and canonical_compiler == 'msvc': return p.with_suffix('.lib') elif env.machines.host.is_windows() or env.machines.host.is_cygwin(): return p.with_suffix('.dll.a') else: return None if self.typ == 'python_bytecode': return p.parent / importlib.util.cache_from_source(p.name) elif self.typ in {'file', 'dir', 'link'}: return p elif self.typ == 'shared_lib': if env.machines.host.is_windows() or env.machines.host.is_cygwin(): # Windows only has foo.dll and foo-X.dll if len(self.version) > 1: return None if self.version: p = p.with_name('{}-{}'.format(p.name, self.version[0])) return p.with_suffix('.dll') p = p.with_name(f'lib{p.name}') if env.machines.host.is_darwin(): # MacOS only has libfoo.dylib and libfoo.X.dylib if len(self.version) > 1: return None # pathlib.Path.with_suffix replaces, not appends suffix = '.dylib' if self.version: suffix = '.{}{}'.format(self.version[0], suffix) else: # pathlib.Path.with_suffix replaces, not appends suffix = '.so' if self.version: suffix = '{}.{}'.format(suffix, '.'.join(self.version)) return p.with_suffix(suffix) elif self.typ == 'exe': if 'mwcc' in canonical_compiler: return p.with_suffix('.nef') elif env.machines.host.is_windows() or env.machines.host.is_cygwin(): return p.with_suffix('.exe') elif self.typ == 'pdb': if self.version: p = p.with_name('{}-{}'.format(p.name, self.version[0])) return p.with_suffix('.pdb') if has_pdb else None elif self.typ in {'implib', 'implibempty'}: if env.machines.host.is_windows() and canonical_compiler == 'msvc': # only MSVC doesn't generate empty implibs if self.typ == 'implibempty' and compiler == 'msvc': return None return p.parent / (re.sub(r'^lib', '', p.name) + '.lib') elif env.machines.host.is_windows() or env.machines.host.is_cygwin(): return p.with_suffix('.dll.a') else: return None elif self.typ == 'expr': return Path(platform_fix_name(p.as_posix(), canonical_compiler, env)) else: raise RuntimeError(f'Invalid installed file type {self.typ}') return p def get_paths(self, compiler: str, env: environment.Environment, installdir: Path) -> T.List[Path]: p = self.get_path(compiler, env) if not p: return [] if self.typ == 'dir': abs_p = installdir / p if not abs_p.exists(): raise RuntimeError(f'{p} does not exist') if not abs_p.is_dir(): raise RuntimeError(f'{p} is not a directory') return [x.relative_to(installdir) for x in abs_p.rglob('*') if x.is_file() or x.is_symlink()] elif self.typ == 'link': abs_p = installdir / p if not abs_p.is_symlink(): raise RuntimeError(f'{p} is not a symlink') return [p] else: return [p] @functools.total_ordering class TestDef: def __init__(self, path: Path, name: T.Optional[str], args: T.List[str], skip: bool = False, skip_category: bool = False): self.category = path.parts[1] self.path = path self.name = name self.args = args self.skip = skip self.env = os.environ.copy() self.installed_files: T.List[InstalledFile] = [] self.do_not_set_opts: T.List[str] = [] self.stdout: T.List[T.Dict[str, str]] = [] self.skip_category = skip_category self.skip_expected = False # Always print a stack trace for Meson exceptions self.env['MESON_FORCE_BACKTRACE'] = '1' def __repr__(self) -> str: return '<{}: {:<48} [{}: {}] -- {}>'.format(type(self).__name__, str(self.path), self.name, self.args, self.skip) def display_name(self) -> mlog.TV_LoggableList: # Remove the redundant 'test cases' part section, id = self.path.parts[1:3] res: mlog.TV_LoggableList = [f'{section}:', bold(id)] if self.name: res += [f' ({self.name})'] return res def __lt__(self, other: object) -> bool: if isinstance(other, TestDef): # None is not sortable, so replace it with an empty string s_id = int(self.path.name.split(' ')[0]) o_id = int(other.path.name.split(' ')[0]) return (s_id, self.path, self.name or '') < (o_id, other.path, other.name or '') return NotImplemented failing_testcases: T.List[str] = [] failing_logs: T.List[str] = [] print_debug = 'MESON_PRINT_TEST_OUTPUT' in os.environ under_ci = 'CI' in os.environ ci_is_github = 'GITHUB_ACTIONS' in os.environ raw_ci_jobname = os.environ.get('MESON_CI_JOBNAME', None) ci_jobname = raw_ci_jobname if raw_ci_jobname != 'thirdparty' else None do_debug = under_ci or print_debug no_meson_log_msg = 'No meson-log.txt found.' host_c_compiler: T.Optional[str] = None compiler_id_map: T.Dict[str, str] = {} tool_vers_map: T.Dict[str, str] = {} compile_commands: T.List[str] clean_commands: T.List[str] test_commands: T.List[str] install_commands: T.List[str] uninstall_commands: T.List[str] backend: 'Backend' backend_flags: T.List[str] stop: bool = False is_worker_process: bool = False # Let's have colors in our CI output if under_ci: def _ci_colorize_console() -> bool: return not is_worker_process mlog.colorize_console = _ci_colorize_console class StopException(Exception): def __init__(self) -> None: super().__init__('Stopped by user') def stop_handler(signal: int, frame: T.Optional['FrameType']) -> None: global stop stop = True signal.signal(signal.SIGINT, stop_handler) signal.signal(signal.SIGTERM, stop_handler) def setup_commands(optbackend: str) -> None: 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) # TODO try to eliminate or at least reduce this function def platform_fix_name(fname: str, canonical_compiler: str, env: environment.Environment) -> str: 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('?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' return fname def validate_install(test: TestDef, installdir: Path, env: environment.Environment) -> str: ret_msg = '' expected_raw: T.List[Path] = [] for i in test.installed_files: try: expected_raw += i.get_paths(host_c_compiler, env, installdir) except RuntimeError as err: ret_msg += f'Expected path error: {err}\n' expected = {x: False for x in expected_raw} found = [x.relative_to(installdir) for x in installdir.rglob('*') if x.is_file() or x.is_symlink()] # Mark all found files as found and detect unexpected files for fname in found: if fname not in expected: ret_msg += f'Extra file {fname} found.\n' continue expected[fname] = True # Check if expected files were found for p, f in expected.items(): if not f: ret_msg += f'Expected file {p} missing.\n' # List dir content on error if ret_msg != '': ret_msg += '\nInstall dir contents:\n' for p in found: ret_msg += f' - {p}\n' return ret_msg def log_text_file(logfile: T.TextIO, testdir: Path, result: TestResult) -> None: logfile.write('%s\nstdout\n\n---\n' % testdir.as_posix()) logfile.write(result.stdo) logfile.write('\n\n---\n\nstderr\n\n---\n') logfile.write(result.stde) logfile.write('\n\n---\n\n') if print_debug: try: print(result.stdo) except UnicodeError: sanitized_out = result.stdo.encode('ascii', errors='replace').decode() print(sanitized_out) try: print(result.stde, file=sys.stderr) except UnicodeError: sanitized_err = result.stde.encode('ascii', errors='replace').decode() print(sanitized_err, file=sys.stderr) def _run_ci_include(args: T.List[str]) -> str: header = f'Included file {args[0]}:' footer = '' if ci_is_github: header = f'::group::==== {header} ====' footer = '::endgroup::' if not args: return 'At least one parameter required' try: data = Path(args[0]).read_text(errors='ignore', encoding='utf-8') return f'{header}\n{data}\n{footer}\n' except Exception: return 'Failed to open {}\n'.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{}'.format(cmd[0], ci_commands[cmd[0]](cmd[1:]))] return res class OutputMatch: def __init__(self, how: str, expected: str, count: int) -> None: self.how = how self.expected = expected self.count = count def match(self, actual: str) -> bool: if self.how == "re": return bool(re.match(self.expected, actual)) return self.expected == actual def _compare_output(expected: T.List[T.Dict[str, str]], output: str, desc: str) -> str: if expected: matches: T.List[OutputMatch] = [] nomatches: T.List[OutputMatch] = [] for item in expected: how = item.get('match', 'literal') expected_line = item.get('line') count = int(item.get('count', -1)) # Simple heuristic to automatically convert path separators for # Windows: # # Any '/' appearing before 'WARNING' or 'ERROR' (i.e. a path in a # filename part of a location) is replaced with '\' (in a re: '\\' # which matches a literal '\') # # (There should probably be a way to turn this off for more complex # cases which don't fit this) if mesonlib.is_windows(): if how != "re": sub = r'\\' else: sub = r'\\\\' expected_line = re.sub(r'/(?=.*(WARNING|ERROR|DEPRECATION))', sub, expected_line) m = OutputMatch(how, expected_line, count) if count == 0: nomatches.append(m) else: matches.append(m) i = 0 for actual in output.splitlines(): # Verify this line does not match any unexpected lines (item.count == 0) for match in nomatches: if match.match(actual): return f'unexpected "{match.expected}" found in {desc}' # If we matched all expected lines, continue to verify there are # no unexpected line. If nomatches is empty then we are done already. if i >= len(matches): if not nomatches: break continue # Check if this line match current expected line match = matches[i] if match.match(actual): if match.count < 0: # count was not specified, continue with next expected line, # it does not matter if this line will be matched again or # not. i += 1 else: # count was specified (must be >0), continue expecting this # same line. If count reached 0 we continue with next # expected line but remember that this one must not match # anymore. match.count -= 1 if match.count == 0: nomatches.append(match) i += 1 if i < len(matches): # reached the end of output without finding expected return f'expected "{matches[i].expected}" not found in {desc}' return '' def validate_output(test: TestDef, stdo: str, stde: str) -> str: return _compare_output(test.stdout, stdo, 'stdout') # There are some class variables and such that cache # information. Clear all of these. The better solution # would be to change the code so that no state is persisted # but that would be a lot of work given that Meson was originally # coded to run as a batch process. def clear_internal_caches() -> None: import mesonbuild.interpreterbase from mesonbuild.dependencies.cmake import CMakeDependency from mesonbuild.mesonlib import PerMachine mesonbuild.interpreterbase.FeatureNew.feature_registry = {} CMakeDependency.class_cmakeinfo = PerMachine(None, None) def run_test_inprocess(testdir: str) -> T.Tuple[int, str, str, str]: 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 = os.path.join('meson-logs', 'testlog.txt') try: returncode_test = mtest.run_with_args(['--no-rebuild']) if os.path.exists(test_log_fname): test_log = _run_ci_include([test_log_fname]) 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 # Build directory name must be the same so Ccache works over # consecutive invocations. def create_deterministic_builddir(test: TestDef, use_tmpdir: bool) -> str: import hashlib src_dir = test.path.as_posix() if test.name: src_dir += test.name rel_dirname = 'b ' + hashlib.sha256(src_dir.encode(errors='ignore')).hexdigest()[0:10] abs_pathname = os.path.join(tempfile.gettempdir() if use_tmpdir else os.getcwd(), rel_dirname) if os.path.exists(abs_pathname): mesonlib.windows_proof_rmtree(abs_pathname) os.mkdir(abs_pathname) return abs_pathname def format_parameter_file(file_basename: str, test: TestDef, test_build_dir: str) -> Path: confdata = ConfigurationData() confdata.values = {'MESON_TEST_ROOT': (str(test.path.absolute()), 'base directory of current test')} template = test.path / (file_basename + '.in') destination = Path(test_build_dir) / file_basename mesonlib.do_conf_file(str(template), str(destination), confdata, 'meson') return destination def detect_parameter_files(test: TestDef, test_build_dir: str) -> T.Tuple[Path, Path]: nativefile = test.path / 'nativefile.ini' crossfile = test.path / 'crossfile.ini' if os.path.exists(str(test.path / 'nativefile.ini.in')): nativefile = format_parameter_file('nativefile.ini', test, test_build_dir) if os.path.exists(str(test.path / 'crossfile.ini.in')): crossfile = format_parameter_file('crossfile.ini', test, test_build_dir) return nativefile, crossfile # In previous python versions the global variables are lost in ProcessPoolExecutor. # So, we use this tuple to restore some of them class GlobalState(T.NamedTuple): compile_commands: T.List[str] clean_commands: T.List[str] test_commands: T.List[str] install_commands: T.List[str] uninstall_commands: T.List[str] backend: 'Backend' backend_flags: T.List[str] host_c_compiler: T.Optional[str] def run_test(test: TestDef, extra_args: T.List[str], should_fail: str, use_tmp: bool, state: T.Optional[GlobalState] = None) -> T.Optional[TestResult]: # Unpack the global state global compile_commands, clean_commands, test_commands, install_commands, uninstall_commands, backend, backend_flags, host_c_compiler if state is not None: compile_commands, clean_commands, test_commands, install_commands, uninstall_commands, backend, backend_flags, host_c_compiler = state # Store that this is a worker process global is_worker_process is_worker_process = True # Setup the test environment assert not test.skip, 'Skipped test should not be run' build_dir = create_deterministic_builddir(test, use_tmp) try: with TemporaryDirectoryWinProof(prefix='i ', dir=None if use_tmp else os.getcwd()) as install_dir: try: return _run_test(test, build_dir, install_dir, extra_args, should_fail) except TestResult as r: return r finally: mlog.shutdown() # Close the log file because otherwise Windows wets itself. finally: mesonlib.windows_proof_rmtree(build_dir) def _run_test(test: TestDef, test_build_dir: str, install_dir: str, extra_args: T.List[str], should_fail: str) -> TestResult: gen_start = time.time() # Configure in-process gen_args = ['setup'] if 'prefix' not in test.do_not_set_opts: gen_args += ['--prefix', 'x:/usr'] if mesonlib.is_windows() else ['--prefix', '/usr'] if 'libdir' not in test.do_not_set_opts: gen_args += ['--libdir', 'lib'] gen_args += [test.path.as_posix(), test_build_dir] + backend_flags + extra_args nativefile, crossfile = detect_parameter_files(test, test_build_dir) if nativefile.exists(): gen_args.extend(['--native-file', nativefile.as_posix()]) if crossfile.exists(): gen_args.extend(['--cross-file', crossfile.as_posix()]) inprocess, res = run_configure(gen_args, env=test.env, catch_exception=True) returncode, stdo, stde = res cmd = '(inprocess) $ ' if inprocess else '$ ' cmd += mesonlib.join_args(gen_args) logfile = os.path.join(test_build_dir, 'meson-logs', 'meson-log.txt') if os.path.exists(logfile): mesonlog = '\n'.join((cmd, _run_ci_include([logfile]))) else: mesonlog = no_meson_log_msg cicmds = run_ci_commands(mesonlog) testresult = TestResult(cicmds) testresult.add_step(BuildStep.configure, '\n'.join((cmd, stdo)), stde, mesonlog, time.time() - gen_start) output_msg = validate_output(test, stdo, stde) testresult.mlog += output_msg if output_msg: testresult.fail('Unexpected output while configuring.') return testresult if should_fail == 'meson': if returncode == 1: return testresult elif returncode != 0: testresult.fail(f'Test exited with unexpected status {returncode}.') return testresult else: testresult.fail('Test that should have failed succeeded.') return testresult if returncode != 0: testresult.fail('Generating the build system failed.') return testresult builddata = build.load(test_build_dir) dir_args = get_backend_args_for_dir(backend, test_build_dir) # Build with subprocess def build_step() -> None: build_start = time.time() pc, o, _ = Popen_safe(compile_commands + dir_args, cwd=test_build_dir, stderr=subprocess.STDOUT) testresult.add_step(BuildStep.build, o, '', '', time.time() - build_start) if should_fail == 'build': if pc.returncode != 0: raise testresult testresult.fail('Test that should have failed to build succeeded.') raise testresult if pc.returncode != 0: testresult.fail('Compiling source code failed.') raise testresult # Touch the meson.build file to force a regenerate def force_regenerate() -> None: ensure_backend_detects_changes(backend) os.utime(str(test.path / 'meson.build')) # just test building build_step() # test that regeneration works for build step force_regenerate() build_step() # TBD: assert nothing gets built after the regenerate? # test that regeneration works for test step force_regenerate() # Test in-process clear_internal_caches() test_start = time.time() (returncode, tstdo, tstde, test_log) = run_test_inprocess(test_build_dir) testresult.add_step(BuildStep.test, tstdo, tstde, test_log, time.time() - test_start) if should_fail == 'test': if returncode != 0: return testresult testresult.fail('Test that should have failed to run unit tests succeeded.') return testresult if returncode != 0: testresult.fail('Running unit tests failed.') return testresult # Do installation, if the backend supports it if install_commands: env = test.env.copy() env['DESTDIR'] = install_dir # Install with subprocess pi, o, e = Popen_safe(install_commands, cwd=test_build_dir, env=env) testresult.add_step(BuildStep.install, o, e) if pi.returncode != 0: testresult.fail('Running install failed.') return testresult # Clean with subprocess env = test.env.copy() pi, o, e = Popen_safe(clean_commands + dir_args, cwd=test_build_dir, env=env) testresult.add_step(BuildStep.clean, o, e) if pi.returncode != 0: testresult.fail('Running clean failed.') return testresult # Validate installed files testresult.add_step(BuildStep.install, '', '') if not install_commands: return testresult install_msg = validate_install(test, Path(install_dir), builddata.environment) if install_msg: testresult.fail('\n' + install_msg) return testresult return testresult # processing of test.json 'skip_*' keys, which can appear at top level, or in # matrix: def _skip_keys(test_def: T.Dict) -> T.Tuple[bool, bool]: skip_expected = False # Test is expected to skip if MESON_CI_JOBNAME contains any of the list of # substrings if ('skip_on_jobname' in test_def) and (ci_jobname is not None): skip_expected = any(s in ci_jobname for s in test_def['skip_on_jobname']) # Test is expected to skip if os matches if 'skip_on_os' in test_def: mesonenv = environment.Environment('', '', get_fake_options('/')) for skip_os in test_def['skip_on_os']: if skip_os.startswith('!'): if mesonenv.machines.host.system != skip_os[1:]: skip_expected = True else: if mesonenv.machines.host.system == skip_os: skip_expected = True # Skip if environment variable is present skip = False if 'skip_on_env' in test_def: for skip_env_var in test_def['skip_on_env']: if skip_env_var in os.environ: skip = True return (skip, skip_expected) def load_test_json(t: TestDef, stdout_mandatory: bool, skip_category: bool = False) -> T.List[TestDef]: all_tests: T.List[TestDef] = [] test_def = {} test_def_file = t.path / 'test.json' if test_def_file.is_file(): test_def = json.loads(test_def_file.read_text(encoding='utf-8')) # Handle additional environment variables env: T.Dict[str, str] = {} if 'env' in test_def: assert isinstance(test_def['env'], dict) env = test_def['env'] for key, val in env.items(): val = val.replace('@ROOT@', t.path.resolve().as_posix()) val = val.replace('@PATH@', t.env.get('PATH', '')) env[key] = val # Handle installed files installed: T.List[InstalledFile] = [] if 'installed' in test_def: installed = [InstalledFile(x) for x in test_def['installed']] # Handle expected output stdout = test_def.get('stdout', []) if stdout_mandatory and not stdout: raise RuntimeError(f"{test_def_file} must contain a non-empty stdout key") # Handle the do_not_set_opts list do_not_set_opts: T.List[str] = test_def.get('do_not_set_opts', []) (t.skip, t.skip_expected) = _skip_keys(test_def) # Skip tests if the tool requirements are not met if 'tools' in test_def: assert isinstance(test_def['tools'], dict) for tool, vers_req in test_def['tools'].items(): if tool not in tool_vers_map: t.skip = True elif not mesonlib.version_compare(tool_vers_map[tool], vers_req): t.skip = True # Skip the matrix code and just update the existing test if 'matrix' not in test_def: t.env.update(env) t.installed_files = installed t.do_not_set_opts = do_not_set_opts t.stdout = stdout return [t] new_opt_list: T.List[T.List[T.Tuple[str, str, bool, bool]]] # 'matrix; entry is present, so build multiple tests from matrix definition opt_list: T.List[T.List[T.Tuple[str, str, bool, bool]]] = [] matrix = test_def['matrix'] assert "options" in matrix for key, val in matrix["options"].items(): assert isinstance(val, list) tmp_opts: T.List[T.Tuple[str, str, bool, bool]] = [] for i in val: assert isinstance(i, dict) assert "val" in i (skip, skip_expected) = _skip_keys(i) # Only run the test if all compiler ID's match if 'compilers' in i: for lang, id_list in i['compilers'].items(): if lang not in compiler_id_map or compiler_id_map[lang] not in id_list: skip = True break # Add an empty matrix entry if i['val'] is None: tmp_opts += [(key, None, skip, skip_expected)] continue tmp_opts += [(key, i['val'], skip, skip_expected)] if opt_list: new_opt_list = [] 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] # Exclude specific configurations if 'exclude' in matrix: assert isinstance(matrix['exclude'], list) new_opt_list = [] for i in opt_list: exclude = False opt_tuple = [(x[0], x[1]) for x in i] for j in matrix['exclude']: ex_list = [(k, v) for k, v in j.items()] if all([x in opt_tuple for x in ex_list]): exclude = True break if not exclude: new_opt_list += [i] opt_list = new_opt_list for i in opt_list: name = ' '.join([f'{x[0]}={x[1]}' for x in i if x[1] is not None]) opts = [f'-D{x[0]}={x[1]}' for x in i if x[1] is not None] skip = any([x[2] for x in i]) skip_expected = any([x[3] for x in i]) test = TestDef(t.path, name, opts, skip or t.skip, skip_category) test.env.update(env) test.installed_files = installed test.do_not_set_opts = do_not_set_opts test.stdout = stdout test.skip_expected = skip_expected or t.skip_expected all_tests.append(test) return all_tests def gather_tests(testdir: Path, stdout_mandatory: bool, only: T.List[str], skip_category: bool) -> T.List[TestDef]: all_tests: T.List[TestDef] = [] for t in testdir.iterdir(): # Filter non-tests files (dot files, etc) if not t.is_dir() or t.name.startswith('.'): continue if t.name in {'18 includedirxyz'}: continue if only and not any(t.name.startswith(prefix) for prefix in only): continue test_def = TestDef(t, None, [], skip_category=skip_category) all_tests.extend(load_test_json(test_def, stdout_mandatory, skip_category)) return sorted(all_tests) def have_d_compiler() -> bool: 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'], capture_output=True) if cp.stdout == b'': return False return True return False def have_objc_compiler(use_tmp: bool) -> bool: with TemporaryDirectoryWinProof(prefix='b ', dir=None if use_tmp else '.') as build_dir: env = environment.Environment('', build_dir, get_fake_options('/')) try: objc_comp = detect_objc_compiler(env, 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(use_tmp: bool) -> bool: with TemporaryDirectoryWinProof(prefix='b ', dir=None if use_tmp else '.') as build_dir: env = environment.Environment('', build_dir, get_fake_options('/')) try: objcpp_comp = detect_objcpp_compiler(env, 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() -> bool: if shutil.which('javac') and shutil.which('java'): return True return False def skip_dont_care(t: TestDef) -> bool: # Everything is optional when not running on CI if ci_jobname is None: return True # Non-frameworks test are allowed to determine their own skipping under CI (currently) if not t.category.endswith('frameworks'): return True if mesonlib.is_osx() and '6 gettext' in str(t.path): return True return False def skip_csharp(backend: 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 = Path('brokenrusttest') if dirname.exists(): mesonlib.windows_proof_rmtree(dirname.as_posix()) dirname.mkdir() sanity_file = dirname / 'sanity.rs' sanity_file.write_text('fn main() {\n}\n', encoding='utf-8') pc = subprocess.run(['rustc', '-o', 'sanity.exe', 'sanity.rs'], cwd=dirname.as_posix(), stdout = subprocess.DEVNULL, stderr = subprocess.DEVNULL) mesonlib.windows_proof_rmtree(dirname.as_posix()) 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(): if has_broken_rustc(): return True return False def should_skip_wayland() -> bool: if mesonlib.is_windows() or mesonlib.is_osx(): return True if not shutil.which('wayland-scanner'): return True return False def detect_tests_to_run(only: T.Dict[str, T.List[str]], use_tmp: bool) -> T.List[T.Tuple[str, T.List[TestDef], bool]]: """ Parameters ---------- only: dict of categories and list of test cases, 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('nagfor') or shutil.which('ifort') or shutil.which('ifx')) skip_cmake = ((os.environ.get('compiler') == 'msvc2015' and under_ci) or 'cmake' not in tool_vers_map or not mesonlib.version_compare(tool_vers_map['cmake'], '>=3.14')) class TestCategory: def __init__(self, category: str, subdir: str, skip: bool = False, stdout_mandatory: bool = False): self.category = category # category name self.subdir = subdir # subdirectory self.skip = skip # skip condition self.stdout_mandatory = stdout_mandatory # expected stdout is mandatory for tests in this category all_tests = [ TestCategory('cmake', 'cmake', skip_cmake), TestCategory('common', 'common'), TestCategory('native', 'native'), TestCategory('warning-meson', 'warning', stdout_mandatory=True), TestCategory('failing-meson', 'failing', stdout_mandatory=True), TestCategory('failing-build', 'failing build'), TestCategory('failing-test', 'failing test'), TestCategory('keyval', 'keyval'), TestCategory('platform-osx', 'osx', not mesonlib.is_osx()), TestCategory('platform-windows', 'windows', not mesonlib.is_windows() and not mesonlib.is_cygwin()), TestCategory('platform-linux', 'linuxlike', mesonlib.is_osx() or mesonlib.is_windows()), TestCategory('java', 'java', backend is not Backend.ninja or not have_java()), TestCategory('C#', 'csharp', skip_csharp(backend)), TestCategory('vala', 'vala', backend is not Backend.ninja or not shutil.which(os.environ.get('VALAC', 'valac'))), TestCategory('cython', 'cython', backend is not Backend.ninja or not shutil.which(os.environ.get('CYTHON', 'cython'))), TestCategory('rust', 'rust', should_skip_rust(backend)), TestCategory('d', 'd', backend is not Backend.ninja or not have_d_compiler()), TestCategory('objective c', 'objc', backend not in (Backend.ninja, Backend.xcode) or not have_objc_compiler(options.use_tmpdir)), TestCategory('objective c++', 'objcpp', backend not in (Backend.ninja, Backend.xcode) or not have_objcpp_compiler(options.use_tmpdir)), TestCategory('fortran', 'fortran', skip_fortran or backend != Backend.ninja), TestCategory('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 TestCategory('cuda', 'cuda', backend not in (Backend.ninja, Backend.xcode) or not shutil.which('nvcc')), TestCategory('python3', 'python3', backend is not Backend.ninja or 'python3' not in sys.executable), TestCategory('python', 'python'), TestCategory('fpga', 'fpga', shutil.which('yosys') is None), TestCategory('frameworks', 'frameworks'), TestCategory('nasm', 'nasm'), TestCategory('wasm', 'wasm', shutil.which('emcc') is None or backend is not Backend.ninja), TestCategory('wayland', 'wayland', should_skip_wayland()), ] categories = [t.category for t in all_tests] assert categories == ALL_TESTS, 'argparse("--only", choices=ALL_TESTS) need to be updated to match all_tests categories' if only: for key in only.keys(): assert key in categories, f'key `{key}` is not a recognized category' all_tests = [t for t in all_tests if t.category in only.keys()] gathered_tests = [(t.category, gather_tests(Path('test cases', t.subdir), t.stdout_mandatory, only[t.category], t.skip), t.skip) for t 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], use_tmp: bool, num_workers: int) -> T.Tuple[int, int, int]: txtname = log_name_base + '.txt' with open(txtname, 'w', encoding='utf-8', errors='ignore') as lf: return _run_tests(all_tests, log_name_base, failfast, extra_args, use_tmp, num_workers, lf) class TestStatus(Enum): OK = normal_green(' [SUCCESS] ') SKIP = yellow(' [SKIPPED] ') ERROR = red(' [ERROR] ') UNEXSKIP = red('[UNEXSKIP] ') UNEXRUN = red(' [UNEXRUN] ') CANCELED = cyan('[CANCELED] ') RUNNING = blue(' [RUNNING] ') # Should never be actually printed LOG = bold(' [LOG] ') # Should never be actually printed def default_print(*args: mlog.TV_Loggable, sep: str = ' ') -> None: print(*args, sep=sep) safe_print = default_print class TestRunFuture: def __init__(self, name: str, testdef: TestDef, future: T.Optional['Future[T.Optional[TestResult]]']) -> None: super().__init__() self.name = name self.testdef = testdef self.future = future self.status = TestStatus.RUNNING if self.future is not None else TestStatus.SKIP @property def result(self) -> T.Optional[TestResult]: return self.future.result() if self.future else None def log(self) -> None: without_install = '' if install_commands else '(without install)' safe_print(self.status.value, without_install, *self.testdef.display_name()) def update_log(self, new_status: TestStatus) -> None: self.status = new_status self.log() def cancel(self) -> None: if self.future is not None and self.future.cancel(): self.status = TestStatus.CANCELED class LogRunFuture: def __init__(self, msgs: mlog.TV_LoggableList) -> None: self.msgs = msgs self.status = TestStatus.LOG def log(self) -> None: safe_print(*self.msgs, sep='') def cancel(self) -> None: pass RunFutureUnion = T.Union[TestRunFuture, LogRunFuture] 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], use_tmp: bool, num_workers: int, logfile: T.TextIO) -> T.Tuple[int, int, int]: global stop, host_c_compiler xmlname = log_name_base + '.xml' junit_root = ET.Element('testsuites') conf_time: float = 0 build_time: float = 0 test_time: float = 0 passing_tests = 0 failing_tests = 0 skipped_tests = 0 print(f'\nRunning tests with {num_workers} workers') # Pack the global state state = GlobalState(compile_commands, clean_commands, test_commands, install_commands, uninstall_commands, backend, backend_flags, host_c_compiler) executor = ProcessPoolExecutor(max_workers=num_workers) futures: T.List[RunFutureUnion] = [] # First, collect and start all tests and also queue log messages for name, test_cases, skipped in all_tests: current_suite = ET.SubElement(junit_root, 'testsuite', {'name': name, 'tests': str(len(test_cases))}) if skipped: futures += [LogRunFuture(['\n', bold(f'Not running {name} tests.'), '\n'])] else: futures += [LogRunFuture(['\n', bold(f'Running {name} tests.'), '\n'])] 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 += f' ({t.name})' should_fail = '' 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] if skipped or t.skip: futures += [TestRunFuture(testname, t, None)] continue result_future = executor.submit(run_test, t, extra_args + suite_args + t.args, should_fail, use_tmp, state=state) futures += [TestRunFuture(testname, t, result_future)] # Ensure we only cancel once tests_canceled = False # Optionally enable the tqdm progress bar, but only if there is at least # one LogRunFuture and one TestRunFuture global safe_print futures_iter: T.Iterable[RunFutureUnion] = futures if len(futures) > 2 and sys.stdout.isatty(): try: from tqdm import tqdm futures_iter = tqdm(futures, desc='Running tests', unit='test') def tqdm_print(*args: mlog.TV_Loggable, sep: str = ' ') -> None: tqdm.write(sep.join([str(x) for x in args])) safe_print = tqdm_print except ImportError: pass # Wait and handle the test results and print the stored log output for f in futures_iter: # Just a log entry to print something to stdout sys.stdout.flush() if isinstance(f, LogRunFuture): f.log() continue # Actual Test run testname = f.name t = f.testdef try: result = f.result except (CancelledError, KeyboardInterrupt): f.status = TestStatus.CANCELED if stop and not tests_canceled: num_running = sum(1 if f2.status is TestStatus.RUNNING else 0 for f2 in futures) for f2 in futures: f2.cancel() executor.shutdown() num_canceled = sum(1 if f2.status is TestStatus.CANCELED else 0 for f2 in futures) safe_print(f'\nCanceled {num_canceled} out of {num_running} running tests.') safe_print(f'Finishing the remaining {num_running - num_canceled} tests.\n') tests_canceled = True # Handle canceled tests if f.status is TestStatus.CANCELED: f.log() continue # Handle skipped tests if result is None: # skipped due to skipped category skip or 'tools:' or 'skip_on_env:' is_skipped = True skip_reason = 'not run because preconditions were not met' skip_as_expected = True else: # skipped due to test outputting 'MESON_SKIP_TEST' is_skipped, skip_reason = handle_meson_skip_test(result.stdo) if not skip_dont_care(t): skip_as_expected = (is_skipped == t.skip_expected) else: skip_as_expected = True if is_skipped: skipped_tests += 1 if is_skipped and skip_as_expected: f.update_log(TestStatus.SKIP) if not t.skip_category: safe_print(bold('Reason:'), skip_reason) current_test = ET.SubElement(current_suite, 'testcase', {'name': testname, 'classname': t.category}) ET.SubElement(current_test, 'skipped', {}) continue if not skip_as_expected: failing_tests += 1 if is_skipped: skip_msg = f'Test asked to be skipped ({skip_reason}), but was not expected to' status = TestStatus.UNEXSKIP else: skip_msg = 'Test ran, but was expected to be skipped' status = TestStatus.UNEXRUN result.msg = f"{skip_msg} for MESON_CI_JOBNAME '{ci_jobname}'" f.update_log(status) safe_print(bold('Reason:'), result.msg) current_test = ET.SubElement(current_suite, 'testcase', {'name': testname, 'classname': t.category}) ET.SubElement(current_test, 'failure', {'message': result.msg}) continue # Handle Failed tests if result.msg != '': f.update_log(TestStatus.ERROR) safe_print(bold('During:'), result.step.name) safe_print(bold('Reason:'), result.msg) failing_tests += 1 # Append a visual separator for the different test cases cols = shutil.get_terminal_size((100, 20)).columns name_str = ' '.join([str(x) for x in f.testdef.display_name()]) name_len = len(re.sub(r'\x1B[^m]+m', '', name_str)) # Do not count escape sequences left_w = (cols // 2) - (name_len // 2) - 1 left_w = max(3, left_w) right_w = cols - left_w - name_len - 2 right_w = max(3, right_w) failing_testcases.append(name_str) failing_logs.append(f'\n\x1b[31m{"="*left_w}\x1b[0m {name_str} \x1b[31m{"="*right_w}\x1b[0m\n') _during = bold('Failed during:') _reason = bold('Reason:') failing_logs.append(f'{_during} {result.step.name}\n{_reason} {result.msg}\n') 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: safe_print("Cancelling the rest of the tests") for f2 in futures: f2.cancel() else: f.update_log(TestStatus.OK) 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) current_test = ET.SubElement( current_suite, 'testcase', {'name': testname, 'classname': t.category, '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 # Reset, just in case safe_print = default_print print() print("Total 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_meson_commands_work(use_tmpdir: bool, extra_args: T.List[str]) -> None: 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 TemporaryDirectoryWinProof(prefix='b ', dir=None if use_tmpdir else '.') as build_dir: print('Checking that configuring works...') gen_cmd = meson_commands + ['setup' , testdir, build_dir] + backend_flags + extra_args pc, o, e = Popen_safe(gen_cmd) if pc.returncode != 0: raise RuntimeError(f'Failed to configure {testdir!r}:\n{e}\n{o}') print('Checking that introspect works...') pc, o, e = Popen_safe(meson_commands + ['introspect', '--targets'], cwd=build_dir) json.loads(o) if pc.returncode != 0: raise RuntimeError(f'Failed to introspect --targets {testdir!r}:\n{e}\n{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(f'Failed to build {testdir!r}:\n{e}\n{o}') print('Checking that testing works...') pc, o, e = Popen_safe(test_commands, cwd=build_dir) if pc.returncode != 0: raise RuntimeError(f'Failed to test {testdir!r}:\n{e}\n{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(f'Failed to install {testdir!r}:\n{e}\n{o}') def detect_system_compiler(options: 'CompilerArgumentType') -> None: global host_c_compiler, compiler_id_map fake_opts = get_fake_options('/') if options.cross_file: fake_opts.cross_file = [options.cross_file] if options.native_file: fake_opts.native_file = [options.native_file] env = environment.Environment('', '', fake_opts) print_compilers(env, MachineChoice.HOST) if options.cross_file: print_compilers(env, MachineChoice.BUILD) for lang in sorted(compilers.all_languages): try: comp = compiler_from_language(env, lang, MachineChoice.HOST) # note compiler id for later use with test.json matrix compiler_id_map[lang] = comp.get_id() except mesonlib.MesonException: comp = None # note C compiler for later use by platform_fix_name() if lang == 'c': if comp: host_c_compiler = comp.get_id() else: raise RuntimeError("Could not find C compiler.") def print_compilers(env: 'Environment', machine: MachineChoice) -> None: print() print(f'{machine.get_lower_case_name()} machine compilers') print() for lang in sorted(compilers.all_languages): try: comp = compiler_from_language(env, lang, machine) details = '{:<10} {} {}'.format('[' + comp.get_id() + ']', ' '.join(comp.get_exelist()), comp.get_version_string()) except mesonlib.MesonException: details = '[not found]' print(f'{lang:<7}: {details}') class ToolInfo(T.NamedTuple): tool: str args: T.List[str] regex: T.Pattern match_group: int def print_tool_versions() -> None: tools: T.List[ToolInfo] = [ ToolInfo( 'ninja', ['--version'], re.compile(r'^([0-9]+(\.[0-9]+)*(-[a-z0-9]+)?)$'), 1, ), ToolInfo( 'cmake', ['--version'], re.compile(r'^cmake version ([0-9]+(\.[0-9]+)*(-[a-z0-9]+)?)$'), 1, ), ToolInfo( 'hotdoc', ['--version'], re.compile(r'^([0-9]+(\.[0-9]+)*(-[a-z0-9]+)?)$'), 1, ), ] def get_version(t: ToolInfo) -> 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 f'{exe} (invalid {t.tool} executable)' for i in o.split('\n'): i = i.strip('\n\r\t ') m = t.regex.match(i) if m is not None: tool_vers_map[t.tool] = m.group(t.match_group) return '{} ({})'.format(exe, m.group(t.match_group)) return f'{exe} (unknown)' print() print('tools') print() 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() tmpdir = list(Path('.').glob('test cases/**/*install functions and follow symlinks')) assert(len(tmpdir) == 1) symlink_test_dir = tmpdir[0] symlink_file1 = symlink_test_dir / 'foo/link1' symlink_file2 = symlink_test_dir / 'foo/link2.h' del tmpdir def clear_transitive_files() -> None: a = Path('test cases/common') for d in a.glob('*subproject subdir/subprojects/subsubsub*'): if d.is_dir(): mesonlib.windows_proof_rmtree(str(d)) else: mesonlib.windows_proof_rm(str(d)) try: symlink_file1.unlink() except FileNotFoundError: pass try: symlink_file2.unlink() except FileNotFoundError: pass def setup_symlinks() -> None: symlink_file1.symlink_to('file1') symlink_file2.symlink_to('file1') if __name__ == '__main__': if under_ci and not raw_ci_jobname: raise SystemExit('Running under CI but $MESON_CI_JOBNAME is not set (set to "thirdparty" if you are running outside of the github org)') setup_vsenv() 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 two processes') num_workers = 2 if num_workers > 64: # Too much parallelism seems to trigger a potential Python bug: # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1004107 num_workers = 64 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('-j', dest='num_workers', type=int, default=num_workers, help=f'Maximum number of parallel tests (default {num_workers})') 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', default=[], help='name of test(s) to run, in format "category[/name]" where category is one of: ' + ', '.join(ALL_TESTS), nargs='+') parser.add_argument('--cross-file', action='store', help='File describing cross compilation environment.') parser.add_argument('--native-file', action='store', help='File describing native compilation environment.') parser.add_argument('--use-tmpdir', action='store_true', help='Use tmp directory for temporary files.') options = T.cast('ArgumentType', parser.parse_args()) if options.cross_file: options.extra_args += ['--cross-file', options.cross_file] if options.native_file: options.extra_args += ['--native-file', options.native_file] clear_transitive_files() setup_symlinks() mesonlib.set_meson_command(get_meson_script()) print('Meson build system', meson_version, 'Project Tests') print('Using python', sys.version.split('\n')[0], f'({sys.executable!r})') if 'VSCMD_VER' in os.environ: print('VSCMD version', os.environ['VSCMD_VER']) setup_commands(options.backend) detect_system_compiler(options) print_tool_versions() script_dir = os.path.split(__file__)[0] if script_dir != '': os.chdir(script_dir) check_meson_commands_work(options.use_tmpdir, options.extra_args) only = collections.defaultdict(list) for i in options.only: try: cat, case = i.split('/') only[cat].append(case) except ValueError: only[i].append('') try: all_tests = detect_tests_to_run(only, options.use_tmpdir) res = run_tests(all_tests, 'meson-test-run', options.failfast, options.extra_args, options.use_tmpdir, options.num_workers) (passing_tests, failing_tests, skipped_tests) = res except StopException: pass 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') print() print('Total 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('\nAll failures:') for c in failing_testcases: print(f' -> {c}') for name, dirs, _ in all_tests: dir_names = list({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 {} suite contains duplicate "{}" tests: "{}"'.format(name, k, '", "'.join(tests))) clear_transitive_files() raise SystemExit(failing_tests) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/run_tests.py0000755000175000017500000004156314562742363015460 0ustar00jpakkanejpakkane#!/usr/bin/env python3 # Copyright 2012-2021 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Work around some pathlib bugs... from mesonbuild import _pathlib import sys sys.modules['pathlib'] = _pathlib import collections import os import time import shutil import subprocess import platform import argparse import traceback from io import StringIO from enum import Enum from glob import glob from pathlib import Path from unittest import mock import typing as T from mesonbuild.compilers.c import CCompiler from mesonbuild.compilers.detect import detect_c_compiler from mesonbuild.dependencies.pkgconfig import PkgConfigInterface from mesonbuild import mesonlib from mesonbuild import mesonmain from mesonbuild import mtest from mesonbuild import mlog from mesonbuild.environment import Environment, detect_ninja, detect_machine_info from mesonbuild.coredata import backendlist, version as meson_version from mesonbuild.mesonlib import OptionKey, setup_vsenv NINJA_1_9_OR_NEWER = False NINJA_CMD = None # If we're on CI, detecting ninja for every subprocess unit test that we run is slow # Optimize this by respecting $NINJA and skipping detection, then exporting it on # first run. try: NINJA_1_9_OR_NEWER = bool(int(os.environ['NINJA_1_9_OR_NEWER'])) NINJA_CMD = [os.environ['NINJA']] except (KeyError, ValueError): # Look for 1.9 to see if https://github.com/ninja-build/ninja/issues/1219 # is fixed NINJA_CMD = detect_ninja('1.9') if NINJA_CMD is not None: NINJA_1_9_OR_NEWER = True else: mlog.warning('Found ninja <1.9, tests will run slower', once=True) NINJA_CMD = detect_ninja() if NINJA_CMD is not None: os.environ['NINJA_1_9_OR_NEWER'] = str(int(NINJA_1_9_OR_NEWER)) os.environ['NINJA'] = NINJA_CMD[0] else: raise RuntimeError('Could not find Ninja v1.7 or newer') # Emulate running meson with -X utf8 by making sure all open() calls have a # sane encoding. This should be a python default, but PEP 540 considered it not # backwards compatible. Instead, much line noise in diffs to update this, and in # python 3.10 we can also make it a warning when absent. os.environ['PYTHONWARNDEFAULTENCODING'] = '1' # work around https://bugs.python.org/issue34624 os.environ['MESON_RUNNING_IN_PROJECT_TESTS'] = '1' # python 3.11 adds a warning that in 3.15, UTF-8 mode will be default. # This is fantastic news, we'd love that. Less fantastic: this warning is silly, # we *want* these checks to be affected. Plus, the recommended alternative API # would (in addition to warning people when UTF-8 mode removed the problem) also # require using a minimum python version of 3.11 (in which the warning was added) # or add verbose if/else soup. if sys.version_info >= (3, 10): import warnings warnings.filterwarnings('ignore', message="UTF-8 Mode affects .*getpreferredencoding", category=EncodingWarning) def guess_backend(backend_str: str, msbuild_exe: str) -> T.Tuple['Backend', T.List[str]]: # Auto-detect backend if unspecified backend_flags = [] if backend_str is None: if msbuild_exe is not None and (mesonlib.is_windows() and not _using_intelcl()): backend_str = 'vs' # Meson will auto-detect VS version to use else: backend_str = 'ninja' # Set backend arguments for Meson if backend_str.startswith('vs'): backend_flags = ['--backend=' + backend_str] backend = Backend.vs elif backend_str == 'xcode': backend_flags = ['--backend=xcode'] backend = Backend.xcode elif backend_str == 'ninja': backend_flags = ['--backend=ninja'] backend = Backend.ninja else: raise RuntimeError(f'Unknown backend: {backend_str!r}') 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 = [] # TODO: use a typing.Protocol here def get_fake_options(prefix: str = '') -> argparse.Namespace: 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.options[OptionKey('args', lang='c')] = FakeCompilerOptions() env.machines.host.cpu_family = 'x86_64' # Used on macOS inside find_library # Invalidate cache when using a different Environment object. clear_meson_configure_class_caches() return env def get_convincing_fake_env_and_cc(bdir, prefix): ''' Return a fake env and C compiler with the fake env machine info properly detected using that compiler. Useful for running compiler checks in the unit tests. ''' env = get_fake_env('', bdir, prefix) cc = detect_c_compiler(env, mesonlib.MachineChoice.HOST) # Detect machine info env.machines.host = detect_machine_info({'c':cc}) return (env, cc) 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 handle_meson_skip_test(out: str) -> T.Tuple[bool, str]: for line in out.splitlines(): for prefix in {'Problem encountered', 'Assert failed', 'Failed to configure the CMake subproject'}: if f'{prefix}: MESON_SKIP_TEST' in line: offset = line.index('MESON_SKIP_TEST') + 16 reason = line[offset:].strip() return (True, reason) return (False, '') def get_meson_script() -> str: ''' 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(f'Could not find {meson_script!r} or a meson in PATH') def get_backend_args_for_dir(backend: Backend, builddir: str) -> T.List[str]: ''' 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 = fr'{t}\s*\{ext}' else: p = fr'{t}' for _, _, files in os.walk(builddir): for f in fnmatch.filter(files, '*.vcxproj'): f = os.path.join(builddir, f) with open(f, encoding='utf-8') as o: if re.search(p, o.read(), flags=re.MULTILINE): return f raise RuntimeError(f'No vcxproj matching {p!r} in {builddir!r}') def get_builddir_target_args(backend: 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(f'Unknown backend: {backend!r}') return target_args + dir_args def get_backend_commands(backend: Backend, debug: bool = False) -> \ T.Tuple[T.List[str], T.List[str], T.List[str], T.List[str], T.List[str]]: install_cmd: T.List[str] = [] uninstall_cmd: T.List[str] = [] clean_cmd: T.List[str] cmd: T.List[str] test_cmd: T.List[str] 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'] clean_cmd = cmd + ['-alltargets', 'clean'] test_cmd = cmd + ['-target', 'RUN_TESTS'] elif backend is Backend.ninja: global NINJA_CMD cmd = NINJA_CMD + ['-w', 'dupbuild=err', '-d', 'explain'] if debug: cmd += ['-v'] clean_cmd = cmd + ['clean'] test_cmd = cmd + ['test', 'benchmark'] install_cmd = cmd + ['install'] uninstall_cmd = cmd + ['uninstall'] else: raise AssertionError(f'Unknown backend: {backend!r}') return cmd, clean_cmd, test_cmd, install_cmd, uninstall_cmd def ensure_backend_detects_changes(backend: Backend) -> None: global NINJA_1_9_OR_NEWER if backend is not Backend.ninja: return need_workaround = False # 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: T.List[str]) -> T.Tuple[int, str, str]: out = StringIO() with mock.patch.object(sys, 'stdout', out), mock.patch.object(sys, 'stderr', out): returncode = mtest.run_with_args(commandlist) return returncode, out.getvalue() def clear_meson_configure_class_caches() -> None: CCompiler.find_library_cache.clear() CCompiler.find_framework_cache.clear() PkgConfigInterface.class_impl.assign(False, False) mesonlib.project_meson_versions.clear() def run_configure_inprocess(commandlist: T.List[str], env: T.Optional[T.Dict[str, str]] = None, catch_exception: bool = False) -> T.Tuple[int, str, str]: stderr = StringIO() stdout = StringIO() returncode = 0 with mock.patch.dict(os.environ, env or {}), mock.patch.object(sys, 'stdout', stdout), mock.patch.object(sys, 'stderr', stderr): try: returncode = mesonmain.run(commandlist, get_meson_script()) except Exception: if catch_exception: returncode = 1 traceback.print_exc() else: raise finally: clear_meson_configure_class_caches() return returncode, stdout.getvalue(), stderr.getvalue() def run_configure_external(full_command: T.List[str], env: T.Optional[T.Dict[str, str]] = None) -> T.Tuple[int, str, str]: pc, o, e = mesonlib.Popen_safe(full_command, env=env) return pc.returncode, o, e def run_configure(commandlist: T.List[str], env: T.Optional[T.Dict[str, str]] = None, catch_exception: bool = False) -> T.Tuple[bool, T.Tuple[int, str, str]]: global meson_exe if meson_exe: return (False, run_configure_external(meson_exe + commandlist, env=env)) return (True, run_configure_inprocess(commandlist, env=env, catch_exception=catch_exception)) def print_system_info(): print(mlog.bold('System information.')) print('Architecture:', platform.architecture()) print('Machine:', platform.machine()) print('Platform:', platform.system()) print('Processor:', platform.processor()) print('System:', platform.system()) print('') print(flush=True) def subprocess_call(cmd, **kwargs): print(f'$ {mesonlib.join_args(cmd)}') return subprocess.call(cmd, **kwargs) def main(): print_system_info() parser = argparse.ArgumentParser() parser.add_argument('--backend', default=None, dest='backend', choices=backendlist) parser.add_argument('--cross', default=[], dest='cross', action='append') parser.add_argument('--cross-only', 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() returncode = 0 _, backend_flags = 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 # Can't pass arguments to unit tests, so set the backend to use in the environment env = os.environ.copy() if not options.cross: cmd = mesonlib.python_command + ['run_meson_command_tests.py', '-v'] if options.failfast: cmd += ['--failfast'] returncode += subprocess_call(cmd, env=env) if options.failfast and returncode != 0: return returncode if no_unittests: print('Skipping all unit tests.') print(flush=True) returncode = 0 else: print(mlog.bold('Running unittests.')) print(flush=True) cmd = mesonlib.python_command + ['run_unittests.py', '-v'] + backend_flags 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'] for cf in options.cross: print(mlog.bold(f'Running {cf} cross tests.')) print(flush=True) cmd = cross_test_args + ['cross/' + cf] if options.failfast: cmd += ['--failfast'] if options.cross_only: cmd += ['--cross-only'] returncode += subprocess_call(cmd, env=env) if options.failfast and returncode != 0: return returncode return returncode if __name__ == '__main__': setup_vsenv() print('Meson build system', meson_version, 'Project and Unit Tests') raise SystemExit(main()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/run_unittests.py0000755000175000017500000001350014562742363016346 0ustar00jpakkanejpakkane#!/usr/bin/env python3 # Copyright 2016-2021 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Work around some pathlib bugs... from mesonbuild import _pathlib import sys sys.modules['pathlib'] = _pathlib import time import subprocess import os import unittest import mesonbuild.mlog import mesonbuild.depfile import mesonbuild.dependencies.base import mesonbuild.dependencies.factory import mesonbuild.compilers import mesonbuild.envconfig import mesonbuild.environment import mesonbuild.coredata import mesonbuild.modules.gnome from mesonbuild.mesonlib import python_command, setup_vsenv import mesonbuild.modules.pkgconfig from unittests.allplatformstests import AllPlatformTests from unittests.cargotests import CargoVersionTest, CargoCfgTest from unittests.darwintests import DarwinTests from unittests.failuretests import FailureTests from unittests.linuxcrosstests import LinuxCrossArmTests, LinuxCrossMingwTests from unittests.machinefiletests import NativeFileTests, CrossFileTests from unittests.rewritetests import RewriterTests from unittests.taptests import TAPParserTests from unittests.datatests import DataTests from unittests.internaltests import InternalTests from unittests.linuxliketests import LinuxlikeTests from unittests.pythontests import PythonTests from unittests.subprojectscommandtests import SubprojectsCommandTests from unittests.windowstests import WindowsTests from unittests.platformagnostictests import PlatformAgnosticTests 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('-'): if arg in ('-f', '--failfast'): arg = '--exitfirst' pytest_args.append(arg) 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 running_single_tests(argv, cases): ''' Check whether we only got arguments for running individual tests, not entire testcases, and not all testcases (no test args). ''' got_test_arg = False for arg in argv: if arg.startswith('-'): continue for case in cases: if not arg.startswith(case): continue if '.' not in arg: # Got a testcase, done return False got_test_arg = True return got_test_arg def setup_backend(): filtered = [] be = 'ninja' for a in sys.argv: if a.startswith('--backend'): be = a.split('=')[1] else: filtered.append(a) # Since we invoke the tests via unittest or xtest test runner # we need to pass the backend to use to the spawned process via # this side channel. Yes it sucks, but at least is is fully # internal to this file. os.environ['MESON_UNIT_TEST_BACKEND'] = be sys.argv = filtered def main(): unset_envs() setup_backend() cases = ['InternalTests', 'DataTests', 'AllPlatformTests', 'FailureTests', 'PythonTests', 'NativeFileTests', 'RewriterTests', 'CrossFileTests', 'TAPParserTests', 'SubprojectsCommandTests', 'PlatformAgnosticTests', 'LinuxlikeTests', 'LinuxCrossArmTests', 'LinuxCrossMingwTests', 'WindowsTests', 'DarwinTests'] try: import pytest # noqa: F401 pytest_args = [] try: # Need pytest-xdist for `-n` arg import xdist # noqa: F401 # Don't use pytest-xdist when running single unit tests since it wastes # time spawning a lot of processes to distribute tests to in that case. if not running_single_tests(sys.argv, cases): pytest_args += ['-n', 'auto'] except ImportError: print('pytest-xdist not found, tests will not be distributed across CPU cores') # Let there be colors! if 'CI' in os.environ: pytest_args += ['--color=yes'] pytest_args += ['unittests'] pytest_args += convert_args(sys.argv[1:]) # Always disable pytest-cov because we use a custom setup try: import pytest_cov # noqa: F401 print('Disabling pytest-cov') pytest_args += ['-p' 'no:cov'] except ImportError: pass return subprocess.run(python_command + ['-m', 'pytest'] + pytest_args).returncode except ImportError: print('pytest not found, using unittest instead') # Fallback to plain unittest. return unittest.main(defaultTest=cases, buffer=True) if __name__ == '__main__': setup_vsenv() print('Meson build system', mesonbuild.coredata.version, 'Unit Tests') start = time.monotonic() try: raise SystemExit(main()) finally: print('Total time: {:.3f} seconds'.format(time.monotonic() - start)) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853070.4466803 meson-1.3.2/setup.cfg0000644000175000017500000000353214562742416014667 0ustar00jpakkanejpakkane[metadata] name = meson version = attr: mesonbuild.coredata.version description = A high performance build system author = Jussi Pakkanen author_email = jpakkane@gmail.com url = https://mesonbuild.com project_urls = Source = https://github.com/mesonbuild/meson keywords = meson mesonbuild build system cmake license = Apache License, Version 2.0 license_files = 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.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 Programming Language :: Python :: 3.12 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] packages = find: python_requires = >= 3.7 [options.entry_points] console_scripts = meson = mesonbuild.mesonmain:main [options.extras_require] ninja = ninja>=1.8.2 progress = tqdm typing = mypy typing_extensions; python_version <"3.8" [options.package_data] mesonbuild.scripts = cmd_or_ps.ps1 mesonbuild.cmake.data = * mesonbuild.dependencies.data = * [options.packages.find] include = mesonbuild, mesonbuild.* [tool:pytest] python_classes = python_files = unittests/*tests.py [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/setup.py0000644000175000017500000000213714562742363014561 0ustar00jpakkanejpakkane#!/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, 7): raise SystemExit('ERROR: Tried to install Meson with an unsupported Python version: \n{}' '\nMeson requires Python 3.7.0 or greater'.format(sys.version)) from setuptools import setup 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'])] setup(data_files=data_files,) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.3946342 meson-1.3.2/test cases/0000755000175000017500000000000014562742413015076 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7706246 meson-1.3.2/test cases/cmake/0000755000175000017500000000000014562742413016156 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1707853067.79064 meson-1.3.2/test cases/cmake/1 basic/0000755000175000017500000000000014562742414017361 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/1 basic/main.cpp0000644000175000017500000000023213716006331020775 0ustar00jpakkanejpakkane#include #include using namespace std; int main(void) { cmModClass obj("Hello"); cout << obj.getStr() << endl; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1699894002.0 meson-1.3.2/test cases/cmake/1 basic/meson.build0000644000175000017500000000114014524451362021514 0ustar00jpakkanejpakkaneproject('cmakeSubTest', ['c', 'cpp']) cm = import('cmake') sub_pro = cm.subproject('cmMod') sub_dep = sub_pro.dependency('cmModLib++', include_type: 'system') 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') assert(sub_dep.include_type() == 'system', 'the include_type kwarg of dependency() works') exe1 = executable('main', ['main.cpp'], dependencies: [sub_dep]) test('test1', exe1) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7506244 meson-1.3.2/test cases/cmake/1 basic/subprojects/0000755000175000017500000000000014562742413021723 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.7946403 meson-1.3.2/test cases/cmake/1 basic/subprojects/cmMod/0000755000175000017500000000000014562742414022763 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/1 basic/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000106314031433465025515 0ustar00jpakkanejpakkanecmake_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) target_compile_definitions(cmModLib++ PRIVATE MESON_MAGIC_FLAG=21) target_compile_definitions(cmModLib++ INTERFACE MESON_MAGIC_FLAG=42) # Test PCH support if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16.0") target_precompile_headers(cmModLib++ PRIVATE "cpp_pch.hpp") endif() include(GenerateExportHeader) generate_export_header(cmModLib++) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/1 basic/subprojects/cmMod/cmMod.cpp0000644000175000017500000000035713716006331024522 0ustar00jpakkanejpakkane#include "cmMod.hpp" using namespace std; #if MESON_MAGIC_FLAG != 21 #error "Invalid MESON_MAGIC_FLAG (private)" #endif cmModClass::cmModClass(string foo) { str = foo + " World"; } string cmModClass::getStr() const { return str; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/1 basic/subprojects/cmMod/cmMod.hpp0000644000175000017500000000045213716006331024523 0ustar00jpakkanejpakkane#pragma once #include "cmmodlib++_export.h" #include #if MESON_MAGIC_FLAG != 42 && MESON_MAGIC_FLAG != 21 #error "Invalid MESON_MAGIC_FLAG" #endif class CMMODLIB___EXPORT cmModClass { private: std::string str; public: cmModClass(std::string foo); std::string getStr() const; }; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/1 basic/subprojects/cmMod/cpp_pch.hpp0000644000175000017500000000004414031433465025100 0ustar00jpakkanejpakkane#include #include ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.7946403 meson-1.3.2/test cases/cmake/10 header only/0000755000175000017500000000000014562742414020552 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/10 header only/main.cpp0000644000175000017500000000045713716006331022177 0ustar00jpakkanejpakkane#include #include using namespace std; #define EXPECTED "Hello World compDef 42" int main(void) { cmModClass obj("Hello"); cout << obj.getStr() << endl; if (obj.getStr() != EXPECTED) { cerr << "Expected: '" << EXPECTED << "'" << endl; return 1; } return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421418.0 meson-1.3.2/test cases/cmake/10 header only/meson.build0000644000175000017500000000062014516755252022715 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7506244 meson-1.3.2/test cases/cmake/10 header only/subprojects/0000755000175000017500000000000014562742413023114 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8026404 meson-1.3.2/test cases/cmake/10 header only/subprojects/cmMod/0000755000175000017500000000000014562742414024154 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/10 header only/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000101713716006331026702 0ustar00jpakkanejpakkanecmake_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") target_compile_definitions(cmModLib INTERFACE MESON_MAGIC_FLAG=42) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8026404 meson-1.3.2/test cases/cmake/10 header only/subprojects/cmMod/include/0000755000175000017500000000000014562742414025577 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/10 header only/subprojects/cmMod/include/cmMod.hpp0000644000175000017500000000071213716006331027336 0ustar00jpakkanejpakkane#pragma once #include #ifndef CMAKE_FLAG_MUST_BE_PRESENT #error "The flag CMAKE_FLAG_MUST_BE_PRESENT was not set" #endif #define xstr(s) str(s) #define str(s) #s class cmModClass { private: std::string str; public: cmModClass(std::string foo) { str = foo + " World "; str += CMAKE_COMPILER_DEFINE_STR; str += ' '; str += xstr(MESON_MAGIC_FLAG); } inline std::string getStr() const { return str; } }; ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8026404 meson-1.3.2/test cases/cmake/11 cmake_module_path/0000755000175000017500000000000014562742414022022 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8026404 meson-1.3.2/test cases/cmake/11 cmake_module_path/cmake/0000755000175000017500000000000014562742414023102 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/11 cmake_module_path/cmake/FindSomethingLikePython.cmake0000644000175000017500000000040614031433465030643 0ustar00jpakkanejpakkanecmake_policy(VERSION 3.7) find_package(Python COMPONENTS Interpreter) if(Python_FOUND OR PYTHONINTERP_FOUND) set(SomethingLikePython_FOUND ON) set(SomethingLikePython_EXECUTABLE ${Python_EXECUTABLE}) else() set(SomethingLikePython_FOUND OFF) endif() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421420.0 meson-1.3.2/test cases/cmake/11 cmake_module_path/meson.build0000644000175000017500000000207214516755254024172 0ustar00jpakkanejpakkane# 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', ['c', 'cpp'], meson_version: '>= 0.55.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') # Test a custom target with Python::Interpreter in COMMAND cm = import('cmake') op = cm.subproject_options() op.add_cmake_defines({'CMAKE_MODULE_PATH': meson.source_root() / 'cmake'}) sp = cm.subproject('cmMod', options: op) main = sp.target('main') test('main', main) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7506244 meson-1.3.2/test cases/cmake/11 cmake_module_path/subprojects/0000755000175000017500000000000014562742413024364 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8026404 meson-1.3.2/test cases/cmake/11 cmake_module_path/subprojects/cmMod/0000755000175000017500000000000014562742414025424 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/11 cmake_module_path/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000064714031433465030165 0ustar00jpakkanejpakkanecmake_minimum_required(VERSION 3.5) project(cmMod) message(STATUS "CMAKE_MODULE_PATH: '${CMAKE_MODULE_PATH}'") find_package(SomethingLikePython REQUIRED) add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/main.c" COMMAND Python::Interpreter "${CMAKE_CURRENT_SOURCE_DIR}/gen.py" WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" ) add_executable(main "${CMAKE_CURRENT_BINARY_DIR}/main.c") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/11 cmake_module_path/subprojects/cmMod/gen.py0000644000175000017500000000021014031433465026532 0ustar00jpakkanejpakkanewith open('main.c', 'w') as fp: print(''' #include int main(void) { printf(\"Hello World\"); return 0; } ''', file=fp) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8106406 meson-1.3.2/test cases/cmake/12 generator expressions/0000755000175000017500000000000014562742414022713 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/12 generator expressions/main.cpp0000644000175000017500000000023213716006331024327 0ustar00jpakkanejpakkane#include #include using namespace std; int main(void) { cmModClass obj("Hello"); cout << obj.getStr() << endl; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421419.0 meson-1.3.2/test cases/cmake/12 generator expressions/meson.build0000644000175000017500000000062014516755253025057 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7506244 meson-1.3.2/test cases/cmake/12 generator expressions/subprojects/0000755000175000017500000000000014562742413025255 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8106406 meson-1.3.2/test cases/cmake/12 generator expressions/subprojects/cmMod/0000755000175000017500000000000014562742414026315 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/cmake/12 generator expressions/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000220614253672217031055 0ustar00jpakkanejpakkanecmake_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> INTERFACE $>,-DCMAKE_TRUE_FLAG,-DCMAKE_FALSE_FLAG> INTERFACE $,-DCMAKE_TGT_EXISTS,-DCMAKE_TGT_NEXISTS> INTERFACE $,-DCMAKE_PROP1_OK,-DCMAKE_PROP1_ERROR> INTERFACE $,-DCMAKE_PROP2_ERROR,-DCMAKE_PROP2_OK> ) target_include_directories(cmModLib INTERFACE $ $ ) set_target_properties(cmModLib PROPERTIES IMPORTED_NO_SONAME 1 IMPORT_SUFFIX 0 ) target_compile_definitions(cmModLib INTERFACE -DCMAKE_COMPILER_DEFINE_STR="compDef") ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8146405 meson-1.3.2/test cases/cmake/12 generator expressions/subprojects/cmMod/include/0000755000175000017500000000000014562742414027740 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/cmake/12 generator expressions/subprojects/cmMod/include/cmMod.hpp0000644000175000017500000000231214253672217031506 0ustar00jpakkanejpakkane#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 #ifndef CMAKE_TRUE_FLAG #error "The flag CMAKE_TRUE_FLAG was not set" #endif #ifdef CMAKE_FALSE_FLAG #error "The flag CMAKE_FALSE_FLAG was set" #endif #ifndef CMAKE_TGT_EXISTS #error "The flag CMAKE_TGT_EXISTS was not set" #endif #ifdef CMAKE_TGT_NEXISTS #error "The flag CMAKE_TGT_NEXISTS was set" #endif #ifndef CMAKE_PROP1_OK #error "The flag CMAKE_PROP1_OK was not set" #endif #ifdef CMAKE_PROP1_ERROR #error "The flag CMAKE_PROP1_ERROR was set" #endif #ifndef CMAKE_PROP2_OK #error "The flag CMAKE_PROP2_OK was not set" #endif #ifdef CMAKE_PROP2_ERROR #error "The flag CMAKE_PROP2_ERROR 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; } }; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/cmake/12 generator expressions/test.json0000644000175000017500000000005314253672217024563 0ustar00jpakkanejpakkane{ "tools": { "cmake": ">=3.19" } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8146405 meson-1.3.2/test cases/cmake/13 system includes/0000755000175000017500000000000014562742414021476 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/13 system includes/main.cpp0000644000175000017500000000023213716006331023112 0ustar00jpakkanejpakkane#include #include using namespace std; int main(void) { cmModClass obj("Hello"); cout << obj.getStr() << endl; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421424.0 meson-1.3.2/test cases/cmake/13 system includes/meson.build0000644000175000017500000000070614516755260023645 0ustar00jpakkanejpakkaneproject( '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: Skip 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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7506244 meson-1.3.2/test cases/cmake/13 system includes/subprojects/0000755000175000017500000000000014562742413024040 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8266406 meson-1.3.2/test cases/cmake/13 system includes/subprojects/cmMod/0000755000175000017500000000000014562742414025100 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/13 system includes/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000062113716006331027626 0ustar00jpakkanejpakkanecmake_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") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/13 system includes/subprojects/cmMod/cmMod.cpp0000644000175000017500000000032413716006331026631 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/13 system includes/subprojects/cmMod/cmMod.hpp0000644000175000017500000000032013716006331026632 0ustar00jpakkanejpakkane#pragma once #include #include "cmmodlib_export.h" class CMMODLIB_EXPORT cmModClass { private: std::string str; public: cmModClass(std::string foo); std::string getStr() const; }; ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8266406 meson-1.3.2/test cases/cmake/13 system includes/subprojects/cmMod/sysInc/0000755000175000017500000000000014562742414026350 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/13 system includes/subprojects/cmMod/sysInc/triggerWarn.hpp0000644000175000017500000000027013716006331031342 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8306408 meson-1.3.2/test cases/cmake/14 fortran threads/0000755000175000017500000000000014562742414021452 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421423.0 meson-1.3.2/test cases/cmake/14 fortran threads/meson.build0000644000175000017500000000070214516755257023623 0ustar00jpakkanejpakkaneproject('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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8346407 meson-1.3.2/test cases/cmake/15 object library advanced/0000755000175000017500000000000014562742414023006 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/15 object library advanced/main.cpp0000644000175000017500000000027513716006331024431 0ustar00jpakkanejpakkane#include #include "libA.hpp" #include "libB.hpp" using namespace std; int main(void) { cout << getLibStr() << endl; cout << getZlibVers() << endl; return EXIT_SUCCESS; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421424.0 meson-1.3.2/test cases/cmake/15 object library advanced/meson.build0000644000175000017500000000077314516755260025161 0ustar00jpakkanejpakkaneproject('cmake_object_lib_test', 'cpp', default_options: ['cpp_std=c++11']) if meson.is_cross_build() error('MESON_SKIP_TEST this test does not cross compile correctly.') endif 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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7546244 meson-1.3.2/test cases/cmake/15 object library advanced/subprojects/0000755000175000017500000000000014562742413025350 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.850641 meson-1.3.2/test cases/cmake/15 object library advanced/subprojects/cmObjLib/0000755000175000017500000000000014562742414027032 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/15 object library advanced/subprojects/cmObjLib/CMakeLists.txt0000644000175000017500000000114613716006331031563 0ustar00jpakkanejpakkanecmake_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") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/15 object library advanced/subprojects/cmObjLib/genC.cpp0000644000175000017500000000071313716006331030402 0ustar00jpakkanejpakkane#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; }././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/15 object library advanced/subprojects/cmObjLib/libA.cpp0000644000175000017500000000022013716006331030366 0ustar00jpakkanejpakkane#include "libA.hpp" #if not BUILD_AS_OBJ #error "BUILD_AS_OBJ was not defined" #endif std::string getLibStr(void) { return "Hello World"; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/15 object library advanced/subprojects/cmObjLib/libA.hpp0000644000175000017500000000055213716006331030403 0ustar00jpakkanejpakkane#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(); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/15 object library advanced/subprojects/cmObjLib/libB.cpp0000644000175000017500000000014113716006331030371 0ustar00jpakkanejpakkane#include "libB.hpp" #include "libC.hpp" std::string getZlibVers(void) { return getGenStr(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/15 object library advanced/subprojects/cmObjLib/libB.hpp0000644000175000017500000000055413716006331030406 0ustar00jpakkanejpakkane#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(); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8666413 meson-1.3.2/test cases/cmake/16 threads/0000755000175000017500000000000014562742414020020 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/16 threads/main.cpp0000644000175000017500000000022513716006331021436 0ustar00jpakkanejpakkane#include "cmMod.hpp" #include int main() { CmMod cc; cc.asyncIncrement(); return cc.getNum() == 1 ? EXIT_SUCCESS : EXIT_FAILURE; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421429.0 meson-1.3.2/test cases/cmake/16 threads/meson.build0000644000175000017500000000070614516755265022174 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/16 threads/meson_options.txt0000644000175000017500000000012513716006331023442 0ustar00jpakkanejpakkaneoption('use_pthread', type: 'combo', choices: ['ON', 'OFF', 'NOT_SET'], value: 'ON') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7546244 meson-1.3.2/test cases/cmake/16 threads/subprojects/0000755000175000017500000000000014562742413022362 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8706415 meson-1.3.2/test cases/cmake/16 threads/subprojects/cmMod/0000755000175000017500000000000014562742414023422 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/cmake/16 threads/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000063314107166547026166 0ustar00jpakkanejpakkanecmake_minimum_required(VERSION 3.5) project(cmMod C 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/16 threads/subprojects/cmMod/cmMod.cpp0000644000175000017500000000035113716006331025153 0ustar00jpakkanejpakkane#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(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/16 threads/subprojects/cmMod/cmMod.hpp0000644000175000017500000000063713716006331025167 0ustar00jpakkanejpakkane#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(); }; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/16 threads/subprojects/cmMod/main.cpp0000644000175000017500000000022513716006331025040 0ustar00jpakkanejpakkane#include "cmMod.hpp" #include int main() { CmMod cc; cc.asyncIncrement(); return cc.getNum() == 1 ? EXIT_SUCCESS : EXIT_FAILURE; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/16 threads/test.json0000644000175000017500000000024513716006331021662 0ustar00jpakkanejpakkane{ "matrix": { "options": { "use_pthread": [ { "val": "ON" }, { "val": "OFF" }, { "val": "NOT_SET" } ] } } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8826416 meson-1.3.2/test cases/cmake/17 include path order/0000755000175000017500000000000014562742414022023 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/17 include path order/main.cpp0000644000175000017500000000023213716006331023437 0ustar00jpakkanejpakkane#include #include using namespace std; int main(void) { cmModClass obj("Hello"); cout << obj.getStr() << endl; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421430.0 meson-1.3.2/test cases/cmake/17 include path order/meson.build0000644000175000017500000000034514516755266024177 0ustar00jpakkanejpakkaneproject('include_path_order', ['c', 'cpp']) cm = import('cmake') sub_pro = cm.subproject('cmMod') sub_dep = sub_pro.dependency('cmModLib++') exe1 = executable('main', ['main.cpp'], dependencies: [sub_dep]) test('test1', exe1) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7546244 meson-1.3.2/test cases/cmake/17 include path order/subprojects/0000755000175000017500000000000014562742413024365 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8826416 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/0000755000175000017500000000000014562742414025425 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000162613716006331030161 0ustar00jpakkanejpakkanecmake_minimum_required(VERSION 3.5) project(cmMod) set (CMAKE_CXX_STANDARD 14) include_directories( ${CMAKE_CURRENT_BINARY_DIR} # The one and only correct include dir ${CMAKE_CURRENT_SOURCE_DIR}/incG # All of these are traps ${CMAKE_CURRENT_SOURCE_DIR}/incL ${CMAKE_CURRENT_SOURCE_DIR}/incM ${CMAKE_CURRENT_SOURCE_DIR}/incO ${CMAKE_CURRENT_SOURCE_DIR}/incF ${CMAKE_CURRENT_SOURCE_DIR}/incI ${CMAKE_CURRENT_SOURCE_DIR}/incE ${CMAKE_CURRENT_SOURCE_DIR}/incD ${CMAKE_CURRENT_SOURCE_DIR}/incH ${CMAKE_CURRENT_SOURCE_DIR}/incN ${CMAKE_CURRENT_SOURCE_DIR}/incA ${CMAKE_CURRENT_SOURCE_DIR}/incB ${CMAKE_CURRENT_SOURCE_DIR}/incJ ${CMAKE_CURRENT_SOURCE_DIR}/incP ${CMAKE_CURRENT_SOURCE_DIR}/incC ${CMAKE_CURRENT_SOURCE_DIR}/incK ) add_definitions("-DDO_NOTHING_JUST_A_FLAG=1") add_library(cmModLib++ SHARED cmMod.cpp) include(GenerateExportHeader) generate_export_header(cmModLib++) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/cmMod.cpp0000644000175000017500000000024013716006331027153 0ustar00jpakkanejpakkane#include "cmMod.hpp" using namespace std; cmModClass::cmModClass(string foo) { str = foo + " World"; } string cmModClass::getStr() const { return str; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8826416 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incA/0000755000175000017500000000000014562742414026277 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incA/cmMod.hpp0000644000175000017500000000011713716006331030035 0ustar00jpakkanejpakkane// cmMod.hpp (A) #pragma once #error "cmMod.hpp in incA must not be included" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8906417 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incB/0000755000175000017500000000000014562742414026300 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incB/cmMod.hpp0000644000175000017500000000011713716006331030036 0ustar00jpakkanejpakkane// cmMod.hpp (B) #pragma once #error "cmMod.hpp in incB must not be included" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8946416 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incC/0000755000175000017500000000000014562742414026301 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incC/cmMod.hpp0000644000175000017500000000011713716006331030037 0ustar00jpakkanejpakkane// cmMod.hpp (C) #pragma once #error "cmMod.hpp in incC must not be included" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8986418 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incD/0000755000175000017500000000000014562742414026302 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incD/cmMod.hpp0000644000175000017500000000011713716006331030040 0ustar00jpakkanejpakkane// cmMod.hpp (D) #pragma once #error "cmMod.hpp in incD must not be included" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8986418 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incE/0000755000175000017500000000000014562742414026303 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incE/cmMod.hpp0000644000175000017500000000011713716006331030041 0ustar00jpakkanejpakkane// cmMod.hpp (E) #pragma once #error "cmMod.hpp in incE must not be included" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8986418 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incF/0000755000175000017500000000000014562742414026304 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incF/cmMod.hpp0000644000175000017500000000011713716006331030042 0ustar00jpakkanejpakkane// cmMod.hpp (F) #pragma once #error "cmMod.hpp in incF must not be included" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.8986418 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incG/0000755000175000017500000000000014562742414026305 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incG/cmMod.hpp0000644000175000017500000000031313716006331030041 0ustar00jpakkanejpakkane#pragma once #include "cmmodlib++_export.h" #include class CMMODLIB___EXPORT cmModClass { private: std::string str; public: cmModClass(std::string foo); std::string getStr() const; }; ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.906642 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incH/0000755000175000017500000000000014562742414026306 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incH/cmMod.hpp0000644000175000017500000000011713716006331030044 0ustar00jpakkanejpakkane// cmMod.hpp (H) #pragma once #error "cmMod.hpp in incH must not be included" ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.906642 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incI/0000755000175000017500000000000014562742414026307 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incI/cmMod.hpp0000644000175000017500000000011713716006331030045 0ustar00jpakkanejpakkane// cmMod.hpp (I) #pragma once #error "cmMod.hpp in incI must not be included" ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.910642 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incJ/0000755000175000017500000000000014562742414026310 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incJ/cmMod.hpp0000644000175000017500000000011713716006331030046 0ustar00jpakkanejpakkane// cmMod.hpp (J) #pragma once #error "cmMod.hpp in incJ must not be included" ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.910642 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incL/0000755000175000017500000000000014562742414026312 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incL/cmMod.hpp0000644000175000017500000000011713716006331030050 0ustar00jpakkanejpakkane// cmMod.hpp (L) #pragma once #error "cmMod.hpp in incL must not be included" ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.914642 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incM/0000755000175000017500000000000014562742414026313 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incM/cmMod.hpp0000644000175000017500000000011713716006331030051 0ustar00jpakkanejpakkane// cmMod.hpp (M) #pragma once #error "cmMod.hpp in incM must not be included" ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.918642 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incN/0000755000175000017500000000000014562742414026314 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incN/cmMod.hpp0000644000175000017500000000011713716006331030052 0ustar00jpakkanejpakkane// cmMod.hpp (N) #pragma once #error "cmMod.hpp in incN must not be included" ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.918642 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incO/0000755000175000017500000000000014562742414026315 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incO/cmMod.hpp0000644000175000017500000000011713716006331030053 0ustar00jpakkanejpakkane// cmMod.hpp (O) #pragma once #error "cmMod.hpp in incO must not be included" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.9266422 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incP/0000755000175000017500000000000014562742414026316 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/17 include path order/subprojects/cmMod/incP/cmMod.hpp0000644000175000017500000000011713716006331030054 0ustar00jpakkanejpakkane// cmMod.hpp (P) #pragma once #error "cmMod.hpp in incP must not be included" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.9306424 meson-1.3.2/test cases/cmake/18 skip include files/0000755000175000017500000000000014562742414022025 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/18 skip include files/main.cpp0000644000175000017500000000023213716006331023441 0ustar00jpakkanejpakkane#include #include using namespace std; int main(void) { cmModClass obj("Hello"); cout << obj.getStr() << endl; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421432.0 meson-1.3.2/test cases/cmake/18 skip include files/meson.build0000644000175000017500000000033714516755270024175 0ustar00jpakkanejpakkaneproject('cmakeSubTest', ['c', 'cpp']) cm = import('cmake') sub_pro = cm.subproject('cmMod') sub_dep = sub_pro.dependency('cmModLib++') exe1 = executable('main', ['main.cpp'], dependencies: [sub_dep]) test('test1', exe1) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7586246 meson-1.3.2/test cases/cmake/18 skip include files/subprojects/0000755000175000017500000000000014562742413024367 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.9386425 meson-1.3.2/test cases/cmake/18 skip include files/subprojects/cmMod/0000755000175000017500000000000014562742414025427 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/18 skip include files/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000044413716006331030160 0ustar00jpakkanejpakkanecmake_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") set(SRCS ${CMAKE_CURRENT_LIST_DIR}/cmMod.hpp ${CMAKE_CURRENT_LIST_DIR}/cmMod.cpp ) add_subdirectory(fakeInc) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/18 skip include files/subprojects/cmMod/cmMod.cpp0000644000175000017500000000034513716006331027163 0ustar00jpakkanejpakkane#include "cmMod.hpp" using namespace std; #define MESON_INCLUDE_IMPL #include "fakeInc/cmModInc1.cpp" #include "fakeInc/cmModInc2.cpp" #include "fakeInc/cmModInc3.cpp" #include "fakeInc/cmModInc4.cpp" #undef MESON_INCLUDE_IMPL ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/18 skip include files/subprojects/cmMod/cmMod.hpp0000644000175000017500000000041113716006331027162 0ustar00jpakkanejpakkane#pragma once #include "cmmodlib++_export.h" #include class CMMODLIB___EXPORT cmModClass { private: std::string str; std::string getStr1() const; std::string getStr2() const; public: cmModClass(std::string foo); std::string getStr() const; }; ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.9586427 meson-1.3.2/test cases/cmake/18 skip include files/subprojects/cmMod/fakeInc/0000755000175000017500000000000014562742414026767 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/18 skip include files/subprojects/cmMod/fakeInc/CMakeLists.txt0000644000175000017500000000103213716006331031512 0ustar00jpakkanejpakkanelist(APPEND SRCS cmModInc1.cpp cmModInc2.cpp cmModInc3.cpp cmModInc4.cpp ) set(SRC_A cmModInc1.cpp ${CMAKE_CURRENT_LIST_DIR}/cmModInc2.cpp ) set_property( SOURCE ${SRC_A} PROPERTY HEADER_FILE_ONLY ON ) set_source_files_properties( cmModInc3.cpp ${CMAKE_CURRENT_LIST_DIR}/cmModInc4.cpp PROPERTIES LABELS "CMake;Lists;are;fun" HEADER_FILE_ONLY ON ) include_directories(${CMAKE_CURRENT_BINARY_DIR}) add_library(cmModLib++ SHARED ${SRCS}) include(GenerateExportHeader) generate_export_header(cmModLib++) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/18 skip include files/subprojects/cmMod/fakeInc/cmModInc1.cpp0000644000175000017500000000024413716006331031234 0ustar00jpakkanejpakkane#ifndef MESON_INCLUDE_IMPL #error "MESON_INCLUDE_IMPL is not defined" #endif // !MESON_INCLUDE_IMPL cmModClass::cmModClass(string foo) { str = foo + " World"; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/18 skip include files/subprojects/cmMod/fakeInc/cmModInc2.cpp0000644000175000017500000000023713716006331031237 0ustar00jpakkanejpakkane#ifndef MESON_INCLUDE_IMPL #error "MESON_INCLUDE_IMPL is not defined" #endif // !MESON_INCLUDE_IMPL string cmModClass::getStr() const { return getStr2(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/18 skip include files/subprojects/cmMod/fakeInc/cmModInc3.cpp0000644000175000017500000000024013716006331031232 0ustar00jpakkanejpakkane#ifndef MESON_INCLUDE_IMPL #error "MESON_INCLUDE_IMPL is not defined" #endif // !MESON_INCLUDE_IMPL string cmModClass::getStr1() const { return getStr2(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/18 skip include files/subprojects/cmMod/fakeInc/cmModInc4.cpp0000644000175000017500000000023213716006331031234 0ustar00jpakkanejpakkane#ifndef MESON_INCLUDE_IMPL #error "MESON_INCLUDE_IMPL is not defined" #endif // !MESON_INCLUDE_IMPL string cmModClass::getStr2() const { return str; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.9666429 meson-1.3.2/test cases/cmake/19 advanced options/0000755000175000017500000000000014562742414021612 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/19 advanced options/main.cpp0000644000175000017500000000047513716006331023237 0ustar00jpakkanejpakkane#include #include #include using namespace std; int main(void) { cmModClass obj("Hello"); cout << obj.getStr() << endl; int v1 = obj.getInt(); int v2 = getTestInt(); if (v1 != ((1 + v2) * 2)) { cerr << "Number test failed" << endl; return 1; } return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421434.0 meson-1.3.2/test cases/cmake/19 advanced options/meson.build0000644000175000017500000000225714516755272023767 0ustar00jpakkanejpakkaneproject('cmake_set_opt', ['c', 'cpp']) comp = meson.get_compiler('cpp') if comp.get_argument_syntax() == 'msvc' error('MESON_SKIP_TEST: MSVC is not supported because it does not support C++11') endif cm = import('cmake') opts = cm.subproject_options() opts.add_cmake_defines({'SOME_CMAKE_VAR': 'something', 'SOME_OTHER_VAR': true}) opts.set_override_option('cpp_std', 'c++11') # Global is C++11 opts.set_override_option('cpp_std', 'c++14', target: 'cmModLib++') # Override it with C++14 for cmModLib++ opts.append_compile_args('cpp', '-DMESON_GLOBAL_FLAG=1') opts.append_compile_args('cpp', ['-DMESON_SPECIAL_FLAG1=1', ['-DMESON_SPECIAL_FLAG2=1']], target: 'cmModLib++') opts.append_compile_args('cpp', '-DMESON_MAGIC_INT=42', target: 'cmModLib++') opts.append_compile_args('cpp', [[[['-DMESON_MAGIC_INT=20']]]], target: 'cmTestLib') opts.set_install(false) opts.set_install(true, target: 'testEXE') sp = cm.subproject('cmOpts', options: opts) dep1 = sp.dependency('cmModLib++') dep2 = sp.dependency('cmTestLib') exe1 = executable('main', ['main.cpp'], dependencies: [dep1, dep2]) test('test1', exe1) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7586246 meson-1.3.2/test cases/cmake/19 advanced options/subprojects/0000755000175000017500000000000014562742413024154 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.986643 meson-1.3.2/test cases/cmake/19 advanced options/subprojects/cmOpts/0000755000175000017500000000000014562742414025422 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/19 advanced options/subprojects/cmOpts/CMakeLists.txt0000644000175000017500000000072113716006331030151 0ustar00jpakkanejpakkanecmake_minimum_required(VERSION 3.7) project(CmOpts) set(CMAKE_CXX_STANDARD 98) set(CMAKE_CXX_STANDARD_REQUIRED ON) if(NOT "${SOME_CMAKE_VAR}" STREQUAL "something") message(FATAL_ERROR "Setting the CMake var failed") endif() add_library(cmModLib++ STATIC cmMod.cpp) add_library(cmTestLib STATIC cmTest.cpp) add_executable(testEXE main.cpp) target_link_libraries(testEXE cmModLib++) install(TARGETS cmTestLib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/19 advanced options/subprojects/cmOpts/cmMod.cpp0000644000175000017500000000100713716006331027152 0ustar00jpakkanejpakkane#include "cmMod.hpp" using namespace std; #if __cplusplus < 201402L #error "At least C++14 is required" #endif #ifndef MESON_GLOBAL_FLAG #error "MESON_GLOBAL_FLAG was not set" #endif #ifndef MESON_SPECIAL_FLAG1 #error "MESON_SPECIAL_FLAG1 was not set" #endif #ifndef MESON_SPECIAL_FLAG2 #error "MESON_SPECIAL_FLAG2 was not set" #endif cmModClass::cmModClass(string foo) { str = foo + " World"; } string cmModClass::getStr() const { return str; } int cmModClass::getInt() const { return MESON_MAGIC_INT; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/19 advanced options/subprojects/cmOpts/cmMod.hpp0000644000175000017500000000026013716006331027157 0ustar00jpakkanejpakkane#pragma once #include class cmModClass { private: std::string str; public: cmModClass(std::string foo); std::string getStr() const; int getInt() const; }; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/19 advanced options/subprojects/cmOpts/cmTest.cpp0000644000175000017500000000065713716006331027364 0ustar00jpakkanejpakkane#include "cmTest.hpp" #if __cplusplus < 201103L #error "At least C++11 is required" #endif #if __cplusplus >= 201402L #error "At most C++11 is required" #endif #ifndef MESON_GLOBAL_FLAG #error "MESON_GLOBAL_FLAG was not set" #endif #ifdef MESON_SPECIAL_FLAG1 #error "MESON_SPECIAL_FLAG1 *was* set" #endif #ifdef MESON_SPECIAL_FLAG2 #error "MESON_SPECIAL_FLAG2 *was* set" #endif int getTestInt() { return MESON_MAGIC_INT; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/19 advanced options/subprojects/cmOpts/cmTest.hpp0000644000175000017500000000004013716006331027353 0ustar00jpakkanejpakkane#pragma once int getTestInt(); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/19 advanced options/subprojects/cmOpts/main.cpp0000644000175000017500000000024513716006331027042 0ustar00jpakkanejpakkane#include #include "cmMod.hpp" using namespace std; int main(void) { cmModClass obj("Hello (LIB TEST)"); cout << obj.getStr() << endl; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/cmake/19 advanced options/test.json0000644000175000017500000000011014253672217023454 0ustar00jpakkanejpakkane{ "installed": [ {"type": "exe", "file": "usr/bin/testEXE"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.9906433 meson-1.3.2/test cases/cmake/2 advanced/0000755000175000017500000000000014562742414020046 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/2 advanced/main.cpp0000644000175000017500000000036013716006331021464 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1699894003.0 meson-1.3.2/test cases/cmake/2 advanced/meson.build0000644000175000017500000000163214524451363022210 0ustar00jpakkanejpakkaneproject('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')) # Test that we can add a new target with the same name as the CMake subproject exe4 = executable('testEXE', ['main.cpp'], dependencies: [sub_sta]) test('test4', exe4) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7586246 meson-1.3.2/test cases/cmake/2 advanced/subprojects/0000755000175000017500000000000014562742413022410 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.0026433 meson-1.3.2/test cases/cmake/2 advanced/subprojects/cmMod/0000755000175000017500000000000014562742414023450 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1660380518.0 meson-1.3.2/test cases/cmake/2 advanced/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000230014275662546026213 0ustar00jpakkanejpakkanecmake_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 "${CMAKE_CURRENT_BINARY_DIR}/config.h") target_link_libraries(cmModLib ZLIB::ZLIB) target_link_libraries(cmModLibStatic ;ZLIB::ZLIB;) target_link_libraries(testEXE cmModLib) if(APPLE) find_library(COREFOUNDATION_FRAMEWORK "CoreFoundation") if(NOT COREFOUNDATION_FRAMEWORK) message(FATAL_ERROR "CoreFoundation framework not found") endif() target_link_libraries(cmModLibStatic "${COREFOUNDATION_FRAMEWORK}") target_compile_definitions(cmModLibStatic PUBLIC USE_FRAMEWORK) endif() target_compile_definitions(cmModLibStatic PUBLIC CMMODLIB_STATIC_DEFINE) install(TARGETS testEXE LIBRARY DESTINATION lib RUNTIME DESTINATION bin) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/2 advanced/subprojects/cmMod/config.h.in0000644000175000017500000000005613716006331025463 0ustar00jpakkanejpakkane#pragma once #define CONFIG_OPT @CONFIG_OPT@ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.0066435 meson-1.3.2/test cases/cmake/2 advanced/subprojects/cmMod/lib/0000755000175000017500000000000014562742414024216 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311580.0 meson-1.3.2/test cases/cmake/2 advanced/subprojects/cmMod/lib/cmMod.cpp0000644000175000017500000000075114031433534025753 0ustar00jpakkanejpakkane#include "cmMod.hpp" #include #include "config.h" #if CONFIG_OPT != 42 #error "Invalid value of CONFIG_OPT" #endif #ifdef USE_FRAMEWORK #include #endif using namespace std; cmModClass::cmModClass(string foo) { str = foo + " World " + zlibVersion(); #ifdef USE_FRAMEWORK CFStringRef ref = CFStringCreateWithCString(NULL, str.c_str(), kCFStringEncodingUTF8); CFRelease(ref); #endif } string cmModClass::getStr() const { return str; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/2 advanced/subprojects/cmMod/lib/cmMod.hpp0000644000175000017500000000032013716006331025750 0ustar00jpakkanejpakkane#pragma once #include #include "cmmodlib_export.h" class CMMODLIB_EXPORT cmModClass { private: std::string str; public: cmModClass(std::string foo); std::string getStr() const; }; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/2 advanced/subprojects/cmMod/main.cpp0000644000175000017500000000033113716006331025064 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/cmake/2 advanced/test.json0000644000175000017500000000011014253672217021710 0ustar00jpakkanejpakkane{ "installed": [ {"type": "exe", "file": "usr/bin/testEXE"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.0106435 meson-1.3.2/test cases/cmake/20 cmake file/0000755000175000017500000000000014562742414020341 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/20 cmake file/foolib.cmake.in0000644000175000017500000000000614031433465023210 0ustar00jpakkanejpakkane@foo@ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421432.0 meson-1.3.2/test cases/cmake/20 cmake file/meson.build0000644000175000017500000000034714516755270022512 0ustar00jpakkanejpakkaneproject( 'cmake config file', ) cmake = import('cmake') cmake.configure_package_config_file( name : 'foolib', input : 'foolib.cmake.in', install_dir : get_option('libdir') / 'cmake', configuration : {'foo': '"bar"'}, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/20 cmake file/test.json0000644000175000017500000000013214031433465022201 0ustar00jpakkanejpakkane{ "installed": [ {"file": "usr/lib/cmake/foolibConfig.cmake", "type": "file"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.0226438 meson-1.3.2/test cases/cmake/21 shared module/0000755000175000017500000000000014562742414021076 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421436.0 meson-1.3.2/test cases/cmake/21 shared module/meson.build0000644000175000017500000000057414516755274023255 0ustar00jpakkanejpakkaneproject('cmakeSharedModule', ['c', 'cpp']) cm = import('cmake') sub_pro = cm.subproject('cmMod') sub_dep = sub_pro.dependency('myMod') dl = meson.get_compiler('c').find_library('dl', required: false) l = shared_library('runtime', 'runtime.c') e = executable('prog', ['prog.c'], link_with: l, dependencies: [sub_dep, dl]) m = sub_pro.target('myMod') test('test1', e, args : m) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/21 shared module/prog.c0000644000175000017500000000425214031433465022206 0ustar00jpakkanejpakkane #include #include "module.h" #if SPECIAL_MAGIC_DEFINE != 42 #error "SPECIAL_MAGIC_DEFINE is not defined" #endif 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/21 shared module/runtime.c0000644000175000017500000000070314031433465022717 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7586246 meson-1.3.2/test cases/cmake/21 shared module/subprojects/0000755000175000017500000000000014562742413023440 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.0266438 meson-1.3.2/test cases/cmake/21 shared module/subprojects/cmMod/0000755000175000017500000000000014562742414024500 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/21 shared module/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000027314031433465027234 0ustar00jpakkanejpakkanecmake_minimum_required(VERSION 3.5) project(cmModule) include_directories("${CMAKE_CURRENT_SOURCE_DIR}/module") add_library(myMod MODULE "${CMAKE_CURRENT_SOURCE_DIR}/module/module.c") ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.034644 meson-1.3.2/test cases/cmake/21 shared module/subprojects/cmMod/module/0000755000175000017500000000000014562742414025765 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/21 shared module/subprojects/cmMod/module/module.c0000644000175000017500000000454414031433465027417 0ustar00jpakkanejpakkane#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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/21 shared module/subprojects/cmMod/module/module.h0000644000175000017500000000005614031433465027416 0ustar00jpakkanejpakkane#pragma once #define SPECIAL_MAGIC_DEFINE 42 ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.042644 meson-1.3.2/test cases/cmake/22 cmake module/0000755000175000017500000000000014562742414020711 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.042644 meson-1.3.2/test cases/cmake/22 cmake module/cmake_project/0000755000175000017500000000000014562742414023517 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/22 cmake module/cmake_project/CMakeLists.txt0000644000175000017500000000013514031433465026250 0ustar00jpakkanejpakkanecmake_minimum_required(VERSION 2.8) project(cmakeMeson C) find_package(cmakeModule REQUIRED)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421434.0 meson-1.3.2/test cases/cmake/22 cmake module/meson.build0000644000175000017500000000154214516755272023062 0ustar00jpakkanejpakkaneproject('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, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/22 cmake module/projectConfig.cmake.in0000644000175000017500000000010414031433465025101 0ustar00jpakkanejpakkane@PACKAGE_INIT@ set(MYVAR "@MYVAR@") set(MYQUOTEDVAR @MYQUOTEDVAR@) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/22 cmake module/test.json0000644000175000017500000000030514031433465022553 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/lib/cmake/cmakeModule/cmakeModuleConfig.cmake"}, {"type": "file", "file": "usr/lib/cmake/cmakeModule/cmakeModuleConfigVersion.cmake"} ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.054644 meson-1.3.2/test cases/cmake/23 cmake toolchain/0000755000175000017500000000000014562742414021405 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/23 cmake toolchain/CMakeToolchain.cmake0000644000175000017500000000003214031433465025215 0ustar00jpakkanejpakkaneset(MESON_TEST_VAR2 VAR2) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421436.0 meson-1.3.2/test cases/cmake/23 cmake toolchain/meson.build0000644000175000017500000000036514516755274023562 0ustar00jpakkanejpakkaneproject('cmake toolchain test', ['c']) if meson.is_cross_build() error('MESON_SKIP_TEST: skip this on cross builds') endif cm = import('cmake') sub_pro = cm.subproject('cmMod') add_languages('cpp') sub_pro = cm.subproject('cmModFortran') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/cmake/23 cmake toolchain/nativefile.ini.in0000644000175000017500000000027214107166547024644 0ustar00jpakkanejpakkane[properties] cmake_toolchain_file = '@MESON_TEST_ROOT@/CMakeToolchain.cmake' cmake_skip_compiler_test = 'always' [cmake] MESON_TEST_VAR1 = 'VAR1 space' MESON_TEST_VAR2 = 'VAR2 error' ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7626245 meson-1.3.2/test cases/cmake/23 cmake toolchain/subprojects/0000755000175000017500000000000014562742413023747 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.054644 meson-1.3.2/test cases/cmake/23 cmake toolchain/subprojects/cmMod/0000755000175000017500000000000014562742414025007 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/cmake/23 cmake toolchain/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000067314107166547027557 0ustar00jpakkanejpakkanecmake_minimum_required(VERSION 3.5) project(cmMod NONE) if(NOT "${MESON_TEST_VAR1}" STREQUAL "VAR1 space") message(FATAL_ERROR "MESON_TEST_VAR1 -- '${MESON_TEST_VAR1}' != 'VAR1 space'") endif() if(NOT "${MESON_TEST_VAR2}" STREQUAL "VAR2") message(FATAL_ERROR "MESON_TEST_VAR2 -- '${MESON_TEST_VAR2}' != 'VAR2'") endif() if(NOT DEFINED CMAKE_C_COMPILER_VERSION) message(FATAL_ERROR "CMAKE_C_COMPILER_VERSION was not defined") endif() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.0586443 meson-1.3.2/test cases/cmake/23 cmake toolchain/subprojects/cmModFortran/0000755000175000017500000000000014562742414026343 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/cmake/23 cmake toolchain/subprojects/cmModFortran/CMakeLists.txt0000644000175000017500000000106314107166547031105 0ustar00jpakkanejpakkanecmake_minimum_required(VERSION 3.5) project(cmMod NONE) if(NOT "${MESON_TEST_VAR1}" STREQUAL "VAR1 space") message(FATAL_ERROR "MESON_TEST_VAR1 -- '${MESON_TEST_VAR1}' != 'VAR1 space'") endif() if(NOT "${MESON_TEST_VAR2}" STREQUAL "VAR2") message(FATAL_ERROR "MESON_TEST_VAR2 -- '${MESON_TEST_VAR2}' != 'VAR2'") endif() if(NOT DEFINED CMAKE_C_COMPILER_VERSION) message(FATAL_ERROR "CMAKE_C_COMPILER_VERSION was not defined") endif() if(NOT DEFINED CMAKE_CXX_COMPILER_VERSION) message(FATAL_ERROR "CMAKE_CXX_COMPILER_VERSION was not defined") endif() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.0626442 meson-1.3.2/test cases/cmake/24 mixing languages/0000755000175000017500000000000014562742414021607 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311580.0 meson-1.3.2/test cases/cmake/24 mixing languages/main.c0000644000175000017500000000007414031433534022667 0ustar00jpakkanejpakkane#include int main(void) { return doStuff(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421439.0 meson-1.3.2/test cases/cmake/24 mixing languages/meson.build0000644000175000017500000000052214516755277023762 0ustar00jpakkanejpakkaneproject('CMake mix', ['c', 'cpp']) if not add_languages('objc', required : false) error('MESON_SKIP_TEST: No ObjC compiler') endif cm = import('cmake') sub_pro = cm.subproject('cmTest') sub_dep = sub_pro.dependency('cmTest', include_type: 'system') exe1 = executable('exe1', ['main.c'], dependencies: [sub_dep]) test('test1', exe1) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7626245 meson-1.3.2/test cases/cmake/24 mixing languages/subprojects/0000755000175000017500000000000014562742413024151 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.0746446 meson-1.3.2/test cases/cmake/24 mixing languages/subprojects/cmTest/0000755000175000017500000000000014562742414025411 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311580.0 meson-1.3.2/test cases/cmake/24 mixing languages/subprojects/cmTest/CMakeLists.txt0000644000175000017500000000032414031433534030137 0ustar00jpakkanejpakkanecmake_minimum_required(VERSION 3.5) project(cmTest) include_directories(${CMAKE_CURRENT_BINARY_DIR}) add_library(cmTest STATIC cmTest.c cmTest.m) target_compile_definitions(cmTest PUBLIC SOME_MAGIC_DEFINE=42) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311580.0 meson-1.3.2/test cases/cmake/24 mixing languages/subprojects/cmTest/cmTest.c0000644000175000017500000000030114031433534026775 0ustar00jpakkanejpakkane#include "cmTest.h" #include #if SOME_MAGIC_DEFINE != 42 #error "SOME_MAGIC_DEFINE != 42" #endif int foo(int x); int doStuff(void) { printf("Hello World\n"); return foo(42); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311580.0 meson-1.3.2/test cases/cmake/24 mixing languages/subprojects/cmTest/cmTest.h0000644000175000017500000000004114031433534027003 0ustar00jpakkanejpakkane#pragma once int doStuff(void); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311580.0 meson-1.3.2/test cases/cmake/24 mixing languages/subprojects/cmTest/cmTest.m0000644000175000017500000000015114031433534027012 0ustar00jpakkanejpakkane#if SOME_MAGIC_DEFINE != 42 #error "SOME_MAGIC_DEFINE != 42" #endif int foo(int x) { return 42 - x; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.0786445 meson-1.3.2/test cases/cmake/25 assembler/0000755000175000017500000000000014562742414020343 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/cmake/25 assembler/main.c0000644000175000017500000000037614107166547021443 0ustar00jpakkanejpakkane#include #include int32_t cmTestFunc(void); int main(void) { if (cmTestFunc() > 4200) { printf("Test success.\n"); return 0; } else { printf("Test failure.\n"); return 1; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421440.0 meson-1.3.2/test cases/cmake/25 assembler/meson.build0000644000175000017500000000033414516755300022502 0ustar00jpakkanejpakkaneproject('assembler test', ['c', 'cpp']) cm = import('cmake') sub_pro = cm.subproject('cmTest') sub_dep = sub_pro.dependency('cmTest') exe1 = executable('exe1', ['main.c'], dependencies: [sub_dep]) test('test1', exe1) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7666247 meson-1.3.2/test cases/cmake/25 assembler/subprojects/0000755000175000017500000000000014562742413022705 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.0866446 meson-1.3.2/test cases/cmake/25 assembler/subprojects/cmTest/0000755000175000017500000000000014562742414024145 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1654626316.0 meson-1.3.2/test cases/cmake/25 assembler/subprojects/cmTest/CMakeLists.txt0000644000175000017500000000262714247714014026707 0ustar00jpakkanejpakkanecmake_minimum_required(VERSION 3.5) project(cmTest) #Detect processor if ("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "amd64") SET(TEST_PROCESSOR "x86_64") elseif ("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "x86_64") SET(TEST_PROCESSOR "x86_64") elseif ("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "i386") SET(TEST_PROCESSOR "x86") elseif ("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "i686") SET(TEST_PROCESSOR "x86") elseif ("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "arm") SET(TEST_PROCESSOR "arm") elseif ("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "aarch64") SET(TEST_PROCESSOR "arm") else () message(FATAL_ERROR "MESON_SKIP_TEST: Unsupported Assembler Platform") endif () #Detect ABI if ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") SET(TEST_ABI "sysv") elseif ("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD") SET(TEST_ABI "sysv") elseif ("${CMAKE_SYSTEM_NAME}" MATCHES "NetBSD") SET(TEST_ABI "sysv") elseif ("${CMAKE_SYSTEM_NAME}" MATCHES "OpenBSD") SET(TEST_ABI "sysv") else () message(FATAL_ERROR "MESON_SKIP_TEST: Unsupported Assembler Platform") endif () SET(TEST_PLATFORM "${TEST_PROCESSOR}-${TEST_ABI}") if ( ("${TEST_PLATFORM}" MATCHES "x86_64-sysv") OR ("${TEST_PLATFORM}" MATCHES "x86-sysv") OR ("${TEST_PLATFORM}" MATCHES "arm-sysv")) SET(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) enable_language(ASM) SET(TEST_SOURCE "cmTestAsm.s") endif () add_library(cmTest STATIC cmTest.c ${TEST_SOURCE}) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/cmake/25 assembler/subprojects/cmTest/cmTest.c0000644000175000017500000000015314107166547025551 0ustar00jpakkanejpakkane#include extern const int32_t cmTestArea; int32_t cmTestFunc(void) { return cmTestArea; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/cmake/25 assembler/subprojects/cmTest/cmTestAsm.s0000644000175000017500000000006314107166547026232 0ustar00jpakkanejpakkane.text .globl cmTestArea cmTestArea: .long 4242 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.0906448 meson-1.3.2/test cases/cmake/26 cmake package prefix dir/0000755000175000017500000000000014562742414023040 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1689971773.0 meson-1.3.2/test cases/cmake/26 cmake package prefix dir/cmakePackagePrefixDirConfig.cmake.in0000644000175000017500000000001714456566075031755 0ustar00jpakkanejpakkane@PACKAGE_INIT@ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421438.0 meson-1.3.2/test cases/cmake/26 cmake package prefix dir/meson.build0000644000175000017500000000126214516755276025214 0ustar00jpakkanejpakkaneproject('cmakePackagePrefixDir', 'c', version: '1.0.0') cmake = import('cmake') cmake.configure_package_config_file( name: 'cmakePackagePrefixDir', input: 'cmakePackagePrefixDirConfig.cmake.in', configuration: configuration_data(), ) # NOTE: can't use fs.read because cmakePackagePrefixDirConfig.cmake is in build_dir python = find_program('python3') lines = run_command(python, '-c', '[print(line, end="") for line in open("@0@")]'.format(meson.current_build_dir() / 'cmakePackagePrefixDirConfig.cmake'), check : true, ).stdout().split('\n') message(lines) assert(lines[5] == 'get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../.." ABSOLUTE)') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1689971773.0 meson-1.3.2/test cases/cmake/26 cmake package prefix dir/test.json0000644000175000017500000000017714456566075024730 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/lib/cmake/cmakePackagePrefixDir/cmakePackagePrefixDirConfig.cmake"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.0946448 meson-1.3.2/test cases/cmake/27 dependency fallback/0000755000175000017500000000000014562742414022226 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/cmake/27 dependency fallback/main.cpp0000644000175000017500000000023214516552205023647 0ustar00jpakkanejpakkane#include #include using namespace std; int main(void) { cmModClass obj("Hello"); cout << obj.getStr() << endl; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/test cases/cmake/27 dependency fallback/meson.build0000644000175000017500000000207014562742363024372 0ustar00jpakkanejpakkaneproject('cmakeSubTest', ['c', 'cpp']) # Fallback to a CMake subproject sub_dep = dependency('cmModLib++') exe1 = executable('main', ['main.cpp'], dependencies: [sub_dep]) test('test1', exe1) # Subproject contains both meson.build and CMakeLists.txt. It should default # to meson but wrap force cmake. subproject('force_cmake') testcase expect_error('Wrap method \'notfound\' is not supported, must be one of: meson, cmake, cargo') subproject('broken_method') endtestcase # With method=meson we can't use cmake.subproject() cmake = import('cmake') testcase expect_error('Wrap method is \'meson\' but we are trying to configure it with cmake') cmake.subproject('meson_method') endtestcase # cmake.subproject() force cmake method even if meson.build exists. testcase expect_error('Subproject exists but has no CMakeLists.txt file.') cmake.subproject('meson_subp') endtestcase # Without specifying the method it defaults to meson even if CMakeLists.txt exists. testcase expect_error('Subproject exists but has no meson.build file.') subproject('cmake_subp') endtestcase ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.0986447 meson-1.3.2/test cases/cmake/27 dependency fallback/subprojects/0000755000175000017500000000000014562742414024571 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/cmake/27 dependency fallback/subprojects/broken_method.wrap0000644000175000017500000000003414516552205030275 0ustar00jpakkanejpakkane[wrap-file] method=notfound ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.110645 meson-1.3.2/test cases/cmake/27 dependency fallback/subprojects/cmMod/0000755000175000017500000000000014562742414025630 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/test cases/cmake/27 dependency fallback/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000106414562742363030374 0ustar00jpakkanejpakkanecmake_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) target_compile_definitions(cmModLib++ PRIVATE MESON_MAGIC_FLAG=21) target_compile_definitions(cmModLib++ INTERFACE MESON_MAGIC_FLAG=42) # Test PCH support if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16.0") target_precompile_headers(cmModLib++ PRIVATE "cpp_pch.hpp") endif() include(GenerateExportHeader) generate_export_header(cmModLib++) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/cmake/27 dependency fallback/subprojects/cmMod/cmMod.cpp0000644000175000017500000000035714516552205027374 0ustar00jpakkanejpakkane#include "cmMod.hpp" using namespace std; #if MESON_MAGIC_FLAG != 21 #error "Invalid MESON_MAGIC_FLAG (private)" #endif cmModClass::cmModClass(string foo) { str = foo + " World"; } string cmModClass::getStr() const { return str; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/cmake/27 dependency fallback/subprojects/cmMod/cmMod.hpp0000644000175000017500000000045214516552205027375 0ustar00jpakkanejpakkane#pragma once #include "cmmodlib++_export.h" #include #if MESON_MAGIC_FLAG != 42 && MESON_MAGIC_FLAG != 21 #error "Invalid MESON_MAGIC_FLAG" #endif class CMMODLIB___EXPORT cmModClass { private: std::string str; public: cmModClass(std::string foo); std::string getStr() const; }; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/cmake/27 dependency fallback/subprojects/cmMod/cpp_pch.hpp0000644000175000017500000000004414516552205027747 0ustar00jpakkanejpakkane#include #include ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/cmake/27 dependency fallback/subprojects/cmMod.wrap0000644000175000017500000000010214516552205026510 0ustar00jpakkanejpakkane[wrap-file] method = cmake [provide] cmModLib++ = cmModLib___dep ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.110645 meson-1.3.2/test cases/cmake/27 dependency fallback/subprojects/cmake_subp/0000755000175000017500000000000014562742414026702 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/cmake/27 dependency fallback/subprojects/cmake_subp/CMakeLists.txt0000644000175000017500000000007014516552205031433 0ustar00jpakkanejpakkanecmake_minimum_required(VERSION 3.5) project(cmModDummy) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.1226451 meson-1.3.2/test cases/cmake/27 dependency fallback/subprojects/force_cmake/0000755000175000017500000000000014562742414027027 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/cmake/27 dependency fallback/subprojects/force_cmake/CMakeLists.txt0000644000175000017500000000006714516552205031566 0ustar00jpakkanejpakkanecmake_minimum_required(VERSION 3.5) project(cmModBoth) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/cmake/27 dependency fallback/subprojects/force_cmake/meson.build0000644000175000017500000000011314516552205031160 0ustar00jpakkanejpakkaneproject('both methods') # Ensure the meson method is not used. notfound() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/cmake/27 dependency fallback/subprojects/force_cmake.wrap0000644000175000017500000000003114516552205027710 0ustar00jpakkanejpakkane[wrap-file] method=cmake ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/cmake/27 dependency fallback/subprojects/meson_method.wrap0000644000175000017500000000003114516552205030133 0ustar00jpakkanejpakkane[wrap-file] method=meson ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.1266453 meson-1.3.2/test cases/cmake/27 dependency fallback/subprojects/meson_subp/0000755000175000017500000000000014562742414026743 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/cmake/27 dependency fallback/subprojects/meson_subp/meson.build0000644000175000017500000000002114516552205031072 0ustar00jpakkanejpakkaneproject('dummy') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.1306453 meson-1.3.2/test cases/cmake/3 advanced no dep/0000755000175000017500000000000014562742414021175 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/3 advanced no dep/main.cpp0000644000175000017500000000036013716006331022613 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1699894002.0 meson-1.3.2/test cases/cmake/3 advanced no dep/meson.build0000644000175000017500000000123014524451362023330 0ustar00jpakkanejpakkaneproject('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('meson-testEXE') == 'executable', 'The type must be executable for obvious reasons') test('test3', sub_pro.target('meson-testEXE')) test('test4', sub_pro.target('benchmark')) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7666247 meson-1.3.2/test cases/cmake/3 advanced no dep/subprojects/0000755000175000017500000000000014562742413023537 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.1346455 meson-1.3.2/test cases/cmake/3 advanced no dep/subprojects/cmMod/0000755000175000017500000000000014562742414024577 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/cmake/3 advanced no dep/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000150014107166547027335 0ustar00jpakkanejpakkanecmake_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(meson-testEXE main.cpp) add_executable(benchmark main.cpp) target_link_libraries(meson-testEXE cmModLib) target_link_libraries(benchmark cmModLib) target_compile_definitions(cmModLibStatic PUBLIC CMMODLIB_STATIC_DEFINE) install(TARGETS meson-testEXE benchmark LIBRARY DESTINATION lib RUNTIME DESTINATION bin) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/3 advanced no dep/subprojects/cmMod/config.h.in0000644000175000017500000000005613716006331026612 0ustar00jpakkanejpakkane#pragma once #define CONFIG_OPT @CONFIG_OPT@ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.1466455 meson-1.3.2/test cases/cmake/3 advanced no dep/subprojects/cmMod/lib/0000755000175000017500000000000014562742414025345 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/3 advanced no dep/subprojects/cmMod/lib/cmMod.cpp0000644000175000017500000000036613716006331027104 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/3 advanced no dep/subprojects/cmMod/lib/cmMod.hpp0000644000175000017500000000032013716006331027077 0ustar00jpakkanejpakkane#pragma once #include #include "cmmodlib_export.h" class CMMODLIB_EXPORT cmModClass { private: std::string str; public: cmModClass(std::string foo); std::string getStr() const; }; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/3 advanced no dep/subprojects/cmMod/main.cpp0000644000175000017500000000025113716006331026214 0ustar00jpakkanejpakkane#include #include "lib/cmMod.hpp" using namespace std; int main(void) { cmModClass obj("Hello (LIB TEST)"); cout << obj.getStr() << endl; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/cmake/3 advanced no dep/test.json0000644000175000017500000000036414253672217023052 0ustar00jpakkanejpakkane{ "installed": [ {"type": "pdb", "file": "usr/bin/cm_meson_testEXE"}, {"type": "exe", "file": "usr/bin/cm_meson_testEXE"}, {"type": "pdb", "file": "usr/bin/cm_benchmark"}, {"type": "exe", "file": "usr/bin/cm_benchmark"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.1506457 meson-1.3.2/test cases/cmake/4 code gen/0000755000175000017500000000000014562742414017747 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/4 code gen/main.cpp0000644000175000017500000000015613716006331021370 0ustar00jpakkanejpakkane#include #include "test.hpp" using namespace std; int main(void) { cout << getStr() << endl; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1699894002.0 meson-1.3.2/test cases/cmake/4 code gen/meson.build0000644000175000017500000000077514524451362022117 0ustar00jpakkanejpakkaneproject('cmake_code_gen', ['c', 'cpp']) if meson.is_cross_build() error('MESON_SKIP_TEST this test does not cross compile correctly.') endif 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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7666247 meson-1.3.2/test cases/cmake/4 code gen/subprojects/0000755000175000017500000000000014562742413022311 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.1546457 meson-1.3.2/test cases/cmake/4 code gen/subprojects/cmCodeGen/0000755000175000017500000000000014562742414024136 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/4 code gen/subprojects/cmCodeGen/CMakeLists.txt0000644000175000017500000000016214031433465026667 0ustar00jpakkanejpakkanecmake_minimum_required(VERSION 3.7) project(CMCodeGen) set(CMAKE_CXX_STANDARD 14) add_executable(genA main.cpp) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/4 code gen/subprojects/cmCodeGen/main.cpp0000644000175000017500000000050513716006331025555 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/4 code gen/test.hpp0000644000175000017500000000006713716006331021431 0ustar00jpakkanejpakkane#pragma once #include std::string getStr(); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.1546457 meson-1.3.2/test cases/cmake/5 object library/0000755000175000017500000000000014562742414021177 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/5 object library/main.cpp0000644000175000017500000000031313716006331022613 0ustar00jpakkanejpakkane#include #include #include "libA.hpp" #include "libB.hpp" using namespace std; int main(void) { cout << getLibStr() << " -- " << getZlibVers() << endl; return EXIT_SUCCESS; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1699894006.0 meson-1.3.2/test cases/cmake/5 object library/meson.build0000644000175000017500000000112214524451366023336 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7706246 meson-1.3.2/test cases/cmake/5 object library/subprojects/0000755000175000017500000000000014562742413023541 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.1666458 meson-1.3.2/test cases/cmake/5 object library/subprojects/cmObjLib/0000755000175000017500000000000014562742414025223 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/5 object library/subprojects/cmObjLib/CMakeLists.txt0000644000175000017500000000050713716006331027754 0ustar00jpakkanejpakkanecmake_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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/5 object library/subprojects/cmObjLib/libA.cpp0000644000175000017500000000011513716006331026562 0ustar00jpakkanejpakkane#include "libA.hpp" std::string getLibStr(void) { return "Hello World"; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/5 object library/subprojects/cmObjLib/libA.hpp0000644000175000017500000000055213716006331026574 0ustar00jpakkanejpakkane#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(); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/5 object library/subprojects/cmObjLib/libB.cpp0000644000175000017500000000014113716006331026562 0ustar00jpakkanejpakkane#include "libB.hpp" #include std::string getZlibVers(void) { return zlibVersion(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/5 object library/subprojects/cmObjLib/libB.hpp0000644000175000017500000000055413716006331026577 0ustar00jpakkanejpakkane#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(); ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.174646 meson-1.3.2/test cases/cmake/6 object library no dep/0000755000175000017500000000000014562742414022326 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/6 object library no dep/main.cpp0000644000175000017500000000031313716006331023742 0ustar00jpakkanejpakkane#include #include #include "libA.hpp" #include "libB.hpp" using namespace std; int main(void) { cout << getLibStr() << " -- " << getZlibVers() << endl; return EXIT_SUCCESS; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1699894005.0 meson-1.3.2/test cases/cmake/6 object library no dep/meson.build0000644000175000017500000000055714524451365024477 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7706246 meson-1.3.2/test cases/cmake/6 object library no dep/subprojects/0000755000175000017500000000000014562742413024670 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.182646 meson-1.3.2/test cases/cmake/6 object library no dep/subprojects/cmObjLib/0000755000175000017500000000000014562742414026352 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/6 object library no dep/subprojects/cmObjLib/CMakeLists.txt0000644000175000017500000000032513716006331031101 0ustar00jpakkanejpakkanecmake_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 $) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/6 object library no dep/subprojects/cmObjLib/libA.cpp0000644000175000017500000000011513716006331027711 0ustar00jpakkanejpakkane#include "libA.hpp" std::string getLibStr(void) { return "Hello World"; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/6 object library no dep/subprojects/cmObjLib/libA.hpp0000644000175000017500000000055213716006331027723 0ustar00jpakkanejpakkane#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(); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/6 object library no dep/subprojects/cmObjLib/libB.cpp0000644000175000017500000000011013716006331027705 0ustar00jpakkanejpakkane#include "libB.hpp" std::string getZlibVers(void) { return "STUB"; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/6 object library no dep/subprojects/cmObjLib/libB.hpp0000644000175000017500000000055413716006331027726 0ustar00jpakkanejpakkane#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(); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.1906462 meson-1.3.2/test cases/cmake/7 cmake options/0000755000175000017500000000000014562742414021042 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1699894005.0 meson-1.3.2/test cases/cmake/7 cmake options/meson.build0000644000175000017500000000017214524451365023204 0ustar00jpakkanejpakkaneproject('cmake_set_opt', ['c', 'cpp']) import('cmake').subproject('cmOpts', cmake_options: '-DSOME_CMAKE_VAR=something') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7706246 meson-1.3.2/test cases/cmake/7 cmake options/subprojects/0000755000175000017500000000000014562742413023404 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.1946464 meson-1.3.2/test cases/cmake/7 cmake options/subprojects/cmOpts/0000755000175000017500000000000014562742414024652 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/7 cmake options/subprojects/cmOpts/CMakeLists.txt0000644000175000017500000000046713716006331027410 0ustar00jpakkanejpakkanecmake_minimum_required(VERSION 3.7) project(testPro) if(NOT "${SOME_CMAKE_VAR}" STREQUAL "something") message(FATAL_ERROR "Setting the CMake var failed") endif() if(NOT "${CMAKE_PREFIX_PATH}" STREQUAL "val1;val2") message(FATAL_ERROR "Setting the CMAKE_PREFIX_PATH failed '${CMAKE_PREFIX_PATH}'") endif() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/7 cmake options/test.json0000644000175000017500000000030614031433465022705 0ustar00jpakkanejpakkane{ "matrix": { "options": { "cmake_prefix_path": [ { "val": ["val1", "val2"] } ], "build.cmake_prefix_path": [ { "val": ["val1", "val2"] } ] } } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.1986463 meson-1.3.2/test cases/cmake/8 custom command/0000755000175000017500000000000014562742414021220 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/8 custom command/main.cpp0000644000175000017500000000027413716006331022642 0ustar00jpakkanejpakkane#include #include using namespace std; int main(void) { cmModClass obj("Hello"); cout << obj.getStr() << endl; cout << obj.getOther() << endl; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421419.0 meson-1.3.2/test cases/cmake/8 custom command/meson.build0000644000175000017500000000100114516755253023356 0ustar00jpakkanejpakkaneproject('cmakeSubTest', ['c', 'cpp']) if meson.is_cross_build() error('MESON_SKIP_TEST this test does not cross compile correctly.') endif 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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7706246 meson-1.3.2/test cases/cmake/8 custom command/subprojects/0000755000175000017500000000000014562742413023562 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.2226467 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/0000755000175000017500000000000014562742414024622 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/CMakeLists.txt0000644000175000017500000001361514562742363027373 0ustar00jpakkanejpakkanecmake_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(genMain genMain.cpp) add_custom_command(OUTPUT main.cpp COMMAND genMain > main.cpp) 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 ) set(CMD_PART) list(APPEND CMD_PART COMMAND mycpy cpyBase.cpp.in cpyBase.cpp.in.gen) list(APPEND CMD_PART COMMAND mycpy cpyBase.cpp.in.gen cpyBase.cpp.out) list(APPEND CMD_PART COMMAND mycpy cpyBase.cpp.out cpyBase.cpp.something) add_custom_command( OUTPUT cpyBase.cpp COMMAND mycpy "${CMAKE_CURRENT_SOURCE_DIR}/cpyBase.cpp.am" cpyBase.cpp.in ${CMD_PART} 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_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/cpyTest/some/directory/cpyTest5.hpp" COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/cpyTest/cpyTest5.hpp" "${CMAKE_CURRENT_BINARY_DIR}/cpyTest/some/directory/cpyTest5.hpp" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/cpyTest/cpyTest5.hpp" ) include_directories("${CMAKE_CURRENT_BINARY_DIR}/cpyTest/some") add_library(cmModLib SHARED cmMod.cpp genTest.cpp cpyBase.cpp cpyBase.hpp cpyNext.cpp cpyNext.hpp cpyTest.cpp cpyTest.hpp cpyTest2.hpp cpyTest3.hpp cpyTest/some/directory/cpyTest5.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) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") message(STATUS "Running the -include test case on macro_name") add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/cpyInc.hpp" COMMAND mycpy "${CMAKE_CURRENT_SOURCE_DIR}/cpyInc.hpp.am" "${CMAKE_CURRENT_BINARY_DIR}/cpyInc.hpp" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/cpyInc.hpp.am" ) target_compile_options(macro_name PUBLIC -DTEST_CMD_INCLUDE -include "${CMAKE_CURRENT_BINARY_DIR}/cpyInc.hpp") endif() # Only executable targets are replaced in the command # all other target names are kept as is add_custom_target(clang-format COMMAND clang-format -i cmMod.cpp) add_dependencies(cmModLib args_test_cmd tgtCpyTest4) add_dependencies(args_test_cmd macro_name_cmd;gen;mycpy) # Reproduce https://github.com/mesonbuild/meson/issues/10244 add_custom_target(mycpy.all) add_dependencies(mycpy.all mycpy) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/args_test.cpp0000644000175000017500000000060213716006331027306 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/cmMod.cpp0000644000175000017500000000070614562742363026373 0ustar00jpakkanejpakkane#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 "Strings:\n - " + getStrCpy() + "\n - " + getStrNext() + "\n - " + getStrCpyTest(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/cmMod.hpp0000644000175000017500000000036213716006331026362 0ustar00jpakkanejpakkane#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; }; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/cp.cpp0000644000175000017500000000060113716006331025714 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyBase.cpp.am0000644000175000017500000000012214562742363027306 0ustar00jpakkanejpakkane#include "cpyBase.hpp" std::string getStrCpy() { return "Hello Copied File"; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyBase.hpp.am0000644000175000017500000000007213716006331027303 0ustar00jpakkanejpakkane#pragma once #include std::string getStrCpy(); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyInc.hpp.am0000644000175000017500000000005514031433465027146 0ustar00jpakkanejpakkane#pragma once #define CPY_INC_WAS_INCLUDED 1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyNext.cpp.am0000644000175000017500000000016013716006331027340 0ustar00jpakkanejpakkane#include "cpyNext.hpp" std::string getStrNext() { return "Hello Copied File -- now even more convoluted!"; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyNext.hpp.am0000644000175000017500000000007313716006331027350 0ustar00jpakkanejpakkane#pragma once #include std::string getStrNext(); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.2346468 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyTest/0000755000175000017500000000000014562742414026255 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyTest/CMakeLists.txt0000644000175000017500000000033613716006331031006 0ustar00jpakkanejpakkaneadd_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") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyTest/cpyTest.hpp0000644000175000017500000000007613716006331030413 0ustar00jpakkanejpakkane#pragma once #include std::string getStrCpyTest(); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyTest/cpyTest2.hpp0000644000175000017500000000005613716006331030473 0ustar00jpakkanejpakkane#pragma once #define CPY_TEST_STR_2 "Hello " ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyTest/cpyTest3.hpp0000644000175000017500000000006013716006331030467 0ustar00jpakkanejpakkane#pragma once #define CPY_TEST_STR_3 "CopyFile" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyTest/cpyTest4.hpp0000644000175000017500000000005513716006331030474 0ustar00jpakkanejpakkane#pragma once #define CPY_TEST_STR_4 " test" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyTest/cpyTest5.hpp0000644000175000017500000000005514031433465030500 0ustar00jpakkanejpakkane#pragma once #define CPY_TEST_STR_5 " test" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyTest.cpp0000644000175000017500000000036714031433465026761 0ustar00jpakkanejpakkane#include "cpyTest.hpp" #include "cpyTest2.hpp" #include "cpyTest3.hpp" #include "ccppyyTTeesstt/cpyTest4.hpp" #include "directory/cpyTest5.hpp" std::string getStrCpyTest() { return CPY_TEST_STR_2 CPY_TEST_STR_3 CPY_TEST_STR_4 CPY_TEST_STR_5; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/genMain.cpp0000644000175000017500000000107413716006331026675 0ustar00jpakkanejpakkane#include using namespace std; int main() { cout << R"asd( #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; } )asd"; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/macro_name.cpp0000644000175000017500000000051214031433465027417 0ustar00jpakkanejpakkane#include #include #include #include using namespace std; #ifdef TEST_CMD_INCLUDE #if CPY_INC_WAS_INCLUDED != 1 #error "cpyInc.hpp was not included" #endif #endif int main() { this_thread::sleep_for(chrono::seconds(1)); ofstream out1("macro_name.txt"); out1 << "FOO"; return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.2346468 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/mycpy/0000755000175000017500000000000014562742414025763 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/cmake/8 custom command/subprojects/cmMod/mycpy/.gitkeep0000644000175000017500000000011114253672217027405 0ustar00jpakkanejpakkane# Required to reproduce https://github.com/mesonbuild/meson/issues/10244 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.2346468 meson-1.3.2/test cases/cmake/9 disabled subproject/0000755000175000017500000000000014562742414022220 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1699894007.0 meson-1.3.2/test cases/cmake/9 disabled subproject/meson.build0000644000175000017500000000026714524451367024371 0ustar00jpakkanejpakkaneproject('cmakeSubTest', ['c', 'cpp']) cm = import('cmake') sub_pro = cm.subproject('nothing', required: false) assert(not sub_pro.found(), 'subproject found() reports wrong value') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.9866278 meson-1.3.2/test cases/common/0000755000175000017500000000000014562742413016366 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.2346468 meson-1.3.2/test cases/common/1 trivial/0000755000175000017500000000000014562742414020162 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421439.0 meson-1.3.2/test cases/common/1 trivial/meson.build0000644000175000017500000000152114516755277022335 0ustar00jpakkanejpakkane# Comment on the first line project('trivial test', # Comment inside a function call + array for language list ['c'], default_options: ['buildtype=debug'], 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 exe = executable('trivialprog', sources : sources) assert(exe.name() == 'trivialprog') 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.') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/1 trivial/trivial.c0000644000175000017500000000013613716006331021767 0ustar00jpakkanejpakkane#include int main(void) { printf("Trivial test is working.\n"); return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.2466471 meson-1.3.2/test cases/common/10 man install/0000755000175000017500000000000014562742414020772 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/10 man install/bar.20000644000175000017500000000007013716006331021605 0ustar00jpakkanejpakkanethis is a man page of bar.2, its contents are irrelevant././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/10 man install/baz.1.in0000644000175000017500000000041413716006331022223 0ustar00jpakkanejpakkaneThis 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. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/10 man install/foo.10000644000175000017500000000007013716006331021623 0ustar00jpakkanejpakkanethis is a man page of foo.1 its contents are irrelevant ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1619506185.0 meson-1.3.2/test cases/common/10 man install/foo.fr.10000644000175000017500000000007014041732011022222 0ustar00jpakkanejpakkanethis is a man page of foo.1 its contents are irrelevant ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421448.0 meson-1.3.2/test cases/common/10 man install/meson.build0000644000175000017500000000052314516755310023132 0ustar00jpakkanejpakkaneproject('man install') m1 = install_man('foo.1') m2 = install_man('bar.2') m3 = install_man('foo.fr.1', locale: 'fr') 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1619506185.0 meson-1.3.2/test cases/common/10 man install/test.json0000644000175000017500000000064414041732011022630 0ustar00jpakkanejpakkane{ "installed": [ { "type": "file", "file": "usr/share/man/man1/foo.1" }, { "type": "file", "file": "usr/share/man/fr/man1/foo.1" }, { "type": "file", "file": "usr/share/man/man2/bar.2" }, { "type": "file", "file": "usr/share/man/man1/vanishing.1" }, { "type": "file", "file": "usr/share/man/man2/vanishing.2" }, { "type": "file", "file": "usr/share/man/man1/baz.1" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.2546473 meson-1.3.2/test cases/common/10 man install/vanishing/0000755000175000017500000000000014562742414022760 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/10 man install/vanishing/meson.build0000644000175000017500000000003313716006331025105 0ustar00jpakkanejpakkaneinstall_man('vanishing.1') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/10 man install/vanishing/vanishing.10000644000175000017500000000006213716006331025015 0ustar00jpakkanejpakkaneThis is a man page of the vanishing subdirectory. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/10 man install/vanishing/vanishing.20000644000175000017500000000007113716006331025016 0ustar00jpakkanejpakkaneThis is a second man page of the vanishing subdirectory. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.2586472 meson-1.3.2/test cases/common/100 postconf with args/0000755000175000017500000000000014562742414022354 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421530.0 meson-1.3.2/test cases/common/100 postconf with args/meson.build0000644000175000017500000000035014516755432024517 0ustar00jpakkanejpakkaneproject('postconf script', 'c') conf = configure_file( configuration : configuration_data(), output : 'out' ) meson.add_postconf_script(find_program('postconf.py'), '5', '33', conf) test('post', executable('prog', 'prog.c')) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/100 postconf with args/postconf.py0000644000175000017500000000072714516512250024557 0ustar00jpakkanejpakkane#!/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, encoding='utf-8') as f: data = f.readline().strip() with open(output_file, 'w', encoding='utf-8') as f: f.write(template.format(data, sys.argv[1], sys.argv[2])) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/100 postconf with args/prog.c0000644000175000017500000000015114516512250023454 0ustar00jpakkanejpakkane#include"generated.h" int main(void) { return THE_NUMBER != 9 || THE_ARG1 != 5 || THE_ARG2 != 33; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/100 postconf with args/raw.dat0000644000175000017500000000000214516512250023617 0ustar00jpakkanejpakkane9 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.2666473 meson-1.3.2/test cases/common/101 testframework options/0000755000175000017500000000000014562742414023222 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421530.0 meson-1.3.2/test cases/common/101 testframework options/meson.build0000644000175000017500000000076514516755432025377 0ustar00jpakkanejpakkane# normally run only from run_tests.py or run_project_tests.py # else do like # meson build '-Dtestoption=A string with spaces' -Dother_one=true -Dcombo_opt=one -Dprefix=/usr -Dlibdir=lib -Dbackend=ninja -Dwerror=True project('options') 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.') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/101 testframework options/meson_options.txt0000644000175000017500000000036014516512250026646 0ustar00jpakkanejpakkaneoption('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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339787.0 meson-1.3.2/test cases/common/101 testframework options/test.json0000644000175000017500000000042014516515713025067 0ustar00jpakkanejpakkane{ "matrix": { "options": { "testoption": [{ "val": "A string with spaces" }], "other_one": [{ "val": "true" }], "combo_opt": [{ "val": "one" }], "werror": [{ "val": "true" }] } } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.2666473 meson-1.3.2/test cases/common/102 extract same name/0000755000175000017500000000000014562742414022133 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/102 extract same name/lib.c0000644000175000017500000000004314516512250023032 0ustar00jpakkanejpakkaneint func1(void) { return 23; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/102 extract same name/main.c0000644000175000017500000000014414516512250023212 0ustar00jpakkanejpakkaneint func1(void); int func2(void); int main(void) { return !(func1() == 23 && func2() == 42); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421532.0 meson-1.3.2/test cases/common/102 extract same name/meson.build0000644000175000017500000000151614516755434024305 0ustar00jpakkanejpakkaneproject('object extraction', 'c') if meson.backend() == 'xcode' # Xcode gives object files unique names but only if they would clash. For example # two files named lib.o instead get the following names: # # lib-4fbe522d8ba4cb1f1b89cc2df640a2336b92e1a5565f0a4c5a79b5b5e2969eb9.o # lib-4fbe522d8ba4cb1f1b89cc2df640a2336deeff2bc2297affaadbe20f5cbfee56.o # # No-one has reverse engineered the naming scheme so we would access them. # IF you feel up to the challenge, patches welcome. error('MESON_SKIP_TEST, Xcode cannot extract objs when they would have the same filename.') endif lib = 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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.2706475 meson-1.3.2/test cases/common/102 extract same name/src/0000755000175000017500000000000014562742414022722 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/102 extract same name/src/lib.c0000644000175000017500000000004314516512250023621 0ustar00jpakkanejpakkaneint func2(void) { return 42; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.2706475 meson-1.3.2/test cases/common/103 has header symbol/0000755000175000017500000000000014562742414022125 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421540.0 meson-1.3.2/test cases/common/103 has header symbol/meson.build0000644000175000017500000000403514516755444024277 0ustar00jpakkanejpakkaneproject( 'has header symbol', 'c', 'cpp', default_options : ['cpp_std=c++11'], ) 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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.2706475 meson-1.3.2/test cases/common/104 has arg/0000755000175000017500000000000014562742414020161 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421534.0 meson-1.3.2/test cases/common/104 has arg/meson.build0000644000175000017500000000542014516755436022333 0ustar00jpakkanejpakkaneproject('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 ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.294648 meson-1.3.2/test cases/common/105 generatorcustom/0000755000175000017500000000000014562742414022076 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/105 generatorcustom/catter.py0000755000175000017500000000044414516512250023727 0ustar00jpakkanejpakkane#!/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) as ifile: content = ifile.read() ofile.write(content) ofile.write('\n') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/105 generatorcustom/gen-resx.py0000755000175000017500000000020214516512250024165 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys ofile = sys.argv[1] num = sys.argv[2] with open(ofile, 'w') as f: f.write(f'res{num}\n') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/105 generatorcustom/gen.c0000644000175000017500000000176314516512250023012 0ustar00jpakkanejpakkane/* SPDX-License-Identifier: Apache-2.0 */ /* Copyright Ā© 2023 Intel Corporation */ #include #include int main(int argc, const char ** argv) { if (argc != 3) { fprintf(stderr, "%s %i %s\n", "Got incorrect number of arguments, got ", argc - 1, ", but expected 2"); exit(1); } FILE * input, * output; if ((input = fopen(argv[1], "rb")) == NULL) { exit(1); } if ((output = fopen(argv[2], "wb")) == NULL) { exit(1); } fprintf(output, "#pragma once\n"); fprintf(output, "#define "); int bytes_copied = 0; int c; while((c = fgetc(input)) != EOF) { if(fputc(c, output) == EOF) { fprintf(stderr, "Writing to output file failed.\n"); return 1; } if(++bytes_copied > 10000) { fprintf(stderr, "File copy stuck in an eternal loop!\n"); return 1; } } fputc('\n', output); fclose(input); fclose(output); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/105 generatorcustom/gen.py0000755000175000017500000000036014516512250023213 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys ifile = sys.argv[1] ofile = sys.argv[2] with open(ifile) as f: resname = f.readline().strip() templ = 'const char %s[] = "%s";\n' with open(ofile, 'w') as f: f.write(templ % (resname, resname)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/105 generatorcustom/host.c0000644000175000017500000000016314516512250023207 0ustar00jpakkanejpakkane#include "res1-cpp.h" int main(void) { #ifdef res1 return 0; #else return 1; #endif } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/105 generatorcustom/main.c0000644000175000017500000000021214516512250023151 0ustar00jpakkanejpakkane#include #include "alltogether.h" int main(void) { printf("%s - %s - %s - %s\n", res1, res2, res3, res4); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421535.0 meson-1.3.2/test cases/common/105 generatorcustom/meson.build0000644000175000017500000000215614516755437024254 0ustar00jpakkanejpakkaneproject('generatorcustom', 'c') creator = find_program('gen.py') catter = find_program('catter.py') gen_resx = find_program('gen-resx.py') gen = generator(creator, output: '@BASENAME@.h', arguments : ['@INPUT@', '@OUTPUT@']) res3 = custom_target('gen-res3', output : 'res3.txt', command : [gen_resx, '@OUTPUT@', '3']) res4 = custom_target('gen-res4', output : 'res4.txt', command : [gen_resx, '@OUTPUT@', '4']) hs = gen.process('res1.txt', 'res2.txt', res3, res4[0]) allinone = custom_target('alltogether', input : hs, output : 'alltogether.h', command : [catter, '@INPUT@', '@OUTPUT@']) proggie = executable('proggie', 'main.c', allinone) test('proggie', proggie) # specifically testing that cross binaries are run with an exe_wrapper if meson.can_run_host_binaries() gen_tool = executable('generator', 'gen.c', native : false) c_gen = generator( gen_tool, output : '@BASENAME@-cpp.h', arguments : ['@INPUT@', '@OUTPUT@'] ) hs2 = c_gen.process('res1.txt') host_exe = executable('host_test', 'host.c', hs2, native : false) test('compiled generator', host_exe) endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/105 generatorcustom/res1.txt0000644000175000017500000000000514516512250023474 0ustar00jpakkanejpakkaneres1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/105 generatorcustom/res2.txt0000644000175000017500000000000514516512250023475 0ustar00jpakkanejpakkaneres2 ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.294648 meson-1.3.2/test cases/common/106 multiple dir configure file/0000755000175000017500000000000014562742414024112 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421535.0 meson-1.3.2/test cases/common/106 multiple dir configure file/meson.build0000644000175000017500000000036014516755437026263 0ustar00jpakkanejpakkaneproject('multiple dir configure file') subdir('subdir') configure_file(input : 'subdir/someinput.in', output : 'outputhere', copy: true) configure_file(input : cfile1, output : '@BASENAME@', copy: true) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.2986479 meson-1.3.2/test cases/common/106 multiple dir configure file/subdir/0000755000175000017500000000000014562742414025402 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/106 multiple dir configure file/subdir/foo.txt0000644000175000017500000000000014516512250026704 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/106 multiple dir configure file/subdir/meson.build0000644000175000017500000000053314516512250027535 0ustar00jpakkanejpakkaneconfigure_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")']) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/106 multiple dir configure file/subdir/someinput.in0000644000175000017500000000000014516512250027733 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.306648 meson-1.3.2/test cases/common/107 spaces backslash/0000755000175000017500000000000014562742414022051 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.306648 meson-1.3.2/test cases/common/107 spaces backslash/asm output/0000755000175000017500000000000014562742414024152 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/107 spaces backslash/asm output/meson.build0000644000175000017500000000011314516512250026277 0ustar00jpakkanejpakkaneconfigure_file(output : 'blank.txt', configuration : configuration_data()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/107 spaces backslash/comparer-end-notstring.c0000644000175000017500000000100014516512250026575 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/107 spaces backslash/comparer-end.c0000644000175000017500000000056714516512250024571 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/107 spaces backslash/comparer.c0000644000175000017500000000061014516512250024012 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.3146482 meson-1.3.2/test cases/common/107 spaces backslash/include/0000755000175000017500000000000014562742414023474 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/107 spaces backslash/include/comparer.h0000644000175000017500000000010214516512250025436 0ustar00jpakkanejpakkane#include #include #define COMPARER_INCLUDED ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421537.0 meson-1.3.2/test cases/common/107 spaces backslash/meson.build0000644000175000017500000000250214516755441024215 0ustar00jpakkanejpakkaneproject('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\\'])) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.3146482 meson-1.3.2/test cases/common/108 ternary/0000755000175000017500000000000014562742414020344 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421537.0 meson-1.3.2/test cases/common/108 ternary/meson.build0000644000175000017500000000077214516755441022517 0ustar00jpakkanejpakkaneproject('ternary operator') 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.') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.318648 meson-1.3.2/test cases/common/109 custom target capture/0000755000175000017500000000000014562742414023066 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/109 custom target capture/data_source.txt0000644000175000017500000000004014516512250026102 0ustar00jpakkanejpakkaneThis is a text only input file. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421538.0 meson-1.3.2/test cases/common/109 custom target capture/meson.build0000644000175000017500000000125214516755442025234 0ustar00jpakkanejpakkaneproject('custom target') 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]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/109 custom target capture/my_compiler.py0000755000175000017500000000054614516512250025757 0ustar00jpakkanejpakkane#!/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.') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/109 custom target capture/test.json0000644000175000017500000000011514516515714024735 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/subdir/data.dat"} ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.318648 meson-1.3.2/test cases/common/11 subdir/0000755000175000017500000000000014562742414020061 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421450.0 meson-1.3.2/test cases/common/11 subdir/meson.build0000644000175000017500000000005514516755312022223 0ustar00jpakkanejpakkaneproject('subdir test', 'c') subdir('subdir') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.3266482 meson-1.3.2/test cases/common/11 subdir/subdir/0000755000175000017500000000000014562742414021351 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1619506185.0 meson-1.3.2/test cases/common/11 subdir/subdir/meson.build0000644000175000017500000000007514041732011023475 0ustar00jpakkanejpakkaneprog = executable('prog', 'prog.c') test('subdirprog', prog) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/11 subdir/subdir/prog.c0000644000175000017500000000003513716006331022451 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.3266482 meson-1.3.2/test cases/common/110 allgenerate/0000755000175000017500000000000014562742414021134 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/110 allgenerate/converter.py0000755000175000017500000000017014516512250023506 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys ifile = sys.argv[1] ofile = sys.argv[2] open(ofile, 'w').write(open(ifile).read()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/110 allgenerate/foobar.cpp.in0000644000175000017500000000012114516512250023477 0ustar00jpakkanejpakkane#include int main(void) { printf("I am a program.\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421542.0 meson-1.3.2/test cases/common/110 allgenerate/meson.build0000644000175000017500000000072114516755446023306 0ustar00jpakkanejpakkane# 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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.3266482 meson-1.3.2/test cases/common/111 pathjoin/0000755000175000017500000000000014562742414020466 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421540.0 meson-1.3.2/test cases/common/111 pathjoin/meson.build0000644000175000017500000000336114516755444022641 0ustar00jpakkanejpakkaneproject('pathjoin') # 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') assert(join_paths('/foo', '') == '/foo/', 'Trailing / on path') # 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') assert(join_paths(['/foo', '']) == '/foo/', 'Trailing / on path') # 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') assert('/foo' / '' == '/foo/', 'Trailing / on path') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.3346484 meson-1.3.2/test cases/common/112 subdir subproject/0000755000175000017500000000000014562742414022304 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421542.0 meson-1.3.2/test cases/common/112 subdir subproject/meson.build0000644000175000017500000000004414516755446024454 0ustar00jpakkanejpakkaneproject('proj', 'c') subdir('prog') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.3346484 meson-1.3.2/test cases/common/112 subdir subproject/prog/0000755000175000017500000000000014562742414023253 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/112 subdir subproject/prog/meson.build0000644000175000017500000000024314516512250025404 0ustar00jpakkanejpakkanesubproject('sub') libSub = dependency('sub', fallback: ['sub', 'libSub']) exe = executable('prog', 'prog.c', dependencies: libSub) test('subdir subproject', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/112 subdir subproject/prog/prog.c0000644000175000017500000000006714516512250024361 0ustar00jpakkanejpakkane#include int main(void) { return sub(); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7786248 meson-1.3.2/test cases/common/112 subdir subproject/subprojects/0000755000175000017500000000000014562742413024646 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.3386486 meson-1.3.2/test cases/common/112 subdir subproject/subprojects/sub/0000755000175000017500000000000014562742414025440 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/112 subdir subproject/subprojects/sub/meson.build0000644000175000017500000000022414516512250027570 0ustar00jpakkanejpakkaneproject('sub', 'c') lib = static_library('sub', 'sub.c') libSub = declare_dependency(include_directories: include_directories('.'), link_with: lib) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/112 subdir subproject/subprojects/sub/sub.c0000644000175000017500000000006214516512250026363 0ustar00jpakkanejpakkane#include "sub.h" int sub(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/112 subdir subproject/subprojects/sub/sub.h0000644000175000017500000000006414516512250026372 0ustar00jpakkanejpakkane#ifndef SUB_H #define SUB_H int sub(void); #endif ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.3386486 meson-1.3.2/test cases/common/113 interpreter copy mutable var on assignment/0000755000175000017500000000000014562742414027063 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421543.0 meson-1.3.2/test cases/common/113 interpreter copy mutable var on assignment/meson.build0000644000175000017500000000104414516755447031235 0ustar00jpakkanejpakkaneproject('foo') 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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.3426485 meson-1.3.2/test cases/common/114 skip/0000755000175000017500000000000014562742414017623 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/114 skip/meson.build0000644000175000017500000000010714516512250021753 0ustar00jpakkanejpakkaneproject('skip') error('MESON_SKIP_TEST this test is always skipped.') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.3506486 meson-1.3.2/test cases/common/115 subproject project arguments/0000755000175000017500000000000014562742414024453 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/115 subproject project arguments/exe.c0000644000175000017500000000041314516512250025366 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/115 subproject project arguments/exe.cpp0000644000175000017500000000042114516512250025725 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421546.0 meson-1.3.2/test cases/common/115 subproject project arguments/meson.build0000644000175000017500000000105614516755452026624 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7786248 meson-1.3.2/test cases/common/115 subproject project arguments/subprojects/0000755000175000017500000000000014562742413027015 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.362649 meson-1.3.2/test cases/common/115 subproject project arguments/subprojects/subexe/0000755000175000017500000000000014562742414030311 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/115 subproject project arguments/subprojects/subexe/meson.build0000644000175000017500000000061414516512250032444 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/115 subproject project arguments/subprojects/subexe/subexe.c0000644000175000017500000000041114516512250031734 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.366649 meson-1.3.2/test cases/common/116 test skip/0000755000175000017500000000000014562742414020565 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421547.0 meson-1.3.2/test cases/common/116 test skip/meson.build0000644000175000017500000000016314516755453022735 0ustar00jpakkanejpakkaneproject('test skip', 'c') exe_test_skip = executable('test_skip', 'test_skip.c') test('test_skip', exe_test_skip) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/116 test skip/test_skip.c0000644000175000017500000000004214516512250022722 0ustar00jpakkanejpakkaneint main(void) { return 77; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.374649 meson-1.3.2/test cases/common/117 shared module/0000755000175000017500000000000014562742414021374 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421548.0 meson-1.3.2/test cases/common/117 shared module/meson.build0000644000175000017500000000246014516755454023547 0ustar00jpakkanejpakkaneproject('shared module', 'c') c = meson.get_compiler('c') # Windows UWP doesn't support the ToolHelp API we use in this test to emulate # runtime symbol resolution. if host_machine.system() == 'windows' if not c.compiles(''' #include #include HANDLE func(void) { return CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0); } ''') error('MESON_SKIP_TEST Windows UWP does not support this test.') endif endif dl = 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', override_options: ['werror=false'], install : true, install_dir : join_paths(get_option('libdir'), 'modules')) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/117 shared module/module.c0000644000175000017500000000454414516512250023024 0ustar00jpakkanejpakkane#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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/117 shared module/nosyms.c0000644000175000017500000000006714516512250023063 0ustar00jpakkanejpakkanestatic int func_not_exported (void) { return 99; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/117 shared module/prog.c0000644000175000017500000000410214516512250022474 0ustar00jpakkanejpakkane #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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/117 shared module/runtime.c0000644000175000017500000000070314516512250023213 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/117 shared module/test.json0000644000175000017500000000031714516515714023247 0ustar00jpakkanejpakkane{ "installed": [ {"type": "expr", "file": "usr/lib/modules/libnosyms?so"}, {"type": "implibempty", "file": "usr/lib/modules/libnosyms"}, {"type": "pdb", "file": "usr/lib/modules/nosyms"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.3946493 meson-1.3.2/test cases/common/118 llvm ir and assembly/0000755000175000017500000000000014562742414022551 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/118 llvm ir and assembly/main.c0000644000175000017500000000032314516512250023627 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/118 llvm ir and assembly/main.cpp0000644000175000017500000000034514516512250024173 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421548.0 meson-1.3.2/test cases/common/118 llvm ir and assembly/meson.build0000644000175000017500000000606514516755454024731 0ustar00jpakkanejpakkaneproject('llvm-ir', 'c', 'cpp') if meson.backend() == 'xcode' error('MESON_SKIP_TEST: asm not supported with the Xcode backend. Patches welcome.') endif cpu = host_machine.cpu_family() supported_cpus = ['arm', 'aarch64', '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 ml.exe or armasm.exe # assembler. Then we can link it into the executable. if cc.get_argument_syntax() == 'msvc' cl = cc.cmd_array() if cpu == 'x86' asmcmd = 'ml' elif cpu == 'x86_64' asmcmd = 'ml64' elif cpu == 'aarch64' asmcmd = 'armasm64' elif cpu == 'arm' asmcmd = 'armasm' else error('Unsupported cpu family: "' + cpu + '"') endif ml = find_program(asmcmd, required: false) if not ml.found() error('MESON_SKIP_TEST: Microsoft assembler (ml/armasm) not found') endif # Preprocess file (ml doesn't support pre-processing) # Force the input 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 if asmcmd.startswith('armasm') square_impl = custom_target(lang + square_impl, input : square_preproc, output : lang + square_base + '.obj', command : [ml, '-nologo', '-o', '@OUTPUT@', '@INPUT@']) else square_impl = custom_target(lang + square_impl, input : square_preproc, output : lang + square_base + '.obj', command : [ml, '/nologo', '/safeseh', '/Fo', '@OUTPUT@', '/c', '@INPUT@']) endif 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/118 llvm ir and assembly/square-aarch64.S0000644000175000017500000000066414516512250025421 0ustar00jpakkanejpakkane#include "symbol-underscore.h" #ifdef _MSC_VER AREA _TEXT, ARM64, CODE, READONLY EXPORT SYMBOL_NAME(square_unsigned) SYMBOL_NAME(square_unsigned) PROC mul x1, x0, x0 mov x0, x1 ret SYMBOL_NAME(square_unsigned) ENDP END #else .text .globl SYMBOL_NAME(square_unsigned) # ifdef __linux__ .type square_unsigned, %function #endif SYMBOL_NAME(square_unsigned): mul x1, x0, x0 mov x0, x1 ret #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/118 llvm ir and assembly/square-arm.S0000644000175000017500000000070014516512250024737 0ustar00jpakkanejpakkane#include "symbol-underscore.h" #ifdef _MSC_VER AREA _TEXT, ARM, CODE, READONLY EXPORT SYMBOL_NAME(square_unsigned) SYMBOL_NAME(square_unsigned) PROC mul r1, r0, r0 mov r0, r1 mov pc, lr SYMBOL_NAME(square_unsigned) ENDP END #else .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 #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/118 llvm ir and assembly/square-x86.S0000644000175000017500000000111114516512250024602 0ustar00jpakkanejpakkane#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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/118 llvm ir and assembly/square-x86_64.S0000644000175000017500000000115714516512250025125 0ustar00jpakkanejpakkane#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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/118 llvm ir and assembly/square.ll0000644000175000017500000000011314516512250024365 0ustar00jpakkanejpakkanedefine i32 @square_unsigned(i32 %a) { %1 = mul i32 %a, %a ret i32 %1 } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/118 llvm ir and assembly/symbol-underscore.h0000644000175000017500000000017314516512250026367 0ustar00jpakkanejpakkane#if defined(MESON_TEST__UNDERSCORE_SYMBOL) # define SYMBOL_NAME(name) _##name #else # define SYMBOL_NAME(name) name #endif ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.3986495 meson-1.3.2/test cases/common/119 cpp and asm/0000755000175000017500000000000014562742414020730 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421551.0 meson-1.3.2/test cases/common/119 cpp and asm/meson.build0000644000175000017500000000156514516755457023113 0ustar00jpakkanejpakkaneproject('c++ and assembly test') add_languages('cpp') if meson.backend() == 'xcode' error('MESON_SKIP_TEST: asm not supported with the Xcode backend. Patches welcome.') endif 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/119 cpp and asm/retval-arm.S0000644000175000017500000000026214516512250023116 0ustar00jpakkanejpakkane#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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/119 cpp and asm/retval-x86.S0000644000175000017500000000026114516512250022763 0ustar00jpakkanejpakkane#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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/119 cpp and asm/retval-x86_64.S0000644000175000017500000000026114516512250023274 0ustar00jpakkanejpakkane#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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/119 cpp and asm/symbol-underscore.h0000644000175000017500000000017314516512250024546 0ustar00jpakkanejpakkane#if defined(MESON_TEST__UNDERSCORE_SYMBOL) # define SYMBOL_NAME(name) _##name #else # define SYMBOL_NAME(name) name #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/119 cpp and asm/trivial.cc0000644000175000017500000000041314516512250022677 0ustar00jpakkanejpakkane#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 } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.4146497 meson-1.3.2/test cases/common/12 data/0000755000175000017500000000000014562742414017503 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/12 data/datafile.dat0000644000175000017500000000002413716006331021731 0ustar00jpakkanejpakkanethis is a data file ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/12 data/etcfile.dat0000644000175000017500000000004013716006331021571 0ustar00jpakkanejpakkaneThis goes into /etc/etcfile.dat ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/12 data/fileobject_datafile.dat0000644000175000017500000000007113716006331024121 0ustar00jpakkanejpakkaneThis is a data file that is installed via a File object. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421450.0 meson-1.3.2/test cases/common/12 data/meson.build0000644000175000017500000000220714516755312021646 0ustar00jpakkanejpakkaneproject('data install test', 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') install_data('subdir/data.txt', preserve_path : true) subproject('moredata') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/12 data/runscript.sh0000644000175000017500000000003413716006331022054 0ustar00jpakkanejpakkane#!/bin/sh echo "Runscript" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/12 data/somefile.txt0000644000175000017500000000000013716006331022024 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.4146497 meson-1.3.2/test cases/common/12 data/subdir/0000755000175000017500000000000014562742414020773 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336264.0 meson-1.3.2/test cases/common/12 data/subdir/data.txt0000644000175000017500000000000014516507010022421 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.7826247 meson-1.3.2/test cases/common/12 data/subprojects/0000755000175000017500000000000014562742413022045 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.4186497 meson-1.3.2/test cases/common/12 data/subprojects/moredata/0000755000175000017500000000000014562742414023642 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336264.0 meson-1.3.2/test cases/common/12 data/subprojects/moredata/data.txt0000644000175000017500000000000114516507010025271 0ustar00jpakkanejpakkane ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336264.0 meson-1.3.2/test cases/common/12 data/subprojects/moredata/meson.build0000644000175000017500000000005614516507010025773 0ustar00jpakkanejpakkaneproject('moredata') install_data('data.txt') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336264.0 meson-1.3.2/test cases/common/12 data/test.json0000644000175000017500000000160714516507010021347 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/share/progname/datafile.dat"}, {"type": "file", "file": "usr/share/progname/fileobject_datafile.dat"}, {"type": "file", "file": "usr/share/progname/vanishing.dat"}, {"type": "file", "file": "usr/share/progname/vanishing2.dat"}, {"type": "file", "file": "usr/share/data install test/renamed file.txt"}, {"type": "file", "file": "usr/share/data install test/somefile.txt"}, {"type": "file", "file": "usr/share/data install test/some/nested/path.txt"}, {"type": "file", "file": "usr/share/renamed/renamed 2.txt"}, {"type": "file", "file": "usr/share/renamed/renamed 3.txt"}, {"type": "file", "file": "etc/etcfile.dat"}, {"type": "file", "file": "usr/bin/runscript.sh"}, {"type": "file", "file": "usr/share/moredata/data.txt"}, {"type": "file", "file": "usr/share/data install test/subdir/data.txt"} ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/12 data/to_be_renamed_1.txt0000644000175000017500000000000013716006331023224 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/12 data/to_be_renamed_3.txt0000644000175000017500000000000013716006331023226 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/12 data/to_be_renamed_4.txt0000644000175000017500000000000013716006331023227 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.4226499 meson-1.3.2/test cases/common/12 data/vanishing/0000755000175000017500000000000014562742414021471 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/12 data/vanishing/meson.build0000644000175000017500000000011013716006331023612 0ustar00jpakkanejpakkaneinstall_data(sources : 'vanishing.dat', install_dir : 'share/progname') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/12 data/vanishing/to_be_renamed_2.txt0000644000175000017500000000000013716006331025213 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/12 data/vanishing/vanishing.dat0000644000175000017500000000006713716006331024143 0ustar00jpakkanejpakkaneThis is a data file to be installed in a subdirectory. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/12 data/vanishing/vanishing2.dat0000644000175000017500000000023613716006331024223 0ustar00jpakkanejpakkaneThis 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. ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1707853068.43865 meson-1.3.2/test cases/common/120 extract all shared library/0000755000175000017500000000000014562742414023731 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/120 extract all shared library/extractor.h0000644000175000017500000000012214516512250026100 0ustar00jpakkanejpakkane#pragma once int func1(void); int func2(void); int func3(void); int func4(void); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/120 extract all shared library/four.c0000644000175000017500000000007114516512250025036 0ustar00jpakkanejpakkane#include"extractor.h" int func4(void) { return 4; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/120 extract all shared library/func1234.def0000644000175000017500000000004414516512250025644 0ustar00jpakkanejpakkaneEXPORTS func1 func2 func3 func4 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421551.0 meson-1.3.2/test cases/common/120 extract all shared library/meson.build0000644000175000017500000000101014516755457026075 0ustar00jpakkanejpakkaneproject('extract all', 'c', 'cpp') if meson.backend() == 'xcode' error('MESON_SKIP_TEST: Xcode backend does not handle libraries with only objects, not sources.') endif a = static_library('a', 'one.c', 'two.c') b = static_library('b', 'three.c', 'four.c') # libc.so cannot be used, it already exists as a reserved name c = shared_library('cee', 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/120 extract all shared library/one.c0000644000175000017500000000007114516512250024644 0ustar00jpakkanejpakkane#include"extractor.h" int func1(void) { return 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/120 extract all shared library/prog.c0000644000175000017500000000031214516512250025030 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/120 extract all shared library/three.c0000644000175000017500000000007114516512250025172 0ustar00jpakkanejpakkane#include"extractor.h" int func3(void) { return 3; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/120 extract all shared library/two.c0000644000175000017500000000007114516512250024674 0ustar00jpakkanejpakkane#include"extractor.h" int func2(void) { return 2; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.4506502 meson-1.3.2/test cases/common/121 object only target/0000755000175000017500000000000014562742414022332 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421553.0 meson-1.3.2/test cases/common/121 object only target/meson.build0000644000175000017500000000263614516755461024510 0ustar00jpakkanejpakkaneproject('object generator', 'c') if meson.backend() == 'xcode' error('MESON_SKIP_TEST object-only libraries not supported in Xcode. Patches welcome.') endif # 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) subdir('objdir') e = executable('prog', 'prog.c', link_with : [obj, shr, stc, subdirfilebuilt_obj, subdirfile_obj, subdirstr_obj], install : true) test('objgen', e) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/121 object only target/obj_generator.py0000755000175000017500000000115214516512250025516 0ustar00jpakkanejpakkane#!/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] elif sys.platform == 'sunos5': cmd = [compiler, '-fpic', '-c', ifile, '-o', ofile] else: cmd = [compiler, '-c', ifile, '-o', ofile] sys.exit(subprocess.call(cmd)) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.4586504 meson-1.3.2/test cases/common/121 object only target/objdir/0000755000175000017500000000000014562742414023603 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/121 object only target/objdir/meson.build0000644000175000017500000000157314516512250025743 0ustar00jpakkanejpakkane #mesonlib.File built source4 = configure_file(input : 'source4.c', output : 'source4' + ext, command : [comp, cc, files('source4.c'), join_paths(meson.current_build_dir(), 'source4' + ext)]) subdirfilebuilt_obj = static_library('subdirfilebuilt_obj', objects : source4) #mesonlib.File not built configure_file(input : 'source5.c', output : 'source5' + ext, command : [comp, cc, files('source5.c'), join_paths(meson.current_build_dir(), 'source5' + ext)]) subdirfile_obj = static_library('subdirfile_obj', objects : files(meson.current_build_dir()/'source5' + ext)) #str configure_file(input : 'source6.c', output : 'source6' + ext, command : [comp, cc, files('source6.c'), join_paths(meson.current_build_dir(), 'source6' + ext)]) subdirstr_obj = static_library('subdirstr_obj', objects : meson.current_build_dir()/'source6' + ext) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/121 object only target/objdir/source4.c0000644000175000017500000000005114516512250025317 0ustar00jpakkanejpakkaneint func4_in_obj(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/121 object only target/objdir/source5.c0000644000175000017500000000005114516512250025320 0ustar00jpakkanejpakkaneint func5_in_obj(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/121 object only target/objdir/source6.c0000644000175000017500000000005114516512250025321 0ustar00jpakkanejpakkaneint func6_in_obj(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/121 object only target/prog.c0000644000175000017500000000043514516512250023437 0ustar00jpakkanejpakkaneint func1_in_obj(void); int func2_in_obj(void); int func3_in_obj(void); int func4_in_obj(void); int func5_in_obj(void); int func6_in_obj(void); int main(void) { return func1_in_obj() + func2_in_obj() + func3_in_obj() + func4_in_obj() + func5_in_obj() + func6_in_obj(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/121 object only target/source.c0000644000175000017500000000005114516512250023762 0ustar00jpakkanejpakkaneint func1_in_obj(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/121 object only target/source2.c0000644000175000017500000000005114516512250024044 0ustar00jpakkanejpakkaneint func2_in_obj(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/121 object only target/source2.def0000644000175000017500000000003514516512250024362 0ustar00jpakkanejpakkaneEXPORTS func2_in_obj ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/121 object only target/source3.c0000644000175000017500000000005114516512250024045 0ustar00jpakkanejpakkaneint func3_in_obj(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/121 object only target/test.json0000644000175000017500000000016214516515714024203 0ustar00jpakkanejpakkane{ "installed": [ {"type": "exe", "file": "usr/bin/prog"}, {"type": "pdb", "file": "usr/bin/prog"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.4626503 meson-1.3.2/test cases/common/122 no buildincdir/0000755000175000017500000000000014562742414021541 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.4666505 meson-1.3.2/test cases/common/122 no buildincdir/include/0000755000175000017500000000000014562742414023164 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/122 no buildincdir/include/header.h0000644000175000017500000000004014516512250024547 0ustar00jpakkanejpakkane#pragma once int foobar(void); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421552.0 meson-1.3.2/test cases/common/122 no buildincdir/meson.build0000644000175000017500000000056714516755460023717 0ustar00jpakkanejpakkaneproject('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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/122 no buildincdir/prog.c0000644000175000017500000000006514516512250022645 0ustar00jpakkanejpakkane#include"header.h" int main(void) { return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.4666505 meson-1.3.2/test cases/common/123 custom target directory install/0000755000175000017500000000000014562742414025052 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/123 custom target directory install/docgen.py0000644000175000017500000000035114516512250026652 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import os import sys out = sys.argv[1] try: os.mkdir(out) except FileExistsError: pass for name in ('a', 'b', 'c'): with open(os.path.join(out, name + '.html'), 'w') as f: f.write(name) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421554.0 meson-1.3.2/test cases/common/123 custom target directory install/meson.build0000644000175000017500000000035714516755462027227 0ustar00jpakkanejpakkaneproject('custom-target-dir-install') docgen = find_program('docgen.py') custom_target('docgen', output : 'html', command : [docgen, '@OUTPUT@'], install : true, install_dir : join_paths(get_option('datadir'), 'doc/testpkgname')) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/123 custom target directory install/test.json0000644000175000017500000000035514516515714026727 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/share/doc/testpkgname/html/a.html"}, {"type": "file", "file": "usr/share/doc/testpkgname/html/b.html"}, {"type": "file", "file": "usr/share/doc/testpkgname/html/c.html"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.4746506 meson-1.3.2/test cases/common/124 dependency file generation/0000755000175000017500000000000014562742414024010 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/124 dependency file generation/main .c0000644000175000017500000000003714516512250025130 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421555.0 meson-1.3.2/test cases/common/124 dependency file generation/meson.build0000644000175000017500000000107614516755463026165 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.4786506 meson-1.3.2/test cases/common/125 configure file in generator/0000755000175000017500000000000014562742414024076 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.4786506 meson-1.3.2/test cases/common/125 configure file in generator/inc/0000755000175000017500000000000014562742414024647 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/125 configure file in generator/inc/confdata.in0000644000175000017500000000001014516512250026735 0ustar00jpakkanejpakkane@VALUE@ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/125 configure file in generator/inc/meson.build0000644000175000017500000000022114516512250026774 0ustar00jpakkanejpakkanecdata = configuration_data() cdata.set('VALUE', '42') cfile = configure_file(input : 'confdata.in', output : 'confdata', configuration : cdata) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421555.0 meson-1.3.2/test cases/common/125 configure file in generator/meson.build0000644000175000017500000000010414516755463026242 0ustar00jpakkanejpakkaneproject('conf file in generator', 'c') subdir('inc') subdir('src') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.4826508 meson-1.3.2/test cases/common/125 configure file in generator/src/0000755000175000017500000000000014562742414024665 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/125 configure file in generator/src/gen.py0000755000175000017500000000034314516512250026003 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys ifile = sys.argv[1] ofile = sys.argv[2] with open(ifile) as f: resval = f.readline().strip() templ = '#define RESULT (%s)\n' with open(ofile, 'w') as f: f.write(templ % (resval, )) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/125 configure file in generator/src/main.c0000644000175000017500000000040014516512250025737 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/125 configure file in generator/src/meson.build0000644000175000017500000000031314516512250027014 0ustar00jpakkanejpakkanecompiler = find_program('gen.py') gen = generator(compiler, output: '@BASENAME@.h', arguments : ['@INPUT@', '@OUTPUT@']) hs = gen.process(cfile, files('source')) executable('proggie', 'main.c', hs) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/125 configure file in generator/src/source0000644000175000017500000000000314516512250026071 0ustar00jpakkanejpakkane23 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.4826508 meson-1.3.2/test cases/common/126 generated llvm ir/0000755000175000017500000000000014562742414022144 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/126 generated llvm ir/copyfile.py0000644000175000017500000000013414516512250024316 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys import shutil shutil.copyfile(sys.argv[1], sys.argv[2]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/126 generated llvm ir/main.c0000644000175000017500000000032314516512250023222 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/126 generated llvm ir/meson.build0000644000175000017500000000143314516512250024277 0ustar00jpakkanejpakkaneproject('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 if meson.backend() == 'xcode' error('MESON_SKIP_TEST: LLVM ir not supported with the Xcode backend. Patches welcome.') endif copy = find_program('copyfile.py') copygen = generator(copy, arguments : ['@INPUT@', '@OUTPUT@'], output : '@BASENAME@') l = 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 = library('square-ct', copyct) test('square-ct-test', executable('square-ct-test', 'main.c', link_with : l)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/126 generated llvm ir/square.ll.in0000644000175000017500000000011314516512250024365 0ustar00jpakkanejpakkanedefine i32 @square_unsigned(i32 %a) { %1 = mul i32 %a, %a ret i32 %1 } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.4946508 meson-1.3.2/test cases/common/127 generated assembly/0000755000175000017500000000000014562742414022417 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/127 generated assembly/copyfile.py0000644000175000017500000000013414516512250024571 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys import shutil shutil.copyfile(sys.argv[1], sys.argv[2]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/127 generated assembly/empty.c0000644000175000017500000000000014516512250023677 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/127 generated assembly/main.c0000644000175000017500000000043414516512250023500 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421559.0 meson-1.3.2/test cases/common/127 generated assembly/meson.build0000644000175000017500000000404014516755467024572 0ustar00jpakkanejpakkaneproject('generated assembly', 'c') cc = meson.get_compiler('c') if ['msvc', 'intel-cl'].contains(cc.get_id()) error('MESON_SKIP_TEST: assembly files cannot be compiled directly by the compiler') endif if meson.backend() == 'xcode' error('MESON_SKIP_TEST: asm not supported with the Xcode backend. Patches welcome.') endif crt_workaround = [] if cc.get_linker_id() == 'lld-link' # It seems that when building without a .c file, lld-link.exe # misses the fact that it needs to include the c runtime to # make a working .dll. So here we add an empty .c file to easily # pull in crt. crt_workaround += 'empty.c' if host_machine.cpu_family() == 'x86' # x86 assembly needs manual annotation to be compatible with # Safe Exception Handlers (?) This assembly doesn't have such # annotation, so just disable the feature. add_project_link_arguments('/SAFESEH:NO', language : 'c') endif 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.get_id() == 'clang-cl' and cc.version().version_compare('< 12.0.0') and cpu == 'arm' # https://reviews.llvm.org/D89622 error('MESON_SKIP_TEST: arm debug symbols not supported in clang-cl < 12.0.0') 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 = library('square-gen', crt_workaround + [copygen.process(input)], vs_module_defs: 'square.def') 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 = library('square-ct', crt_workaround + [copyct], vs_module_defs: 'square.def') test('square-ct-test', executable('square-ct-test', 'main.c', link_with : l)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/127 generated assembly/square-arm.S.in0000644000175000017500000000046714516512250025224 0ustar00jpakkanejpakkane#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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/127 generated assembly/square-x86.S.in0000644000175000017500000000105514516512250025064 0ustar00jpakkanejpakkane#include "symbol-underscore.h" #if defined(_MSC_VER) && !defined(__clang__) .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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/127 generated assembly/square-x86_64.S.in0000644000175000017500000000136414516512250025400 0ustar00jpakkanejpakkane#include "symbol-underscore.h" #if defined(_MSC_VER) && !defined(__clang__) /* 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/127 generated assembly/square.def0000644000175000017500000000003114516512250024361 0ustar00jpakkanejpakkaneEXPORTS square_unsigned ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/127 generated assembly/symbol-underscore.h0000644000175000017500000000017314516512250026235 0ustar00jpakkanejpakkane#if defined(MESON_TEST__UNDERSCORE_SYMBOL) # define SYMBOL_NAME(name) _##name #else # define SYMBOL_NAME(name) name #endif ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.4946508 meson-1.3.2/test cases/common/128 build by default targets in tests/0000755000175000017500000000000014562742414025125 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/128 build by default targets in tests/main.c0000644000175000017500000000003714516512250026205 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421559.0 meson-1.3.2/test cases/common/128 build by default targets in tests/meson.build0000644000175000017500000000164414516755467027307 0ustar00jpakkanejpakkaneproject('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]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/128 build by default targets in tests/write_file.py0000644000175000017500000000013214516512250027614 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys with open(sys.argv[1], 'w') as f: f.write('Test') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.498651 meson-1.3.2/test cases/common/129 build by default/0000755000175000017500000000000014562742414021762 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/129 build by default/checkexists.py0000644000175000017500000000030414516512250024636 0ustar00jpakkanejpakkane#!/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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/129 build by default/foo.c0000644000175000017500000000012514516512250022677 0ustar00jpakkanejpakkane#include int main(void) { printf("Existentialism.\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421559.0 meson-1.3.2/test cases/common/129 build by default/meson.build0000644000175000017500000000212114516755467024133 0ustar00jpakkanejpakkaneproject('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, ) 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]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/129 build by default/mygen.py0000644000175000017500000000017014516512250023441 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys ifile = open(sys.argv[1]) ofile = open(sys.argv[2], 'w') ofile.write(ifile.read()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/129 build by default/source.txt0000644000175000017500000000002614516512250024011 0ustar00jpakkanejpakkaneI am a bunch of text. ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.498651 meson-1.3.2/test cases/common/13 pch/0000755000175000017500000000000014562742414017345 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.502651 meson-1.3.2/test cases/common/13 pch/c/0000755000175000017500000000000014562742415017570 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/c/meson.build0000644000175000017500000000043013716006331021715 0ustar00jpakkanejpakkanecc = 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') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.502651 meson-1.3.2/test cases/common/13 pch/c/pch/0000755000175000017500000000000014562742415020342 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/c/pch/prog.h0000644000175000017500000000025113716006331021446 0ustar00jpakkanejpakkane#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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/common/13 pch/c/prog.c0000644000175000017500000000027614140314117020672 0ustar00jpakkanejpakkane// 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; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.506651 meson-1.3.2/test cases/common/13 pch/cpp/0000755000175000017500000000000014562742415020130 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/cpp/meson.build0000644000175000017500000000007513716006331022262 0ustar00jpakkanejpakkaneexe = executable('prog', 'prog.cc', cpp_pch : 'pch/prog.hh') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.506651 meson-1.3.2/test cases/common/13 pch/cpp/pch/0000755000175000017500000000000014562742415020702 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/cpp/pch/prog.hh0000644000175000017500000000002313716006331022153 0ustar00jpakkanejpakkane#include ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/cpp/prog.cc0000644000175000017500000000046113716006331021375 0ustar00jpakkanejpakkane// 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; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.506651 meson-1.3.2/test cases/common/13 pch/generated/0000755000175000017500000000000014562742415021304 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/generated/gen_custom.py0000644000175000017500000000014213716006331024004 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys with open(sys.argv[1], 'w') as f: f.write("#define FOO 0") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/generated/gen_generator.py0000644000175000017500000000021613716006331024462 0ustar00jpakkanejpakkane#!/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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/generated/generated_generator.in0000644000175000017500000000001613716006331025623 0ustar00jpakkanejpakkane#define BAR 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/generated/meson.build0000644000175000017500000000120113716006331023426 0ustar00jpakkanejpakkanecc = 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') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.506651 meson-1.3.2/test cases/common/13 pch/generated/pch/0000755000175000017500000000000014562742415022056 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/generated/pch/prog.h0000644000175000017500000000010513716006331023160 0ustar00jpakkanejpakkane#include "generated_customTarget.h" #include "generated_generator.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/common/13 pch/generated/prog.c0000644000175000017500000000013614140314117022401 0ustar00jpakkanejpakkane// No includes here, they need to come from the PCH int main(void) { return FOO + BAR; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.514651 meson-1.3.2/test cases/common/13 pch/linkwhole/0000755000175000017500000000000014562742415021342 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667329211.0 meson-1.3.2/test cases/common/13 pch/linkwhole/lib1.c0000644000175000017500000000007414330266273022332 0ustar00jpakkanejpakkanevoid func1() { printf("Calling func2."); func2(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667329211.0 meson-1.3.2/test cases/common/13 pch/linkwhole/lib2.c0000644000175000017500000000016614330266273022335 0ustar00jpakkanejpakkane#include void func2() { const char *cl = GetCommandLineA(); printf("Command line was: %s\n", cl); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667329211.0 meson-1.3.2/test cases/common/13 pch/linkwhole/main.c0000644000175000017500000000020014330266273022416 0ustar00jpakkanejpakkane#include void func1(); int main(int argc, char **argv) { printf("Calling func1\n"); func1(); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667329211.0 meson-1.3.2/test cases/common/13 pch/linkwhole/meson.build0000644000175000017500000000036514330266273023504 0ustar00jpakkanejpakkane# https://github.com/mesonbuild/meson/issues/10745 l2 = static_library('two', 'lib2.c', c_pch: 'pch2/pch_two.h') l1 = static_library('one', 'lib1.c', c_pch: 'pch1/pch_one.h', link_whole: l2) executable('linkprog', 'main.c', link_with: l1) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.514651 meson-1.3.2/test cases/common/13 pch/linkwhole/pch1/0000755000175000017500000000000014562742415022175 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667329211.0 meson-1.3.2/test cases/common/13 pch/linkwhole/pch1/pch_one.h0000644000175000017500000000007114330266273023753 0ustar00jpakkanejpakkane#ifndef PCH_ONE #define PCH_ONE #include #endif ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.514651 meson-1.3.2/test cases/common/13 pch/linkwhole/pch2/0000755000175000017500000000000014562742415022176 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667329211.0 meson-1.3.2/test cases/common/13 pch/linkwhole/pch2/pch_two.h0000644000175000017500000000007314330266273024006 0ustar00jpakkanejpakkane#ifndef PCH_TWO #define PCH_TWO #include #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421454.0 meson-1.3.2/test cases/common/13 pch/meson.build0000644000175000017500000000163514516755316021520 0ustar00jpakkanejpakkaneproject('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 does not support forced includes. Skipping "withIncludeFile" which requires this.') else subdir('withIncludeFile') endif 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 if cc_id == 'msvc' subdir('linkwhole') endif ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5186512 meson-1.3.2/test cases/common/13 pch/mixed/0000755000175000017500000000000014562742415020454 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/mixed/func.c0000644000175000017500000000021613716006331021540 0ustar00jpakkanejpakkanevoid tmp_func(void) { fprintf(stdout, "This is a function that fails if stdio is not #included.\n"); } int cfunc(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/mixed/main.cc0000644000175000017500000000031213716006331021671 0ustar00jpakkanejpakkaneextern "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(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/mixed/meson.build0000644000175000017500000000036613716006331022611 0ustar00jpakkanejpakkanecc = 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'], ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5186512 meson-1.3.2/test cases/common/13 pch/mixed/pch/0000755000175000017500000000000014562742415021226 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/mixed/pch/func.h0000644000175000017500000000002213716006331022312 0ustar00jpakkanejpakkane#include ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/mixed/pch/main.h0000644000175000017500000000002313716006331022304 0ustar00jpakkanejpakkane#include ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5226512 meson-1.3.2/test cases/common/13 pch/userDefined/0000755000175000017500000000000014562742415021603 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/userDefined/meson.build0000644000175000017500000000057113716006331023736 0ustar00jpakkanejpakkanecc = 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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5226512 meson-1.3.2/test cases/common/13 pch/userDefined/pch/0000755000175000017500000000000014562742415022355 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/userDefined/pch/pch.c0000644000175000017500000000006213716006331023257 0ustar00jpakkanejpakkane#include "pch.h" int foo(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/userDefined/pch/pch.h0000644000175000017500000000001313716006331023260 0ustar00jpakkanejpakkaneint foo(); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/userDefined/prog.c0000644000175000017500000000040313716006331022701 0ustar00jpakkanejpakkane// 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(); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5226512 meson-1.3.2/test cases/common/13 pch/withIncludeDirectories/0000755000175000017500000000000014562742415024022 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853066.786625 meson-1.3.2/test cases/common/13 pch/withIncludeDirectories/include/0000755000175000017500000000000014562742413025443 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5226512 meson-1.3.2/test cases/common/13 pch/withIncludeDirectories/include/lib/0000755000175000017500000000000014562742415026213 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/withIncludeDirectories/include/lib/lib.h0000644000175000017500000000002313716006331027113 0ustar00jpakkanejpakkane#include ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/withIncludeDirectories/meson.build0000644000175000017500000000047413716006331026157 0ustar00jpakkanejpakkanecc = 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') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5226512 meson-1.3.2/test cases/common/13 pch/withIncludeDirectories/pch/0000755000175000017500000000000014562742415024574 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/13 pch/withIncludeDirectories/pch/prog.h0000644000175000017500000000002413716006331025676 0ustar00jpakkanejpakkane#include ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/common/13 pch/withIncludeDirectories/prog.c0000644000175000017500000000027614140314117025124 0ustar00jpakkanejpakkane// 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; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5226512 meson-1.3.2/test cases/common/13 pch/withIncludeFile/0000755000175000017500000000000014562742415022425 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/common/13 pch/withIncludeFile/meson.build0000644000175000017500000000060314107166547024567 0ustar00jpakkanejpakkanecc = meson.get_compiler('c') cc_id = cc.get_id() if cc_id == 'lcc' error('MESON_SKIP_TEST: Elbrus compiler does not support PCH.') endif if cc.get_argument_syntax() == 'gcc' c_args = ['-include', 'locale.h'] elif cc.get_argument_syntax() == 'msvc' c_args = ['/FI' + 'locale.h'] else subdir_done() endif exe = executable('prog', 'prog.c', c_args: c_args, c_pch : 'pch/prog.h') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5266514 meson-1.3.2/test cases/common/13 pch/withIncludeFile/pch/0000755000175000017500000000000014562742415023177 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/common/13 pch/withIncludeFile/pch/prog.h0000644000175000017500000000025114107166547024316 0ustar00jpakkanejpakkane#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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/common/13 pch/withIncludeFile/prog.c0000644000175000017500000000044014140314117023520 0ustar00jpakkanejpakkane// No includes here, they need to come from the PCH or explicit inclusion void func(void) { fprintf(stdout, "This is a function that fails if stdio is not #included.\n"); setlocale(LC_ALL, ""); /* This will fail if locale.h is not included */ } int main(void) { return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5266514 meson-1.3.2/test cases/common/130 include order/0000755000175000017500000000000014562742415021373 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5306513 meson-1.3.2/test cases/common/130 include order/ctsub/0000755000175000017500000000000014562742415022513 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/130 include order/ctsub/copyfile.py0000644000175000017500000000013414516512250024664 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys import shutil shutil.copyfile(sys.argv[1], sys.argv[2]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/130 include order/ctsub/emptyfile.c0000644000175000017500000000000014516512250024632 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/130 include order/ctsub/main.h0000644000175000017500000000003714516512250023577 0ustar00jpakkanejpakkane#error "ctsub/main.h included" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/130 include order/ctsub/meson.build0000644000175000017500000000061714516512250024650 0ustar00jpakkanejpakkane# 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@']) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5306513 meson-1.3.2/test cases/common/130 include order/inc1/0000755000175000017500000000000014562742415022225 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/130 include order/inc1/hdr.h0000644000175000017500000000002714516512250023141 0ustar00jpakkanejpakkane#define SOME_DEFINE 42 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5306513 meson-1.3.2/test cases/common/130 include order/inc2/0000755000175000017500000000000014562742415022226 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/130 include order/inc2/hdr.h0000644000175000017500000000002314516512250023136 0ustar00jpakkanejpakkane#undef SOME_DEFINE ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5306513 meson-1.3.2/test cases/common/130 include order/inc3/0000755000175000017500000000000014562742415022227 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/130 include order/inc3/meson.build0000644000175000017500000000015614516512250024362 0ustar00jpakkanejpakkaneconfigure_file(output: 'prefer-build-dir-over-src-dir.h', configuration: configuration_data()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/130 include order/inc3/prefer-build-dir-over-src-dir.h0000644000175000017500000000006714516512250030040 0ustar00jpakkanejpakkane#error "inc3/prefer-build-dir-over-src-dir.h included" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421560.0 meson-1.3.2/test cases/common/130 include order/meson.build0000644000175000017500000000257414516755470023551 0ustar00jpakkanejpakkaneproject('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') # Configures a header file subdir('inc3') # 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', 'inc3') executable('ordertest', 'ordertest.c', include_directories: incs) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/130 include order/ordertest.c0000644000175000017500000000031014516512250023533 0ustar00jpakkanejpakkane#include "hdr.h" #include "prefer-build-dir-over-src-dir.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; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5346515 meson-1.3.2/test cases/common/130 include order/sub1/0000755000175000017500000000000014562742415022245 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/130 include order/sub1/main.h0000644000175000017500000000003614516512250023330 0ustar00jpakkanejpakkane#error "sub1/main.h included" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/130 include order/sub1/meson.build0000644000175000017500000000023714516512250024400 0ustar00jpakkanejpakkanei = include_directories('.') l = shared_library('somelib', 'some.c') dep = declare_dependency(link_with : l, include_directories : i) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/130 include order/sub1/some.c0000644000175000017500000000015614516512250023345 0ustar00jpakkanejpakkane#if defined _WIN32 || defined __CYGWIN__ __declspec(dllexport) #endif int somefunc(void) { return 1984; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/130 include order/sub1/some.h0000644000175000017500000000024414516512250023350 0ustar00jpakkanejpakkane#pragma once #if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllimport) #else #define DLL_PUBLIC #endif DLL_PUBLIC int somefunc(void); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5346515 meson-1.3.2/test cases/common/130 include order/sub2/0000755000175000017500000000000014562742415022246 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/130 include order/sub2/main.h0000644000175000017500000000003614516512250023331 0ustar00jpakkanejpakkane#error "sub2/main.h included" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/130 include order/sub2/meson.build0000644000175000017500000000012414516512250024374 0ustar00jpakkanejpakkanej = include_directories('.') wronginc = declare_dependency(include_directories : j) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5386515 meson-1.3.2/test cases/common/130 include order/sub3/0000755000175000017500000000000014562742415022247 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/130 include order/sub3/main.h0000644000175000017500000000003614516512250023332 0ustar00jpakkanejpakkane#error "sub3/main.h included" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/130 include order/sub3/meson.build0000644000175000017500000000004214516512250024374 0ustar00jpakkanejpakkanesub3 = meson.current_source_dir() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5386515 meson-1.3.2/test cases/common/130 include order/sub4/0000755000175000017500000000000014562742415022250 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/130 include order/sub4/main.c0000644000175000017500000000024614516512250023331 0ustar00jpakkanejpakkane/* Use the <> include notation to force searching in include directories */ #include int main(void) { if (somefunc() == 1984) return 0; return 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/130 include order/sub4/main.h0000644000175000017500000000004014516512250023326 0ustar00jpakkanejpakkane#pragma once #include "some.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/130 include order/sub4/meson.build0000644000175000017500000000035714516512250024406 0ustar00jpakkanejpakkanee = executable('someexe', 'main.c', ctfile, c_args : ['-I' + sub3], include_directories : j, dependencies : dep) correctinc = declare_dependency(include_directories : include_directories('.')) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5466516 meson-1.3.2/test cases/common/131 override options/0000755000175000017500000000000014562742415022150 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/131 override options/four.c0000644000175000017500000000017614516512250023262 0ustar00jpakkanejpakkaneint func(void); static int duplicate_func(void) { return -4; } int main(void) { return duplicate_func() + func(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421563.0 meson-1.3.2/test cases/common/131 override options/meson.build0000644000175000017500000000027314516755473024323 0ustar00jpakkanejpakkaneproject('option override', 'c', default_options : 'unity=on') executable('mustunity', 'one.c', 'two.c') executable('notunity', 'three.c', 'four.c', override_options : ['unity=off']) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/131 override options/one.c0000644000175000017500000000005714516512250023066 0ustar00jpakkanejpakkanestatic int hidden_func(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/131 override options/three.c0000644000175000017500000000014314516512250023410 0ustar00jpakkanejpakkanestatic int duplicate_func(void) { return 4; } int func(void) { return duplicate_func(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/131 override options/two.c0000644000175000017500000000016714516512250023120 0ustar00jpakkanejpakkane/* * Requires a Unity build. Otherwise hidden_func is not specified. */ int main(void) { return hidden_func(); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5466516 meson-1.3.2/test cases/common/132 get define/0000755000175000017500000000000014562742415020650 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/132 get define/concat.h0000644000175000017500000000122614516512250022260 0ustar00jpakkanejpakkane#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" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421565.0 meson-1.3.2/test cases/common/132 get define/meson.build0000644000175000017500000001202714516755475023025 0ustar00jpakkanejpakkaneproject('get define', 'c', 'cpp') host_system = host_machine.system() system_define_map = { 'linux' : ['__linux__', '1'], 'darwin' : ['__APPLE__', '1'], 'windows' : ['_WIN32', '1'], 'cygwin' : ['__CYGWIN__', '1'], 'haiku' : ['__HAIKU__', '1'], 'dragonfly' : ['__DragonFly__', '1'], 'netbsd' : ['__NetBSD__', '1'], 'openbsd' : ['__OpenBSD__', '1'], 'gnu' : ['__GNU__', '1'], 'sunos' : ['__sun__', '1'], # 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. 'freebsd' : ['__FreeBSD__'], } foreach lang : ['c', 'cpp'] cc = meson.get_compiler(lang) if not system_define_map.has_key(host_system) error('Please report a bug and help us improve support for this platform') endif system_define = system_define_map.get(host_system) def_name = system_define[0] def_val = cc.get_define(system_define[0]) def_exist = cc.has_define(system_define[0]) assert((def_val != '') == def_exist, 'The has_define and get_define results for @0@ disagree with each other'.format(def_name)) if system_define.length() == 2 assert(def_val == system_define[1], '@0@ value is @1@ instead of @2@'.format(def_name, def_val, system_define[1])) elif system_define.length() == 1 assert(def_val != '', '@0@ value is unset'.format(def_name)) else error('Invalid number of items in system_define array, this is a bug in the test!') 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_val = cc.get_define('MESON_FAIL_VALUE') have = cc.has_define('MESON_FAIL_VALUE') assert(have_val == '', 'MESON_FAIL_VALUE value is "@0@" instead of ""'.format(have_val)) assert(not have, 'MESON_FAIL_VALUE was found even though it should not have been') # Check that an empty define is reported as existing. have_val = cc.get_define('MESON_EMPTY_VALUE', prefix: ['#define MESON_EMPTY_VALUE']) have = cc.has_define('MESON_EMPTY_VALUE', prefix: ['#define MESON_EMPTY_VALUE']) assert(have_val == '', 'MESON_EMPTY_VALUE value is "@0@" instead of ""'.format(have_val)) assert(have, 'MESON_EMPTY_VALUE was not found even though it should have been') # Check if prefix array works properly and has the expected order have = cc.get_define('MESON_FAIL_VALUE', prefix: ['#define MESON_FAIL_VALUE 1', '#undef MESON_FAIL_VALUE']) assert(have == '', 'MESON_FAIL_VALUE value is "@0@" instead of ""'.format(have)) have = cc.get_define('MESON_SUCCESS_VALUE', prefix: ['#undef MESON_SUCCESS_VALUE', '#define MESON_SUCCESS_VALUE 1']) assert(have == '1', 'MESON_SUCCESS_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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/132 get define/meson_options.txt0000644000175000017500000000007714516512250024300 0ustar00jpakkanejpakkaneoption('MESON_TEST_DEFINE_VALUE', type : 'string', value : '') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/132 get define/test.json0000644000175000017500000000017214516515714022521 0ustar00jpakkanejpakkane{ "matrix": { "options": { "c_std": [ { "val": "none" }, { "val": "c11" } ] } } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5506518 meson-1.3.2/test cases/common/133 c cpp and asm/0000755000175000017500000000000014562742415021130 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/133 c cpp and asm/main.c0000644000175000017500000000017314516512250022210 0ustar00jpakkanejpakkane#include int get_retval(void); int main(void) { printf("C seems to be working.\n"); return get_retval(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/133 c cpp and asm/main.cpp0000644000175000017500000000026514516512250022552 0ustar00jpakkanejpakkane#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(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421566.0 meson-1.3.2/test cases/common/133 c cpp and asm/meson.build0000644000175000017500000000150214516755476023302 0ustar00jpakkanejpakkaneproject('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'])) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/133 c cpp and asm/retval-arm.S0000644000175000017500000000026214516512250023315 0ustar00jpakkanejpakkane#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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/133 c cpp and asm/retval-x86.S0000644000175000017500000000033014516512250023157 0ustar00jpakkanejpakkane#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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/133 c cpp and asm/retval-x86_64.S0000644000175000017500000000026114516512250023473 0ustar00jpakkanejpakkane#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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/133 c cpp and asm/somelib.c0000644000175000017500000000004414516512250022713 0ustar00jpakkanejpakkaneint get_cval (void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/133 c cpp and asm/symbol-underscore.h0000644000175000017500000000017314516512250024745 0ustar00jpakkanejpakkane#if defined(MESON_TEST__UNDERSCORE_SYMBOL) # define SYMBOL_NAME(name) _##name #else # define SYMBOL_NAME(name) name #endif ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5546517 meson-1.3.2/test cases/common/134 compute int/0000755000175000017500000000000014562742415021107 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/134 compute int/config.h.in0000644000175000017500000000015614516512250023123 0ustar00jpakkanejpakkane#define INTSIZE @INTSIZE@ #define FOOBAR_IN_CONFIG_H @FOOBAR@ #define MAXINT @MAXINT@ #define MININT @MININT@ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/134 compute int/foobar.h0000644000175000017500000000014514516512250022517 0ustar00jpakkanejpakkane#ifndef __FOOBAR_H__ #define __FOOBAR_H__ #define FOOBAR_IN_FOOBAR_H 10 #endif /*__FOOBAR_H__*/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421571.0 meson-1.3.2/test cases/common/134 compute int/meson.build0000644000175000017500000000320714516755503023254 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/134 compute int/prog.c.in0000644000175000017500000000140014516512250022611 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5546517 meson-1.3.2/test cases/common/135 custom target object output/0000755000175000017500000000000014562742415024212 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421570.0 meson-1.3.2/test cases/common/135 custom target object output/meson.build0000644000175000017500000000045614516755502026361 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/135 custom target object output/obj_generator.py0000644000175000017500000000101314516512250027366 0ustar00jpakkanejpakkane#!/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)) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5546517 meson-1.3.2/test cases/common/135 custom target object output/objdir/0000755000175000017500000000000014562742415025463 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/135 custom target object output/objdir/meson.build0000644000175000017500000000024114516512250027611 0ustar00jpakkanejpakkane# Generate an object file manually. object = custom_target('object', input : 'source.c', output : outputname, command : [comp, cc, '@INPUT@', '@OUTPUT@']) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/135 custom target object output/objdir/source.c0000644000175000017500000000005114516512250027112 0ustar00jpakkanejpakkaneint func1_in_obj(void) { return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5546517 meson-1.3.2/test cases/common/135 custom target object output/progdir/0000755000175000017500000000000014562742415025660 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/135 custom target object output/progdir/meson.build0000644000175000017500000000005114516512250030005 0ustar00jpakkanejpakkanee = executable('prog', 'prog.c', object) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/135 custom target object output/progdir/prog.c0000644000175000017500000000010714516512250026760 0ustar00jpakkanejpakkaneint func1_in_obj(void); int main(void) { return func1_in_obj(); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5546517 meson-1.3.2/test cases/common/136 empty build file/0000755000175000017500000000000014562742415022000 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421569.0 meson-1.3.2/test cases/common/136 empty build file/meson.build0000644000175000017500000000007714516755501024145 0ustar00jpakkanejpakkaneproject('subdir with empty meson.build test') subdir('subdir') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5546517 meson-1.3.2/test cases/common/136 empty build file/subdir/0000755000175000017500000000000014562742415023270 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/136 empty build file/subdir/meson.build0000644000175000017500000000000014516512250025407 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5546517 meson-1.3.2/test cases/common/137 whole archive/0000755000175000017500000000000014562742415021403 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5626519 meson-1.3.2/test cases/common/137 whole archive/exe/0000755000175000017500000000000014562742415022164 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/137 whole archive/exe/meson.build0000644000175000017500000000011114516512250024306 0ustar00jpakkanejpakkaneexe = executable('prog', '../prog.c', link_with : sh_func2_linked_func1) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5626519 meson-1.3.2/test cases/common/137 whole archive/exe2/0000755000175000017500000000000014562742415022246 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/137 whole archive/exe2/meson.build0000644000175000017500000000011014516512250024367 0ustar00jpakkanejpakkaneexe2 = executable('prog2', '../prog.c', link_with : sh_only_link_whole) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5626519 meson-1.3.2/test cases/common/137 whole archive/exe3/0000755000175000017500000000000014562742415022247 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/137 whole archive/exe3/meson.build0000644000175000017500000000011014516512250024370 0ustar00jpakkanejpakkaneexe3 = executable('prog3', '../prog.c', link_with : sh_func2_dep_func1) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5626519 meson-1.3.2/test cases/common/137 whole archive/exe4/0000755000175000017500000000000014562742415022250 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/137 whole archive/exe4/meson.build0000644000175000017500000000011514516512250024376 0ustar00jpakkanejpakkaneexe4 = executable('prog4', '../prog.c', link_with : sh_func2_transdep_func1) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/137 whole archive/func1.c0000644000175000017500000000011414516512250022546 0ustar00jpakkanejpakkane#define BUILDING_DLL #include int func1(void) { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/137 whole archive/func2.c0000644000175000017500000000011414516512250022547 0ustar00jpakkanejpakkane#define BUILDING_DLL #include int func2(void) { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421571.0 meson-1.3.2/test cases/common/137 whole archive/meson.build0000644000175000017500000000327614516755503023556 0ustar00jpakkanejpakkaneproject('whole archive', 'c') if meson.backend() == 'xcode' or \ meson.backend() == 'vs2010' or \ meson.backend() == 'vs2012' or \ meson.backend() == 'vs2013' error('MESON_SKIP_TEST: whole-archive not supported in Xcode nor pre-VS2015 IDE. Patches welcome.') endif add_project_arguments('-I' + meson.source_root(), language : 'c') # 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/137 whole archive/mylib.h0000644000175000017500000000074314516512250022663 0ustar00jpakkanejpakkane#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); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/137 whole archive/prog.c0000644000175000017500000000010414516512250022500 0ustar00jpakkanejpakkane#include int main(void) { return func1() - func2(); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5626519 meson-1.3.2/test cases/common/137 whole archive/sh_func2_dep_func1/0000755000175000017500000000000014562742415025036 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/137 whole archive/sh_func2_dep_func1/meson.build0000644000175000017500000000045514516512250027173 0ustar00jpakkanejpakkane# 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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5626519 meson-1.3.2/test cases/common/137 whole archive/sh_func2_linked_func1/0000755000175000017500000000000014562742415025534 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/137 whole archive/sh_func2_linked_func1/meson.build0000644000175000017500000000031714516512250027666 0ustar00jpakkanejpakkane# 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) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.566652 meson-1.3.2/test cases/common/137 whole archive/sh_func2_transdep_func1/0000755000175000017500000000000014562742415026106 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/137 whole archive/sh_func2_transdep_func1/meson.build0000644000175000017500000000043614516512250030242 0ustar00jpakkanejpakkane# 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) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.566652 meson-1.3.2/test cases/common/137 whole archive/sh_only_link_whole/0000755000175000017500000000000014562742415025271 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/137 whole archive/sh_only_link_whole/meson.build0000644000175000017500000000013514516512250027421 0ustar00jpakkanejpakkanesh_only_link_whole = shared_library('sh_only_link_whole', link_whole : [st_func1, st_func2]) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.566652 meson-1.3.2/test cases/common/137 whole archive/st_func1/0000755000175000017500000000000014562742415023125 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/137 whole archive/st_func1/meson.build0000644000175000017500000000006414516512250025256 0ustar00jpakkanejpakkanest_func1 = static_library('st_func1', '../func1.c') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.566652 meson-1.3.2/test cases/common/137 whole archive/st_func2/0000755000175000017500000000000014562742415023126 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/137 whole archive/st_func2/meson.build0000644000175000017500000000006414516512250025257 0ustar00jpakkanejpakkanest_func2 = static_library('st_func2', '../func2.c') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.570652 meson-1.3.2/test cases/common/138 C and CPP link/0000755000175000017500000000000014562742415021112 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/138 C and CPP link/dummy.c0000644000175000017500000000000014516512250022366 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/138 C and CPP link/foo.c0000644000175000017500000000121414516512250022026 0ustar00jpakkanejpakkane/* 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/138 C and CPP link/foo.cpp0000644000175000017500000000171314516512250022372 0ustar00jpakkanejpakkane/* 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 ()]; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/138 C and CPP link/foo.h0000644000175000017500000000115114516512250022033 0ustar00jpakkanejpakkane/* 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); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/138 C and CPP link/foo.hpp0000644000175000017500000000125414516512250022377 0ustar00jpakkanejpakkane/* 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/138 C and CPP link/foobar.c0000644000175000017500000000141514516512250022516 0ustar00jpakkanejpakkane/* 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(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/138 C and CPP link/foobar.h0000644000175000017500000000116014516512250022520 0ustar00jpakkanejpakkane/* 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[]); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421575.0 meson-1.3.2/test cases/common/138 C and CPP link/meson.build0000644000175000017500000000762114516755507023267 0ustar00jpakkanejpakkane# 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']) if meson.backend() == 'xcode' error('''MESON_SKIP_TEST: overriding link language is not supported in Xcode. If you really need this, then patches are welcome. The only known way is to create a dummy C++ file in the meson-private directory and adding that to the target's source list when needed. The primitives exist but may need some tweaking. Grep for language_stdlib_only_link_flags to find where this is handled in other backends.''') endif # 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, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/138 C and CPP link/sub.c0000644000175000017500000000121314516512250022033 0ustar00jpakkanejpakkane/* 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/138 C and CPP link/sub.h0000644000175000017500000000115014516512250022040 0ustar00jpakkanejpakkane/* 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); ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.570652 meson-1.3.2/test cases/common/139 mesonintrospect from scripts/0000755000175000017500000000000014562742415024515 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/139 mesonintrospect from scripts/check_env.py0000644000175000017500000000106014516512250027000 0ustar00jpakkanejpakkane#!/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(f'{mesonintrospect!r} does not exist') if do_print: print(some_executable, end='') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/139 mesonintrospect from scripts/check_introspection.py0000644000175000017500000000071014516512250031111 0ustar00jpakkanejpakkane#!/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]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421575.0 meson-1.3.2/test cases/common/139 mesonintrospect from scripts/meson.build0000644000175000017500000000054114516755507026664 0ustar00jpakkanejpakkaneproject('mesonintrospect from scripts') python = import('python3').find_python() ret = run_command(python, ['check_env.py', '1'], check: false) 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') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.582652 meson-1.3.2/test cases/common/14 configure file/0000755000175000017500000000000014562742415021456 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/basename.py0000644000175000017500000000101613716006331023567 0ustar00jpakkanejpakkane#!/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()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/common/14 configure file/check_file.py0000644000175000017500000000170514140314117024071 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import os import sys def permit_osx_workaround(m1, m2): import platform if platform.system().lower() != 'darwin': return False if m2 % 10000 != 0: return False if m1//10000 != m2//10000: return False return True 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: # Under macOS the lower four digits sometimes get assigned # zero, even though shutil.copy2 should preserve metadata. # Just have to accept it, I guess. if not permit_osx_workaround(m1, m2): raise RuntimeError(f'mtime of {f1!r} ({m1!r}) != mtime of {f2!r} ({m2!r})') import filecmp if not filecmp.cmp(f1, f2): raise RuntimeError(f'{f1!r} != {f2!r}') else: raise AssertionError ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/check_inputs.py0000644000175000017500000000053013716006331024473 0ustar00jpakkanejpakkane#!/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") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/config.h0000644000175000017500000000014313716006331023060 0ustar00jpakkanejpakkane#error "This file should not be included. Build dir must become before source dir in search order" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/config.h.in0000644000175000017500000000017013716006331023465 0ustar00jpakkanejpakkane#define MESSAGE "@var@" #define OTHER "@other@" "@second@" "@empty@" #mesondefine BE_TRUE #mesondefine SHOULD_BE_UNDEF ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/config4a.h.in0000644000175000017500000000005013716006331023707 0ustar00jpakkanejpakkane/* Dummy file */ #define RESULTA @ZERO@ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/config4b.h.in0000644000175000017500000000005013716006331023710 0ustar00jpakkanejpakkane/* Dummy file */ #define RESULTB @ZERO@ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/config5.h.in0000644000175000017500000000003013716006331023545 0ustar00jpakkanejpakkane#define MESSAGE "@var@" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/config6.h.in0000644000175000017500000000106213716006331023554 0ustar00jpakkanejpakkane/* 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 "\\ @ \@ \\\\@ \\\\\@" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/config7.h.in0000644000175000017500000000073013716006331023556 0ustar00jpakkanejpakkane/* 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 "\\ ${ \${ \\\\${ \\\\\${" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/config8.h.in0000644000175000017500000000012013716006331023550 0ustar00jpakkanejpakkane#define MESSAGE "@var@" #define "non isolatin1 char Ä fails decode with utf-8" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/depfile0000644000175000017500000000000013716006331022765 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/differentafterbasename1.in0000644000175000017500000000000013716006331026527 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/differentafterbasename2.in0000644000175000017500000000000013716006331026530 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/dummy.dat0000644000175000017500000000000013716006331023257 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/dumpprog.c0000644000175000017500000000240013716006331023441 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1619506185.0 meson-1.3.2/test cases/common/14 configure file/file_contains.py0000644000175000017500000000071614041732011024630 0ustar00jpakkanejpakkane#!/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], encoding='utf-8') as f: for line in f: if line.strip() == text: return 0 return 1 if __name__ == '__main__': sys.exit(main()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1619506185.0 meson-1.3.2/test cases/common/14 configure file/generator-deps.py0000755000175000017500000000071214041732011024731 0ustar00jpakkanejpakkane#!/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(f"{outputf.name}: depfile\n") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/generator-without-input-file.py0000755000175000017500000000050613716006331027563 0ustar00jpakkanejpakkane#!/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") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/common/14 configure file/generator.py0000755000175000017500000000057114140314117024006 0ustar00jpakkanejpakkane#!/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") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/invalid-utf8.bin.in0000644000175000017500000000001213716006331025046 0ustar00jpakkanejpakkaneŠw././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421456.0 meson-1.3.2/test cases/common/14 configure file/meson.build0000644000175000017500000002422414516755320023622 0ustar00jpakkanejpakkaneproject('configure file test', 'c', meson_version: '>=0.63.0') fs = import('fs') 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.') assert(conf.keys() == ['BE_TRUE', 'other', 'second', 'var'], 'Keys function 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, check: false) 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, check: false) 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, check: false) 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, check: true) 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 install_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, check: false) if ret.returncode() != 0 error('Error running command: @0@\n@1@'.format(ret.stdout(), ret.stderr())) endif # Now the same, but using a File object as an argument. inf2 = files('invalid-utf8.bin.in')[0] outf = configure_file(input : inf2, output : 'invalid-utf8.bin', copy: true) ret = run_command(check_file, inf2, outf, check: false) 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, check: false) if ret.returncode() != 0 error('Error running command: @0@\n@1@'.format(ret.stdout(), ret.stderr())) endif # Test the fs replacement # Test copying of an empty configuration data object inf = 'invalid-utf8.bin.in' outf = fs.copyfile(inf, 'invalid-utf8-1.bin', install: true, install_dir: get_option('datadir') / meson.project_name(), install_tag: 'copyfile', ) test('fs.copyfile string', check_file, args: [files(inf), outf]) # Test with default outname of string outf = fs.copyfile(inf) test('fs.copyfile default name', check_file, args: [files(inf), outf]) # Now the same, but using a File object as an argument. inf2 = files('invalid-utf8.bin.in')[0] outf = fs.copyfile(inf2, 'invalid-utf8-2.bin') test('fs.copyfile file', check_file, args: [inf2, outf]) # 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) # 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')] ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/nosubst-nocopy1.txt.in0000644000175000017500000000002513716006331025672 0ustar00jpakkanejpakkane#mesondefine FOO_BAR ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/nosubst-nocopy2.txt.in0000644000175000017500000000001213716006331025667 0ustar00jpakkanejpakkane@FOO_BAR@ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/prog.c0000644000175000017500000000043313716006331022557 0ustar00jpakkanejpakkane#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 } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/prog2.c0000644000175000017500000000010013716006331022630 0ustar00jpakkanejpakkane#include int main(void) { return ZERO_RESULT; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/prog4.c0000644000175000017500000000013613716006331022643 0ustar00jpakkanejpakkane#include #include int main(void) { return RESULTA + RESULTB; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/prog5.c0000644000175000017500000000014313716006331022642 0ustar00jpakkanejpakkane#include #include int main(void) { return strcmp(MESSAGE, "@var2@"); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/prog6.c0000644000175000017500000000045213716006331022646 0ustar00jpakkanejpakkane#include #include int main(void) { return strcmp(MESSAGE1, "foo") || strcmp(MESSAGE2, "@var1@") || strcmp(MESSAGE3, "\\foo") || strcmp(MESSAGE4, "\\@var1@") || strcmp(MESSAGE5, "@var1bar") || strcmp(MESSAGE6, "\\ @ @ \\@ \\@"); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/prog7.c0000644000175000017500000000041013716006331022641 0ustar00jpakkanejpakkane#include #include int main(void) { return strcmp(MESSAGE1, "foo") || strcmp(MESSAGE2, "${var1}") || strcmp(MESSAGE3, "\\foo") || strcmp(MESSAGE4, "\\${var1}") || strcmp(MESSAGE5, "\\ ${ ${ \\${ \\${"); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/prog9.c0000644000175000017500000000056313716006331022654 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/sameafterbasename.in0000644000175000017500000000000013716006331025425 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/sameafterbasename.in20000644000175000017500000000000013716006331025507 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.582652 meson-1.3.2/test cases/common/14 configure file/subdir/0000755000175000017500000000000014562742415022746 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1640535865.0 meson-1.3.2/test cases/common/14 configure file/subdir/meson.build0000644000175000017500000000253114162113471025077 0ustar00jpakkanejpakkane# 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'), check: true) # 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'), check: true) # 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'), check: true) # 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 ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1671216696.0 meson-1.3.2/test cases/common/14 configure file/test.json0000644000175000017500000000054314347137070023326 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/share/appdir/config2.h"}, {"type": "file", "file": "usr/share/appdir/config2b.h"}, {"type": "file", "file": "usr/share/appdireh/config2-1.h"}, {"type": "file", "file": "usr/share/appdirok/config2-2.h"}, {"type": "file", "file": "usr/share/configure file test/invalid-utf8-1.bin"} ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/test.py.in0000644000175000017500000000005713716006331023404 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys sys.exit(0) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/14 configure file/touch.py0000644000175000017500000000050613716006331023141 0ustar00jpakkanejpakkane#!/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()) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.582652 meson-1.3.2/test cases/common/140 custom target multiple outputs/0000755000175000017500000000000014562742415024756 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/140 custom target multiple outputs/generator.py0000755000175000017500000000050214516512250027305 0ustar00jpakkanejpakkane#!/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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421574.0 meson-1.3.2/test cases/common/140 custom target multiple outputs/meson.build0000644000175000017500000000275614516755506027136 0ustar00jpakkanejpakkaneproject('multiple outputs install') 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]) targets = 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'))]) paths = [] foreach i : targets.to_list() paths += i.full_path() endforeach # The Xcode backend has a different output naming scheme. if meson.backend() == 'xcode' assert(paths == [meson.project_build_root() / get_option('buildtype') / 'second.h', meson.project_build_root() / get_option('buildtype') / 'second.sh']) # Skip on Windows because paths are not identical, '/' VS '\'. elif host_machine.system() != 'windows' assert(paths == [meson.current_build_dir() / 'second.h', meson.current_build_dir() / 'second.sh']) endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/140 custom target multiple outputs/test.json0000644000175000017500000000047614516515714026636 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/include/diff.h"}, {"type": "file", "file": "usr/include/first.h"}, {"type": "file", "file": "usr/bin/diff.sh"}, {"type": "file", "file": "usr/bin/second.sh"}, {"type": "file", "file": "opt/same.h"}, {"type": "file", "file": "opt/same.sh"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5866523 meson-1.3.2/test cases/common/141 special characters/0000755000175000017500000000000014562742415022376 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/141 special characters/.editorconfig0000644000175000017500000000005714516512250025044 0ustar00jpakkanejpakkane[meson.build] trim_trailing_whitespace = false ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/141 special characters/arg-char-test.c0000644000175000017500000000041314516512250025170 0ustar00jpakkanejpakkane#include #include int main(int argc, char **argv) { char c = CHAR; assert(argc == 2); if (c != argv[1][0]) fprintf(stderr, "Expected %x, got %x\n", (unsigned int) c, (unsigned int) argv[1][0]); assert(c == argv[1][0]); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/141 special characters/arg-string-test.c0000644000175000017500000000051114516512250025560 0ustar00jpakkanejpakkane#include #include #include int main(int argc, char **argv) { const char *s = CHAR; assert(argc == 2); assert(strlen(s) == 1); if (s[0] != argv[1][0]) fprintf(stderr, "Expected %x, got %x\n", (unsigned int) s[0], (unsigned int) argv[1][0]); assert(s[0] == argv[1][0]); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/141 special characters/arg-unquoted-test.c0000644000175000017500000000075114516512250026124 0ustar00jpakkanejpakkane#include #include #include #define Q(x) #x #define QUOTE(x) Q(x) int main(int argc, char **argv) { const char *s = QUOTE(CHAR); assert(argc == 2); assert(strlen(s) == 1); if (s[0] != argv[1][0]) fprintf(stderr, "Expected %x, got %x\n", (unsigned int) s[0], (unsigned int) argv[1][0]); assert(s[0] == argv[1][0]); // There is no way to convert a macro argument into a character constant. // Otherwise we'd test that as well return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/141 special characters/check_quoting.py0000644000175000017500000000106214516512250025561 0ustar00jpakkanejpakkane#!/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!') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421578.0 meson-1.3.2/test cases/common/141 special characters/meson.build0000644000175000017500000000350014516755512024537 0ustar00jpakkanejpakkaneproject('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')) # Test that we can pass these special characters in compiler arguments # # (this part of the test is crafted so we don't try to use these special # characters in filenames or target names) # # TODO: similar tests needed for languages other than C # TODO: add similar test for quote, doublequote, and hash, carefully # Re hash, see # https://docs.microsoft.com/en-us/cpp/build/reference/d-preprocessor-definitions special = [ ['amp', '&'], ['at', '@'], ['backslash', '\\'], ['dollar', '$'], ['gt', '>'], ['lt', '<'], ['slash', '/'], ] cc = meson.get_compiler('c') foreach s : special args = '-DCHAR="@0@"'.format(s[1]) e = executable('arg-string-' + s[0], 'arg-string-test.c', c_args: args) test('arg-string-' + s[0], e, args: s[1]) args = '-DCHAR=@0@'.format(s[1]) e = executable('arg-unquoted-' + s[0], 'arg-unquoted-test.c', c_args: args) test('arg-unquoted-' + s[0], e, args: s[1]) endforeach foreach s : special args = '-DCHAR=\'@0@\''.format(s[1]) e = executable('arg-char-' + s[0], 'arg-char-test.c', c_args: args) test('arg-char-' + s[0], e, args: s[1]) endforeach ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/141 special characters/test.json0000644000175000017500000000017514516515714024252 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/share/result"}, {"type": "file", "file": "usr/share/result2"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5866523 meson-1.3.2/test cases/common/142 nested links/0000755000175000017500000000000014562742415021242 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421579.0 meson-1.3.2/test cases/common/142 nested links/meson.build0000644000175000017500000000030014516755513023377 0ustar00jpakkanejpakkaneproject('test', 'c') libxserver_dri3 = [] libxserver = [ libxserver_dri3 ] executable('Xephyr', 'xephyr.c', link_with: [ libxserver ]) executable('Zephyr', 'xephyr.c', link_args: [[], []]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/142 nested links/xephyr.c0000644000175000017500000000004114516512250022707 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5866523 meson-1.3.2/test cases/common/143 list of file sources/0000755000175000017500000000000014562742415022564 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/143 list of file sources/foo0000644000175000017500000000001214516512250023252 0ustar00jpakkanejpakkanesome text ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/143 list of file sources/gen.py0000644000175000017500000000025614516512250023701 0ustar00jpakkanejpakkaneimport 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]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421580.0 meson-1.3.2/test cases/common/143 list of file sources/meson.build0000644000175000017500000000041514516755514024731 0ustar00jpakkanejpakkaneproject('test') 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, ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5906522 meson-1.3.2/test cases/common/144 link depends custom target/0000755000175000017500000000000014562742415023763 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/144 link depends custom target/foo.c0000644000175000017500000000034614516512250024704 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/144 link depends custom target/make_file.py0000755000175000017500000000016314516512250026243 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys with open(sys.argv[1], 'w') as f: print('# this file does nothing', file=f) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421580.0 meson-1.3.2/test cases/common/144 link depends custom target/meson.build0000644000175000017500000000062014516755514026126 0ustar00jpakkanejpakkaneproject('link_depends_custom_target', 'c') 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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5906522 meson-1.3.2/test cases/common/145 recursive linking/0000755000175000017500000000000014562742415022305 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5986524 meson-1.3.2/test cases/common/145 recursive linking/3rdorderdeps/0000755000175000017500000000000014562742415024705 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/3rdorderdeps/lib.c.in0000644000175000017500000000024314516512250026212 0ustar00jpakkanejpakkane#include "../lib.h" int get_@DEPENDENCY@dep_value (void); SYMBOL_EXPORT int get_@LIBTYPE@@DEPENDENCY@dep_value (void) { return get_@DEPENDENCY@dep_value (); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/3rdorderdeps/main.c.in0000644000175000017500000000046214516512250026373 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/3rdorderdeps/meson.build0000644000175000017500000000310114516512250027031 0ustar00jpakkanejpakkanedep3_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 + '_test', main_c, link_with : dep3_lib, c_args : build_args) test(name + 'test', dep3_bin) endforeach endforeach endforeach ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5986524 meson-1.3.2/test cases/common/145 recursive linking/circular/0000755000175000017500000000000014562742415024111 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/circular/lib1.c0000644000175000017500000000017414516512250025075 0ustar00jpakkanejpakkaneint get_st2_prop (void); int get_st3_prop (void); int get_st1_value (void) { return get_st2_prop () + get_st3_prop (); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/circular/lib2.c0000644000175000017500000000017414516512250025076 0ustar00jpakkanejpakkaneint get_st1_prop (void); int get_st3_prop (void); int get_st2_value (void) { return get_st1_prop () + get_st3_prop (); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/circular/lib3.c0000644000175000017500000000017414516512250025077 0ustar00jpakkanejpakkaneint get_st1_prop (void); int get_st2_prop (void); int get_st3_value (void) { return get_st1_prop () + get_st2_prop (); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/circular/main.c0000644000175000017500000000077414516512250025200 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/circular/meson.build0000644000175000017500000000034414516512250026243 0ustar00jpakkanejpakkanest1 = 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])) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/circular/prop1.c0000644000175000017500000000005014516512250025300 0ustar00jpakkanejpakkaneint get_st1_prop (void) { return 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/circular/prop2.c0000644000175000017500000000005014516512250025301 0ustar00jpakkanejpakkaneint get_st2_prop (void) { return 2; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/circular/prop3.c0000644000175000017500000000005014516512250025302 0ustar00jpakkanejpakkaneint get_st3_prop (void) { return 3; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5986524 meson-1.3.2/test cases/common/145 recursive linking/edge-cases/0000755000175000017500000000000014562742415024305 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/edge-cases/libsto.c0000644000175000017500000000017714516512250025741 0ustar00jpakkanejpakkane#include "../lib.h" int get_builto_value (void); SYMBOL_EXPORT int get_stodep_value (void) { return get_builto_value (); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/edge-cases/meson.build0000644000175000017500000000104714516512250026440 0ustar00jpakkanejpakkane# 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)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/edge-cases/shstmain.c0000644000175000017500000000035214516512250026266 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/edge-cases/stobuilt.c0000644000175000017500000000012014516512250026276 0ustar00jpakkanejpakkane#include "../lib.h" SYMBOL_EXPORT int get_builto_value (void) { return 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/edge-cases/stomain.c0000644000175000017500000000035014516512250026110 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/lib.h0000644000175000017500000000067614516512250023224 0ustar00jpakkanejpakkane#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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/main.c0000644000175000017500000000175614516512250023375 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421585.0 meson-1.3.2/test cases/common/145 recursive linking/meson.build0000644000175000017500000000152614516755521024454 0ustar00jpakkanejpakkaneproject('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') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5986524 meson-1.3.2/test cases/common/145 recursive linking/shnodep/0000755000175000017500000000000014562742415023745 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/shnodep/lib.c0000644000175000017500000000012014516512250024637 0ustar00jpakkanejpakkane#include "../lib.h" SYMBOL_EXPORT int get_shnodep_value (void) { return 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/shnodep/meson.build0000644000175000017500000000007714516512250026102 0ustar00jpakkanejpakkaneshnodep = shared_library('shnodep', 'lib.c', version: '0.0.0') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.5986524 meson-1.3.2/test cases/common/145 recursive linking/shshdep/0000755000175000017500000000000014562742415023743 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/shshdep/lib.c0000644000175000017500000000020214516512250024636 0ustar00jpakkanejpakkane#include "../lib.h" int get_shnodep_value (void); SYMBOL_EXPORT int get_shshdep_value (void) { return get_shnodep_value (); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/shshdep/meson.build0000644000175000017500000000010214516512250026065 0ustar00jpakkanejpakkaneshshdep = shared_library('shshdep', 'lib.c', link_with : shnodep) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6026525 meson-1.3.2/test cases/common/145 recursive linking/shstdep/0000755000175000017500000000000014562742415023757 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/shstdep/lib.c0000644000175000017500000000020214516512250024652 0ustar00jpakkanejpakkane#include "../lib.h" int get_stnodep_value (void); SYMBOL_EXPORT int get_shstdep_value (void) { return get_stnodep_value (); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/shstdep/meson.build0000644000175000017500000000010214516512250026101 0ustar00jpakkanejpakkaneshstdep = shared_library('shstdep', 'lib.c', link_with : stnodep) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6026525 meson-1.3.2/test cases/common/145 recursive linking/stnodep/0000755000175000017500000000000014562742415023761 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/stnodep/lib.c0000644000175000017500000000012014516512250024653 0ustar00jpakkanejpakkane#include "../lib.h" SYMBOL_EXPORT int get_stnodep_value (void) { return 2; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/stnodep/meson.build0000644000175000017500000000014714516512250026114 0ustar00jpakkanejpakkanestnodep = static_library('stnodep', 'lib.c', c_args : '-DMESON_STATIC_BUILD') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6026525 meson-1.3.2/test cases/common/145 recursive linking/stshdep/0000755000175000017500000000000014562742415023757 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/stshdep/lib.c0000644000175000017500000000020214516512250024652 0ustar00jpakkanejpakkane#include "../lib.h" int get_shnodep_value (void); SYMBOL_EXPORT int get_stshdep_value (void) { return get_shnodep_value (); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/stshdep/meson.build0000644000175000017500000000017414516512250026112 0ustar00jpakkanejpakkanestshdep = static_library('stshdep', 'lib.c', link_with : shnodep, c_args : '-DMESON_STATIC_BUILD') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6026525 meson-1.3.2/test cases/common/145 recursive linking/ststdep/0000755000175000017500000000000014562742415023773 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/ststdep/lib.c0000644000175000017500000000020214516512250024666 0ustar00jpakkanejpakkane#include "../lib.h" int get_stnodep_value (void); SYMBOL_EXPORT int get_ststdep_value (void) { return get_stnodep_value (); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/145 recursive linking/ststdep/meson.build0000644000175000017500000000017414516512250026126 0ustar00jpakkanejpakkaneststdep = static_library('ststdep', 'lib.c', link_with : stnodep, c_args : '-DMESON_STATIC_BUILD') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6066525 meson-1.3.2/test cases/common/146 library at root/0000755000175000017500000000000014562742415021660 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/146 library at root/lib.c0000644000175000017500000000014614516512250022562 0ustar00jpakkanejpakkane#if defined _WIN32 || defined __CYGWIN__ __declspec(dllexport) #endif int fn(void) { return -1; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6066525 meson-1.3.2/test cases/common/146 library at root/main/0000755000175000017500000000000014562742415022604 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/146 library at root/main/main.c0000644000175000017500000000007614516512250023666 0ustar00jpakkanejpakkaneextern int fn(void); int main(void) { return 1 + fn(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/146 library at root/main/meson.build0000644000175000017500000000011514516512250024732 0ustar00jpakkanejpakkaneexe = executable('main', 'main.c', link_with : lib) test('stuff works', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421584.0 meson-1.3.2/test cases/common/146 library at root/meson.build0000644000175000017500000000010614516755520024017 0ustar00jpakkanejpakkaneproject('lib@root', 'c') lib = library('lib', 'lib.c') subdir('main') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6106527 meson-1.3.2/test cases/common/147 simd/0000755000175000017500000000000014562742415017620 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/147 simd/fallback.c0000644000175000017500000000017514516512250021515 0ustar00jpakkanejpakkane#include void increment_fallback(float arr[4]) { int i; for(i=0; i<4; i++) { arr[i]++; } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6106527 meson-1.3.2/test cases/common/147 simd/include/0000755000175000017500000000000014562742415021243 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/147 simd/include/simdheader.h0000644000175000017500000000004514516512250023507 0ustar00jpakkanejpakkane#pragma once #define I_CAN_HAZ_SIMD ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421588.0 meson-1.3.2/test cases/common/147 simd/meson.build0000644000175000017500000000223014516755524021763 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/147 simd/simd_avx.c0000644000175000017500000000176614516512250021577 0ustar00jpakkanejpakkane#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]; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/147 simd/simd_avx2.c0000644000175000017500000000160714516512250021653 0ustar00jpakkanejpakkane#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]; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/147 simd/simd_mmx.c0000644000175000017500000000277614516512250021604 0ustar00jpakkanejpakkane#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; /* This is unused due to below comment about GCC 8. __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); int64_t unpacker = (int64_t)(result); */ /* The above should be * int64_t unpacker = _m_to_int64(result); * but it does not exist on 32 bit platforms for some reason. */ _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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/147 simd/simd_neon.c0000644000175000017500000000067514516512250021736 0ustar00jpakkanejpakkane#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); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/147 simd/simd_sse.c0000644000175000017500000000101114516512250021552 0ustar00jpakkanejpakkane#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); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/147 simd/simd_sse2.c0000644000175000017500000000142614516512250021646 0ustar00jpakkanejpakkane#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]; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/147 simd/simd_sse3.c0000644000175000017500000000162314516512250021646 0ustar00jpakkanejpakkane#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]; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/147 simd/simd_sse41.c0000644000175000017500000000160714516512250021732 0ustar00jpakkanejpakkane#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]; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/147 simd/simd_sse42.c0000644000175000017500000000160214516512250021726 0ustar00jpakkanejpakkane#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]; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/147 simd/simd_ssse3.c0000644000175000017500000000211214516512250022023 0ustar00jpakkanejpakkane#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]; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/147 simd/simdchecker.c0000644000175000017500000000663414516512250022245 0ustar00jpakkanejpakkane#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. */ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6186528 meson-1.3.2/test cases/common/148 shared module resolving symbol in executable/0000755000175000017500000000000014562742415027351 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421587.0 meson-1.3.2/test cases/common/148 shared module resolving symbol in executable/meson.build0000644000175000017500000000212414516755523031515 0ustar00jpakkanejpakkaneproject('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) e_dep = declare_dependency(link_with: e) m = shared_module('module', 'module.c', link_with: e) m2 = shared_module('module2', 'module.c', dependencies: e_dep) test('test', e, args: m.full_path()) test('test2', e, args: m2.full_path()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/148 shared module resolving symbol in executable/module.c0000644000175000017500000000061514516512250030773 0ustar00jpakkanejpakkane#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(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/148 shared module resolving symbol in executable/prog.c0000644000175000017500000000210414516512250030450 0ustar00jpakkanejpakkane#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; (void)argc; // 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; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6186528 meson-1.3.2/test cases/common/149 dotinclude/0000755000175000017500000000000014562742415021020 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/149 dotinclude/dotproc.c0000644000175000017500000000025514516512250022627 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421589.0 meson-1.3.2/test cases/common/149 dotinclude/meson.build0000644000175000017500000000014714516755525023171 0ustar00jpakkanejpakkaneproject('dotinclude', 'c') executable('dotproc', 'dotproc.c', implicit_include_directories : false) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/149 dotinclude/stdio.h0000644000175000017500000000022714516512250022303 0ustar00jpakkanejpakkane// There is no #pragma once because we _want_ to cause an eternal loop // if this wrapper invokes itself. #define WRAPPER_INCLUDED #include ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6186528 meson-1.3.2/test cases/common/15 if/0000755000175000017500000000000014562742415017174 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421454.0 meson-1.3.2/test cases/common/15 if/meson.build0000644000175000017500000000161514516755316021344 0ustar00jpakkanejpakkaneproject('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 # Test plain else var = false if var exe = executable('break', 'break.c') else exe = executable('eprog', 'prog.c') endif test('elsetest', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/15 if/prog.c0000644000175000017500000000003513716006331020273 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6186528 meson-1.3.2/test cases/common/150 reserved targets/0000755000175000017500000000000014562742415022127 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6186528 meson-1.3.2/test cases/common/150 reserved targets/all/0000755000175000017500000000000014562742415022677 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/all/meson.build0000644000175000017500000000004414516512250025026 0ustar00jpakkanejpakkaneexecutable('test-all', '../test.c') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6186528 meson-1.3.2/test cases/common/150 reserved targets/benchmark/0000755000175000017500000000000014562742415024061 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/benchmark/meson.build0000644000175000017500000000005214516512250026207 0ustar00jpakkanejpakkaneexecutable('test-benchmark', '../test.c') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6186528 meson-1.3.2/test cases/common/150 reserved targets/clean/0000755000175000017500000000000014562742415023211 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/clean/meson.build0000644000175000017500000000004614516512250025342 0ustar00jpakkanejpakkaneexecutable('test-clean', '../test.c') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6186528 meson-1.3.2/test cases/common/150 reserved targets/clean-ctlist/0000755000175000017500000000000014562742415024511 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/clean-ctlist/meson.build0000644000175000017500000000005514516512250026642 0ustar00jpakkanejpakkaneexecutable('test-clean-ctlist', '../test.c') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6186528 meson-1.3.2/test cases/common/150 reserved targets/clean-gcda/0000755000175000017500000000000014562742415024105 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/clean-gcda/meson.build0000644000175000017500000000005314516512250026234 0ustar00jpakkanejpakkaneexecutable('test-clean-gcda', '../test.c') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6186528 meson-1.3.2/test cases/common/150 reserved targets/clean-gcno/0000755000175000017500000000000014562742415024135 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/clean-gcno/meson.build0000644000175000017500000000005314516512250026264 0ustar00jpakkanejpakkaneexecutable('test-clean-gcno', '../test.c') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6186528 meson-1.3.2/test cases/common/150 reserved targets/coverage/0000755000175000017500000000000014562742415023722 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/coverage/meson.build0000644000175000017500000000005114516512250026047 0ustar00jpakkanejpakkaneexecutable('test-coverage', '../test.c') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6186528 meson-1.3.2/test cases/common/150 reserved targets/coverage-html/0000755000175000017500000000000014562742415024664 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/coverage-html/meson.build0000644000175000017500000000005614516512250027016 0ustar00jpakkanejpakkaneexecutable('test-coverage-html', '../test.c') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6186528 meson-1.3.2/test cases/common/150 reserved targets/coverage-sonarqube/0000755000175000017500000000000014562742415025717 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/coverage-sonarqube/meson.build0000644000175000017500000000006314516512250030047 0ustar00jpakkanejpakkaneexecutable('test-coverage-sonarqube', '../test.c') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6186528 meson-1.3.2/test cases/common/150 reserved targets/coverage-text/0000755000175000017500000000000014562742415024704 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/coverage-text/meson.build0000644000175000017500000000005614516512250027036 0ustar00jpakkanejpakkaneexecutable('test-coverage-text', '../test.c') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6186528 meson-1.3.2/test cases/common/150 reserved targets/coverage-xml/0000755000175000017500000000000014562742415024520 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/coverage-xml/meson.build0000644000175000017500000000005514516512250026651 0ustar00jpakkanejpakkaneexecutable('test-coverage-xml', '../test.c') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6226528 meson-1.3.2/test cases/common/150 reserved targets/dist/0000755000175000017500000000000014562742415023072 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/dist/meson.build0000644000175000017500000000004514516512250025222 0ustar00jpakkanejpakkaneexecutable('test-dist', '../test.c') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6226528 meson-1.3.2/test cases/common/150 reserved targets/distcheck/0000755000175000017500000000000014562742415024070 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/distcheck/meson.build0000644000175000017500000000005214516512250026216 0ustar00jpakkanejpakkaneexecutable('test-distcheck', '../test.c') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6226528 meson-1.3.2/test cases/common/150 reserved targets/install/0000755000175000017500000000000014562742415023575 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/install/meson.build0000644000175000017500000000005014516512250025721 0ustar00jpakkanejpakkaneexecutable('test-install', '../test.c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421591.0 meson-1.3.2/test cases/common/150 reserved targets/meson.build0000644000175000017500000000155714516755527024310 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6226528 meson-1.3.2/test cases/common/150 reserved targets/phony/0000755000175000017500000000000014562742415023264 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/phony/meson.build0000644000175000017500000000004614516512250025415 0ustar00jpakkanejpakkaneexecutable('test-phony', '../test.c') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6226528 meson-1.3.2/test cases/common/150 reserved targets/reconfigure/0000755000175000017500000000000014562742415024437 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/reconfigure/meson.build0000644000175000017500000000005414516512250026567 0ustar00jpakkanejpakkaneexecutable('test-reconfigure', '../test.c') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6226528 meson-1.3.2/test cases/common/150 reserved targets/runtarget/0000755000175000017500000000000014562742415024142 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/runtarget/echo.py0000644000175000017500000000012114516512250025413 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys if len(sys.argv) > 1: print(sys.argv[1]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/runtarget/meson.build0000644000175000017500000000020614516512250026271 0ustar00jpakkanejpakkaneconfigure_file(output : 'config.h', configuration: configuration_data()) run_target('runtarget', command : [find_program('echo.py')]) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6226528 meson-1.3.2/test cases/common/150 reserved targets/scan-build/0000755000175000017500000000000014562742415024150 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/scan-build/meson.build0000644000175000017500000000005314516512250026277 0ustar00jpakkanejpakkaneexecutable('test-scan-build', '../test.c') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6226528 meson-1.3.2/test cases/common/150 reserved targets/test/0000755000175000017500000000000014562742415023106 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/test/meson.build0000644000175000017500000000004514516512250025236 0ustar00jpakkanejpakkaneexecutable('test-test', '../test.c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/test.c0000644000175000017500000000003714516512250023241 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.630653 meson-1.3.2/test cases/common/150 reserved targets/uninstall/0000755000175000017500000000000014562742415024140 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/150 reserved targets/uninstall/meson.build0000644000175000017500000000005214516512250026266 0ustar00jpakkanejpakkaneexecutable('test-uninstall', '../test.c') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.630653 meson-1.3.2/test cases/common/151 duplicate source names/0000755000175000017500000000000014562742415023176 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.630653 meson-1.3.2/test cases/common/151 duplicate source names/dir1/0000755000175000017500000000000014562742415024035 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/151 duplicate source names/dir1/file.c0000644000175000017500000000042214516512250025105 0ustar00jpakkanejpakkaneextern 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/151 duplicate source names/dir1/meson.build0000644000175000017500000000003314516512250026162 0ustar00jpakkanejpakkanesources += files('file.c') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.630653 meson-1.3.2/test cases/common/151 duplicate source names/dir2/0000755000175000017500000000000014562742415024036 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.630653 meson-1.3.2/test cases/common/151 duplicate source names/dir2/dir1/0000755000175000017500000000000014562742415024675 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/151 duplicate source names/dir2/dir1/file.c0000644000175000017500000000002414516512250025743 0ustar00jpakkanejpakkaneint dir2_dir1 = 21; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/151 duplicate source names/dir2/file.c0000644000175000017500000000001714516512250025106 0ustar00jpakkanejpakkaneint dir2 = 20; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/151 duplicate source names/dir2/meson.build0000644000175000017500000000005214516512250026164 0ustar00jpakkanejpakkanesources += files('file.c', 'dir1/file.c') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.630653 meson-1.3.2/test cases/common/151 duplicate source names/dir3/0000755000175000017500000000000014562742415024037 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.630653 meson-1.3.2/test cases/common/151 duplicate source names/dir3/dir1/0000755000175000017500000000000014562742415024676 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/151 duplicate source names/dir3/dir1/file.c0000644000175000017500000000002414516512250025744 0ustar00jpakkanejpakkaneint dir3_dir1 = 31; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/151 duplicate source names/dir3/file.c0000644000175000017500000000001714516512250025107 0ustar00jpakkanejpakkaneint dir3 = 30; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/151 duplicate source names/dir3/meson.build0000644000175000017500000000006514516512250026171 0ustar00jpakkanejpakkanelib = static_library('lib', 'file.c', 'dir1/file.c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421591.0 meson-1.3.2/test cases/common/151 duplicate source names/meson.build0000644000175000017500000000134114516755527025346 0ustar00jpakkanejpakkaneproject('proj', 'c') if meson.backend() == 'xcode' # Xcode gives object files unique names but only if they would clash. For example # two files named lib.o instead get the following names: # # lib-4fbe522d8ba4cb1f1b89cc2df640a2336b92e1a5565f0a4c5a79b5b5e2969eb9.o # lib-4fbe522d8ba4cb1f1b89cc2df640a2336deeff2bc2297affaadbe20f5cbfee56.o # # No-one has reverse engineered the naming scheme so we would access them. # IF you feel up to the challenge, patches welcome. error('MESON_SKIP_TEST, Xcode cannot extract objs when they would have the same filename.') endif sources = [] subdir('dir1') subdir('dir2') subdir('dir3') executable('a.out', sources : sources, objects : lib.extract_all_objects()) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.630653 meson-1.3.2/test cases/common/152 index customtarget/0000755000175000017500000000000014562742415022471 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/152 index customtarget/check_args.py0000644000175000017500000000043714516512250025127 0ustar00jpakkanejpakkane#!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()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/test cases/common/152 index customtarget/gen_sources.py0000644000175000017500000000233414562742363025363 0ustar00jpakkanejpakkane# 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() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/152 index customtarget/lib.c0000644000175000017500000000124314516512250023372 0ustar00jpakkanejpakkane/* 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); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421592.0 meson-1.3.2/test cases/common/152 index customtarget/meson.build0000644000175000017500000000352114516755530024635 0ustar00jpakkanejpakkane# 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.') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.630653 meson-1.3.2/test cases/common/152 index customtarget/subdir/0000755000175000017500000000000014562742415023761 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/152 index customtarget/subdir/foo.c0000644000175000017500000000126714516512250024705 0ustar00jpakkanejpakkane/* 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/152 index customtarget/subdir/meson.build0000644000175000017500000000123114516512250026107 0ustar00jpakkanejpakkane# 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', ) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.638653 meson-1.3.2/test cases/common/153 wrap file should not failed/0000755000175000017500000000000014562742415023777 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421593.0 meson-1.3.2/test cases/common/153 wrap file should not failed/meson.build0000644000175000017500000000114514516755531026144 0ustar00jpakkanejpakkaneproject('mainproj', 'c', default_options : ['wrap_mode=nodownload'], ) if not find_program('patch', required : false).found() and not find_program('git', required : false).found() error('MESON_SKIP_TEST: patch/git not found.') endif subproject('zlib') foo = subproject('foo') bar = subproject('bar') libfoo = foo.get_variable('libfoo') libbar = bar.get_variable('libbar') executable('grabprog', files('src/subprojects/prog.c')) executable('grabprog2', files('src/subprojects/foo/prog2.c')) subdir('src') subproject('patchdir') exe = subproject('patchfile').get_variable('foo_exe') test('test_foo', exe) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.638653 meson-1.3.2/test cases/common/153 wrap file should not failed/src/0000755000175000017500000000000014562742415024566 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/src/meson.build0000644000175000017500000000031514516512250026716 0ustar00jpakkanejpakkaneexecutable('grabprog3', files('subprojects/prog.c')) executable('grabprog4', files('subprojects/foo/prog2.c')) texe = executable('testexe', files('test.c'), link_with: [libfoo, libbar]) test('t1', texe) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.638653 meson-1.3.2/test cases/common/153 wrap file should not failed/src/subprojects/0000755000175000017500000000000014562742415027131 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.638653 meson-1.3.2/test cases/common/153 wrap file should not failed/src/subprojects/foo/0000755000175000017500000000000014562742415027714 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/src/subprojects/foo/prog2.c0000644000175000017500000000026614516512250031104 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/src/subprojects/prog.c0000644000175000017500000000026614516512250030237 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/src/test.c0000644000175000017500000000024714516512250025703 0ustar00jpakkanejpakkane#include int bar_dummy_func(void); int dummy_func(void); int main(void) { printf("Hello world %d\n", bar_dummy_func() + dummy_func()); return 0; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.638653 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/0000755000175000017500000000000014562742415026342 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/.gitignore0000644000175000017500000000004414516512250030317 0ustar00jpakkanejpakkane/foo-1.0 /bar-1.0 /foo-1.0-patchdir ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.638653 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/bar-1.0/0000755000175000017500000000000014562742415027402 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1584785146.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/bar-1.0/bar.c0000644000175000017500000000005413635363372030312 0ustar00jpakkanejpakkaneint bar_dummy_func(void) { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1587823156.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/bar-1.0/meson.build0000664000175000017500000000010713651041064031532 0ustar00jpakkanejpakkaneproject('static lib bar', 'c') libbar = static_library('bar', 'bar.c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/bar.wrap0000644000175000017500000000033314516512250027767 0ustar00jpakkanejpakkane[wrap-file] directory = bar-1.0 lead_directory_missing = true source_filename = bar-1.0.tar.xz source_hash = f0f61948530dc0d33e3028cd71a9f8ee869f6b3665960d8f41d715cf4aed6467 patch_filename = bar-1.0-patch.tar.xz ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.638653 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/foo-1.0/0000755000175000017500000000000014562742415027421 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1584786184.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/foo-1.0/foo.c0000664000175000017500000000005013635365410030341 0ustar00jpakkanejpakkaneint dummy_func(void) { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1587822749.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/foo-1.0/meson.build0000664000175000017500000000010313651040235031544 0ustar00jpakkanejpakkaneproject('static lib', 'c') libfoo = static_library('foo', 'foo.c') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.638653 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/foo-1.0-patchdir/0000755000175000017500000000000014562742415031215 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1584786184.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/foo-1.0-patchdir/foo.c0000664000175000017500000000005013635365410032135 0ustar00jpakkanejpakkaneint dummy_func(void) { return 42; } ././@PaxHeader0000000000000000000000000000020600000000000010213 xustar00112 path=meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/foo-1.0-patchdir/meson.build 22 mtime=1619506221.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/foo-1.0-patchdir/meson.bui0000644000175000017500000000011414041732055033022 0ustar00jpakkanejpakkaneproject('static lib patchdir', 'c') libfoo = static_library('foo', 'foo.c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/foo.wrap0000644000175000017500000000056614516512250030016 0ustar00jpakkanejpakkane[wrap-file] directory = foo-1.0 source_url = http://something.invalid source_filename = foo-1.0.tar.xz source_hash = 9ed8f67d75e43d3be161efb6eddf30dd01995a958ca83951ea64234bac8908c1 lead_directory_missing = true patch_url = https://something.invalid/patch patch_filename = foo-1.0-patch.tar.xz patch_hash = d0ddc5e60fdb27d808552f5ac8d0bb603ea2cba306538b4427b985535b26c9c5 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6466532 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagecache/0000755000175000017500000000000014562742415030721 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000021300000000000010211 xustar00117 path=meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagecache/foo-1.0-patch.tar.xz 22 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagecache/foo-1.0-patch0000644000175000017500000000036414516512250033012 0ustar00jpakkanejpakkaneż7zXZęÖ“F!t/å£ą ’“]3ģZ1łkE爩ļ—āŻóG¢=”%Ž•õMOŪG "B`ˆęŃ֑ļ ‚XĖnŒ‹>²x±y²¬DY'ŸŪp9„ąčdøŪłŸŗŽ+Ұ•4dXHBݦ÷yŖŲn÷¼so‡ŗ”ĢpĒčĆūP«w M ¤NMŅ9ūuõ kõqu!, c—Ų2Ż™MķīŽi±vć“\œæKµy1+Š·ŅĄ:Ī D‘”!ēQÆ0Š€Õ\}±ÄgūYZ././@PaxHeader0000000000000000000000000000020500000000000010212 xustar00111 path=meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagecache/foo-1.0.tar.xz 22 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagecache/foo-1.0.tar.x0000644000175000017500000000030414516512250032742 0ustar00jpakkanejpakkaneż7zXZęÖ“F!t/å£ą’„]3ģ\cjz"ŠxÄIœęĀŹüx6EB_†H‰ļhmDPĮ’Ͷ%„°T1KCb¹_]źa'ĄUŅ Ŗø‹Žź³ņ‘h2ɵ[B¶f ĪŠė1ĀŽŠ’ųPÉ M{Fņ€)ō鵄–ū “ †źś5Ō—‰€‹Wī÷¦ér…ŖN}[?:ĻG@3Į €ČłV±ÄgūYZ././@PaxHeader0000000000000000000000000000021400000000000010212 xustar00118 path=meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagecache/zlib-1.2.8-8-wrap.zip 22 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagecache/zlib-1.2.8-8-0000644000175000017500000000000614516512250032455 0ustar00jpakkanejpakkanedummy ././@PaxHeader0000000000000000000000000000021000000000000010206 xustar00114 path=meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagecache/zlib-1.2.8.tar.gz 22 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagecache/zlib-1.2.8.ta0000644000175000017500000000000614516512250032636 0ustar00jpakkanejpakkanedummy ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6466532 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagefiles/0000755000175000017500000000000014562742415030760 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000021300000000000010211 xustar00117 path=meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagefiles/bar-1.0-patch.tar.xz 22 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagefiles/bar-1.0-patch0000644000175000017500000000036414516512250033032 0ustar00jpakkanejpakkaneż7zXZęÖ“F!t/å£ą ’³]1J§Ė«#ĪæM&1l°Zē,Ekę;K& ‚²·6ét(3ōĀ:”¢ŚOĪżMTĖĶįī„Į*µhßė’ęhc<ŒéK•ö€P>ėeė„­Xar1ĒC× UŒ“HpKmŠķ.i¦ƒ|÷‹5Å¢Ö öĪĮČNHt„Fq {Ž7H¶ˆB³ū5Ś»!C!GĆ-zÄŻˆėĀ‘ō;Ną%|7Aæ=õZS@āõŠ^bbbC!¢v +ņ?œļŗĻ€›ģżč±ÄgūYZ././@PaxHeader0000000000000000000000000000020500000000000010212 xustar00111 path=meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagefiles/bar-1.0.tar.xz 22 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagefiles/bar-1.0.tar.x0000644000175000017500000000031014516512250032757 0ustar00jpakkanejpakkaneż7zXZęÖ“F!t/å£ą’†]1J§niĀ]j±¾pcJ?¹|å•.”+yo}¼i©Šļü$ózŌą°ÉZrjÅŗ=ŒC=ļU@Ž(®Ņ½äAĢ÷¼Nuį ›mśķr¹pÜ>8nH­[ĻƑO~•ĆO…¹ K'ćĪĘ©–T3ŹÓkQD˜ !®?§øm©ŒpŽĻhļ;Ą¾q}¢ž³+l¢€ĆXž[±ÄgūYZ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6466532 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagefiles/foo-1.0/0000755000175000017500000000000014562742415032037 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000021200000000000010210 xustar00116 path=meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagefiles/foo-1.0/meson.build 22 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagefiles/foo-1.0/meson0000644000175000017500000000011414516512250033066 0ustar00jpakkanejpakkaneproject('static lib patchdir', 'c') libfoo = static_library('foo', 'foo.c') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6466532 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagefiles/patchfile/0000755000175000017500000000000014562742415032717 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000024400000000000010215 xustar00142 path=meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagefiles/patchfile/0001-Change-foo-to-executable.patch 22 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagefiles/patchfile/0000000644000175000017500000000136414516512250033134 0ustar00jpakkanejpakkaneFrom b79f6cc4a096f6c2888f73b947b652491885896a Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Fri, 30 Nov 2018 14:13:47 -0500 Subject: [PATCH] Change foo to executable --- foo.c | 4 ++++ meson.build | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/foo.c b/foo.c index 54f9119..468f033 100644 --- a/foo.c +++ b/foo.c @@ -1,3 +1,7 @@ int dummy_func(void) { return 44; } + +int main(void) { + return dummy_func() == 44 ? 0 : 1; +} diff --git a/meson.build b/meson.build index 318e81d..4a281d9 100644 --- a/meson.build +++ b/meson.build @@ -1,2 +1,2 @@ project('static lib patchdir', 'c') -libfoo = static_library('foo', 'foo.c') +foo_exe = executable('foo', 'foo.c') -- 2.17.1 ././@PaxHeader0000000000000000000000000000024500000000000010216 xustar00143 path=meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagefiles/patchfile/0001-Change-return-value-to-43.patch 22 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagefiles/patchfile/0000000644000175000017500000000067714516512250033142 0ustar00jpakkanejpakkaneFrom 7001dcc738e5ae7dfa8af20ed582b9a985804f72 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Fri, 30 Nov 2018 10:15:33 -0500 Subject: [PATCH 1/2] Change return value to 43 --- foo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/foo.c b/foo.c index 019f2ba..e4577b8 100644 --- a/foo.c +++ b/foo.c @@ -1,3 +1,3 @@ int dummy_func(void) { - return 42; + return 43; } -- 2.17.1 ././@PaxHeader0000000000000000000000000000024500000000000010216 xustar00143 path=meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagefiles/patchfile/0002-Change-return-value-to-44.patch 22 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/packagefiles/patchfile/0000000644000175000017500000000067714516512250033142 0ustar00jpakkanejpakkaneFrom c2da2e490b09f2e251c7f4ef7c1240acee215fec Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Fri, 30 Nov 2018 10:15:47 -0500 Subject: [PATCH 2/2] Change return value to 44 --- foo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/foo.c b/foo.c index e4577b8..54f9119 100644 --- a/foo.c +++ b/foo.c @@ -1,3 +1,3 @@ int dummy_func(void) { - return 43; + return 44; } -- 2.17.1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/patchdir.wrap0000644000175000017500000000037114516512250031023 0ustar00jpakkanejpakkane[wrap-file] directory = foo-1.0-patchdir source_url = http://something.invalid source_filename = foo-1.0.tar.xz source_hash = 9ed8f67d75e43d3be161efb6eddf30dd01995a958ca83951ea64234bac8908c1 lead_directory_missing = true patch_directory = foo-1.0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/patchfile.wrap0000644000175000017500000000063414516512250031166 0ustar00jpakkanejpakkane[wrap-file] directory = foo-1.0-patchfile source_url = http://something.invalid source_filename = foo-1.0.tar.xz source_hash = 9ed8f67d75e43d3be161efb6eddf30dd01995a958ca83951ea64234bac8908c1 lead_directory_missing = true patch_directory = foo-1.0 diff_files = patchfile/0001-Change-return-value-to-43.patch, patchfile/0002-Change-return-value-to-44.patch, patchfile/0001-Change-foo-to-executable.patch ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6466532 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/zlib-1.2.8/0000755000175000017500000000000014562742415027746 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/zlib-1.2.8/foo.c0000644000175000017500000000005014516512250030657 0ustar00jpakkanejpakkaneint dummy_func(void) { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/zlib-1.2.8/meson.build0000644000175000017500000000006314516512250032076 0ustar00jpakkanejpakkaneproject('shared lib', 'c') library('foo', 'foo.c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/153 wrap file should not failed/subprojects/zlib.wrap0000644000175000017500000000061714516512250030170 0ustar00jpakkanejpakkane[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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6466532 meson-1.3.2/test cases/common/154 includedir subproj/0000755000175000017500000000000014562742415022451 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421594.0 meson-1.3.2/test cases/common/154 includedir subproj/meson.build0000644000175000017500000000017514516755532024621 0ustar00jpakkanejpakkaneproject('include dir in subproj test', 'c') subproject('inctest') exe = executable('prog', 'prog.c') test('dummy', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/154 includedir subproj/prog.c0000644000175000017500000000003714516512250023553 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.8186255 meson-1.3.2/test cases/common/154 includedir subproj/subprojects/0000755000175000017500000000000014562742413025012 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6546533 meson-1.3.2/test cases/common/154 includedir subproj/subprojects/inctest/0000755000175000017500000000000014562742415026465 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6546533 meson-1.3.2/test cases/common/154 includedir subproj/subprojects/inctest/include/0000755000175000017500000000000014562742415030110 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/154 includedir subproj/subprojects/inctest/include/incfile.h0000644000175000017500000000005414516512250031660 0ustar00jpakkanejpakkane /* file which is used in the subproject */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/154 includedir subproj/subprojects/inctest/meson.build0000644000175000017500000000044314516512250030617 0ustar00jpakkanejpakkane 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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6546533 meson-1.3.2/test cases/common/155 subproject dir name collision/0000755000175000017500000000000014562742415024457 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/155 subproject dir name collision/a.c0000644000175000017500000000027714516512250025040 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.8186255 meson-1.3.2/test cases/common/155 subproject dir name collision/custom_subproject_dir/0000755000175000017500000000000014562742413031065 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6546533 meson-1.3.2/test cases/common/155 subproject dir name collision/custom_subproject_dir/B/0000755000175000017500000000000014562742415031250 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/155 subproject dir name collision/custom_subproject_dir/B/b.c0000644000175000017500000000065414516512250031631 0ustar00jpakkanejpakkane#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'; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/155 subproject dir name collision/custom_subproject_dir/B/meson.build0000644000175000017500000000014514516512250033401 0ustar00jpakkanejpakkaneproject('B', 'c') C = subproject('C') c = C.get_variable('c') b = library('b', 'b.c', link_with : c) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6586533 meson-1.3.2/test cases/common/155 subproject dir name collision/custom_subproject_dir/C/0000755000175000017500000000000014562742415031251 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/155 subproject dir name collision/custom_subproject_dir/C/c.c0000644000175000017500000000052414516512250031627 0ustar00jpakkanejpakkane#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'; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/155 subproject dir name collision/custom_subproject_dir/C/meson.build0000644000175000017500000000015314516512250033401 0ustar00jpakkanejpakkaneproject('C', 'c') # libc.so cannot be used, it already exists as a reserved name c = library('cee', 'c.c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421595.0 meson-1.3.2/test cases/common/155 subproject dir name collision/meson.build0000644000175000017500000000035614516755533026631 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6586533 meson-1.3.2/test cases/common/155 subproject dir name collision/other_subdir/0000755000175000017500000000000014562742415027150 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6586533 meson-1.3.2/test cases/common/155 subproject dir name collision/other_subdir/custom_subproject_dir/0000755000175000017500000000000014562742415033560 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000021200000000000010210 xustar00116 path=meson-1.3.2/test cases/common/155 subproject dir name collision/other_subdir/custom_subproject_dir/other.c 22 mtime=1698337960.0 meson-1.3.2/test cases/common/155 subproject dir name collision/other_subdir/custom_subproject_dir/o0000644000175000017500000000062414516512250033732 0ustar00jpakkanejpakkane#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'; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/155 subproject dir name collision/other_subdir/meson.build0000644000175000017500000000007214516512250031300 0ustar00jpakkanejpakkaneother = library('other', 'custom_subproject_dir/other.c') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6586533 meson-1.3.2/test cases/common/156 config tool variable/0000755000175000017500000000000014562742415022635 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421594.0 meson-1.3.2/test cases/common/156 config tool variable/meson.build0000644000175000017500000000211114516755532024775 0ustar00jpakkanejpakkane# 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], check: false) else cmd = run_command(['ls', includedir], check: false) endif assert(cmd.returncode() == 0, 'did not run successfully') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6586533 meson-1.3.2/test cases/common/157 custom target subdir depend files/0000755000175000017500000000000014562742415025222 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/157 custom target subdir depend files/copyfile.py0000644000175000017500000000013414516512250027373 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys import shutil shutil.copyfile(sys.argv[1], sys.argv[2]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421595.0 meson-1.3.2/test cases/common/157 custom target subdir depend files/meson.build0000644000175000017500000000020414516755533027364 0ustar00jpakkanejpakkaneproject('custom target subdir depend files', 'c') copy = find_program('copyfile.py') subdir('subdir') executable('foo', foo_src) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6586533 meson-1.3.2/test cases/common/157 custom target subdir depend files/subdir/0000755000175000017500000000000014562742415026512 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/157 custom target subdir depend files/subdir/dep.dat0000644000175000017500000000003414516512250027740 0ustar00jpakkanejpakkaneYou can depend on this file.././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/157 custom target subdir depend files/subdir/foo.c.in0000644000175000017500000000012614516512250030034 0ustar00jpakkanejpakkane#include int main(void) { printf("foo is working.\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/157 custom target subdir depend files/subdir/meson.build0000644000175000017500000000022514516512250030642 0ustar00jpakkanejpakkanefoo_src = custom_target('foo_src', depend_files : 'dep.dat', input : 'foo.c.in', output : 'foo.c', command : [copy, '@INPUT@', '@OUTPUT@'] ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6586533 meson-1.3.2/test cases/common/158 disabler/0000755000175000017500000000000014562742415020453 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421597.0 meson-1.3.2/test cases/common/158 disabler/meson.build0000644000175000017500000001106614516755535022627 0ustar00jpakkanejpakkaneproject('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 set_variable('d6', disabler()) 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(is_disabler(d6), 'set_variable with a disabler should set variable to 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.') assert(d6, 'set_variable with a disabler did not cause this to be skipped.') 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.') assert(not is_disabler(is_variable('d6')), 'is_variable should not return a disabler') assert(is_variable('d6'), 'is_variable for a disabler should return true') if_is_not_disabled = false if is_variable('d6') if_is_not_disabled = true else if_is_not_disabled = true endif assert(if_is_not_disabled, 'Disabler in is_variable should not skip blocks') get_d = get_variable('d6') assert(is_disabler(get_d), 'get_variable should yield a disabler') get_fallback_d = get_variable('nonexistent', disabler()) assert(is_disabler(get_fallback_d), 'get_variable fallback should yield a disabler') var_true = true get_no_fallback_d = get_variable('var_true', disabler()) assert(not is_disabler(get_no_fallback_d), 'get_variable should not fallback to disabler') assert(get_no_fallback_d, 'get_variable should yield true') assert(is_disabler(get_variable(disabler())), 'get_variable should yield a disabler') assert(is_disabler(get_variable(disabler(), var_true)), 'get_variable should yield a disabler') 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') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6586533 meson-1.3.2/test cases/common/159 array option/0000755000175000017500000000000014562742415021276 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421596.0 meson-1.3.2/test cases/common/159 array option/meson.build0000644000175000017500000000131414516755534023444 0ustar00jpakkanejpakkane# 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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/159 array option/meson_options.txt0000644000175000017500000000121414516512250024720 0ustar00jpakkanejpakkane# 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'], ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6626534 meson-1.3.2/test cases/common/16 comparison/0000755000175000017500000000000014562742415020751 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421456.0 meson-1.3.2/test cases/common/16 comparison/meson.build0000644000175000017500000000560514516755320023117 0ustar00jpakkanejpakkaneproject('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) # "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'}''') assert('a' in 'abc') assert('b' not in 'def') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1619506221.0 meson-1.3.2/test cases/common/16 comparison/prog.c0000644000175000017500000000003514041732055022051 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6626534 meson-1.3.2/test cases/common/160 custom target template substitution/0000755000175000017500000000000014562742415025771 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/160 custom target template substitution/checkcopy.py0000644000175000017500000000031214516512250030276 0ustar00jpakkanejpakkane#!/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])) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/160 custom target template substitution/foo.c.in0000644000175000017500000000012614516512250027313 0ustar00jpakkanejpakkane#include int main(void) { printf("foo is working.\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421597.0 meson-1.3.2/test cases/common/160 custom target template substitution/meson.build0000644000175000017500000000076014516755535030144 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6626534 meson-1.3.2/test cases/common/161 not-found dependency/0000755000175000017500000000000014562742415022670 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421598.0 meson-1.3.2/test cases/common/161 not-found dependency/meson.build0000644000175000017500000000071314516755536025042 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6626534 meson-1.3.2/test cases/common/161 not-found dependency/sub/0000755000175000017500000000000014562742415023461 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/161 not-found dependency/sub/meson.build0000644000175000017500000000006114516512250025607 0ustar00jpakkanejpakkaneerror('should be disabled by subdir(if_found:)') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.8226254 meson-1.3.2/test cases/common/161 not-found dependency/subprojects/0000755000175000017500000000000014562742413025231 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6666534 meson-1.3.2/test cases/common/161 not-found dependency/subprojects/trivial/0000755000175000017500000000000014562742415026705 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/161 not-found dependency/subprojects/trivial/meson.build0000644000175000017500000000024114516512250031033 0ustar00jpakkanejpakkaneproject('trivial subproject', 'c') trivial_lib = static_library('trivial', 'trivial.c', install: false) trivial_dep = declare_dependency(link_with: trivial_lib) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/161 not-found dependency/subprojects/trivial/trivial.c0000644000175000017500000000004514516512250030511 0ustar00jpakkanejpakkaneint subfunc(void) { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/161 not-found dependency/testlib.c0000644000175000017500000000000014516512250024457 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6666534 meson-1.3.2/test cases/common/162 subdir if_found/0000755000175000017500000000000014562742415021723 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421598.0 meson-1.3.2/test cases/common/162 subdir if_found/meson.build0000644000175000017500000000043614516755536024077 0ustar00jpakkanejpakkaneproject('subdir if found') 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.') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6666534 meson-1.3.2/test cases/common/162 subdir if_found/subdir/0000755000175000017500000000000014562742415023213 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/162 subdir if_found/subdir/meson.build0000644000175000017500000000001514516512250025340 0ustar00jpakkanejpakkanevariable = 5 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6666534 meson-1.3.2/test cases/common/163 default options prefix dependent defaults/0000755000175000017500000000000014562742415026757 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421599.0 meson-1.3.2/test cases/common/163 default options prefix dependent defaults/meson.build0000644000175000017500000000017014516755537031127 0ustar00jpakkanejpakkaneproject('default options prefix dependent defaults ', default_options : ['sharedstatedir=/sharedstate', 'prefix=/usr']) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6666534 meson-1.3.2/test cases/common/164 dependency factory/0000755000175000017500000000000014562742415022431 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421602.0 meson-1.3.2/test cases/common/164 dependency factory/meson.build0000644000175000017500000000350614516755542024603 0ustar00jpakkanejpakkaneproject('dependency factory', 'c', meson_version : '>=0.53') dep = dependency('gl', method: 'pkg-config', required: false) if dep.found() assert(dep.type_name() == 'pkgconfig') dep.get_pkgconfig_variable('prefix') endif dep = dependency('SDL2', method: 'pkg-config', required: false) if dep.found() assert(dep.type_name() == 'pkgconfig') dep.get_pkgconfig_variable('prefix') endif dep = dependency('SDL2', method: 'config-tool', required: false) if dep.found() assert(dep.type_name() == 'config-tool') dep.get_configtool_variable('prefix') endif dep = dependency('Vulkan', method: 'pkg-config', required: false) if dep.found() assert(dep.type_name() == 'pkgconfig') dep.get_pkgconfig_variable('prefix') endif dep = dependency('pcap', method: 'pkg-config', required: false) if dep.found() assert(dep.type_name() == 'pkgconfig') dep.get_pkgconfig_variable('prefix') endif dep = dependency('pcap', method: 'config-tool', required: false) if dep.found() assert(dep.type_name() == 'config-tool') dep.get_configtool_variable('prefix') endif dep = dependency('cups', method: 'pkg-config', required: false) if dep.found() assert(dep.type_name() == 'pkgconfig') dep.get_pkgconfig_variable('prefix') endif dep = dependency('cups', method: 'config-tool', required: false) if dep.found() assert(dep.type_name() == 'config-tool') dep.get_configtool_variable('prefix') endif dep = dependency('libwmf', method: 'pkg-config', required: false) if dep.found() assert(dep.type_name() == 'pkgconfig') dep.get_pkgconfig_variable('prefix') endif dep = dependency('libwmf', method: 'config-tool', required: false) if dep.found() assert(dep.type_name() == 'config-tool') dep.get_configtool_variable('prefix') endif dep = dependency('boost', method: 'system', required: false) if dep.found() assert(dep.type_name() == 'system') endif ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6666534 meson-1.3.2/test cases/common/165 get project license/0000755000175000017500000000000014562742415022475 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/165 get project license/bar.c0000644000175000017500000000013514516512250023373 0ustar00jpakkanejpakkane#include int main(void) { printf("I'm a main project bar.\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421600.0 meson-1.3.2/test cases/common/165 get project license/meson.build0000644000175000017500000000032314516755540024637 0ustar00jpakkanejpakkaneproject('bar', 'c', license: 'Apache-2.0') executable('bar', 'bar.c') license = meson.project_license()[0] if license != 'Apache-2.0' error('The license should be Apache-2.0, but it is: ' + license) endif ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6666534 meson-1.3.2/test cases/common/166 yield/0000755000175000017500000000000014562742415017773 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421600.0 meson-1.3.2/test cases/common/166 yield/meson.build0000644000175000017500000000053014516755540022135 0ustar00jpakkanejpakkaneproject('yield_options') 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..') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/166 yield/meson_options.txt0000644000175000017500000000025714516512250023423 0ustar00jpakkanejpakkaneoption('unshared_option', type : 'string', value : 'one') option('shared_option', type : 'string', value : 'two') option('wrongtype_option', type : 'string', value : 'three') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.8226254 meson-1.3.2/test cases/common/166 yield/subprojects/0000755000175000017500000000000014562742413022334 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6666534 meson-1.3.2/test cases/common/166 yield/subprojects/sub/0000755000175000017500000000000014562742415023127 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/166 yield/subprojects/sub/meson.build0000644000175000017500000000046514516512250025265 0ustar00jpakkanejpakkaneproject('subbie') 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.') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/166 yield/subprojects/sub/meson_options.txt0000644000175000017500000000033314516512250026552 0ustar00jpakkanejpakkaneoption('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6746535 meson-1.3.2/test cases/common/167 subproject nested subproject dirs/0000755000175000017500000000000014562742415025374 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.8226254 meson-1.3.2/test cases/common/167 subproject nested subproject dirs/contrib/0000755000175000017500000000000014562742413027032 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.8306255 meson-1.3.2/test cases/common/167 subproject nested subproject dirs/contrib/subprojects/0000755000175000017500000000000014562742413031375 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6746535 meson-1.3.2/test cases/common/167 subproject nested subproject dirs/contrib/subprojects/alpha/0000755000175000017500000000000014562742415032464 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/167 subproject nested subproject dirs/contrib/subprojects/alpha/a.c0000644000175000017500000000054514516512250033043 0ustar00jpakkanejpakkaneint 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(); } ././@PaxHeader0000000000000000000000000000021100000000000010207 xustar00115 path=meson-1.3.2/test cases/common/167 subproject nested subproject dirs/contrib/subprojects/alpha/meson.build 22 mtime=1698337960.0 meson-1.3.2/test cases/common/167 subproject nested subproject dirs/contrib/subprojects/alpha/meson.0000644000175000017500000000022314516512250033572 0ustar00jpakkanejpakkaneproject('alpha project', 'c', subproject_dir: 'var/subprojects') b = subproject('beta') l = library('a', 'a.c', link_with : b.get_variable('lb')) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.8306255 meson-1.3.2/test cases/common/167 subproject nested subproject dirs/contrib/subprojects/alpha/var/0000755000175000017500000000000014562742413033252 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000022400000000000010213 xustar00120 path=meson-1.3.2/test cases/common/167 subproject nested subproject dirs/contrib/subprojects/alpha/var/subprojects/ 28 mtime=1707853068.6746535 meson-1.3.2/test cases/common/167 subproject nested subproject dirs/contrib/subprojects/alpha/var/su0000755000175000017500000000000014562742415033624 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000024600000000000010217 xustar00144 path=meson-1.3.2/test cases/common/167 subproject nested subproject dirs/contrib/subprojects/alpha/var/subprojects/wrap_files_might_be_here 22 mtime=1698337960.0 meson-1.3.2/test cases/common/167 subproject nested subproject dirs/contrib/subprojects/alpha/var/su0000644000175000017500000000000114516512250033604 0ustar00jpakkanejpakkane ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6746535 meson-1.3.2/test cases/common/167 subproject nested subproject dirs/contrib/subprojects/beta/0000755000175000017500000000000014562742415032312 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/167 subproject nested subproject dirs/contrib/subprojects/beta/b.c0000644000175000017500000000052314516512250032666 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000021000000000000010206 xustar00114 path=meson-1.3.2/test cases/common/167 subproject nested subproject dirs/contrib/subprojects/beta/meson.build 22 mtime=1698337960.0 meson-1.3.2/test cases/common/167 subproject nested subproject dirs/contrib/subprojects/beta/meson.b0000644000175000017500000000015214516512250033563 0ustar00jpakkanejpakkaneproject('beta project', 'c') lb = shared_library('b', 'b.c') notfound = dependency('', required : false) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421602.0 meson-1.3.2/test cases/common/167 subproject nested subproject dirs/meson.build0000644000175000017500000000060614516755542027544 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/167 subproject nested subproject dirs/prog.c0000644000175000017500000000010514516512250026472 0ustar00jpakkanejpakkaneint func(void); int main(void) { return func() == 42 ? 0 : 1; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6746535 meson-1.3.2/test cases/common/168 preserve gendir/0000755000175000017500000000000014562742415021753 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/168 preserve gendir/base.inp0000644000175000017500000000000514516512250023357 0ustar00jpakkanejpakkanebase ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.8306255 meson-1.3.2/test cases/common/168 preserve gendir/com/0000755000175000017500000000000014562742413022527 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6746535 meson-1.3.2/test cases/common/168 preserve gendir/com/mesonbuild/0000755000175000017500000000000014562742415024672 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/168 preserve gendir/com/mesonbuild/subbie.inp0000644000175000017500000000000714516512250026637 0ustar00jpakkanejpakkanesubbie ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/168 preserve gendir/genprog.py0000755000175000017500000000225414516512250023763 0ustar00jpakkanejpakkane#!/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(f'Input file {ifile} does not start with search dir {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)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421602.0 meson-1.3.2/test cases/common/168 preserve gendir/meson.build0000644000175000017500000000064314516755542024124 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/168 preserve gendir/testprog.c0000644000175000017500000000014514516512250023755 0ustar00jpakkanejpakkane#include"base.h" #include"com/mesonbuild/subbie.h" int main(void) { return base() + subbie(); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6826537 meson-1.3.2/test cases/common/169 source in dep/0000755000175000017500000000000014562742415021310 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/169 source in dep/bar.cpp0000644000175000017500000000010614516512250022544 0ustar00jpakkanejpakkaneextern "C" int foo(void); int main(void) { return foo() != 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/169 source in dep/foo.c0000644000175000017500000000004114516512250022221 0ustar00jpakkanejpakkaneint foo(void) { return 42; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6826537 meson-1.3.2/test cases/common/169 source in dep/generated/0000755000175000017500000000000014562742415023246 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/169 source in dep/generated/funname0000644000175000017500000000002614516512250024607 0ustar00jpakkanejpakkanemy_wonderful_function ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/169 source in dep/generated/genheader.py0000755000175000017500000000033314516512250025533 0ustar00jpakkanejpakkane#!/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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/169 source in dep/generated/main.c0000644000175000017500000000012414516512250024322 0ustar00jpakkanejpakkane#include"funheader.h" int main(void) { return my_wonderful_function() != 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/169 source in dep/generated/meson.build0000644000175000017500000000042214516512250025375 0ustar00jpakkanejpakkanefp = 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421603.0 meson-1.3.2/test cases/common/169 source in dep/meson.build0000644000175000017500000000022114516755543023452 0ustar00jpakkanejpakkaneproject('foo', 'c', 'cpp') dep = declare_dependency(sources : 'foo.c') executable('bar', 'bar.cpp', dependencies : dep) subdir('generated') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6826537 meson-1.3.2/test cases/common/17 array/0000755000175000017500000000000014562742415017716 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1619506221.0 meson-1.3.2/test cases/common/17 array/func.c0000644000175000017500000000003514041732055021002 0ustar00jpakkanejpakkaneint func(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421457.0 meson-1.3.2/test cases/common/17 array/meson.build0000644000175000017500000000017314516755321022060 0ustar00jpakkanejpakkaneproject('array test', 'c') arr = [ 'func.c', 'prog.c'] exe = executable('prog', sources : arr) test('arr test', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1619506221.0 meson-1.3.2/test cases/common/17 array/prog.c0000644000175000017500000000007214041732055021017 0ustar00jpakkanejpakkaneextern int func(void); int main(void) { return func(); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6826537 meson-1.3.2/test cases/common/170 generator link whole/0000755000175000017500000000000014562742415022663 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/170 generator link whole/export.h0000644000175000017500000000070214516512250024343 0ustar00jpakkanejpakkane#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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/170 generator link whole/generator.py0000755000175000017500000000115414516512250025216 0ustar00jpakkanejpakkane#!/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() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/170 generator link whole/main.c0000644000175000017500000000030514516512250023740 0ustar00jpakkanejpakkane#include "meson_test_function.h" #include int main(void) { if (meson_test_function() != 19) { printf("Bad meson_test_function()\n"); return 1; } return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421605.0 meson-1.3.2/test cases/common/170 generator link whole/meson.build0000644000175000017500000000421614516755545025037 0ustar00jpakkanejpakkaneproject('generator link_whole', 'c') if meson.backend() == 'xcode' error('MESON_SKIP_TEST: whole-archive not supported in Xcode. Patches welcome.') 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/170 generator link whole/meson_test_function.tmpl0000644000175000017500000000000014516512250027623 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/170 generator link whole/pull_meson_test_function.c0000644000175000017500000000020114516512250030130 0ustar00jpakkanejpakkane#include "export.h" #include "meson_test_function.h" int DLL_PUBLIC function_puller(void) { return meson_test_function(); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6826537 meson-1.3.2/test cases/common/171 initial c_args/0000755000175000017500000000000014562742415021531 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421605.0 meson-1.3.2/test cases/common/171 initial c_args/meson.build0000644000175000017500000000047614516755545023711 0ustar00jpakkanejpakkaneproject('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.') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/171 initial c_args/test.json0000644000175000017500000000025414516515714023403 0ustar00jpakkanejpakkane{ "matrix": { "options": { "c_args": [{ "val": "-funroll-loops" }], "c_link_args": [{ "val": "-Dtest_harmless_but_useless_link_arg" }] } } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6866539 meson-1.3.2/test cases/common/172 identical target name in subproject flat layout/0000755000175000017500000000000014562742415027723 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/172 identical target name in subproject flat layout/foo.c0000644000175000017500000000005514516512250030641 0ustar00jpakkanejpakkaneint meson_test_main_foo(void) { return 10; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/172 identical target name in subproject flat layout/main.c0000644000175000017500000000053314516512250031003 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421605.0 meson-1.3.2/test cases/common/172 identical target name in subproject flat layout/meson.build0000644000175000017500000000112314516755545032071 0ustar00jpakkanejpakkaneproject('subproject targets', 'c') if meson.backend() == 'xcode' error('MESON_SKIP_TEST: many targets with the same name not supported in Xcode. Patches welcome.') endif # 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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.8346257 meson-1.3.2/test cases/common/172 identical target name in subproject flat layout/subprojects/0000755000175000017500000000000014562742413032264 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000021400000000000010212 xustar00112 path=meson-1.3.2/test cases/common/172 identical target name in subproject flat layout/subprojects/subproj/ 28 mtime=1707853068.6866539 meson-1.3.2/test cases/common/172 identical target name in subproject flat layout/subprojects/subpro0000755000175000017500000000000014562742415033521 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000021300000000000010211 xustar00117 path=meson-1.3.2/test cases/common/172 identical target name in subproject flat layout/subprojects/subproj/foo.c 22 mtime=1698337960.0 meson-1.3.2/test cases/common/172 identical target name in subproject flat layout/subprojects/subpro0000644000175000017500000000006014516512250033506 0ustar00jpakkanejpakkaneint meson_test_subproj_foo(void) { return 20; } ././@PaxHeader0000000000000000000000000000022100000000000010210 xustar00123 path=meson-1.3.2/test cases/common/172 identical target name in subproject flat layout/subprojects/subproj/meson.build 22 mtime=1698337960.0 meson-1.3.2/test cases/common/172 identical target name in subproject flat layout/subprojects/subpro0000644000175000017500000000012714516512250033512 0ustar00jpakkanejpakkaneproject('subproj', 'c') foo = static_library('foo', 'foo.c', name_prefix : 'subproj') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6866539 meson-1.3.2/test cases/common/173 as-needed/0000755000175000017500000000000014562742415020510 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/173 as-needed/config.h0000644000175000017500000000057714516512250022126 0ustar00jpakkanejpakkane#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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/173 as-needed/libA.cpp0000644000175000017500000000015614516512250022054 0ustar00jpakkanejpakkane#define BUILDING_DLL #include "libA.h" namespace meson_test_as_needed { DLL_PUBLIC bool linked = false; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/173 as-needed/libA.h0000644000175000017500000000013114516512250021512 0ustar00jpakkanejpakkane#include "config.h" namespace meson_test_as_needed { DLL_PUBLIC extern bool linked; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/173 as-needed/libB.cpp0000644000175000017500000000044114516512250022052 0ustar00jpakkanejpakkane#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; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/173 as-needed/main.cpp0000644000175000017500000000020014516512250022117 0ustar00jpakkanejpakkane#include #include "libA.h" int main(void) { return !meson_test_as_needed::linked ? EXIT_SUCCESS : EXIT_FAILURE; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1702314114.0 meson-1.3.2/test cases/common/173 as-needed/meson.build0000644000175000017500000000141414535640202022641 0ustar00jpakkanejpakkaneproject('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) # Since Sonoma / Xcode 15 the macos linker considers the dependency via the # initializer sufficient to pull in the other other library. There's no good # way to detect the linker version here, so just skip the on macos. if host_machine.system() == 'darwin' error('MESON_SKIP_TEST: the macos linker is too smart for this test') endif ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6906538 meson-1.3.2/test cases/common/174 ndebug if-release enabled/0000755000175000017500000000000014562742415023500 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/174 ndebug if-release enabled/main.c0000644000175000017500000000053014516512250024555 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421607.0 meson-1.3.2/test cases/common/174 ndebug if-release enabled/meson.build0000644000175000017500000000027014516755547025652 0ustar00jpakkanejpakkaneproject('ndebug enabled', 'c', default_options : [ 'buildtype=debugoptimized', 'b_ndebug=if-release', ]) test('exe', executable('main', 'main.c')) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6906538 meson-1.3.2/test cases/common/175 ndebug if-release disabled/0000755000175000017500000000000014562742415023656 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/175 ndebug if-release disabled/main.c0000644000175000017500000000014414516512250024734 0ustar00jpakkanejpakkane#include #include int main(void) { assert(0); return EXIT_SUCCESS; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421607.0 meson-1.3.2/test cases/common/175 ndebug if-release disabled/meson.build0000644000175000017500000000026214516755547026031 0ustar00jpakkanejpakkaneproject('ndebug disabled', 'c', default_options : [ 'buildtype=release', 'b_ndebug=if-release', ]) test('exe', executable('main', 'main.c')) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6906538 meson-1.3.2/test cases/common/176 subproject version/0000755000175000017500000000000014562742415022514 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421607.0 meson-1.3.2/test cases/common/176 subproject version/meson.build0000644000175000017500000000027614516755547024674 0ustar00jpakkanejpakkaneproject('subproject version', version : '2.3.4', license: 'mylicense') subproject('a') liba_dep = dependency('a', fallback: ['a', 'liba_dep'], version: ['>= 0.30.0', '!= 0.99.0']) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.8346257 meson-1.3.2/test cases/common/176 subproject version/subprojects/0000755000175000017500000000000014562742413025055 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6906538 meson-1.3.2/test cases/common/176 subproject version/subprojects/a/0000755000175000017500000000000014562742415025277 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/176 subproject version/subprojects/a/meson.build0000644000175000017500000000017214516512250027430 0ustar00jpakkanejpakkaneproject('mysubproject', version : '1.0.0', license : 'sublicense') liba_dep = declare_dependency (version : '1.0.0') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.6906538 meson-1.3.2/test cases/common/177 subdir_done/0000755000175000017500000000000014562742415021164 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421608.0 meson-1.3.2/test cases/common/177 subdir_done/meson.build0000644000175000017500000000037714516755550023340 0ustar00jpakkanejpakkane# 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') if true subdir_done() endif executable('main', 'main.cpp') error('Unreachable') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.694654 meson-1.3.2/test cases/common/178 bothlibraries/0000755000175000017500000000000014562742415021521 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/178 bothlibraries/dummy.py0000644000175000017500000000024214516512250023213 0ustar00jpakkanejpakkane#!/usr/bin/env python3 from pathlib import Path import sys if __name__ == '__main__': Path(sys.argv[1]).write_text('Hello World\n') raise SystemExit(0) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/178 bothlibraries/foo.cpp0000644000175000017500000000024114516512250022774 0ustar00jpakkanejpakkane#include #include "mylib.h" extern "C" { DO_EXPORT int foo(void); } int foo(void) { auto bptr = std::make_shared(0); return *bptr; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/178 bothlibraries/libfile.c0000644000175000017500000000014014516512250023255 0ustar00jpakkanejpakkane#include "mylib.h" DO_EXPORT int retval = 42; DO_EXPORT int func(void) { return retval; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/178 bothlibraries/main.c0000644000175000017500000000017514516512250022603 0ustar00jpakkanejpakkane#include "mylib.h" DO_IMPORT int func(void); DO_IMPORT int retval; int main(void) { return func() == retval ? 0 : 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/178 bothlibraries/main2.c0000644000175000017500000000023614516512250022663 0ustar00jpakkanejpakkane#include "mylib.h" DO_IMPORT int func(void); DO_IMPORT int foo(void); DO_IMPORT int retval; int main(void) { return func() + foo() == retval ? 0 : 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421611.0 meson-1.3.2/test cases/common/178 bothlibraries/meson.build0000644000175000017500000000510514516755553023672 0ustar00jpakkanejpakkaneproject('both libraries linking test', 'c', 'cpp') both_libs = both_libraries('mylib', 'libfile.c') dep = declare_dependency(link_with: both_libs) 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) exe_dep = executable('prog-dep', 'main.c', dependencies : [dep]) # Try using it in a custom_target custom_target('tgt_a', command: [ find_program('./dummy.py'), '@OUTPUT@', both_libs, ], output: ['hello1.txt'], input: [both_libs], ) test('runtest-shared', exe_shared) test('runtest-static', exe_static) test('runtest-both', exe_both) test('runtest-dep', exe_dep) # 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 {set,get}_variable set_variable('both_libs2', both_libs) both_libs3 = get_variable('both_libs') # Ensure that calling the build target methods also works assert(both_libs.name() == 'mylib') assert(both_libs2.name() == 'mylib') assert(both_libs3.name() == 'mylib') assert(both_libs2.get_shared_lib().name() == 'mylib') assert(both_libs3.get_static_lib().name() == 'mylib') test('runtest-shared-2', exe_shared2) test('runtest-static-2', exe_static2) test('runtest-both-2', exe_both2) # Regression test: libccpp has both C and C++ sources. The executable only has # C sources. It should still link using the C++ compiler. When using # both_libraries the static has no sources and thus no compilers, resulting in # the executable linking using the C compiler. # https://github.com/Netflix/vmaf/issues/1107 libccpp = both_libraries('ccpp', 'foo.cpp', 'libfile.c', cpp_args : ['-std=c++11'], c_static_args : ['-DSTATIC_COMPILATION'], cpp_static_args : ['-DSTATIC_COMPILATION'], ) exe = executable('prog-ccpp', 'main2.c', link_with: libccpp.get_static_lib(), c_args : ['-DSTATIC_COMPILATION'], ) test('runtest-ccpp', exe) exe = executable('prog-ccpp-shared', 'main2.c', link_with: libccpp.get_shared_lib(), ) test('runtest-ccpp-shared', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/178 bothlibraries/mylib.h0000644000175000017500000000037014516512250022775 0ustar00jpakkanejpakkane#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 ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.694654 meson-1.3.2/test cases/common/179 escape and unicode/0000755000175000017500000000000014562742415022263 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/179 escape and unicode/file.c.in0000644000175000017500000000014714516512250023744 0ustar00jpakkanejpakkane#include const char* does_it_work(void) { printf("{NAME}\n"); return "yes it does"; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/179 escape and unicode/file.py0000644000175000017500000000033514516512250023544 0ustar00jpakkanejpakkane#!/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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/179 escape and unicode/find.py0000644000175000017500000000025214516512250023543 0ustar00jpakkanejpakkane#!/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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/179 escape and unicode/fun.c0000644000175000017500000000004214516512250023202 0ustar00jpakkanejpakkaneint a_fun(void) { return 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/179 escape and unicode/main.c0000644000175000017500000000027514516512250023346 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421610.0 meson-1.3.2/test cases/common/179 escape and unicode/meson.build0000644000175000017500000000213414516755552024432 0ustar00jpakkanejpakkaneproject('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'), check: true) 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 ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.694654 meson-1.3.2/test cases/common/18 includedir/0000755000175000017500000000000014562742415020723 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.694654 meson-1.3.2/test cases/common/18 includedir/include/0000755000175000017500000000000014562742415022346 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1619506221.0 meson-1.3.2/test cases/common/18 includedir/include/func.h0000644000175000017500000000007314041732055023441 0ustar00jpakkanejpakkane#ifndef FUNC_H__ #define FUNC_H__ int func(void); #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421457.0 meson-1.3.2/test cases/common/18 includedir/meson.build0000644000175000017500000000227014516755321023065 0ustar00jpakkanejpakkaneproject('include dir test', 'c') inc = include_directories('include') subdir('src') errormsg = '''Tried to form an absolute path to a dir in the source tree. You should not do that but use relative paths instead, for directories that are part of your project. 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. Note that this error message can also be triggered by external dependencies being installed within your source tree - it's not recommended to do this. ''' testcase expect_error(errormsg) include_directories(meson.current_source_dir() / 'include') endtestcase # Test for issue #12217 include_directories(meson.current_source_dir() + 'xyz') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.698654 meson-1.3.2/test cases/common/18 includedir/src/0000755000175000017500000000000014562742415021512 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1619506221.0 meson-1.3.2/test cases/common/18 includedir/src/func.c0000644000175000017500000000006414041732055022600 0ustar00jpakkanejpakkane#include "func.h" int func(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1619506221.0 meson-1.3.2/test cases/common/18 includedir/src/meson.build0000644000175000017500000000031714041732055023644 0ustar00jpakkanejpakkaneexe = 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1619506221.0 meson-1.3.2/test cases/common/18 includedir/src/prog.c0000644000175000017500000000007114041732055022612 0ustar00jpakkanejpakkane#include "func.h" int main(void) { return func(); } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.698654 meson-1.3.2/test cases/common/18 includedirxyz/0000755000175000017500000000000014562742415021476 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/18 includedirxyz/do_not_delete0000644000175000017500000000005514516512250024214 0ustar00jpakkanejpakkaneThis file is to ensure this directory exists ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.698654 meson-1.3.2/test cases/common/180 has link arg/0000755000175000017500000000000014562742415021104 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421611.0 meson-1.3.2/test cases/common/180 has link arg/meson.build0000644000175000017500000000407514516755553023262 0ustar00jpakkanejpakkaneproject('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.') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.702654 meson-1.3.2/test cases/common/181 same target name flat layout/0000755000175000017500000000000014562742415024164 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/181 same target name flat layout/foo.c0000644000175000017500000000005514516512250025102 0ustar00jpakkanejpakkaneint meson_test_main_foo(void) { return 10; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/181 same target name flat layout/main.c0000644000175000017500000000053314516512250025244 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421611.0 meson-1.3.2/test cases/common/181 same target name flat layout/meson.build0000644000175000017500000000107414516755553026336 0ustar00jpakkanejpakkaneproject('subdir targets', 'c') if meson.backend() == 'xcode' error('MESON_SKIP_TEST: many targets with the same name not supported in Xcode. Patches welcome.') endif # 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) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.702654 meson-1.3.2/test cases/common/181 same target name flat layout/subdir/0000755000175000017500000000000014562742415025454 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/181 same target name flat layout/subdir/foo.c0000644000175000017500000000006014516512250026366 0ustar00jpakkanejpakkaneint meson_test_subproj_foo(void) { return 20; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/181 same target name flat layout/subdir/meson.build0000644000175000017500000000010414516512250027600 0ustar00jpakkanejpakkanesubdir_foo = static_library('foo', 'foo.c', name_prefix : 'subdir') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.702654 meson-1.3.2/test cases/common/182 find override/0000755000175000017500000000000014562742415021403 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421613.0 meson-1.3.2/test cases/common/182 find override/meson.build0000644000175000017500000000204614516755555023557 0ustar00jpakkanejpakkaneproject('find program override', 'c') gencodegen = find_program('gencodegen', required : false) six_prog = find_program('six_meson_exe', required : false) assert(not gencodegen.found(), 'gencodegen is an internal program, should not be found') assert(not six_prog.found(), 'six_meson_exe 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') tool = find_program('sometool') assert(tool.found()) assert(tool.full_path() != '') assert(tool.full_path() == tool.path()) # six_meson_exe is an overridden project executable six_prog = find_program('six_meson_exe') assert(six_prog.found()) assert(six_prog.full_path() != '') assert(six_prog.full_path() == six_prog.path()) # We have prog-version.py in current directory, but it's version 1.0. # This needs to use fallback for "prog-version" name which will be version 2.0. prog = find_program('prog-version.py', 'prog-version', version: '>= 2.0') assert(prog.found()) assert(prog.version() == '2.0') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.706654 meson-1.3.2/test cases/common/182 find override/otherdir/0000755000175000017500000000000014562742415023223 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/182 find override/otherdir/main.c0000644000175000017500000000012614516512250024301 0ustar00jpakkanejpakkaneint be_seeing_you(void); int main(void) { return be_seeing_you() == 6 ? 0 : 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/182 find override/otherdir/main2.c0000644000175000017500000000013414516512250024362 0ustar00jpakkanejpakkaneint number_returner(void); int main(void) { return number_returner() == 100 ? 0 : 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/182 find override/otherdir/meson.build0000644000175000017500000000121514516512250025353 0ustar00jpakkanejpakkanegen = 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) # Override stuff with an executables meson.override_find_program('six_meson_exe', 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/182 find override/otherdir/source.desc0000644000175000017500000000001614516512250025347 0ustar00jpakkanejpakkanebe_seeing_you ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/182 find override/otherdir/source2.desc0000644000175000017500000000002014516512250025424 0ustar00jpakkanejpakkanenumber_returner ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/182 find override/prog-version.py0000755000175000017500000000004614516512250024401 0ustar00jpakkanejpakkane#! /usr/bin/env python3 print('1.0') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.706654 meson-1.3.2/test cases/common/182 find override/subdir/0000755000175000017500000000000014562742415022673 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/182 find override/subdir/converter.py0000755000175000017500000000037214516512250025250 0ustar00jpakkanejpakkane#!/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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/182 find override/subdir/gencodegen.py.in0000755000175000017500000000040114516512250025735 0ustar00jpakkanejpakkane#!/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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/182 find override/subdir/meson.build0000644000175000017500000000052014516512250025021 0ustar00jpakkanejpakkanex = 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) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.706654 meson-1.3.2/test cases/common/182 find override/subprojects/0000755000175000017500000000000014562742415023746 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.706654 meson-1.3.2/test cases/common/182 find override/subprojects/sub/0000755000175000017500000000000014562742415024537 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/182 find override/subprojects/sub/meson.build0000644000175000017500000000014014516512250026663 0ustar00jpakkanejpakkaneproject('tools') exe = find_program('gencodegen') meson.override_find_program('sometool', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/182 find override/subprojects/sub.wrap0000644000175000017500000000010014516512250025410 0ustar00jpakkanejpakkane[wrap-file] directory = sub [provide] program_names = sometool ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7146542 meson-1.3.2/test cases/common/182 find override/subprojects/sub2/0000755000175000017500000000000014562742415024621 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/182 find override/subprojects/sub2/meson.build0000644000175000017500000000015214516512250026750 0ustar00jpakkanejpakkaneproject('sub2') prog = find_program('prog-version.py') meson.override_find_program('prog-version', prog) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/182 find override/subprojects/sub2/prog-version.py0000755000175000017500000000004614516512250027617 0ustar00jpakkanejpakkane#! /usr/bin/env python3 print('2.0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/182 find override/subprojects/sub2.wrap0000644000175000017500000000010514516512250025477 0ustar00jpakkanejpakkane[wrap-file] directory = sub2 [provide] program_names = prog-version ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7146542 meson-1.3.2/test cases/common/183 partial dependency/0000755000175000017500000000000014562742415022417 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7146542 meson-1.3.2/test cases/common/183 partial dependency/declare_dependency/0000755000175000017500000000000014562742415026214 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7146542 meson-1.3.2/test cases/common/183 partial dependency/declare_dependency/headers/0000755000175000017500000000000014562742415027627 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/183 partial dependency/declare_dependency/headers/foo.c0000644000175000017500000000121114516512250030540 0ustar00jpakkanejpakkane/* 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." ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/183 partial dependency/declare_dependency/headers/foo.h0000644000175000017500000000115114516512250030550 0ustar00jpakkanejpakkane/* 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); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/183 partial dependency/declare_dependency/main.c0000644000175000017500000000133314516512250027273 0ustar00jpakkanejpakkane/* 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; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/183 partial dependency/declare_dependency/meson.build0000644000175000017500000000170614516512250030351 0ustar00jpakkanejpakkane# 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/183 partial dependency/declare_dependency/other.c0000644000175000017500000000121414516512250027466 0ustar00jpakkanejpakkane/* 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421614.0 meson-1.3.2/test cases/common/183 partial dependency/meson.build0000644000175000017500000000122314516755556024570 0ustar00jpakkanejpakkane# 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') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7186542 meson-1.3.2/test cases/common/184 openmp/0000755000175000017500000000000014562742415020163 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/184 openmp/main.c0000644000175000017500000000051414516512250021242 0ustar00jpakkanejpakkane#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 } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/184 openmp/main.cpp0000644000175000017500000000054314516512250021604 0ustar00jpakkanejpakkane#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 } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/184 openmp/main.f900000644000175000017500000000032714516512250021420 0ustar00jpakkanejpakkaneuse, 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0 meson-1.3.2/test cases/common/184 openmp/meson.build0000644000175000017500000000356714562742373022343 0ustar00jpakkanejpakkaneproject('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' and cc.version().version_compare('<10.0.0') error('MESON_SKIP_TEST clang-cl is too old to 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())) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7186542 meson-1.3.2/test cases/common/185 same target name/0000755000175000017500000000000014562742415021763 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/185 same target name/file.c0000644000175000017500000000004114516512250023030 0ustar00jpakkanejpakkaneint func(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421614.0 meson-1.3.2/test cases/common/185 same target name/meson.build0000644000175000017500000000011114516755556024127 0ustar00jpakkanejpakkaneproject('same name', 'c') static_library('foo', 'file.c') subdir('sub') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7186542 meson-1.3.2/test cases/common/185 same target name/sub/0000755000175000017500000000000014562742415022554 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/185 same target name/sub/file2.c0000644000175000017500000000004114516512250023703 0ustar00jpakkanejpakkaneint func(void) { return 5; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/185 same target name/sub/meson.build0000644000175000017500000000004114516512250024700 0ustar00jpakkanejpakkanestatic_library('foo', 'file2.c') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7226543 meson-1.3.2/test cases/common/186 test depends/0000755000175000017500000000000014562742415021251 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/186 test depends/gen.py0000755000175000017500000000027014516512250022365 0ustar00jpakkanejpakkane#!/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() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/186 test depends/main.c0000644000175000017500000000003514516512250022326 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421616.0 meson-1.3.2/test cases/common/186 test depends/meson.build0000644000175000017500000000121114516755560023412 0ustar00jpakkanejpakkaneproject('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(), ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/186 test depends/test.py0000755000175000017500000000054414516512250022577 0ustar00jpakkanejpakkane#!/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() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7226543 meson-1.3.2/test cases/common/187 args flattening/0000755000175000017500000000000014562742415021740 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421616.0 meson-1.3.2/test cases/common/187 args flattening/meson.build0000644000175000017500000000203514516755560024106 0ustar00jpakkanejpakkaneproject('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') arr = meson.get_cross_property('does-not-exist', ['bar', 'baz']) assert(arr == ['bar', 'baz'], 'meson.get_cross_property with array fallback is broken') arr = meson.get_external_property('does-not-exist', ['bar', 'baz']) assert(arr == ['bar', 'baz'], 'meson.get_external_property with array fallback is broken') arr = meson.get_external_property('does-not-exist', ['bar', 'baz'], native: true) assert(arr == ['bar', 'baz'], 'meson.get_external_property native:true with array fallback is broken') arr = meson.get_external_property('does-not-exist', ['bar', 'baz'], native: false) assert(arr == ['bar', 'baz'], 'meson.get_external_property native:false with array fallback is broken') # Test deprecated behaviour conf = configuration_data() conf.set(['foo', 'bar']) message(conf.get('foo')) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7226543 meson-1.3.2/test cases/common/188 dict/0000755000175000017500000000000014562742415017614 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421617.0 meson-1.3.2/test cases/common/188 dict/meson.build0000644000175000017500000000441014516755561021762 0ustar00jpakkanejpakkaneproject('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') # Complex types d = { 'sanity': 1, 'host': host_machine, 'meson': meson, } assert(d['sanity'] == 1) assert(not is_disabler(d['meson'])) assert(not is_disabler(d['host'])) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/188 dict/prog.c0000644000175000017500000000017414516512250020720 0ustar00jpakkanejpakkane#include int main(int argc, char **argv) { if (argc != 3) return 1; return strcmp(argv[1], argv[2]); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7226543 meson-1.3.2/test cases/common/189 check header/0000755000175000017500000000000014562742415021160 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421619.0 meson-1.3.2/test cases/common/189 check header/meson.build0000644000175000017500000000355014516755563023334 0ustar00jpakkanejpakkaneproject('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 nonexistent header.') endforeach ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/189 check header/ouagadougou.h0000644000175000017500000000004314516512250023634 0ustar00jpakkanejpakkane#define OMG_THIS_SHOULDNT_BE_FOUND ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7266543 meson-1.3.2/test cases/common/19 header in file list/0000755000175000017500000000000014562742415022255 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421271.0 meson-1.3.2/test cases/common/19 header in file list/header.h0000644000175000017500000000002214516755027023652 0ustar00jpakkanejpakkane#include ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421459.0 meson-1.3.2/test cases/common/19 header in file list/meson.build0000644000175000017500000000111514516755323024416 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/19 header in file list/prog.c0000644000175000017500000000006214516512250023355 0ustar00jpakkanejpakkane#include "header.h" int main(void) { return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7306545 meson-1.3.2/test cases/common/190 install_mode/0000755000175000017500000000000014562742415021334 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/190 install_mode/config.h.in0000644000175000017500000000017014516512250023344 0ustar00jpakkanejpakkane#define MESSAGE "@var@" #define OTHER "@other@" "@second@" "@empty@" #mesondefine BE_TRUE #mesondefine SHOULD_BE_UNDEF ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/190 install_mode/data_source.txt0000644000175000017500000000004014516512250024347 0ustar00jpakkanejpakkaneThis is a text only input file. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/190 install_mode/foo.10000644000175000017500000000007014516512250022165 0ustar00jpakkanejpakkanethis is a man page of foo.1 its contents are irrelevant ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421619.0 meson-1.3.2/test cases/common/190 install_mode/meson.build0000644000175000017500000000307714516755563023514 0ustar00jpakkanejpakkaneproject('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, build_rpath: meson.current_build_dir(), install_mode : ['rwxr-sr-x', 'root', 'root']) # test install_mode in static_library static_library('stat', 'stat.c', install : true, install_mode : ['rw---Sr--']) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/190 install_mode/rootdir.h0000644000175000017500000000007614516512250023161 0ustar00jpakkanejpakkane/* This header goes to include dir root. */ int root_func(); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/190 install_mode/runscript.sh0000644000175000017500000000003414516512250023705 0ustar00jpakkanejpakkane#!/bin/sh echo "Runscript" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/190 install_mode/stat.c0000644000175000017500000000003714516512250022442 0ustar00jpakkanejpakkaneint func(void) { return 933; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7306545 meson-1.3.2/test cases/common/190 install_mode/sub1/0000755000175000017500000000000014562742415022206 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/190 install_mode/sub1/second.dat0000644000175000017500000000006614516512250024144 0ustar00jpakkanejpakkaneTest that multiple install_subdirs meld their results.././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7306545 meson-1.3.2/test cases/common/190 install_mode/sub2/0000755000175000017500000000000014562742415022207 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/190 install_mode/sub2/stub0000644000175000017500000000000014516512250023064 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/190 install_mode/test.json0000644000175000017500000000135314516515714023207 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/bin/runscript.sh"}, {"type": "exe", "file": "usr/bin/trivialprog"}, {"type": "pdb", "file": "usr/bin/trivialprog"}, {"type": "file", "file": "usr/include/config.h"}, {"type": "file", "file": "usr/include/rootdir.h"}, {"type": "file", "file": "usr/libtest/libstat.a"}, {"type": "file", "file": "usr/share/man/man1/foo.1"}, {"type": "file", "file": "usr/share/sub1/second.dat"}, {"type": "file", "file": "usr/share/sub2/stub"}, {"type": "file", "file": "usr/subdir/data.dat"} ], "do_not_set_opts": ["libdir"], "stdout": [ { "line": ".* DEPRECATION: install_mode with the sticky bit on a file", "match": "re", "count": 3 } ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/190 install_mode/trivial.c0000644000175000017500000000013614516512250023141 0ustar00jpakkanejpakkane#include int main(void) { printf("Trivial test is working.\n"); return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7306545 meson-1.3.2/test cases/common/191 subproject array version/0000755000175000017500000000000014562742415023610 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421619.0 meson-1.3.2/test cases/common/191 subproject array version/meson.build0000644000175000017500000000011014516755563025751 0ustar00jpakkanejpakkaneproject('master') x = subproject('foo', version : ['>=1.0.0', '<2.0']) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.8426256 meson-1.3.2/test cases/common/191 subproject array version/subprojects/0000755000175000017500000000000014562742413026151 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7306545 meson-1.3.2/test cases/common/191 subproject array version/subprojects/foo/0000755000175000017500000000000014562742415026736 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/191 subproject array version/subprojects/foo/meson.build0000644000175000017500000000004214516512250031063 0ustar00jpakkanejpakkaneproject('foo', version : '1.0.0') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7306545 meson-1.3.2/test cases/common/192 feature option/0000755000175000017500000000000014562742415021610 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421620.0 meson-1.3.2/test cases/common/192 feature option/meson.build0000644000175000017500000001037214516755564023765 0ustar00jpakkanejpakkaneproject('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(feature_opts.allowed(), '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(required_opt.allowed(), 'Should be enabled option') assert(required_opt.require(true, error_message: 'xyz').enabled(), 'Should be enabled option') assert(required_opt.enable_if(true, error_message: 'xyz').enabled(), 'Should be enabled option') assert(required_opt.enable_if(false, error_message: 'xyz').enabled(), 'Should be enabled option') assert(required_opt.disable_if(false, error_message: 'xyz').enabled(), 'Should be enabled option') assert(required_opt.disable_auto_if(true).enabled(), 'Should be enabled option') assert(required_opt.disable_auto_if(false).enabled(), 'Should be enabled option') assert(required_opt.enable_auto_if(true).enabled(), 'Should be enabled option') assert(required_opt.enable_auto_if(false).enabled(), '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(optional_opt.allowed(), 'Should be auto option') assert(optional_opt.require(true).auto(), 'Should be auto option') assert(optional_opt.require(false, error_message: 'xyz').disabled(), 'Should be disabled auto option') assert(optional_opt.enable_if(true).enabled(), 'Should be enabled option') assert(optional_opt.enable_if(false).auto(), 'Should be auto option') assert(optional_opt.disable_if(true).disabled(), 'Should be disabled auto option') assert(optional_opt.disable_if(false).auto(), 'Should be auto option') assert(optional_opt.disable_auto_if(true).disabled(), 'Should be disabled auto option') assert(optional_opt.disable_auto_if(false).auto(), 'Should be auto option') assert(optional_opt.enable_auto_if(true).enabled(), 'Should be disabled auto option') assert(optional_opt.enable_auto_if(false).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') assert(not disabled_opt.allowed(), 'Should be disabled option') assert(disabled_opt.require(true).disabled(), 'Should be disabled option') assert(disabled_opt.require(false, error_message: 'xyz').disabled(), 'Should be disabled option') assert(disabled_opt.enable_if(false).disabled(), 'Should be disabled option') assert(disabled_opt.disable_if(true).disabled(), 'Should be disabled option') assert(disabled_opt.disable_if(false).disabled(), 'Should be disabled option') assert(disabled_opt.disable_auto_if(true).disabled(), 'Should be disabled option') assert(disabled_opt.disable_auto_if(false).disabled(), 'Should be disabled option') assert(disabled_opt.enable_auto_if(true).disabled(), 'Should be disabled option') assert(disabled_opt.enable_auto_if(false).disabled(), '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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/192 feature option/meson_options.txt0000644000175000017500000000042414516512250025234 0ustar00jpakkanejpakkaneoption('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') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7306545 meson-1.3.2/test cases/common/193 feature option disabled/0000755000175000017500000000000014562742415023341 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421620.0 meson-1.3.2/test cases/common/193 feature option disabled/meson.build0000644000175000017500000000175014516755564025516 0ustar00jpakkanejpakkaneproject('feature user option', 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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/193 feature option disabled/meson_options.txt0000644000175000017500000000042414516512250026765 0ustar00jpakkanejpakkaneoption('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') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7306545 meson-1.3.2/test cases/common/194 static threads/0000755000175000017500000000000014562742415021570 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/194 static threads/lib1.c0000644000175000017500000000025314516512250022552 0ustar00jpakkanejpakkane#if defined _WIN32 #include #else #include #endif void *f(void) { #if defined _WIN32 return CreateThread; #else return pthread_create; #endif } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/194 static threads/lib2.c0000644000175000017500000000006714516512250022556 0ustar00jpakkanejpakkaneextern void *f(void); void *g(void) { return f(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421621.0 meson-1.3.2/test cases/common/194 static threads/meson.build0000644000175000017500000000044414516755565023745 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/194 static threads/prog.c0000644000175000017500000000007514516512250022674 0ustar00jpakkanejpakkaneextern void *g(void); int main(void) { g(); return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7306545 meson-1.3.2/test cases/common/195 generator in subdir/0000755000175000017500000000000014562742415022515 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.8466258 meson-1.3.2/test cases/common/195 generator in subdir/com/0000755000175000017500000000000014562742413023271 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7306545 meson-1.3.2/test cases/common/195 generator in subdir/com/mesonbuild/0000755000175000017500000000000014562742415025434 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/195 generator in subdir/com/mesonbuild/meson.build0000644000175000017500000000047414516512250027572 0ustar00jpakkanejpakkanegprog = find_program('tooldir/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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/195 generator in subdir/com/mesonbuild/subbie.inp0000644000175000017500000000000714516512250027401 0ustar00jpakkanejpakkanesubbie ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/195 generator in subdir/com/mesonbuild/testprog.c0000644000175000017500000000007414516512250027437 0ustar00jpakkanejpakkane#include"subbie.h" int main(void) { return subbie(); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7346544 meson-1.3.2/test cases/common/195 generator in subdir/com/mesonbuild/tooldir/0000755000175000017500000000000014562742415027110 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/195 generator in subdir/com/mesonbuild/tooldir/genprog.py0000644000175000017500000000225414516512250031115 0ustar00jpakkanejpakkane#!/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(f'Input file {ifile} does not start with search dir {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)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421622.0 meson-1.3.2/test cases/common/195 generator in subdir/meson.build0000644000175000017500000000007614516755566024674 0ustar00jpakkanejpakkaneproject('generator in subdir', 'c') subdir('com/mesonbuild') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7346544 meson-1.3.2/test cases/common/196 subproject with features/0000755000175000017500000000000014562742415023603 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421624.0 meson-1.3.2/test cases/common/196 subproject with features/meson.build0000644000175000017500000000200514516755570025747 0ustar00jpakkanejpakkaneproject('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, 'Subproject 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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/196 subproject with features/meson_options.txt0000644000175000017500000000030514516512250027225 0ustar00jpakkanejpakkaneoption('use-subproject', type : 'feature', value : 'auto') option('disabled-subproject', type : 'feature', value : 'disabled') option('auto-sub-with-missing-dep', type : 'feature', value : 'auto') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/196 subproject with features/nothing.c0000644000175000017500000000004114516512250025377 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.8506258 meson-1.3.2/test cases/common/196 subproject with features/subprojects/0000755000175000017500000000000014562742413026144 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7346544 meson-1.3.2/test cases/common/196 subproject with features/subprojects/auto_sub_with_missing_dep/0000755000175000017500000000000014562742415033403 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000021400000000000010212 xustar00118 path=meson-1.3.2/test cases/common/196 subproject with features/subprojects/auto_sub_with_missing_dep/meson.build 22 mtime=1698337960.0 meson-1.3.2/test cases/common/196 subproject with features/subprojects/auto_sub_with_missing_dep/mes0000644000175000017500000000010514516512250034075 0ustar00jpakkanejpakkaneproject('sub', 'c') dependency('no_way_this_exists', required: true)././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7346544 meson-1.3.2/test cases/common/196 subproject with features/subprojects/disabled_sub/0000755000175000017500000000000014562742415030566 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7346544 meson-1.3.2/test cases/common/196 subproject with features/subprojects/disabled_sub/lib/0000755000175000017500000000000014562742415031334 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/196 subproject with features/subprojects/disabled_sub/lib/meson.build0000644000175000017500000000020014516512250033455 0ustar00jpakkanejpakkanelib = static_library('sub', 'sub.c') libSub = declare_dependency(include_directories: include_directories('.'), link_with: lib)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/196 subproject with features/subprojects/disabled_sub/lib/sub.c0000644000175000017500000000006214516512250032256 0ustar00jpakkanejpakkane#include "sub.h" int sub(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/196 subproject with features/subprojects/disabled_sub/lib/sub.h0000644000175000017500000000006014516512250032261 0ustar00jpakkanejpakkane#ifndef SUB_H #define SUB_H int sub(); #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/196 subproject with features/subprojects/disabled_sub/meson.build0000644000175000017500000000005314516512250032715 0ustar00jpakkanejpakkaneproject('disabled_sub', 'c') subdir('lib')././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7346544 meson-1.3.2/test cases/common/196 subproject with features/subprojects/sub/0000755000175000017500000000000014562742415026737 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7426546 meson-1.3.2/test cases/common/196 subproject with features/subprojects/sub/lib/0000755000175000017500000000000014562742415027505 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/196 subproject with features/subprojects/sub/lib/meson.build0000644000175000017500000000020014516512250031626 0ustar00jpakkanejpakkanelib = static_library('sub', 'sub.c') libSub = declare_dependency(include_directories: include_directories('.'), link_with: lib) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/196 subproject with features/subprojects/sub/lib/sub.c0000644000175000017500000000006014516512250030425 0ustar00jpakkanejpakkane#include "sub.h" int sub(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/196 subproject with features/subprojects/sub/lib/sub.h0000644000175000017500000000006414516512250030436 0ustar00jpakkanejpakkane#ifndef SUB_H #define SUB_H int sub(void); #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/196 subproject with features/subprojects/sub/meson.build0000644000175000017500000000004214516512250031064 0ustar00jpakkanejpakkaneproject('sub', 'c') subdir('lib')././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7426546 meson-1.3.2/test cases/common/197 function attributes/0000755000175000017500000000000014562742415022665 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1702314114.0 meson-1.3.2/test cases/common/197 function attributes/meson.build0000644000175000017500000001012714535640202025017 0ustar00jpakkanejpakkane# 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 = {} expected_default = 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', 'always_inline', 'cold', 'const', 'constructor', 'constructor_priority', 'deprecated', 'destructor', 'flatten', 'format', 'format_arg', 'gnu_inline', 'hot', 'malloc', 'noinline', 'nonnull', 'noreturn', 'nothrow', 'pure', 'section', 'sentinel', 'unused', 'used', 'vector_size', 'warn_unused_result', 'weak', 'dllexport', 'dllimport', ] expected += { 'dllexport': ['windows', 'cygwin'].contains(host_machine.system()), 'dllimport': ['windows', 'cygwin'].contains(host_machine.system()), } if c.get_id() == 'gcc' and ['windows', 'cygwin'].contains(host_machine.system()) expected += { 'visibility': false, 'visibility:hidden': false, 'visibility:internal': false, 'visibility:protected': false, } endif 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' attributes += 'visibility:default' attributes += 'visibility:hidden' attributes += 'visibility:internal' attributes += 'visibility:protected' attributes += 'alloc_size' endif # gcc doesn't support constructor_priority on darwin if c.get_id() == 'gcc' and host_machine.system() == 'darwin' expected += {'constructor_priority': false} 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 # XXX(arsen): limited to clang 13+ even though gcc 11 has it, since gcc # detects support for it at compile time based on binutils version if c.get_id() == 'clang' and c.version().version_compare('>= 13.0.0') attributes += 'retain' endif endif if get_option('mode') == 'single' foreach a : attributes x = c.has_function_attribute(a) expected_result = expected.get(a, expected_default) 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 else multi_expected = [] foreach a : attributes if expected.get(a, expected_default) multi_expected += a endif endforeach 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++)') endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/197 function attributes/meson_options.txt0000644000175000017500000000026614516512250026315 0ustar00jpakkanejpakkaneoption( 'mode', type : 'combo', choices : ['single', 'parallel'], value : 'single', description : 'Test the one at a time function or many at a time function.' ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/197 function attributes/test.json0000644000175000017500000000020014516515714024526 0ustar00jpakkanejpakkane{ "matrix": { "options": { "mode": [ { "val": "single" }, { "val": "parallel" } ] } } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7426546 meson-1.3.2/test cases/common/198 broken subproject/0000755000175000017500000000000014562742415022313 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421624.0 meson-1.3.2/test cases/common/198 broken subproject/meson.build0000644000175000017500000000011114516755570024453 0ustar00jpakkanejpakkaneproject('test broken subproject') subproject('broken', required : false) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.8506258 meson-1.3.2/test cases/common/198 broken subproject/subprojects/0000755000175000017500000000000014562742413024654 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7426546 meson-1.3.2/test cases/common/198 broken subproject/subprojects/broken/0000755000175000017500000000000014562742415026136 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/198 broken subproject/subprojects/broken/broken.c0000644000175000017500000000003514516512250027547 0ustar00jpakkanejpakkane#error This must not compile ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/198 broken subproject/subprojects/broken/meson.build0000644000175000017500000000014114516512250030263 0ustar00jpakkanejpakkaneproject('broken', 'c') executable('app', 'broken.c') assert(false, 'This subproject must fail') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7426546 meson-1.3.2/test cases/common/199 argument syntax/0000755000175000017500000000000014562742415022024 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421627.0 meson-1.3.2/test cases/common/199 argument syntax/meson.build0000644000175000017500000000077114516755573024203 0ustar00jpakkanejpakkaneproject( '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())) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7466547 meson-1.3.2/test cases/common/2 cpp/0000755000175000017500000000000014562742415017274 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/common/2 cpp/VERSIONFILE0000644000175000017500000000000614107166547021001 0ustar00jpakkanejpakkane1.0.0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/common/2 cpp/cpp.C0000644000175000017500000000015314107166547020162 0ustar00jpakkanejpakkane#include int main(void) { std::cout << "C++ seems to be working." << std::endl; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421443.0 meson-1.3.2/test cases/common/2 cpp/meson.build0000644000175000017500000000205414516755303021436 0ustar00jpakkanejpakkaneproject('c++ test', 'cpp', version: files('VERSIONFILE')) 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.') if cpp.get_id() == 'msvc' exe = executable('cppprog', 'cpp.C', cpp_args : '/TP') else exe = executable('cppprog', 'cpp.C') endif test('cpptest', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/2 cpp/something.txt0000644000175000017500000000010613716006331022015 0ustar00jpakkanejpakkaneThis file is only here so it shows up in IDEs as part of this target. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/2 cpp/trivial.cc0000644000175000017500000000015313716006331021242 0ustar00jpakkanejpakkane#include int main(void) { std::cout << "C++ seems to be working." << std::endl; return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7506547 meson-1.3.2/test cases/common/20 global arg/0000755000175000017500000000000014562742415020564 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421459.0 meson-1.3.2/test cases/common/20 global arg/meson.build0000644000175000017500000000070714516755323022733 0ustar00jpakkanejpakkaneproject('global arg test', 'cpp', 'c') add_global_arguments('-DMYTHING', language : 'c') add_global_arguments('-DMYCPPTHING', language : 'cpp') add_global_arguments('-DGLOBAL_HOST', language : 'c') build_c_args = ['-DARG_BUILD'] c_args = ['-DARG_HOST'] add_global_arguments('-DMYCANDCPPTHING', language: ['c', 'cpp']) exe2 = executable('prog2', 'prog.c', c_args : c_args) exe3 = executable('prog3', 'prog.cc') test('prog2', exe2) test('prog3', exe3) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/20 global arg/prog.c0000644000175000017500000000146614516512250021675 0ustar00jpakkanejpakkane#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 global_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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/20 global arg/prog.cc0000644000175000017500000000032714516512250022033 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7506547 meson-1.3.2/test cases/common/200 install name_prefix name_suffix/0000755000175000017500000000000014562742415025063 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/200 install name_prefix name_suffix/libfile.c0000644000175000017500000000052114516512250026622 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421627.0 meson-1.3.2/test cases/common/200 install name_prefix name_suffix/meson.build0000644000175000017500000000124014516755573027232 0ustar00jpakkanejpakkaneproject('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) # exercise default name_prefix and name_suffix shared_library('garply', 'libfile.c', name_prefix: [], name_suffix: [], install : true) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/200 install name_prefix name_suffix/test.json0000644000175000017500000000142114516515714026732 0ustar00jpakkanejpakkane{ "installed": [ {"type": "pdb", "file": "usr/bin/baz"}, {"type": "pdb", "file": "usr/bin/bowcorge"}, {"type": "pdb", "file": "usr/bin/foo"}, {"type": "expr", "file": "usr/?lib/bowcorge.stern"}, {"type": "expr", "file": "usr/lib/?libbaz.cheese"}, {"type": "file", "file": "usr/lib/bar.a"}, {"type": "implib", "file": "usr/lib/bowcorge"}, {"type": "file", "file": "usr/lib/bowgrault.stern"}, {"type": "implib", "file": "usr/lib/foo"}, {"type": "expr", "file": "usr/lib/foo?so"}, {"type": "implib", "file": "usr/lib/libbaz"}, {"type": "file", "file": "usr/lib/libqux.cheese"}, {"type": "expr", "file": "usr/?lib/libgarply?so"}, {"type": "implib", "file": "usr/lib/libgarply"}, {"type": "pdb", "file": "usr/bin/garply"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7506547 meson-1.3.2/test cases/common/201 kwarg entry/0000755000175000017500000000000014562742415021110 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.754655 meson-1.3.2/test cases/common/201 kwarg entry/inc/0000755000175000017500000000000014562742415021661 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/201 kwarg entry/inc/prog.h0000644000175000017500000000005714516512250022772 0ustar00jpakkanejpakkane#pragma once #define MESSAGE "Hello there.\n" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421629.0 meson-1.3.2/test cases/common/201 kwarg entry/meson.build0000644000175000017500000000024714516755575023267 0ustar00jpakkanejpakkaneproject('kwarg', 'c') default_kwargs = {'install': true, 'include_directories': include_directories('inc')} executable('prog', 'prog.c', kwargs: default_kwargs) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/201 kwarg entry/prog.c0000644000175000017500000000013214516512250022206 0ustar00jpakkanejpakkane#include #include int main(void) { printf(MESSAGE); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/201 kwarg entry/test.json0000644000175000017500000000016214516515714022760 0ustar00jpakkanejpakkane{ "installed": [ {"type": "exe", "file": "usr/bin/prog"}, {"type": "pdb", "file": "usr/bin/prog"} ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.754655 meson-1.3.2/test cases/common/202 custom target build by default/0000755000175000017500000000000014562742415024515 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/202 custom target build by default/docgen.py0000644000175000017500000000027614516512250026322 0ustar00jpakkanejpakkane#!/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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421629.0 meson-1.3.2/test cases/common/202 custom target build by default/meson.build0000644000175000017500000000041314516755575026667 0ustar00jpakkanejpakkaneproject('custom-target-dir-install') 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')) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/202 custom target build by default/test.json0000644000175000017500000000003214516515714026361 0ustar00jpakkanejpakkane{ "installed": [ ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.754655 meson-1.3.2/test cases/common/203 find_library and headers/0000755000175000017500000000000014562742415023440 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/203 find_library and headers/foo.h0000644000175000017500000000001714516512250024361 0ustar00jpakkanejpakkane#define VAL 42 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421630.0 meson-1.3.2/test cases/common/203 find_library and headers/meson.build0000644000175000017500000000121614516755576025615 0ustar00jpakkanejpakkaneproject('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') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.754655 meson-1.3.2/test cases/common/204 line continuation/0000755000175000017500000000000014562742415022300 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421630.0 meson-1.3.2/test cases/common/204 line continuation/meson.build0000644000175000017500000000041214516755576024452 0ustar00jpakkanejpakkaneproject('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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7586548 meson-1.3.2/test cases/common/205 native file path override/0000755000175000017500000000000014562742415023562 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/205 native file path override/main.cpp0000644000175000017500000000012614516512250025200 0ustar00jpakkanejpakkane#include int main(void) { std::cout << "Hello world!" << std::endl; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421633.0 meson-1.3.2/test cases/common/205 native file path override/meson.build0000644000175000017500000000031514516755601025723 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/205 native file path override/nativefile.ini0000644000175000017500000000004114516512250026373 0ustar00jpakkanejpakkane[paths] bindir = 'custom_bindir' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/205 native file path override/test.json0000644000175000017500000000020614516515714025431 0ustar00jpakkanejpakkane{ "installed": [ {"type": "exe", "file": "usr/custom_bindir/main"}, {"type": "pdb", "file": "usr/custom_bindir/main"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7586548 meson-1.3.2/test cases/common/206 tap tests/0000755000175000017500000000000014562742415020567 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/206 tap tests/cat.c0000644000175000017500000000107214516512250021471 0ustar00jpakkanejpakkane#include #include int main(int argc, char **argv) { char buf[1024]; size_t len; FILE *fh; if (argc != 2) { fprintf(stderr, "Incorrect number of arguments, got %i\n", argc); return 1; } fh = fopen(argv[1], "r"); if (fh == NULL) { fprintf(stderr, "Opening %s: errno=%i\n", argv[1], errno); return 1; } do { len = fread(buf, 1, sizeof(buf), fh); if (len > 0) { fwrite(buf, 1, len, stdout); } } while (len > 0); fclose(fh); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/206 tap tests/issue7515.txt0000644000175000017500000000453614516512250023001 0ustar00jpakkanejpakkane1..26 ok 1 Gtk overrides UI template sets up internal and public template children ok 2 Gtk overrides UI template sets up public template children with the correct widgets ok 3 Gtk overrides UI template sets up internal template children with the correct widgets ok 4 Gtk overrides UI template connects template callbacks to the correct handler ok 5 Gtk overrides UI template binds template callbacks to the correct object ok 6 Gtk overrides UI template from resource sets up internal and public template children ok 7 Gtk overrides UI template from resource sets up public template children with the correct widgets ok 8 Gtk overrides UI template from resource sets up internal template children with the correct widgets ok 9 Gtk overrides UI template from resource connects template callbacks to the correct handler ok 10 Gtk overrides UI template from resource binds template callbacks to the correct object ok 11 Gtk overrides UI template from file sets up internal and public template children ok 12 Gtk overrides UI template from file sets up public template children with the correct widgets ok 13 Gtk overrides UI template from file sets up internal template children with the correct widgets ok 14 Gtk overrides UI template from file connects template callbacks to the correct handler ok 15 Gtk overrides UI template from file binds template callbacks to the correct object ok 16 Gtk overrides Class inheriting from template class sets up internal and public template children # SKIP pending ok 17 Gtk overrides Class inheriting from template class sets up public template children with the correct widgets # SKIP pending ok 18 Gtk overrides Class inheriting from template class sets up internal template children with the correct widgets # SKIP pending ok 19 Gtk overrides Class inheriting from template class connects template callbacks to the correct handler # SKIP pending ok 20 Gtk overrides Class inheriting from template class binds template callbacks to the correct object # SKIP pending ok 21 Gtk overrides sets CSS names on classes ok 22 Gtk overrides avoid crashing when GTK vfuncs are called in garbage collection ok 23 Gtk overrides accepts string in place of GdkAtom ok 24 Gtk overrides accepts null in place of GdkAtom as GDK_NONE ok 25 Gtk overrides uses the correct GType for null child properties ok 26 Gtk overrides can create a Gtk.TreeIter with accessible stamp field ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421632.0 meson-1.3.2/test cases/common/206 tap tests/meson.build0000644000175000017500000000160614516755600022733 0ustar00jpakkanejpakkaneproject('test features', 'c') tester = executable('tester', 'tester.c') cat = executable('cat', 'cat.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('partially skipped', tester, args : ['ok 1\nok 2 # skip'], suite: ['verbose'], protocol: 'tap', verbose: true) test('partially skipped (real-world example)', cat, args : [files('issue7515.txt')], protocol: 'tap') test('skip comment', tester, args : ['ok # Skipped: with a comment'], 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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/206 tap tests/tester.c0000644000175000017500000000032014516512250022223 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7586548 meson-1.3.2/test cases/common/207 warning level 0/0000755000175000017500000000000014562742415021536 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/207 warning level 0/main.cpp0000644000175000017500000000041014516512250023150 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421633.0 meson-1.3.2/test cases/common/207 warning level 0/meson.build0000644000175000017500000000017614516755601023704 0ustar00jpakkanejpakkaneproject('warning_level', 'cpp', default_options : ['warning_level=0']) exe = executable('main', 'main.cpp', install : false) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7586548 meson-1.3.2/test cases/common/208 link custom/0000755000175000017500000000000014562742415021112 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/208 link custom/custom_stlib.py0000755000175000017500000000520314516512250024165 0ustar00jpakkanejpakkane#!/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', 'darwin'] or sys.platform == '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)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/208 link custom/custom_target.c0000644000175000017500000000012314516512250024121 0ustar00jpakkanejpakkanevoid outer_lib_func(void); int main(void) { outer_lib_func(); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/208 link custom/custom_target.py0000644000175000017500000000016514516512250024335 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import shutil, sys if __name__ == '__main__': shutil.copyfile(sys.argv[1], sys.argv[2]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/208 link custom/dummy.c0000644000175000017500000000003414516512250022375 0ustar00jpakkanejpakkanevoid inner_lib_func(void) {}././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/208 link custom/lib.c0000644000175000017500000000007214516512250022012 0ustar00jpakkanejpakkanevoid flob(void); int foo(void) { flob(); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421633.0 meson-1.3.2/test cases/common/208 link custom/meson.build0000644000175000017500000000552714516755601023265 0ustar00jpakkanejpakkaneproject('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 if meson.backend() == 'xcode' message('Xcode does not support link whole so skipping.') else 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) endif # 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) # Link whole tests if meson.backend() == 'xcode' message('Xcode does not support link whole so skipping.') else shared_library('lib1', 'lib.c', link_whole: clib) 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) endif # Link with custom target dummy = static_library('dummy', 'dummy.c') custom_prog = find_program('custom_target.py') t = custom_target('custom', input: dummy, output: 'libcustom.a', command: [custom_prog, '@INPUT@', '@OUTPUT@']) dep1 = declare_dependency(link_with: t) dep2 = declare_dependency(link_with: t[0]) lib1 = static_library('lib1', 'outerlib.c', dependencies: dep1) lib2 = static_library('lib2', 'outerlib.c', dependencies: dep2) exe1 = executable('exe1', 'custom_target.c', link_with: lib1) test('custom_target_1', exe1) exe1_2 = executable('exe1_2', 'custom_target.c', link_with: lib2) test('custom_target_2', exe2) # Link with custom target containing a SONAME dummy3 = shared_library('dummy3', 'dummy.c', version: '1.0') t = custom_target(input: dummy, output: 'libcustom@PLAINNAME@', command: [custom_prog, '@INPUT@', '@OUTPUT@']) lib3 = static_library('lib3', 'outerlib.c', link_with: t) exe3 = executable('exe3', 'custom_target.c', link_with: lib3) test('custom_target_3', exe3) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/208 link custom/outerlib.c0000644000175000017500000000011314516512250023065 0ustar00jpakkanejpakkanevoid inner_lib_func(void); void outer_lib_func(void) { inner_lib_func(); }././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/208 link custom/prog.c0000644000175000017500000000007714516512250022220 0ustar00jpakkanejpakkanevoid flob(void); int main(void) { flob(); return 0; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.766655 meson-1.3.2/test cases/common/209 link custom_i single from multiple/0000755000175000017500000000000014562742415025425 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/209 link custom_i single from multiple/generate_conflicting_stlibs.py0000644000175000017500000000547714516512250033534 0ustar00jpakkanejpakkane#!/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)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421635.0 meson-1.3.2/test cases/common/209 link custom_i single from multiple/meson.build0000644000175000017500000000235314516755603027574 0ustar00jpakkanejpakkaneproject('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 if meson.backend() == 'xcode' message('Xcode does not support link whole so skipping.') subdir_done() endif 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/209 link custom_i single from multiple/prog.c0000644000175000017500000000010614516512250026524 0ustar00jpakkanejpakkaneint flob(void); int main(void) { return (flob() == 1 ? 0 : 1); } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.766655 meson-1.3.2/test cases/common/21 target arg/0000755000175000017500000000000014562742415020613 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/21 target arg/func.c0000644000175000017500000000021614516512250021700 0ustar00jpakkanejpakkane#ifndef CTHING #error "Local argument not set" #endif #ifdef CPPTHING #error "Wrong local argument set" #endif int func(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/21 target arg/func2.c0000644000175000017500000000025114516512250021761 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421460.0 meson-1.3.2/test cases/common/21 target arg/meson.build0000644000175000017500000000034514516755324022761 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/21 target arg/prog.cc0000644000175000017500000000025714516512250022064 0ustar00jpakkanejpakkane#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(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/21 target arg/prog2.cc0000644000175000017500000000031214516512250022136 0ustar00jpakkanejpakkane#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(); } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.770655 meson-1.3.2/test cases/common/210 link custom_i multiple from multiple/0000755000175000017500000000000014562742415025767 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/210 link custom_i multiple from multiple/generate_stlibs.py0000644000175000017500000000562314516512250031510 0ustar00jpakkanejpakkane#!/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)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421635.0 meson-1.3.2/test cases/common/210 link custom_i multiple from multiple/meson.build0000644000175000017500000000234514516755603030137 0ustar00jpakkanejpakkaneproject('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 if meson.backend() == 'xcode' message('Xcode does not support link whole so skipping.') subdir_done() endif 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/210 link custom_i multiple from multiple/prog.c0000644000175000017500000000014414516512250027070 0ustar00jpakkanejpakkanevoid flob_1(void); void flob_2(void); int main(void) { flob_1(); flob_2(); return 0; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.770655 meson-1.3.2/test cases/common/211 dependency get_variable method/0000755000175000017500000000000014562742415024640 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421639.0 meson-1.3.2/test cases/common/211 dependency get_variable method/meson.build0000644000175000017500000000651114516755607027013 0ustar00jpakkanejpakkaneproject( '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.') assert(dep.get_variable(pkgconfig : 'pkgvarnotfound', default_value : '') == '') 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(variables : {'foo' : 'value'}) assert(idep.get_variable(pkgconfig : 'foo', cmake : 'foo', configtool : 'foo', internal : 'foo', default_value : default) == 'value', 'internal got default when it shouldn\'t have.') assert(idep.get_variable(pkgconfig : 'foo', cmake : 'foo', configtool : 'foo', internal : 'bar', default_value : default) == default, 'internal didn\'t default when it should have.') idep = declare_dependency() assert(idep.get_variable(pkgconfig : 'foo', cmake : 'foo', configtool : 'foo', default_value : default) == default, 'something went wrong with an InternalDependency with no variables.') idep = declare_dependency(variables : ['foo=value']) assert(idep.get_variable(internal: 'foo') == 'value') assert(idep.get_variable('foo') == 'value') assert(idep.get_variable('invalid', internal: 'foo') == 'value') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/211 dependency get_variable method/test.json0000644000175000017500000000017414516515714026513 0ustar00jpakkanejpakkane{ "stdout": [ { "line": ".*pkgvarnotfound.*", "match": "re", "count": 0 } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.774655 meson-1.3.2/test cases/common/212 source set configuration_data/0000755000175000017500000000000014562742415024552 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/212 source set configuration_data/a.c0000644000175000017500000000012614516512250025124 0ustar00jpakkanejpakkane#include #include "all.h" int main(void) { if (p) abort(); f(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/212 source set configuration_data/all.h0000644000175000017500000000032214516512250025457 0ustar00jpakkanejpakkaneextern void f(void); extern void g(void); extern void h(void); extern void undefined(void); /* Defined in nope.c and f.c, * value depends on the source set and configuration used. */ extern void (*p)(void); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/212 source set configuration_data/f.c0000644000175000017500000000011214516512250025124 0ustar00jpakkanejpakkane#include "all.h" void (*p)(void) = (void *)0x12AB34CD; void f(void) { } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/212 source set configuration_data/g.c0000644000175000017500000000005414516512250025132 0ustar00jpakkanejpakkane#include "all.h" void g(void) { h(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421637.0 meson-1.3.2/test cases/common/212 source set configuration_data/meson.build0000644000175000017500000000351014516755605026717 0ustar00jpakkanejpakkaneproject('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'), not_found]) 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'), not_found]) 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/212 source set configuration_data/nope.c0000644000175000017500000000005714516512250025650 0ustar00jpakkanejpakkane#include "all.h" void (*p)(void) = undefined; ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.774655 meson-1.3.2/test cases/common/212 source set configuration_data/subdir/0000755000175000017500000000000014562742415026042 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/212 source set configuration_data/subdir/b.c0000644000175000017500000000016114516512250026414 0ustar00jpakkanejpakkane#include #include "all.h" void h(void) { } int main(void) { if (p) abort(); f(); g(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/212 source set configuration_data/subdir/meson.build0000644000175000017500000000007514516512250030175 0ustar00jpakkanejpakkanesources.add(when: ['YES2', good], if_true: [ files('b.c') ]) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.778655 meson-1.3.2/test cases/common/213 source set dictionary/0000755000175000017500000000000014562742415023060 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/213 source set dictionary/a.c0000644000175000017500000000012614516512250023432 0ustar00jpakkanejpakkane#include #include "all.h" int main(void) { if (p) abort(); f(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/213 source set dictionary/all.h0000644000175000017500000000032214516512250023765 0ustar00jpakkanejpakkaneextern void f(void); extern void g(void); extern void h(void); extern void undefined(void); /* Defined in nope.c and f.c, * value depends on the source set and configuration used. */ extern void (*p)(void); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/213 source set dictionary/f.c0000644000175000017500000000011214516512250023432 0ustar00jpakkanejpakkane#include "all.h" void (*p)(void) = (void *)0x1234ABCD; void f(void) { } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/213 source set dictionary/g.c0000644000175000017500000000005414516512250023440 0ustar00jpakkanejpakkane#include "all.h" void g(void) { h(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421638.0 meson-1.3.2/test cases/common/213 source set dictionary/meson.build0000644000175000017500000000331414516755606025230 0ustar00jpakkanejpakkaneproject('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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/213 source set dictionary/nope.c0000644000175000017500000000005714516512250024156 0ustar00jpakkanejpakkane#include "all.h" void (*p)(void) = undefined; ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.778655 meson-1.3.2/test cases/common/213 source set dictionary/subdir/0000755000175000017500000000000014562742415024350 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/213 source set dictionary/subdir/b.c0000644000175000017500000000016114516512250024722 0ustar00jpakkanejpakkane#include #include "all.h" void h(void) { } int main(void) { if (p) abort(); f(); g(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/213 source set dictionary/subdir/meson.build0000644000175000017500000000007514516512250026503 0ustar00jpakkanejpakkanesources.add(when: ['YES2', good], if_true: [ files('b.c') ]) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7826552 meson-1.3.2/test cases/common/214 source set custom target/0000755000175000017500000000000014562742415023475 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/214 source set custom target/a.c0000644000175000017500000000006714516512250024053 0ustar00jpakkanejpakkane#include "all.h" int main(void) { f(); g(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/214 source set custom target/all.h0000644000175000017500000000005214516512250024402 0ustar00jpakkanejpakkaneextern void f(void); extern void g(void); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/214 source set custom target/cp.py0000644000175000017500000000013014516512250024432 0ustar00jpakkanejpakkane#! /usr/bin/env python3 import sys from shutil import copyfile copyfile(*sys.argv[1:]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/214 source set custom target/f.c0000644000175000017500000000004314516512250024052 0ustar00jpakkanejpakkane#include "all.h" void f(void) { } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/214 source set custom target/g.c0000644000175000017500000000004314516512250024053 0ustar00jpakkanejpakkane#include "all.h" void g(void) { } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421638.0 meson-1.3.2/test cases/common/214 source set custom target/meson.build0000644000175000017500000000157614516755606025655 0ustar00jpakkanejpakkane# 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()) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7866552 meson-1.3.2/test cases/common/215 source set realistic example/0000755000175000017500000000000014562742415024310 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7866552 meson-1.3.2/test cases/common/215 source set realistic example/boards/0000755000175000017500000000000014562742415025562 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7866552 meson-1.3.2/test cases/common/215 source set realistic example/boards/arm/0000755000175000017500000000000014562742415026341 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/boards/arm/aarch64.cc0000644000175000017500000000027014516512250030066 0ustar00jpakkanejpakkane#include "common.h" #include void initialize_target() { std::cout << ANSI_START << "some " << THE_TARGET << " initialization" << ANSI_END << std::endl; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/boards/arm/arm.cc0000644000175000017500000000016114516512250027414 0ustar00jpakkanejpakkane#include "arm.h" const char *ARMBoard::target() { return THE_TARGET; } void ARMBoard::some_arm_thing() { } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/boards/arm/arm.h0000644000175000017500000000021614516512250027257 0ustar00jpakkanejpakkane#ifndef ARM_H #define ARM_H 1 #include "common.h" struct ARMBoard: Board { const char *target(); void some_arm_thing(); }; #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/boards/arm/arm32.cc0000644000175000017500000000027714516512250027571 0ustar00jpakkanejpakkane#include "common.h" #include void initialize_target() { std::cout << ANSI_START << "a different " << THE_TARGET << " initialization" << ANSI_END << std::endl; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/boards/arm/versatilepb.cc0000644000175000017500000000047714516512250031167 0ustar00jpakkanejpakkane#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; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/boards/arm/virt.cc0000644000175000017500000000043414516512250027624 0ustar00jpakkanejpakkane#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; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/boards/arm/xlnx_zcu102.cc0000644000175000017500000000047414516512250030741 0ustar00jpakkanejpakkane#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; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/boards/meson.build0000644000175000017500000000073514516512250027720 0ustar00jpakkanejpakkanespecific.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')) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7866552 meson-1.3.2/test cases/common/215 source set realistic example/boards/x86/0000755000175000017500000000000014562742415026207 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/boards/x86/pc.cc0000644000175000017500000000066314516512250027114 0ustar00jpakkanejpakkane#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; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/common.h0000644000175000017500000000127314516512250025743 0ustar00jpakkanejpakkane#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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7906554 meson-1.3.2/test cases/common/215 source set realistic example/config/0000755000175000017500000000000014562742415025555 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/config/aarch640000644000175000017500000000013114516512250026712 0ustar00jpakkanejpakkaneTARGET_AARCH64=y CONFIG_VIRT=y CONFIG_XLNX_ZCU102=y CONFIG_VIRTIO=y CONFIG_VIRTIO_MMIO=y ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/config/arm0000644000175000017500000000006014516512250026242 0ustar00jpakkanejpakkaneTARGET_ARM=y CONFIG_VIRT=y CONFIG_VERSATILEPB=y ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/config/x860000644000175000017500000000007514516512250026116 0ustar00jpakkanejpakkaneTARGET_X86=y CONFIG_PC=y CONFIG_VIRTIO=y CONFIG_VIRTIO_PCI=y ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7906554 meson-1.3.2/test cases/common/215 source set realistic example/devices/0000755000175000017500000000000014562742415025732 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/devices/meson.build0000644000175000017500000000032514516512250030063 0ustar00jpakkanejpakkanespecific.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')) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/devices/virtio-mmio.cc0000644000175000017500000000050714516512250030505 0ustar00jpakkanejpakkane#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; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/devices/virtio-pci.cc0000644000175000017500000000050214516512250030312 0ustar00jpakkanejpakkane#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; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/devices/virtio.cc0000644000175000017500000000015014516512250027540 0ustar00jpakkanejpakkane#include #include "common.h" #include "virtio.h" void VirtioDevice::some_virtio_thing() { } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/devices/virtio.h0000644000175000017500000000020114516512250027377 0ustar00jpakkanejpakkane#ifndef VIRTIO_H #define VIRTIO_H 1 #include "common.h" struct VirtioDevice: Device { void some_virtio_thing(); }; #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/dummy.cpp0000644000175000017500000000000014516512250026124 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/main.cc0000644000175000017500000000130214516512250025526 0ustar00jpakkanejpakkane#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(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421643.0 meson-1.3.2/test cases/common/215 source set realistic example/meson.build0000644000175000017500000000342314516755613026457 0ustar00jpakkanejpakkane# a sort-of realistic example that combines the sourceset and keyval # 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') keyval = import('keyval') zlib = declare_dependency(compile_args: '-DZLIB=1') another = declare_dependency(compile_args: '-DANOTHER=1') not_found = dependency('not-found', required: false, method : 'pkg-config') 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() common.add(files('dummy.cpp')) 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 = keyval.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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/not-found.cc0000644000175000017500000000024714516512250026522 0ustar00jpakkanejpakkane#include #include "common.h" void some_random_function() { std::cout << ANSI_START << "everything's alright" << ANSI_END << std::endl; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/was-found.cc0000644000175000017500000000020314516512250026504 0ustar00jpakkanejpakkane#include void some_random_function() { std::cout << ANSI_START << "huh?" << ANSI_END << std::endl; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/215 source set realistic example/zlib.cc0000644000175000017500000000044714516512250025553 0ustar00jpakkanejpakkane#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; ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7986555 meson-1.3.2/test cases/common/216 custom target input extracted objects/0000755000175000017500000000000014562742415026140 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/216 custom target input extracted objects/check_object.py0000644000175000017500000000072614516512250031111 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys, os if __name__ == '__main__': if len(sys.argv) < 4: print(sys.argv[0], 'n output objects...') sys.exit(1) if len(sys.argv) != int(sys.argv[1]) + 3: print(f'expected {sys.argv[1]} objects, got {len(sys.argv) - 3}') sys.exit(1) for i in sys.argv[3:]: print('testing', i) if not os.path.exists(i): sys.exit(1) with open(sys.argv[2], 'wb') as out: pass ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7986555 meson-1.3.2/test cases/common/216 custom target input extracted objects/libdir/0000755000175000017500000000000014562742415027405 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/216 custom target input extracted objects/libdir/gen.py0000644000175000017500000000023714516512250030521 0ustar00jpakkanejpakkane#! /usr/bin/env python3 import sys with open(sys.argv[1], 'r') as f: for l in f: l = l.rstrip() print(l.replace(sys.argv[2], sys.argv[3])) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/216 custom target input extracted objects/libdir/meson.build0000644000175000017500000000153414516512250031541 0ustar00jpakkanejpakkanegen_py = find_program('gen.py') ctsrc = custom_target('custom_target sources', output: 'ct-source.c', input: 'source.c', command: [ gen_py, '@INPUT@', 'func1', 'func2' ], capture: true) gen = generator(gen_py, arguments: ['@INPUT@', 'func1', 'func3'], output: 'gen-@PLAINNAME@', capture: true) gensrc = gen.process('source.c') gen = generator(gen_py, arguments: ['@INPUT@', 'func1', 'func4'], output: 'gen-@PLAINNAME@', capture: true) sublibsrc = gen.process('source.c') subobjlib = static_library('subobject', sublibsrc) objlib = static_library('object', 'source.c', ctsrc, gensrc, objects: subobjlib.extract_all_objects(recursive: false), override_options : ['unity=off']) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/216 custom target input extracted objects/libdir/source.c0000644000175000017500000000005114516512250031034 0ustar00jpakkanejpakkaneint func1_in_obj(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421642.0 meson-1.3.2/test cases/common/216 custom target input extracted objects/meson.build0000644000175000017500000000253514516755612030311 0ustar00jpakkanejpakkaneproject('custom target input extracted objects', 'c') if meson.backend() == 'xcode' error('MESON_SKIP_TEST: sometimes Xcode puts object files in weird paths and we cannot extract them.') endif 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, '1', '@OUTPUT@', '@INPUT@'], build_by_default: true) custom_target('checkct', input: objlib.extract_objects(ctsrc), output: 'objcheck-ct', command: [checker, '1', '@OUTPUT@', '@INPUT@'], build_by_default: true) custom_target('checkcti', input: objlib.extract_objects(ctsrc[0]), output: 'objcheck-cti', command: [checker, '1', '@OUTPUT@', '@INPUT@'], build_by_default: true) custom_target('checkgen', input: objlib.extract_objects(gensrc), output: 'objcheck-gen', command: [checker, '1', '@OUTPUT@', '@INPUT@'], build_by_default: true) custom_target('checkall', input: objlib.extract_all_objects(recursive: false), output: 'objcheck-all', command: [checker, '3', '@OUTPUT@', '@INPUT@'], build_by_default: true) custom_target('checkall-recursive', input: objlib.extract_all_objects(recursive: true), output: 'objcheck-all-recursive', command: [checker, '4', '@OUTPUT@', '@INPUT@'], build_by_default: true) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7986555 meson-1.3.2/test cases/common/217 test priorities/0000755000175000017500000000000014562742415022013 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421642.0 meson-1.3.2/test cases/common/217 test priorities/meson.build0000644000175000017500000000053714516755612024164 0ustar00jpakkanejpakkaneproject('test priorities') 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 ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/217 test priorities/testprog.py0000644000175000017500000000006714516512250024226 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys print(sys.argv[1]) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7986555 meson-1.3.2/test cases/common/218 include_dir dot/0000755000175000017500000000000014562742415021713 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421643.0 meson-1.3.2/test cases/common/218 include_dir dot/meson.build0000644000175000017500000000025614516755613024063 0ustar00jpakkanejpakkaneproject('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')././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/218 include_dir dot/rone.h0000644000175000017500000000001714516512250023014 0ustar00jpakkanejpakkaneint rOne(void);././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7986555 meson-1.3.2/test cases/common/218 include_dir dot/src/0000755000175000017500000000000014562742415022502 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/218 include_dir dot/src/main.c0000644000175000017500000000007114516512250023557 0ustar00jpakkanejpakkane#include "rone.h" int main(void) { return rOne(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/218 include_dir dot/src/meson.build0000644000175000017500000000017014516512250024631 0ustar00jpakkanejpakkanet = executable( 'main', ['main.c', 'rone.c'], include_directories : inc, implicit_include_directories : false, )././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/218 include_dir dot/src/rone.c0000644000175000017500000000004014516512250023572 0ustar00jpakkanejpakkaneint rOne(void) { return 1; }././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7986555 meson-1.3.2/test cases/common/219 include_type dependency/0000755000175000017500000000000014562742415023447 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/219 include_type dependency/main.cpp0000644000175000017500000000016414516512250025067 0ustar00jpakkanejpakkane#include #include using namespace std; int main(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0 meson-1.3.2/test cases/common/219 include_type dependency/meson.build0000644000175000017500000000350514562742373025617 0ustar00jpakkanejpakkaneproject( 'dependency include_type', ['c', 'cpp'], default_options: ['cpp_std=c++11'], ) dep = dependency('zlib', method: 'pkg-config', required : false) boost_dep = dependency('boost', modules: ['graph'], include_type : 'system', required: false) if not dep.found() error('MESON_SKIP_TEST zlib was not found') endif if not boost_dep.found() error('MESON_SKIP_TEST boost 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') fallback = dependency('sdffgagf_does_not_exist', include_type: 'system', fallback: ['subDep', 'subDep_dep']) assert(fallback.include_type() == 'system', 'include_type works with dependency fallback') fallback_empty = dependency('', include_type: 'system', fallback: ['subDep', 'subDep_dep']) assert(fallback_empty.include_type() == 'system', 'include_type works with empty name dependency fallback') # Check that PCH works with `include_type : 'system'` See https://github.com/mesonbuild/meson/issues/7167 main_exe = executable('main_exe', 'main.cpp', cpp_pch: 'pch/test.hpp', dependencies: boost_dep) test('main_test', main_exe) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7986555 meson-1.3.2/test cases/common/219 include_type dependency/pch/0000755000175000017500000000000014562742415024221 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/219 include_type dependency/pch/test.hpp0000644000175000017500000000005214516512250025675 0ustar00jpakkanejpakkane#include ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.8706262 meson-1.3.2/test cases/common/219 include_type dependency/subprojects/0000755000175000017500000000000014562742413026010 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.7986555 meson-1.3.2/test cases/common/219 include_type dependency/subprojects/subDep/0000755000175000017500000000000014562742415027234 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/219 include_type dependency/subprojects/subDep/meson.build0000644000175000017500000000011714516512250031364 0ustar00jpakkanejpakkaneproject('subDep', ['cpp']) subDep_dep = declare_dependency(compile_args : []) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8066556 meson-1.3.2/test cases/common/22 object extraction/0000755000175000017500000000000014562742415022203 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/22 object extraction/check-obj.py0000644000175000017500000000073614516512250024377 0ustar00jpakkanejpakkane#! /usr/bin/env python3 import json import sys import os cc = None output = None # Only the ninja backend produces compile_commands.json if sys.argv[1] == 'ninja': with open('compile_commands.json') as f: cc = json.load(f) output = {x['output'] for x in cc} for obj in sys.argv[2:]: if not os.path.exists(obj): sys.exit(f'File {obj} not found.') if sys.argv[1] == 'ninja' and obj not in output: sys.exit(1) print('Verified', obj) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/22 object extraction/create-source.py0000644000175000017500000000010614516512250025302 0ustar00jpakkanejpakkane#! /usr/bin/env python3 import sys print(f'#include "{sys.argv[1]}"') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/22 object extraction/header.h0000644000175000017500000000007214516512250023572 0ustar00jpakkanejpakkane/* Check that extract_all_objects works with headers. */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/22 object extraction/lib.c0000644000175000017500000000004214516512250023100 0ustar00jpakkanejpakkaneint func(void) { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/22 object extraction/lib2.c0000644000175000017500000000004214516512250023162 0ustar00jpakkanejpakkaneint retval(void) { return 43; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/22 object extraction/main.c0000644000175000017500000000010514516512250023256 0ustar00jpakkanejpakkaneint func(void); int main(void) { return func() == 42 ? 0 : 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421461.0 meson-1.3.2/test cases/common/22 object extraction/meson.build0000644000175000017500000000376014516755325024356 0ustar00jpakkanejpakkaneproject('object extraction', 'c') if meson.is_unity() message('Skipping extraction test because this is a Unity build.') else lib1 = library('somelib', 'src/lib.c') lib2 = library('somelib2', 'lib.c', 'header.h', 'lib2.c') obj1 = lib1.extract_objects('src/lib.c') obj2 = lib2.extract_objects(['lib.c']) obj3 = lib2.extract_objects(files('lib.c')) obj4 = lib2.extract_objects(['lib.c', 'lib.c']) obj5 = lib2.extract_objects(['lib.c', 'header.h']) obj6 = lib2.extract_all_objects(recursive: true) e1 = executable('main1', 'main.c', objects : obj1) e2 = executable('main2', 'main.c', objects : obj2) e3 = executable('main3', 'main.c', objects : obj3) e4 = executable('main4', 'main.c', objects : obj4) e5 = executable('main5', 'main.c', objects : obj5) e6 = executable('main6', 'main.c', objects : obj6) ct_src = custom_target('lib3.c', output: 'lib3.c', capture: true, command: [find_program('create-source.py'), 'lib.c']) lib3 = library('somelib3', ct_src) e7 = executable('main7', 'main.c', objects: lib3.extract_objects(ct_src[0])) e8 = executable('main8', 'main.c', objects: lib3.extract_objects(ct_src)) gen = generator(find_program('create-source.py'), arguments: ['@INPUT@'], output: '@BASENAME@4.c', capture: true) gen_src = gen.process('lib.c') lib4 = library('somelib4', gen_src) e9 = executable('main9', 'main.c', objects: lib4.extract_objects(gen_src)) custom_target('custom_target with object inputs', output: 'objs', input: [obj1, obj2, obj3, obj5, obj6], build_by_default: true, command: [find_program('check-obj.py'), meson.backend(), '@INPUT@'], capture: true) test('extraction test 1', e1) test('extraction test 2', e2) test('extraction test 3', e3) test('extraction test 4', e4) test('extraction test 5', e5) test('extraction test 6', e6) test('extraction test 7', e7) test('extraction test 8', e8) test('extraction test 9', e9) endif ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8066556 meson-1.3.2/test cases/common/22 object extraction/src/0000755000175000017500000000000014562742415022772 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/22 object extraction/src/lib.c0000644000175000017500000000004214516512250023667 0ustar00jpakkanejpakkaneint func(void) { return 42; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8066556 meson-1.3.2/test cases/common/220 fs module/0000755000175000017500000000000014562742415020532 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421645.0 meson-1.3.2/test cases/common/220 fs module/meson.build0000644000175000017500000001671714516755615022715 0ustar00jpakkanejpakkaneproject('fs module test', 'c') is_windows = build_machine.system() == 'windows' fs = import('fs') f = files('meson.build') assert(fs.exists('meson.build'), 'Existing file reported as missing.') assert(not fs.exists('nonexisting'), 'Nonexisting file was found.') if not is_windows and build_machine.system() != 'cygwin' # Symlinks on Windows have specific requirements including: # * Meson running under Python >= 3.8 # * Windows user permissions to create symlinks, and/or Windows in Developer mode # so at this time the symlink test is skipped for Windows. symlink = meson.current_build_dir() / 'a_symlink' run_command('ln', '-s', '-f', meson.current_source_dir() / 'meson.build', symlink, check: true) assert(fs.is_symlink(symlink), 'Symlink not detected.') assert(not fs.is_symlink('meson.build'), 'Regular file detected as symlink.') assert(not fs.is_symlink(f[0]), '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('~'), 'home directory not detected') assert(not fs.is_file('~'), 'home directory detected as file') # -- expanduser assert(fs.expanduser('~') != '~','expanduser failed') assert(fs.expanduser('~/foo').endswith('foo'), 'expanduser with tail failed') # -- as_posix assert(fs.as_posix('/') == '/', 'as_posix idempotent') assert(fs.as_posix('\\') == '/', 'as_posix simple') # Python 3.12 changed how these paths are handled, so deal with both. drivepath = fs.as_posix('\\\\') assert(drivepath == '/' or drivepath == '//', 'as_posix simple') assert(fs.as_posix('foo\\bar/baz') == 'foo/bar/baz', 'as_posix mixed slash') # -- is_absolute winabs = 'q:/foo' unixabs = '/foo' if is_windows assert(fs.is_absolute(winabs), 'is_absolute windows not detected') assert(not fs.is_absolute(unixabs), 'is_absolute unix false positive') else assert(fs.is_absolute(unixabs), 'is_absolute unix not detected') assert(not fs.is_absolute(winabs), 'is_absolute windows false positive') endif # -- replace_suffix original = 'foo' assert(fs.replace_suffix(original, '') == original, 'replace_suffix idempotent') assert(fs.replace_suffix(f[0], '') == 'meson', 'replace_suffix trim') original = 'foo.txt' new = fs.replace_suffix(original, '.ini') assert(new == 'foo.ini', 'replace_suffix failed') new = fs.replace_suffix(f[0], '.ini') assert(new == 'meson.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') f = files('subdir/subdirfile.txt') md5 = fs.hash(f[0], 'md5') assert(md5 == 'd0795db41614d25affdd548314b30b3b', 'md5sum did not match') sha256 = fs.hash(f[0], 'sha256') assert(sha256 == 'be2170b0dae535b73f6775694fffa3fd726a43b5fabea11b7342f0605917a42a', 'sha256sum did not match') # -- size size = fs.size('subdir/subdirfile.txt') assert(size == 19, 'file size not found correctly') size = fs.size(f[0]) 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 detecting same files') assert(fs.is_samepath(meson.source_root(), 'subdir/..'), 'is_samepath not detecting same directory') assert(fs.is_samepath(meson.project_source_root(), 'subdir/..'), 'is_samepath not detecting same directory') assert(fs.is_samepath(meson.project_build_root(), meson.current_build_dir() / 'subdir/..'), 'is_samepath not detecting same directory') assert(fs.is_samepath(meson.global_source_root(), meson.current_source_dir()), 'is_samepath not detecting same directory') assert(fs.is_samepath(meson.global_build_root(), meson.current_build_dir()), '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') f = files('meson.build', 'subdir/../meson.build') assert(fs.is_samepath(f[0], f[1]), 'is_samepath not detecting same files') if not is_windows and build_machine.system() != 'cygwin' assert(fs.is_samepath(symlink, 'meson.build'), 'symlink is_samepath fail') endif # parts of path assert(fs.parent('foo/bar') == 'foo', 'failed to get dirname') if not is_windows assert(fs.parent(f[1]) == 'subdir/..', 'failed to get dirname') else assert(fs.parent(f[1]) == 'subdir\..', 'failed to get dirname') endif assert(fs.name('foo/bar') == 'bar', 'failed to get basename') assert(fs.name(f[1]) == 'meson.build', 'failed to get basename') assert(fs.name('foo/bar/baz.dll.a') == 'baz.dll.a', 'failed to get basename with compound suffix') assert(fs.stem('foo/bar/baz.dll') == 'baz', 'failed to get stem with suffix') assert(fs.stem('foo/bar/baz.dll.a') == 'baz.dll', 'failed to get stem with compound suffix') # relative_to if build_machine.system() == 'windows' # strings assert(fs.relative_to('c:\\prefix\\lib\\foo', 'c:\\prefix') == 'lib\\foo') assert(fs.relative_to('c:\\prefix\\lib', 'c:\\prefix\\bin') == '..\\lib') assert(fs.relative_to('c:\\proj1\\foo', 'd:\\proj1\\bar') == 'c:\\proj1\\foo') assert(fs.relative_to('prefix\\lib\\foo', 'prefix') == 'lib\\foo') assert(fs.relative_to('prefix\\lib', 'prefix\\bin') == '..\\lib') assert(fs.relative_to('proj1\\foo', 'proj1\\bar') == '..\\foo') assert(fs.relative_to('subdir/subdirfile.txt', meson.current_source_dir()) == 'subdir\\subdirfile.txt') assert(fs.relative_to(files('meson.build'), files('subdir/meson.build')) == '..\\..\\meson.build') assert(fs.relative_to(files('meson.build'), 'subdir/meson.build') == '..\\..\\meson.build') else # strings assert(fs.relative_to('/prefix/lib/foo', '/prefix') == 'lib/foo') assert(fs.relative_to('/prefix/lib', '/prefix/bin') == '../lib') assert(fs.relative_to('prefix/lib/foo', 'prefix') == 'lib/foo') assert(fs.relative_to('prefix/lib', 'prefix/bin') == '../lib') assert(fs.relative_to('subdir/subdirfile.txt', meson.current_source_dir()) == 'subdir/subdirfile.txt') assert(fs.relative_to(files('meson.build'), files('subdir/meson.build')) == '../../meson.build') assert(fs.relative_to(files('meson.build'), 'subdir/meson.build') == '../../meson.build') endif subdir('subdir') subproject('subbie') testcase expect_error('File notfound does not exist.') fs.read('notfound') endtestcase ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8066556 meson-1.3.2/test cases/common/220 fs module/subdir/0000755000175000017500000000000014562742415022022 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/220 fs module/subdir/btgt.c0000644000175000017500000000004114516512250023110 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/220 fs module/subdir/meson.build0000644000175000017500000000430114516512250024151 0ustar00jpakkanejpakkanesubdirfiles = files('subdirfile.txt') assert(fs.exists('subdirfile.txt'), 'Subdir file lookup is broken.') assert(fs.is_samepath(meson.project_source_root(), '..'), 'is_samepath not detecting same directory') assert(fs.is_samepath(meson.project_build_root(), meson.current_build_dir() / '..'), 'is_samepath not detecting same directory') assert(fs.is_samepath(subdirfiles[0], 'subdirfile.txt'), 'is_samepath not detecting same directory when using File and str') # More relative_to to test subdir/builddir components build_to_src = fs.relative_to(meson.current_source_dir(), meson.current_build_dir()) src_to_build = fs.relative_to(meson.current_build_dir(), meson.current_source_dir()) btgt = executable('btgt', 'btgt.c') ctgt = fs.copyfile('subdirfile.txt') if build_machine.system() == 'windows' # Test that CustomTarget works assert(fs.relative_to('subdirfile.txt', ctgt) == '..\\@0@\\subdirfile.txt'.format(build_to_src)) assert(fs.relative_to(ctgt, 'subdirfile.txt') == '..\\@0@\\subdirfile.txt'.format(src_to_build)) # Test that CustomTargetIndex works assert(fs.relative_to('subdirfile.txt', ctgt[0]) == '..\\@0@\\subdirfile.txt'.format(build_to_src)) assert(fs.relative_to(ctgt[0], 'subdirfile.txt') == '..\\@0@\\subdirfile.txt'.format(src_to_build)) # Test that BuildTarget works assert(fs.relative_to('subdirfile.txt', btgt) == '..\\@0@\\subdirfile.txt'.format(build_to_src)) assert(fs.relative_to(btgt, 'subdirfile.txt') == '..\\@0@\\@1@'.format(src_to_build, fs.name(btgt.full_path()))) else # Test that CustomTarget works assert(fs.relative_to('subdirfile.txt', ctgt) == '../@0@/subdirfile.txt'.format(build_to_src)) assert(fs.relative_to(ctgt, 'subdirfile.txt') == '../@0@/subdirfile.txt'.format(src_to_build)) # Test that CustomTargetIndex works assert(fs.relative_to('subdirfile.txt', ctgt[0]) == '../@0@/subdirfile.txt'.format(build_to_src)) assert(fs.relative_to(ctgt[0], 'subdirfile.txt') == '../@0@/subdirfile.txt'.format(src_to_build)) # Test that BuildTarget works assert(fs.relative_to('subdirfile.txt', btgt) == '../@0@/subdirfile.txt'.format(build_to_src)) assert(fs.relative_to(btgt, 'subdirfile.txt') == '../@0@/@1@'.format(src_to_build, fs.name(btgt.full_path()))) endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/220 fs module/subdir/subdirfile.txt0000644000175000017500000000002314516512250024675 0ustar00jpakkanejpakkaneI have no content. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.8706262 meson-1.3.2/test cases/common/220 fs module/subprojects/0000755000175000017500000000000014562742413023073 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8106556 meson-1.3.2/test cases/common/220 fs module/subprojects/subbie/0000755000175000017500000000000014562742415024346 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/220 fs module/subprojects/subbie/meson.build0000644000175000017500000000120114516512250026471 0ustar00jpakkanejpakkaneproject('subbie') fs = import('fs') assert(fs.exists('subprojectfile.txt'), 'Subproject root file not found.') assert(fs.is_samepath(meson.project_source_root(), meson.current_source_dir()), 'is_samepath not detecting same directory') assert(fs.is_samepath(meson.project_build_root(), meson.current_build_dir()), 'is_samepath not detecting same directory') assert(fs.is_samepath(meson.global_source_root(), meson.current_source_dir() / '../..'), 'is_samepath not detecting same directory') assert(fs.is_samepath(meson.global_build_root(), meson.current_build_dir() / '../..'), 'is_samepath not detecting same directory') subdir('subsub') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/220 fs module/subprojects/subbie/subprojectfile.txt0000644000175000017500000000005114516512250030112 0ustar00jpakkanejpakkaneI'm not empty. So there's at least that. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8106556 meson-1.3.2/test cases/common/220 fs module/subprojects/subbie/subsub/0000755000175000017500000000000014562742415025651 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/220 fs module/subprojects/subbie/subsub/meson.build0000644000175000017500000000051414516512250030002 0ustar00jpakkanejpakkaneassert(fs.exists('subsubfile.txt'), 'Subproject subdir lookup failed.') assert(fs.is_samepath(meson.project_source_root(), meson.current_source_dir() / '..'), 'is_samepath not detecting same directory') assert(fs.is_samepath(meson.project_build_root(), meson.current_build_dir() / '..'), 'is_samepath not detecting same directory') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/220 fs module/subprojects/subbie/subsub/subsubfile.txt0000644000175000017500000000004114516512250030537 0ustar00jpakkanejpakkaneThank you for looking inside me. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8106556 meson-1.3.2/test cases/common/221 zlib/0000755000175000017500000000000014562742415017615 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/221 zlib/meson.build0000644000175000017500000000201714516512250021746 0ustar00jpakkanejpakkaneproject('zlib system dependency', 'c') if not ['darwin', 'freebsd', 'dragonfly', 'windows', 'android'].contains(host_machine.system()) error('MESON_SKIP_TEST only applicable on macOS, FreeBSD, DragonflyBSD, Windows, and Android.') endif cc = meson.get_compiler('c') if host_machine.system() == 'darwin' and cc.get_id() != 'clang' # this will only work on mac if using Apple's clang compiler, but there is no # way in the meson source level to differentiate apple clang and llvm clang # In the meson CI only apple clang is tested error('MESON_SKIP_TEST on macOS only clang is supported.') endif if not (cc.find_library('z', required: false).found() or cc.find_library('zlib', required : false).found() or cc.find_library('zlib1', required : false).found()) error('MESON_SKIP_TEST Cannot seem to find zlib via find_library, this test will probably fail.') endif z = dependency('zlib', method : 'system') assert(z.version().version_compare('>= 1.2'), 'Version does not seem to have been detected correctly.') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8106556 meson-1.3.2/test cases/common/222 native prop/0000755000175000017500000000000014562742415021105 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/222 native prop/crossfile.ini0000644000175000017500000000010314516512250023560 0ustar00jpakkanejpakkane[properties] astring = 'cross' anarray = ['one', 'two'] red = true ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421644.0 meson-1.3.2/test cases/common/222 native prop/meson.build0000644000175000017500000000472314516755614023261 0ustar00jpakkanejpakkaneproject('get prop') x = meson.get_external_property('astring') ref = meson.is_cross_build() ? 'cross' : 'mystring' assert(x==ref, 'did not get native property string. did you use "meson setup --native-file native.txt"') x = meson.get_external_property('astring', native: true) assert(x=='mystring', 'did not get native property with native:true and non-cross build.') x = meson.get_external_property('astring', 'fallback', native: false) assert(x==ref, 'did not get native property with native:false and non-cross build.') x = meson.get_external_property('nonexistent', 'fallback') assert(x=='fallback', 'fallback did not work') x = meson.get_external_property('nonexistent', 'fallback', native: true) assert(x=='fallback', 'fallback native:true did not work') x = meson.get_external_property('nonexistent', 'fallback', native: false) assert(x=='fallback', 'fallback native:false did not work') x = meson.get_external_property('anarray') assert(x==['one', 'two'], 'array did not work') assert(meson.has_external_property('anarray'), 'expected property "anarray" to exist') assert(meson.has_external_property('astring'), 'expected property "astring" to exist') assert(not meson.has_external_property('abool'), 'did not expect property "abool" to exist') # These exist in both assert(meson.has_external_property('anarray', native: false), 'FIXME') assert(meson.has_external_property('anarray', native: true), 'FIXME') assert(meson.has_external_property('astring', native: false), 'FIXME') assert(meson.has_external_property('astring', native: true), 'FIXME') if meson.is_cross_build() # This property only exists in the cross file assert(meson.has_external_property('red'), 'expected property "red" to exist in cross file') assert(meson.has_external_property('red', native: false), 'expected property "red" to exist in cross file') assert(not meson.has_external_property('red', native: true), 'did not expect property "red" to exist in native file') assert(not meson.has_external_property('abool', native: false), 'FIXME') assert(not meson.has_external_property('abool', native: false), 'FIXME') else assert(not meson.has_external_property('red'), 'did not expect property "red" to exist in native file') assert(not meson.has_external_property('red', native: false), 'did not expect property "red" to exist in cross file because we are not doing a cross build') assert(not meson.has_external_property('red', native: true), 'did not expect property "red" to exist in native file') endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0 meson-1.3.2/test cases/common/222 native prop/nativefile.ini0000644000175000017500000000020214562742373023731 0ustar00jpakkanejpakkane[properties] astring = 'mystring' anarray = ['one', 'two'] withparentheses = ('anotherstring') # Ensure parentheses can be parsed././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8146558 meson-1.3.2/test cases/common/223 persubproject options/0000755000175000017500000000000014562742415023222 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/223 persubproject options/foo.c0000644000175000017500000000005614516512250024141 0ustar00jpakkanejpakkaneint foo(void); int foo(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/223 persubproject options/main.cpp0000644000175000017500000000005514516512250024641 0ustar00jpakkanejpakkaneint foo(); int main(void) { return foo(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421653.0 meson-1.3.2/test cases/common/223 persubproject options/meson.build0000644000175000017500000000132014516755625025366 0ustar00jpakkanejpakkaneproject('persubproject options', 'c', 'cpp', default_options : ['werror=true', 'warning_level=3', 'cpp_std=c++11']) assert(get_option('default_library') == 'both', 'Parent default_library should be "both"') assert(get_option('werror')) assert(get_option('warning_level') == '3') assert(get_option('cpp_std') == 'c++11') # Check it build both by calling a method only both_libraries target implement lib = library('lib1', 'foo.c') lib.get_static_lib() subproject('sub1') libcpp14_dep = dependency('libcpp14', fallback: 'sub2', default_options : ['default_library=static']) exe = executable('test1', 'main.cpp', dependencies : libcpp14_dep) test('mixing-cpp-version', exe) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.8746262 meson-1.3.2/test cases/common/223 persubproject options/subprojects/0000755000175000017500000000000014562742413025563 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8146558 meson-1.3.2/test cases/common/223 persubproject options/subprojects/sub1/0000755000175000017500000000000014562742415026437 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/223 persubproject options/subprojects/sub1/foo.c0000644000175000017500000000033314516512250027354 0ustar00jpakkanejpakkaneint foo(void); int foo(void) { /* This is built with -Werror, it would error if warning_level=3 was inherited * from main project and not overridden by this subproject's default_options. */ int x; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/223 persubproject options/subprojects/sub1/meson.build0000644000175000017500000000057614516512250030600 0ustar00jpakkanejpakkaneproject('sub1', 'c', 'cpp', default_options : ['warning_level=0']) assert(get_option('default_library') == 'both', 'Should inherit parent project default_library') assert(get_option('warning_level') == '0') assert(get_option('cpp_std') == 'c++11') # Check it build both by calling a method only both_libraries target implement lib = library('lib1', 'foo.c') lib.get_static_lib() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8146558 meson-1.3.2/test cases/common/223 persubproject options/subprojects/sub2/0000755000175000017500000000000014562742415026440 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/223 persubproject options/subprojects/sub2/foo.c0000644000175000017500000000015514516512250027357 0ustar00jpakkanejpakkaneint foo(void); #ifdef __GNUC__ #warning This should not produce error #endif int foo(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/223 persubproject options/subprojects/sub2/foo.cpp0000644000175000017500000000016014516512250027713 0ustar00jpakkanejpakkane#include class Dummy { int x; }; int foo() { auto obj = std::make_unique(); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/223 persubproject options/subprojects/sub2/meson.build0000644000175000017500000000135514516512250030575 0ustar00jpakkanejpakkaneproject('sub2', 'c', 'cpp', default_options : ['default_library=shared', 'werror=false', 'cpp_std=c++14']) assert(get_option('default_library') == 'static', 'Parent should override default_library') assert(not get_option('werror')) assert(get_option('cpp_std') == 'c++14') # If it doesn't build only a static library, it would make target name clash. library('lib1', 'foo.c') shared_library('lib1', 'foo.c') # Parent project is c++11 but this one uses c++14 to build. libcpp14 = library('lib2', 'foo.cpp') meson.override_dependency('libcpp14', declare_dependency(link_with: libcpp14)) # Compiler checks should be using c++14 as well cxx = meson.get_compiler('cpp') assert(cxx.compiles(files('foo.cpp'))) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/223 persubproject options/test.json0000644000175000017500000000015614516515714025075 0ustar00jpakkanejpakkane{ "matrix": { "options": { "default_library": [ { "val": "both" } ] } } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8146558 meson-1.3.2/test cases/common/224 arithmetic operators/0000755000175000017500000000000014562742415023010 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421645.0 meson-1.3.2/test cases/common/224 arithmetic operators/meson.build0000644000175000017500000000040514516755615025156 0ustar00jpakkanejpakkaneproject('arithmetic operators') assert(5 - 3 - 1 == 1) assert(5 - (3 - 1) == 3) assert(5 - 1 * 3 - 3 == -1) assert(420 - 300 - 51 == 69) assert(1000 / 2 / 2 / 2 == 125) assert(4 * 9 / 3 % 8 - 3 - 10 / 2 == -4) assert(94 - 30 + (2 - (40 - 6 + 7) - 9) - 10 == 6) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8146558 meson-1.3.2/test cases/common/225 link language/0000755000175000017500000000000014562742415021362 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/225 link language/c_linkage.cpp0000644000175000017500000000007714516512250023775 0ustar00jpakkanejpakkaneextern "C" { int makeInt(void) { return 0; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/225 link language/c_linkage.h0000644000175000017500000000013114516512250023431 0ustar00jpakkanejpakkane #ifdef __cplusplus extern "C" { #endif int makeInt(void); #ifdef __cplusplus } #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/225 link language/lib.cpp0000644000175000017500000000007714516512250022627 0ustar00jpakkanejpakkaneextern "C" { int makeInt(void) { return 1; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/225 link language/main.c0000644000175000017500000000010114516512250022431 0ustar00jpakkanejpakkane#include "c_linkage.h" int main(void) { return makeInt(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421647.0 meson-1.3.2/test cases/common/225 link language/meson.build0000644000175000017500000000033114516755617023530 0ustar00jpakkanejpakkaneproject( 'link_language', ['c', 'cpp'], ) exe = executable( 'main', ['main.c', 'c_linkage.cpp'], link_language : 'c', ) lib = library( 'mylib', ['lib.cpp'], link_language : 'c', ) test('main', exe) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8186557 meson-1.3.2/test cases/common/226 link depends indexed custom target/0000755000175000017500000000000014562742415025365 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/226 link depends indexed custom target/check_arch.py0000644000175000017500000000132314516512250027777 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import re import sys import shutil import subprocess exepath = sys.argv[1] want_arch = sys.argv[2] dummy_output = sys.argv[3] with open(dummy_output, 'w') as f: f.write('') if not shutil.which('dumpbin'): print('dumpbin not found, skipping') sys.exit(0) out = subprocess.check_output(['dumpbin', '/HEADERS', exepath], universal_newlines=True) for line in out.split('\n'): m = re.match(r'.* machine \(([A-Za-z0-9]+)\)$', line) if m: arch = m.groups()[0].lower() if arch == 'arm64': arch = 'aarch64' elif arch == 'x64': arch = 'x86_64' if arch != want_arch: raise RuntimeError(f'Wanted arch {want_arch} but exe uses {arch}') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/226 link depends indexed custom target/foo.c0000644000175000017500000000034614516512250026306 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/226 link depends indexed custom target/make_file.py0000644000175000017500000000030414516512250027637 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys with open(sys.argv[1], 'w') as f: print('# this file does nothing', file=f) with open(sys.argv[2], 'w') as f: print('# this file does nothing', file=f) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421647.0 meson-1.3.2/test cases/common/226 link depends indexed custom target/meson.build0000644000175000017500000000120214516755617027531 0ustar00jpakkanejpakkaneproject('link_depends_indexed_custom_target', 'c') cmd = find_program('make_file.py') dep_files = custom_target('gen_dep', command: [cmd, '@OUTPUT@'], output: ['dep_file1', 'dep_file2']) exe = executable('foo', 'foo.c', link_depends: dep_files[1], c_args: ['-DDEPFILE="' + dep_files[0].full_path()+ '"']) check_arch = find_program('check_arch.py') custom_target('check-arch', command: [check_arch, exe, host_machine.cpu_family(), '@OUTPUT@'], build_by_default: true, output: 'dummy.txt') # check that dep_file1 exists, which means that link_depends target ran test('runtest', exe) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8186557 meson-1.3.2/test cases/common/227 very long command line/0000755000175000017500000000000014562742415023077 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/227 very long command line/codegen.py0000755000175000017500000000023414516512250025046 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys from pathlib import Path Path(sys.argv[2]).write_text( 'int func{n}(void) {{ return {n}; }}'.format(n=sys.argv[1])) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/227 very long command line/main.c0000644000175000017500000000003514516512250024154 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698344951.0 meson-1.3.2/test cases/common/227 very long command line/meson.build0000644000175000017500000000332414516527767025255 0ustar00jpakkanejpakkaneproject('very long command lines', 'c') # Get the current system's commandline length limit. if build_machine.system() == 'windows' # Various limits on windows: # cmd.exe: 8kb # CreateProcess: 32kb limit = 32767 # NOTE: filename limit is 260 characters unless # 1. Python >= 3.6 is being used # 2. Windows 10 registry has been edited to enable long pathnames # ninja backend uses absolute filenames, so we ensure they don't exceed 260. elif build_machine.system() == 'cygwin' # cygwin-to-win32: see above # cygwin-to-cygwin: no limit? # Cygwin is slow, so only test it lightly here. limit = 8192 else # ninja passes whole line as a single argument, for which # the limit is 128k as of Linux 2.6.23. See MAX_ARG_STRLEN. # BSD seems similar, see https://www.in-ulm.de/~mascheck/various/argmax limit = 131072 endif # Now exceed that limit, but not so far that the test takes too long. namelen = 260 nfiles = 50 + limit / namelen message('Expected link commandline length is approximately ' + '@0@'.format((nfiles * (namelen+28)))) seq = run_command('name_gen.py', nfiles.to_string(), meson.build_root(), check: true).stdout().strip().split('\n') sources = [] codegen = find_program('codegen.py') i=0 foreach name : seq sources += custom_target('codegen' + i.to_string(), command: [codegen, i.to_string(), '@OUTPUT@'], output: name + '.c') i+=1 endforeach shared_library('sharedlib', sources) static_library('staticlib', sources) executable('app', 'main.c', sources) # Also test short commandlines to make sure that doesn't regress shared_library('sharedlib0', sources[0]) static_library('staticlib0', sources[0]) executable('app0', 'main.c', sources[0]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/227 very long command line/name_gen.py0000755000175000017500000000145014516512250025214 0ustar00jpakkanejpakkane#!/usr/bin/env python3 """ generate sequence of filename that does not exceed MAX_LEN=260 for Python < 3.6 and Windows without modified registry """ import sys import string name_len = 260 - len(sys.argv[2]) - 4 - 39 - 4 - 2 if name_len < 1: raise ValueError('The meson build directory pathname is so long ' 'that we cannot generate filenames within 260 characters.') # leave room for suffix and file separators, and meson generated text # e.g. ".c.obj.d" and other decorators added by Meson at configuration # for intermediate files base = string.ascii_letters * 5 # 260 characters max_num_len = len(str(sys.argv[1])) base = base[: name_len - max_num_len] for i in range(int(sys.argv[1])): print("{base}{i:0{max_num_len}d}".format(base=base, max_num_len=max_num_len, i=i)) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8186557 meson-1.3.2/test cases/common/228 custom_target source/0000755000175000017500000000000014562742415023025 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/228 custom_target source/a0000644000175000017500000000000014516512250023145 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421653.0 meson-1.3.2/test cases/common/228 custom_target source/meson.build0000644000175000017500000000023214516755625025172 0ustar00jpakkanejpakkaneproject('a', ['c']) x = find_program('x.py') outs = custom_target('foo', output: ['x.c', 'y'], input: 'a', command: [x]) executable('testprog', outs[0]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/228 custom_target source/x.py0000644000175000017500000000020414516512250023631 0ustar00jpakkanejpakkane#! /usr/bin/env python3 with open('x.c', 'w') as f: print('int main(void) { return 0; }', file=f) with open('y', 'w'): pass ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8266559 meson-1.3.2/test cases/common/229 disabler array addition/0000755000175000017500000000000014562742415023325 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421653.0 meson-1.3.2/test cases/common/229 disabler array addition/meson.build0000644000175000017500000000025414516755625025476 0ustar00jpakkanejpakkaneproject('disabler_inside_array', 'c') exes = [] exes += library('a', 'test.c') exes += library('b', 'test.c', dependencies : disabler()) exes += library('c', 'test.c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/229 disabler array addition/test.c0000644000175000017500000000003514516512250024435 0ustar00jpakkanejpakkaneint stub(void) { return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8266559 meson-1.3.2/test cases/common/23 endian/0000755000175000017500000000000014562742415020033 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421461.0 meson-1.3.2/test cases/common/23 endian/meson.build0000644000175000017500000000025214516755325022177 0ustar00jpakkanejpakkaneproject('endian check', 'c') if host_machine.endian() == 'big' add_global_arguments('-DIS_BE', language : 'c') endif test('endiantest', executable('prog', 'prog.c')) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/23 endian/prog.c0000644000175000017500000000056714516512250021145 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8266559 meson-1.3.2/test cases/common/230 external project/0000755000175000017500000000000014562742415022126 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/230 external project/app.c0000644000175000017500000000011514516512250023036 0ustar00jpakkanejpakkane#include int main(void) { return call_foo() == 42 ? 0 : 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/230 external project/func.c0000644000175000017500000000006414516512250023214 0ustar00jpakkanejpakkane#include "func.h" int func(void) { return 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/230 external project/func.h0000644000175000017500000000002014516512250023211 0ustar00jpakkanejpakkaneint func(void); ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.830656 meson-1.3.2/test cases/common/230 external project/libfoo/0000755000175000017500000000000014562742415023400 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/230 external project/libfoo/configure0000755000175000017500000000126314516512250025300 0ustar00jpakkanejpakkane#! /bin/sh srcdir=$(dirname "$0") for i in "$@" do case $i in --prefix=*) PREFIX="${i#*=}" shift ;; --libdir=*) LIBDIR="${i#*=}" shift ;; --includedir=*) INCDIR="${i#*=}" shift ;; --libext=*) LIBEXT="${i#*=}" shift ;; *) shift ;; esac done DEP_ARGS=$(pkg-config --cflags --libs somelib) cat > Makefile << EOL all: libfoo.$LIBEXT libfoo.$LIBEXT: $CC "$srcdir/libfoo.c" -shared -fPIC $DEP_ARGS -o \$@ install: libfoo.$LIBEXT mkdir -p "\$(DESTDIR)$LIBDIR"; mkdir -p "\$(DESTDIR)$LIBDIR/pkgconfig"; mkdir -p "\$(DESTDIR)$INCDIR"; cp \$< "\$(DESTDIR)$LIBDIR"; cp "$srcdir/libfoo.h" "\$(DESTDIR)$INCDIR"; EOL ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/230 external project/libfoo/libfoo.c0000644000175000017500000000013014516512250024777 0ustar00jpakkanejpakkane#include "libfoo.h" int func(void); int call_foo() { return func() == 1 ? 42 : 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/230 external project/libfoo/libfoo.h0000644000175000017500000000004214516512250025006 0ustar00jpakkanejpakkane#pragma once int call_foo(void); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/230 external project/libfoo/meson.build0000644000175000017500000000101314516512250025524 0ustar00jpakkanejpakkanemod = import('unstable-external_project') target_system = target_machine.system() if target_system in ['windows', 'cygwin'] libext = 'dll' elif target_system == 'darwin' libext = 'dylib' else libext = 'so' endif p = mod.add_project('configure', configure_options : [ '--prefix=@PREFIX@', '--libdir=@PREFIX@/@LIBDIR@', '--includedir=@PREFIX@/@INCLUDEDIR@', '--libext=' + libext, ], depends: somelib, ) libfoo_dep = declare_dependency(link_with : somelib, dependencies : p.dependency('foo')) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421654.0 meson-1.3.2/test cases/common/230 external project/meson.build0000644000175000017500000000135014516755626024276 0ustar00jpakkanejpakkaneproject('test external project', 'c') if not find_program('pkg-config', required: false).found() error('MESON_SKIP_TEST: pkg-config not found') endif if not find_program('make', required : false).found() error('MESON_SKIP_TEST: make not found') endif if host_machine.system() == 'windows' error('MESON_SKIP_TEST: The fake configure script is too dumb to work on Windows') endif if meson.is_cross_build() # CI uses PKG_CONFIG_SYSROOT_DIR which breaks -uninstalled.pc usage. error('MESON_SKIP_TEST: Cross build support is too limited for this test') endif pkg = import('pkgconfig') somelib = library('somelib', 'func.c') pkg.generate(somelib) subdir('libfoo') executable('test-find-library', 'app.c', dependencies : libfoo_dep) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/230 external project/test.json0000644000175000017500000000030714516515714023777 0ustar00jpakkanejpakkane{ "installed": [ { "type": "shared_lib", "file": "usr/lib/foo" }, { "type": "file", "file": "usr/include/libfoo.h" }, { "type": "file", "file": "usr/lib/pkgconfig/somelib.pc" } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.830656 meson-1.3.2/test cases/common/231 subdir files/0000755000175000017500000000000014562742415021231 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421654.0 meson-1.3.2/test cases/common/231 subdir files/meson.build0000644000175000017500000000013714516755626023403 0ustar00jpakkanejpakkaneproject('subdir files test', 'c') subdir('subdir') executable('prog', sources: subdir_sources) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.830656 meson-1.3.2/test cases/common/231 subdir files/subdir/0000755000175000017500000000000014562742415022521 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/231 subdir files/subdir/meson.build0000644000175000017500000000004314516512250024647 0ustar00jpakkanejpakkanesubdir_sources = files(['prog.c']) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/231 subdir files/subdir/prog.c0000644000175000017500000000003514516512250023621 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.830656 meson-1.3.2/test cases/common/232 dependency allow_fallback/0000755000175000017500000000000014562742415023713 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421655.0 meson-1.3.2/test cases/common/232 dependency allow_fallback/meson.build0000644000175000017500000000065014516755627026066 0ustar00jpakkanejpakkaneproject('subproject fallback') foob_dep = dependency('foob', allow_fallback: true, required: false) assert(foob_dep.found()) # Careful! Once a submodule has been triggered and it has # overridden the dependency, it sticks. foob_dep = dependency('foob', allow_fallback: false, required: false) assert(foob_dep.found()) foob3_dep = dependency('foob3', allow_fallback: false, required: false) assert(not foob3_dep.found()) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.8826263 meson-1.3.2/test cases/common/232 dependency allow_fallback/subprojects/0000755000175000017500000000000014562742413026254 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.830656 meson-1.3.2/test cases/common/232 dependency allow_fallback/subprojects/foob/0000755000175000017500000000000014562742415027203 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/232 dependency allow_fallback/subprojects/foob/meson.build0000644000175000017500000000011514516512250031331 0ustar00jpakkanejpakkaneproject('foob', 'c') meson.override_dependency('foob', declare_dependency()) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.834656 meson-1.3.2/test cases/common/232 dependency allow_fallback/subprojects/foob3/0000755000175000017500000000000014562742415027266 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/232 dependency allow_fallback/subprojects/foob3/meson.build0000644000175000017500000000010714516512250031415 0ustar00jpakkanejpakkaneproject('foob3', 'c') # Note that there is no override_dependency here ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.834656 meson-1.3.2/test cases/common/233 wrap case/0000755000175000017500000000000014562742415020525 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421656.0 meson-1.3.2/test cases/common/233 wrap case/meson.build0000644000175000017500000000020614516755630022667 0ustar00jpakkanejpakkaneproject('CaSe DePenDenCy In Wrap', 'c') d = dependency('UP_down') e = executable('prog', 'prog.c', dependencies: d) test('prog', e) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/233 wrap case/prog.c0000644000175000017500000000031714516512250021630 0ustar00jpakkanejpakkane#include #include int main(int argc, char **argv) { if(argc == 42) { printf("Very sneaky, %s\n", argv[0]); } #ifdef UP_IS_DOWN return 0; #else return 1; #endif } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.834656 meson-1.3.2/test cases/common/233 wrap case/subprojects/0000755000175000017500000000000014562742415023070 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.834656 meson-1.3.2/test cases/common/233 wrap case/subprojects/up_down/0000755000175000017500000000000014562742415024543 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/233 wrap case/subprojects/up_down/meson.build0000644000175000017500000000012414516512250026671 0ustar00jpakkanejpakkaneproject('up down', 'c') up_down_dep = declare_dependency(include_directories: '.') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/233 wrap case/subprojects/up_down/up_down.h0000644000175000017500000000004114516512250026351 0ustar00jpakkanejpakkane#pragma once #define UP_IS_DOWN ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/233 wrap case/subprojects/up_down.wrap0000644000175000017500000000010114516512250025415 0ustar00jpakkanejpakkane[wrap-file] directory = up_down [provide] UP_down = up_down_dep ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.834656 meson-1.3.2/test cases/common/234 get_file_contents/0000755000175000017500000000000014562742415022354 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/234 get_file_contents/.gitattributes0000644000175000017500000000002314516512250025231 0ustar00jpakkanejpakkaneutf-16-text binary ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/234 get_file_contents/VERSION0000644000175000017500000000000614516512250023407 0ustar00jpakkanejpakkane1.2.0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421656.0 meson-1.3.2/test cases/common/234 get_file_contents/meson.build0000644000175000017500000000100514516755630024514 0ustar00jpakkanejpakkaneproject( 'meson-fs-read-file', [], version: files('VERSION') ) fs = import('fs') assert(fs.read('VERSION').strip() == meson.project_version(), 'file misread') expected = ( '∮ Eā‹…da = Q, n → āˆž, āˆ‘ f(i) = āˆ g(i), āˆ€xāˆˆā„: ⌈xāŒ‰ = āˆ’āŒŠāˆ’xāŒ‹, α ∧ ¬β = ¬(¬α ∨ β)' ) assert( fs.read('utf-16-text', encoding: 'utf-16').strip() == expected, 'file was not decoded correctly' ) # Make sure we handle `files()` objects properly, too version_file = files('VERSION') subdir('other') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.834656 meson-1.3.2/test cases/common/234 get_file_contents/other/0000755000175000017500000000000014562742415023475 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/234 get_file_contents/other/meson.build0000644000175000017500000000016414516512250025627 0ustar00jpakkanejpakkanefs = import('fs') assert(fs.read(version_file).strip() == '1.2.0') assert(fs.read('../VERSION').strip() == '1.2.0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/234 get_file_contents/utf-16-text0000644000175000017500000000022614516512250024272 0ustar00jpakkanejpakkane’ž." EÅ"da = Q, n ’! ", " f(i) = " g(i), "x"!: #x # = " #"x #, ± '" ¬² = ¬(¬± (" ²)././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.834656 meson-1.3.2/test cases/common/235 invalid standard overridden to valid/0000755000175000017500000000000014562742415025676 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/235 invalid standard overridden to valid/main.c0000644000175000017500000000004114516512250026750 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421656.0 meson-1.3.2/test cases/common/235 invalid standard overridden to valid/meson.build0000644000175000017500000000024114516755630030037 0ustar00jpakkanejpakkaneproject( 'invalid C standard overridden to valid one', 'c', default_options : ['c_std=invalid99'], ) exe = executable('main', 'main.c') test('main', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/235 invalid standard overridden to valid/test.json0000644000175000017500000000013714516515714027550 0ustar00jpakkanejpakkane{ "matrix": { "options": { "c_std": [ { "val": "c89" } ] } } } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.834656 meson-1.3.2/test cases/common/236 proper args splitting/0000755000175000017500000000000014562742415023105 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/236 proper args splitting/main.c0000644000175000017500000000020314516512250024157 0ustar00jpakkanejpakkane#ifndef FOO # error "FOO is not defined" #endif #ifndef BAR # error "BAR is not defined" #endif int main(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421657.0 meson-1.3.2/test cases/common/236 proper args splitting/meson.build0000644000175000017500000000014514516755631025252 0ustar00jpakkanejpakkaneproject('proper args splitting', 'c') test( 'main', executable( 'main', 'main.c', ) ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/236 proper args splitting/test.json0000644000175000017500000000015014516515714024752 0ustar00jpakkanejpakkane{ "matrix": { "options": { "c_args": [ { "val": "-DFOO -DBAR" } ] } } } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.834656 meson-1.3.2/test cases/common/237 fstrings/0000755000175000017500000000000014562742415020523 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421658.0 meson-1.3.2/test cases/common/237 fstrings/meson.build0000644000175000017500000000022614516755632022671 0ustar00jpakkanejpakkaneproject('meson-test') n = 10 m = 'bar' s = f'test @n@ string (@@n@@): @m@' assert(s == 'test 10 string (@10@): bar', 'Incorrect string formatting') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.834656 meson-1.3.2/test cases/common/238 dependency include_type inconsistency/0000755000175000017500000000000014562742415026321 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.838656 meson-1.3.2/test cases/common/238 dependency include_type inconsistency/bar/0000755000175000017500000000000014562742415027065 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/238 dependency include_type inconsistency/bar/meson.build0000644000175000017500000000031614516512250031216 0ustar00jpakkanejpakkanebaz_dep = dependency('baz', fallback: ['baz', 'baz_dep'], include_type: 'system', method: 'pkg-config', # if we comment this out or change to 'auto' the build is successful required: false) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421658.0 meson-1.3.2/test cases/common/238 dependency include_type inconsistency/meson.build0000644000175000017500000000012414516755632030464 0ustar00jpakkanejpakkaneproject('test') foo_dep = subproject('foo').get_variable('foo_dep') subdir('bar') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.838656 meson-1.3.2/test cases/common/238 dependency include_type inconsistency/subprojects/0000755000175000017500000000000014562742415030664 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.838656 meson-1.3.2/test cases/common/238 dependency include_type inconsistency/subprojects/baz/0000755000175000017500000000000014562742415031440 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/238 dependency include_type inconsistency/subprojects/baz/meson.build0000644000175000017500000000005714516512250033573 0ustar00jpakkanejpakkaneproject('baz') baz_dep = declare_dependency() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/238 dependency include_type inconsistency/subprojects/baz.wrap0000644000175000017500000000012514516512250032320 0ustar00jpakkanejpakkane[wrap-file] source_url = http://host.invalid/baz.tar.gz source_filename = baz.tar.gz ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.838656 meson-1.3.2/test cases/common/238 dependency include_type inconsistency/subprojects/foo/0000755000175000017500000000000014562742415031447 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/238 dependency include_type inconsistency/subprojects/foo/meson.build0000644000175000017500000000031614516512250033600 0ustar00jpakkanejpakkaneproject('foo') baz_dep = dependency('baz', fallback: ['baz', 'baz_dep'], include_type: 'system', method: 'pkg-config', required: false) foo_dep = declare_dependency(dependencies: baz_dep) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/238 dependency include_type inconsistency/subprojects/foo.wrap0000644000175000017500000000012514516512250032327 0ustar00jpakkanejpakkane[wrap-file] source_url = http://host.invalid/foo.tar.gz source_filename = foo.tar.gz ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.838656 meson-1.3.2/test cases/common/239 includedir violation/0000755000175000017500000000000014562742415022775 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421659.0 meson-1.3.2/test cases/common/239 includedir violation/meson.build0000644000175000017500000000051714516755633025147 0ustar00jpakkanejpakkaneproject('foo') # It is fine to include the root source dir include_directories('.') subproject('sub') # This is here rather than in failing because this needs a # transition period to avoid breaking existing projects. # Once this becomes an error, move this under failing tests. inc = include_directories('subprojects/sub/include') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.8906264 meson-1.3.2/test cases/common/239 includedir violation/subprojects/0000755000175000017500000000000014562742413025336 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.838656 meson-1.3.2/test cases/common/239 includedir violation/subprojects/sub/0000755000175000017500000000000014562742415026131 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.846656 meson-1.3.2/test cases/common/239 includedir violation/subprojects/sub/include/0000755000175000017500000000000014562742415027554 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/239 includedir violation/subprojects/sub/include/placeholder.h0000644000175000017500000000012714516512250032176 0ustar00jpakkanejpakkane#pragma once // Git cannot handle empty directories, so there must be something here. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/239 includedir violation/subprojects/sub/meson.build0000644000175000017500000000005514516512250030262 0ustar00jpakkanejpakkaneproject('subproj') include_directories('.') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/239 includedir violation/test.json0000644000175000017500000000021314516515714024642 0ustar00jpakkanejpakkane{ "stdout": [ { "line": ".*WARNING: include_directories sandbox violation!", "match": "re", "count": 1 } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.846656 meson-1.3.2/test cases/common/24 library versions/0000755000175000017500000000000014562742415022073 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/24 library versions/lib.c0000644000175000017500000000052414516512250022775 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421462.0 meson-1.3.2/test cases/common/24 library versions/meson.build0000644000175000017500000000026414516755326024243 0ustar00jpakkanejpakkaneproject('library versions', 'c') shared_library('somelib', 'lib.c', name_prefix : 'prefix', name_suffix : 'suffix', install_dir : 'lib', install : true) subdir('subdir') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.846656 meson-1.3.2/test cases/common/24 library versions/subdir/0000755000175000017500000000000014562742415023363 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/24 library versions/subdir/meson.build0000644000175000017500000000051014516512250025510 0ustar00jpakkanejpakkane# 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339787.0 meson-1.3.2/test cases/common/24 library versions/test.json0000644000175000017500000000030514516515713023741 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/lib/prefixsomelib.suffix"}, {"type": "implib", "file": "usr/lib/prefixsomelib"}, {"type": "pdb", "file": "usr/lib/prefixsomelib"} ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.846656 meson-1.3.2/test cases/common/240 dependency native host == build/0000755000175000017500000000000014562742415024513 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421659.0 meson-1.3.2/test cases/common/240 dependency native host == build/meson.build0000644000175000017500000000104714516755633026664 0ustar00jpakkanejpakkaneproject('foo') if meson.is_cross_build() error('MESON_SKIP_TEST Test does not make sense for cross builds') endif dep_zlib = dependency('zlib', required : false) if not dep_zlib.found() error('MESON_SKIP_TEST Test requires zlib') endif dependency('zlib', native : true, required : false) dependency('zlib', native : false) # `native: true` should not make a difference when doing a native build. meson.override_dependency('expat', declare_dependency()) dependency('expat') dependency('expat', native : true) dependency('expat', native : false) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/240 dependency native host == build/test.json0000644000175000017500000000037014516515714026364 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "Dependency zlib found: YES .* \\(cached\\)", "match": "re", "count": 2 }, { "line": "Dependency expat found: YES .* \\(overridden\\)", "match": "re", "count": 3 } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8506563 meson-1.3.2/test cases/common/241 set and get variable/0000755000175000017500000000000014562742415022503 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421659.0 meson-1.3.2/test cases/common/241 set and get variable/meson.build0000644000175000017500000000346614516755633024663 0ustar00jpakkanejpakkaneproject('set and get') var1 = 'test1.txt' var2 = files('test1.txt')[0] # Use is_disabler for accessing variables assert(var1 == 'test1.txt') assert(not is_disabler(var2)) # Ensure that set variables behave correctly set_variable('var3', 'test2.txt') set_variable('var4', files('test2.txt')[0]) assert(var3 == 'test2.txt') assert(not is_disabler(var4)) # Test Equality assert(var1 == get_variable('var1')) assert(var2 == get_variable('var2')) # Test get_variable directly assert(get_variable('var1') == 'test1.txt') assert(not is_disabler(get_variable('var2'))) assert(get_variable('var3') == 'test2.txt') assert(not is_disabler(get_variable('var4'))) # Test get_variable indirectly var5 = get_variable('var1') var6 = get_variable('var2') var7 = get_variable('var3') var8 = get_variable('var4') set_variable('var9', get_variable('var7')) set_variable('var0', get_variable('var8')) assert(var5 == 'test1.txt') assert(not is_disabler(var6)) assert(var7 == 'test2.txt') assert(not is_disabler(var8)) assert(get_variable('var9') == 'test2.txt') assert(not is_disabler(get_variable('var0'))) assert(not is_disabler(get_variable('var0', var8))) assert(not is_disabler(get_variable('----', var8))) assert(not is_disabler(get_variable('----', [var8]))) assert(not is_disabler(get_variable('----', {'asd': var8}))) # test dict get dict = {'a': var2} dict_t1 = dict['a'] dict_t2 = dict.get('a') dict_t3 = dict.get('a', var2) dict_t4 = dict.get('b', var2) assert(not is_disabler(dict_t1)) assert(not is_disabler(dict_t2)) assert(not is_disabler(dict_t3)) assert(not is_disabler(dict_t4)) # test lists list = [var2] list_t1 = list[0] list_t2 = list.get(0) list_t3 = list.get(0, var2) list_t4 = list.get(1, var2) assert(not is_disabler(list_t1)) assert(not is_disabler(list_t2)) assert(not is_disabler(list_t3)) assert(not is_disabler(list_t4)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/241 set and get variable/test1.txt0000644000175000017500000000000014516512250024261 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/241 set and get variable/test2.txt0000644000175000017500000000000014516512250024262 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8506563 meson-1.3.2/test cases/common/242 custom target feed/0000755000175000017500000000000014562742415022325 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/242 custom target feed/data_source.txt0000644000175000017500000000004014516512250025340 0ustar00jpakkanejpakkaneThis is a text only input file. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421659.0 meson-1.3.2/test cases/common/242 custom target feed/meson.build0000644000175000017500000000125514516755633024477 0ustar00jpakkanejpakkaneproject('custom target feed') 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', feed : true, command : [python3, comp, '@OUTPUT@'], 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]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/242 custom target feed/my_compiler.py0000755000175000017500000000056714516512250025220 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys if __name__ == '__main__': if len(sys.argv) != 2: print(sys.argv[0], 'output_file') sys.exit(1) ifile = sys.stdin.read() if ifile != 'This is a text only input file.\n': print('Malformed input') sys.exit(1) with open(sys.argv[1], 'w+') as f: f.write('This is a binary output file.') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/242 custom target feed/test.json0000644000175000017500000000011514516515714024173 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/subdir/data.dat"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8506563 meson-1.3.2/test cases/common/243 escape++/0000755000175000017500000000000014562742415020247 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421660.0 meson-1.3.2/test cases/common/243 escape++/meson.build0000644000175000017500000000013714516755634022420 0ustar00jpakkanejpakkaneproject('regex escape test', 'c') exe = executable('testprog', 'test.c') test('runtest', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/243 escape++/test.c0000644000175000017500000000004114516512250021354 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8506563 meson-1.3.2/test cases/common/244 variable scope/0000755000175000017500000000000014562742415021541 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421660.0 meson-1.3.2/test cases/common/244 variable scope/meson.build0000644000175000017500000000030614516755634023710 0ustar00jpakkanejpakkaneproject('variable scope') x = 1 assert(is_variable('x')) assert(get_variable('x') == 1) set_variable('x', 10) assert(get_variable('x') == 10) unset_variable('x') assert(not is_variable('x')) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8506563 meson-1.3.2/test cases/common/245 custom target index source/0000755000175000017500000000000014562742415024015 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/245 custom target index source/code_source.c0000644000175000017500000000007514516512250026444 0ustar00jpakkanejpakkaneextern int genfunc(void); int genfunc(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/245 custom target index source/copyfile.py0000644000175000017500000000013414516512250026166 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys import shutil shutil.copyfile(sys.argv[1], sys.argv[2]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/245 custom target index source/copyfile2.py0000644000175000017500000000020614516512250026250 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys import shutil shutil.copyfile(sys.argv[1], sys.argv[2]) shutil.copyfile(sys.argv[3], sys.argv[4]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/245 custom target index source/header_source.h0000644000175000017500000000003214516512250026760 0ustar00jpakkanejpakkaneextern int genfunc(void); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/245 custom target index source/main.c0000644000175000017500000000020214516512250025066 0ustar00jpakkanejpakkane#include #include "gen.h" int main(int argc, char **argv) { (void)argv; assert(argc == 3); return genfunc(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421661.0 meson-1.3.2/test cases/common/245 custom target index source/meson.build0000644000175000017500000000264314516755635026173 0ustar00jpakkanejpakkaneproject('custom target index source', 'c') # Test that using a custom target index as a sourcefile works correctly copy1 = find_program('copyfile.py') copy2 = find_program('copyfile2.py') step_1 = custom_target('step_1', input: ['code_source.c', files('header_source.h')], output: ['step_1.c', 'step_1.h'], command: [copy2, '@INPUT0@', '@OUTPUT0@', '@INPUT1@', '@OUTPUT1@'], build_by_default: false) # test custom target with a single CustomTargetIndex input step_2_c = custom_target('step_2_c', input: step_1[0], output: 'step_2.c', command: [copy1, '@INPUT0@', '@OUTPUT0@'], build_by_default: false) step_2_h = custom_target('step_2_h', input: step_1[1], output: 'step_2.h', command: [copy1, '@INPUT0@', '@OUTPUT0@'], build_by_default: false, ) # test custom target with multiple CustomTargetIndex inputs gen = custom_target('step_3', input: [step_2_c, step_2_h], output: ['gen.c', 'gen.h'], command: [copy2, '@INPUT0@', '@OUTPUT0@', '@INPUT1@', '@OUTPUT1@'], build_by_default: false) gen_c = gen[0] gen_h = gen[1] exe_separate = executable('exe_separate', ['main.c', gen_c, gen_h], build_by_default: false, install: false, ) exe_together = executable('exe_together', ['main.c', gen], build_by_default: false, install: false, ) # also cover passing custom target to tests as arguments test('exe_separate', exe_separate, args: [gen_c, gen_h]) test('exe_together', exe_together, args: gen) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8506563 meson-1.3.2/test cases/common/246 dependency fallbacks/0000755000175000017500000000000014562742415022705 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421660.0 meson-1.3.2/test cases/common/246 dependency fallbacks/meson.build0000644000175000017500000000046114516755634025056 0ustar00jpakkanejpakkaneproject('dependency fallbacks') # pkg-config has 'libpng' but cmake has 'png' and we have a 'png' subproject # for platforms that have neither. d = dependency('libpng', 'png', 'foo') assert(d.found()) # Check that dependency 'foo' has been implicitly overridden. d = dependency('foo') assert(d.found()) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.9026268 meson-1.3.2/test cases/common/246 dependency fallbacks/subprojects/0000755000175000017500000000000014562742413025246 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8506563 meson-1.3.2/test cases/common/246 dependency fallbacks/subprojects/png/0000755000175000017500000000000014562742415026034 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/246 dependency fallbacks/subprojects/png/meson.build0000644000175000017500000000011214516512250030157 0ustar00jpakkanejpakkaneproject('png') meson.override_dependency('libpng', declare_dependency()) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8506563 meson-1.3.2/test cases/common/247 deprecated option/0000755000175000017500000000000014562742415022256 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421660.0 meson-1.3.2/test cases/common/247 deprecated option/meson.build0000644000175000017500000000072014516755634024425 0ustar00jpakkanejpakkaneproject('deprecated options', default_options: [ 'o1=false', 'o2=a,b', 'o3=a,b', 'o4=true', 'o5=auto', 'o6=false', 'o8=/foo', ] ) assert(get_option('o1') == false) assert(get_option('o2') == ['a', 'b']) assert(get_option('o3') == ['c', 'b']) assert(get_option('o4').enabled()) assert(get_option('o5') == false) assert(get_option('o6') == false) assert(get_option('o7').disabled()) assert(get_option('python.platlibdir') == '/foo') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/247 deprecated option/meson_options.txt0000644000175000017500000000235114516512250025703 0ustar00jpakkanejpakkane# Option fully deprecated, it warns when any value is set. option('o1', type: 'boolean', deprecated: true) # One of the choices is deprecated, it warns only when 'a' is in the list of values. option('o2', type: 'array', choices: ['a', 'b'], deprecated: ['a']) # One of the choices is deprecated, it warns only when 'a' is in the list of values # and replace it by 'c'. option('o3', type: 'array', choices: ['a', 'b', 'c'], deprecated: {'a': 'c'}) # A boolean option has been replaced by a feature, old true/false values are remapped. option('o4', type: 'feature', deprecated: {'true': 'enabled', 'false': 'disabled'}) # A feature option has been replaced by a boolean, enabled/disabled/auto values are remapped. option('o5', type: 'boolean', deprecated: {'enabled': 'true', 'disabled': 'false', 'auto': 'false'}) # A boolean option has been replaced by a feature with another name, old true/false values # are accepted by the new option for backward compatibility. option('o6', type: 'boolean', value: true, deprecated: 'o7') option('o7', type: 'feature', value: 'enabled', deprecated: {'true': 'enabled', 'false': 'disabled'}) # A project option is replaced by a module option option('o8', type: 'string', value: '', deprecated: 'python.platlibdir') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/247 deprecated option/test.json0000644000175000017500000000117514516515714024133 0ustar00jpakkanejpakkane{ "stdout": [ { "line": ".*DEPRECATION: Option 'o1' is deprecated", "match": "re", "count": 1 }, { "line": ".*DEPRECATION: Option 'o2' value 'a' is deprecated", "match": "re", "count": 1 }, { "line": ".*DEPRECATION: Option 'o3' value 'a' is replaced by 'c'", "match": "re", "count": 1 }, { "line": ".*DEPRECATION: Option 'o4' value 'true' is replaced by 'enabled'", "match": "re", "count": 1 }, { "line": ".*DEPRECATION: Option 'o5' value 'auto' is replaced by 'false'", "match": "re", "count": 1 } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8506563 meson-1.3.2/test cases/common/248 install_emptydir/0000755000175000017500000000000014562742415022251 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421661.0 meson-1.3.2/test cases/common/248 install_emptydir/meson.build0000644000175000017500000000031214516755635024416 0ustar00jpakkanejpakkaneproject('install_emptydir') install_emptydir(get_option('datadir')/'new_directory', install_mode: 'rwx------') install_emptydir(get_option('datadir')/'new_directory/subdir', install_mode: 'rwxr-----') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/248 install_emptydir/test.json0000644000175000017500000000022414516515714024120 0ustar00jpakkanejpakkane{ "installed": [ { "type": "dir", "file": "usr/share/new_directory" }, { "type": "dir", "file": "usr/share/new_directory/subdir" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8586564 meson-1.3.2/test cases/common/249 install_symlink/0000755000175000017500000000000014562742415022103 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/249 install_symlink/datafile.dat0000644000175000017500000000002414516512250024331 0ustar00jpakkanejpakkanethis is a data file ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421661.0 meson-1.3.2/test cases/common/249 install_symlink/meson.build0000644000175000017500000000072714516755635024262 0ustar00jpakkanejpakkaneproject('install_emptydir') if build_machine.system() == 'windows' and meson.backend() == 'ninja' error('MESON_SKIP_TEST windows does not support symlinks unless root or in development mode') endif install_data('datafile.dat', install_dir: 'share/progname/C') install_symlink('datafile.dat', pointing_to: '../C/datafile.dat', install_dir: 'share/progname/es') install_symlink('rename_datafile.dat', pointing_to: '../C/datafile.dat', install_dir: 'share/progname/fr') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/249 install_symlink/test.json0000644000175000017500000000035214516515714023754 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/share/progname/C/datafile.dat"}, {"type": "file", "file": "usr/share/progname/es/datafile.dat"}, {"type": "file", "file": "usr/share/progname/fr/rename_datafile.dat"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8586564 meson-1.3.2/test cases/common/25 config subdir/0000755000175000017500000000000014562742415021315 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8586564 meson-1.3.2/test cases/common/25 config subdir/include/0000755000175000017500000000000014562742415022740 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/25 config subdir/include/config.h.in0000644000175000017500000000011314516512250024745 0ustar00jpakkanejpakkane#ifndef CONFIG_H_ #define CONFIG_H_ #define RETURN_VALUE @number@ #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/25 config subdir/include/meson.build0000644000175000017500000000021714516512250025071 0ustar00jpakkanejpakkaneconf_data = configuration_data() conf_data.set('number', '0') configure_file(input:'config.h.in', output:'config.h', configuration:conf_data) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421462.0 meson-1.3.2/test cases/common/25 config subdir/meson.build0000644000175000017500000000014414516755326023462 0ustar00jpakkanejpakkaneproject('subdirconfig', 'c') inc = include_directories('include') subdir('include') subdir('src') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8586564 meson-1.3.2/test cases/common/25 config subdir/src/0000755000175000017500000000000014562742415022104 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/25 config subdir/src/meson.build0000644000175000017500000000013114516512250024230 0ustar00jpakkanejpakkaneexe = executable('prog', 'prog.c', include_directories : inc) test('subdir config', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/25 config subdir/src/prog.c0000644000175000017500000000010114516512250023176 0ustar00jpakkanejpakkane#include "config.h" int main(void) { return RETURN_VALUE; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8626564 meson-1.3.2/test cases/common/250 system include dir/0000755000175000017500000000000014562742415022346 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8626564 meson-1.3.2/test cases/common/250 system include dir/lib/0000755000175000017500000000000014562742415023114 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/250 system include dir/lib/lib.hpp0000644000175000017500000000015614516512250024364 0ustar00jpakkanejpakkane#pragma once // This will trigger -Wsign-conversion inline unsigned convert_to_unsigned(int i) { return i; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/250 system include dir/main.cpp0000644000175000017500000000005514516512250023765 0ustar00jpakkanejpakkane#include int main() { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421662.0 meson-1.3.2/test cases/common/250 system include dir/meson.build0000644000175000017500000000112414516755636024516 0ustar00jpakkanejpakkaneproject('system_include_dir', 'cpp', version : '0.1', default_options : 'werror=true', ) compiler_id = meson.get_compiler('cpp').get_id() if not ['gcc', 'clang', 'clang-cl'].contains(compiler_id) error('MESON_SKIP_TEST: compiler @0@ either doesn\'t support is_system includes or needs to have support for this test added'.format(compiler_id)) endif lib_include_directories = include_directories('lib', is_system: true) add_project_arguments('-Wsign-conversion', language: 'cpp') executable('system_include_dir_test', sources: 'main.cpp', include_directories: lib_include_directories) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8626564 meson-1.3.2/test cases/common/251 add_project_dependencies/0000755000175000017500000000000014562742415023644 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8626564 meson-1.3.2/test cases/common/251 add_project_dependencies/inc/0000755000175000017500000000000014562742415024415 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/251 add_project_dependencies/inc/lib.h0000644000175000017500000000004214516512250025317 0ustar00jpakkanejpakkane#pragma once extern int ok(void); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/251 add_project_dependencies/lib.c0000644000175000017500000000034514516512250024547 0ustar00jpakkanejpakkane#include #include #ifndef DEFINED #error expected compile_arg not found #endif double zero; int ok(void) { void * something = deflate; if(something != 0) return 0; return (int)cos(zero); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/251 add_project_dependencies/main.c0000644000175000017500000000006614516512250024725 0ustar00jpakkanejpakkane#include "lib.h" int main(void) { return ok(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421662.0 meson-1.3.2/test cases/common/251 add_project_dependencies/meson.build0000644000175000017500000000135614516755636026023 0ustar00jpakkanejpakkaneproject('zlib system dependency', 'c') cc = meson.get_compiler('c') m = cc.find_library('m', required: false) add_project_dependencies(m, language: ['c']) z = dependency('zlib', method: 'system', required: false) if not z.found() error('MESON_SKIP_TEST zlib not present') endif z_c_args = z.partial_dependency(compile_args: true, includes: true) add_project_dependencies(z_c_args, language: 'c', native: false) global_dep = declare_dependency(include_directories: include_directories('inc'), compile_args: '-DDEFINED') add_project_dependencies(global_dep, language: 'c', native: false) lib = static_library('rary', 'lib.c') exe = executable('prog', 'main.c', link_with: lib, dependencies: z) test('test', exe) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8666565 meson-1.3.2/test cases/common/252 install data structured/0000755000175000017500000000000014562742415023406 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8666565 meson-1.3.2/test cases/common/252 install data structured/dir1/0000755000175000017500000000000014562742415024245 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/252 install data structured/dir1/bad0000644000175000017500000000000014516512250024673 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/252 install data structured/dir1/file10000644000175000017500000000000014516512250025145 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/252 install data structured/dir1/file20000644000175000017500000000000014516512250025146 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/252 install data structured/dir1/file30000644000175000017500000000000014516512250025147 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8666565 meson-1.3.2/test cases/common/252 install data structured/dir2/0000755000175000017500000000000014562742415024246 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/252 install data structured/dir2/bad0000644000175000017500000000000014516512250024674 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/252 install data structured/dir2/file10000644000175000017500000000000014516512250025146 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/252 install data structured/dir2/file20000644000175000017500000000000014516512250025147 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/252 install data structured/dir2/file30000644000175000017500000000000014516512250025150 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8666565 meson-1.3.2/test cases/common/252 install data structured/dir3/0000755000175000017500000000000014562742415024247 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/252 install data structured/dir3/bad0000644000175000017500000000000014516512250024675 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/252 install data structured/dir3/file10000644000175000017500000000000014516512250025147 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/252 install data structured/dir3/file20000644000175000017500000000000014516512250025150 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/252 install data structured/dir3/file30000644000175000017500000000000014516512250025151 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421662.0 meson-1.3.2/test cases/common/252 install data structured/meson.build0000644000175000017500000000052314516755636025560 0ustar00jpakkanejpakkaneproject('install structured data', default_options: ['python.bytecompile=-1']) install_data( 'dir1/file1', 'dir1/file2', 'dir1/file3', 'dir2/file1', 'dir2/file2', 'dir2/file3', 'dir3/file1', 'dir3/file2', 'dir3/file3', install_dir: get_option('datadir'), preserve_path: true, ) subdir('pysrc') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8666565 meson-1.3.2/test cases/common/252 install data structured/pysrc/0000755000175000017500000000000014562742415024546 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/252 install data structured/pysrc/__init__.py0000644000175000017500000000002314516512250026641 0ustar00jpakkanejpakkane'''init for mod''' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/252 install data structured/pysrc/bad.py0000644000175000017500000000004614516512250025635 0ustar00jpakkanejpakkane'''mod.bad should not be installed''' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/252 install data structured/pysrc/bar.py0000644000175000017500000000002514516512250025650 0ustar00jpakkanejpakkane'''mod.bar module''' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/252 install data structured/pysrc/foo.py0000644000175000017500000000002514516512250025667 0ustar00jpakkanejpakkane'''mod.foo module''' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/252 install data structured/pysrc/meson.build0000644000175000017500000000032514516512250026677 0ustar00jpakkanejpakkanepy_inst = import('python').find_installation() py_inst.install_sources( '__init__.py', 'foo.py', 'bar.py', 'submod/__init__.py', 'submod/baz.py', subdir: 'mod', preserve_path: true, ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8666565 meson-1.3.2/test cases/common/252 install data structured/pysrc/submod/0000755000175000017500000000000014562742415026037 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/252 install data structured/pysrc/submod/__init__.py0000644000175000017500000000002614516512250030135 0ustar00jpakkanejpakkane'''init for submod''' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/252 install data structured/pysrc/submod/bad.py0000644000175000017500000000005514516512250027126 0ustar00jpakkanejpakkane'''mod.submod.bad should not be installed''' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/252 install data structured/pysrc/submod/baz.py0000644000175000017500000000003414516512250027151 0ustar00jpakkanejpakkane'''mod.submod.baz module''' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/252 install data structured/test.json0000644000175000017500000000157614516515714025270 0ustar00jpakkanejpakkane{ "installed": [ {"type": "python_file", "file": "usr/@PYTHON_PURELIB@/mod/__init__.py"}, {"type": "python_file", "file": "usr/@PYTHON_PURELIB@/mod/foo.py"}, {"type": "python_file", "file": "usr/@PYTHON_PURELIB@/mod/bar.py"}, {"type": "python_file", "file": "usr/@PYTHON_PURELIB@/mod/submod/__init__.py"}, {"type": "python_file", "file": "usr/@PYTHON_PURELIB@/mod/submod/baz.py"}, {"type": "file", "file": "usr/share/dir1/file1"}, {"type": "file", "file": "usr/share/dir1/file2"}, {"type": "file", "file": "usr/share/dir1/file3"}, {"type": "file", "file": "usr/share/dir2/file1"}, {"type": "file", "file": "usr/share/dir2/file2"}, {"type": "file", "file": "usr/share/dir2/file3"}, {"type": "file", "file": "usr/share/dir3/file1"}, {"type": "file", "file": "usr/share/dir3/file2"}, {"type": "file", "file": "usr/share/dir3/file3"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8666565 meson-1.3.2/test cases/common/253 subproject dependency variables/0000755000175000017500000000000014562742415025072 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421663.0 meson-1.3.2/test cases/common/253 subproject dependency variables/meson.build0000644000175000017500000000056214516755637027250 0ustar00jpakkanejpakkaneproject('subproject dependency variables', 'c') subfiles_dep = subproject('subfiles').get_variable('files_dep') executable( 'foo', join_paths(subfiles_dep.get_variable('pkgdatadir'), 'foo.c') ) executable( 'foo2', subfiles_dep.get_variable('pkgdatadir2') / 'foo.c' ) executable( 'foor32', subfiles_dep.get_variable('pkgdatadir3') / 'foo.c' ) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853066.910627 meson-1.3.2/test cases/common/253 subproject dependency variables/subprojects/0000755000175000017500000000000014562742413027433 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8666565 meson-1.3.2/test cases/common/253 subproject dependency variables/subprojects/subfiles/0000755000175000017500000000000014562742415031251 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/253 subproject dependency variables/subprojects/subfiles/foo.c0000644000175000017500000000003514516512250032165 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/253 subproject dependency variables/subprojects/subfiles/meson.build0000644000175000017500000000174214516512250033406 0ustar00jpakkanejpakkaneproject('dependency variable resource') files_dep = declare_dependency( variables: [ 'pkgdatadir=@0@/subdir'.format(meson.current_source_dir()), 'pkgdatadir2=@0@/subdir2'.format(meson.current_source_dir()), 'pkgdatadir3=@0@'.format(meson.current_source_dir()), ] ) install_data('subdir/foo.c', install_dir: get_option('datadir') / 'subdir') install_subdir('subdir2', install_dir: get_option('datadir')) install_data('foo.c', install_dir: get_option('datadir')) import('pkgconfig').generate( name: 'depvar_resource', description: 'Get a resource file from pkgconfig or a subproject', version: '0.1', variables: [ 'pkgdatadir=${datadir}/subdir', 'pkgdatadir2=${datadir}/subdir2', ], uninstalled_variables: [ 'pkgdatadir=@0@/subdir'.format(meson.current_source_dir()), 'pkgdatadir2=@0@/subdir2'.format(meson.current_source_dir()), 'pkgdatadir3=@0@'.format(meson.current_source_dir()), ], dataonly: true, ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8746567 meson-1.3.2/test cases/common/253 subproject dependency variables/subprojects/subfiles/subdir/0000755000175000017500000000000014562742415032541 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/253 subproject dependency variables/subprojects/subfiles/subdir/foo.c0000644000175000017500000000003514516512250033455 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8746567 meson-1.3.2/test cases/common/253 subproject dependency variables/subprojects/subfiles/subdir2/0000755000175000017500000000000014562742415032623 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/253 subproject dependency variables/subprojects/subfiles/subdir2/foo.c0000644000175000017500000000003514516512250033537 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/253 subproject dependency variables/test.json0000644000175000017500000000041614516515714026744 0ustar00jpakkanejpakkane{ "installed": [ { "type": "file", "file": "usr/share/pkgconfig/depvar_resource.pc" }, { "type": "file", "file": "usr/share/foo.c" }, { "type": "file", "file": "usr/share/subdir/foo.c" }, { "type": "file", "file": "usr/share/subdir2/foo.c" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8746567 meson-1.3.2/test cases/common/254 long output/0000755000175000017500000000000014562742415021143 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/254 long output/dumper.c0000644000175000017500000000053414516512250022574 0ustar00jpakkanejpakkane#include int main(void) { for (int i = 0 ; i < 100000 ; i++) fprintf(stderr, "# Iteration %d to stderr\n", i + 1); printf("ok 1 - dumper to stderr\n"); for (int i = 0 ; i < 100000 ; i++) fprintf(stdout, "# Iteration %d to stdout\n", i + 1); printf("ok 2 - dumper to stdout\n1..2\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421663.0 meson-1.3.2/test cases/common/254 long output/meson.build0000644000175000017500000000025314516755637023316 0ustar00jpakkanejpakkaneproject('long-stderr', 'c') dumper = executable('dumper', 'dumper.c') test('dump-test', dumper, timeout: 60) test('dump-test-TAP', dumper, protocol : 'tap', timeout: 60) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8746567 meson-1.3.2/test cases/common/255 module warnings/0000755000175000017500000000000014562742415021762 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421663.0 meson-1.3.2/test cases/common/255 module warnings/meson.build0000644000175000017500000000071014516755637024133 0ustar00jpakkanejpakkaneproject('module warnings', meson_version : '>= 0.56') import('python3') # deprecated module import('java') # new module import('unstable-keyval') # module that has been stabilized, import with unstable- import('unstable_simd') # A module with the deprecated `unstable_foo` instead of `unstable-foo` ice = import('icestorm', required : false) assert(not ice.found(), 'unstable-icestorm module should not be importable as `simd`') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/255 module warnings/test.json0000644000175000017500000000142014516515714023630 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/common/255 module warnings/meson.build:3: WARNING: Project targets '>= 0.56' but uses feature deprecated since '0.48.0': module python3." }, { "line": "test cases/common/255 module warnings/meson.build:4: WARNING: Project targets '>= 0.56' but uses feature introduced in '0.60.0': module java." }, { "line": "test cases/common/255 module warnings/meson.build:5: WARNING: Project targets '>= 0.56' but uses feature deprecated since '0.56.0': module keyval has been stabilized. drop \"unstable-\" prefix from the module name" }, { "line": "test cases/common/255 module warnings/meson.build:6: DEPRECATION: Importing unstable modules as \"unstable_simd\" instead of \"unstable-simd\"" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8746567 meson-1.3.2/test cases/common/256 subproject extracted objects/0000755000175000017500000000000014562742415024423 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/256 subproject extracted objects/foo.c0000644000175000017500000000031214516512250025335 0ustar00jpakkanejpakkane#if defined _WIN32 || defined __CYGWIN__ #define DLL_IMPORT __declspec(dllimport) #else #define DLL_IMPORT #endif int DLL_IMPORT cppfunc(void); int otherfunc(void) { return cppfunc() != 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421664.0 meson-1.3.2/test cases/common/256 subproject extracted objects/meson.build0000644000175000017500000000025714516755640026574 0ustar00jpakkanejpakkaneproject('link to extracted objects', 'c') sublib = subproject('myobjects').get_variable('sublib') mainlib = static_library('foo', 'foo.c', install: true, link_with: sublib) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.9146268 meson-1.3.2/test cases/common/256 subproject extracted objects/subprojects/0000755000175000017500000000000014562742413026764 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8786566 meson-1.3.2/test cases/common/256 subproject extracted objects/subprojects/myobjects/0000755000175000017500000000000014562742415030765 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/256 subproject extracted objects/subprojects/myobjects/cpplib.cpp0000644000175000017500000000014514516512250032731 0ustar00jpakkanejpakkane#define BUILDING_DLL #include "cpplib.h" extern "C" int DLL_PUBLIC cppfunc(void) { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/256 subproject extracted objects/subprojects/myobjects/cpplib.h0000644000175000017500000000060014516512250032372 0ustar00jpakkanejpakkane/* See http://gcc.gnu.org/wiki/Visibility#How_to_use_the_new_C.2B-.2B-_visibility_support */ #if defined(_WIN32) || defined(__CYGWIN__) #ifdef BUILDING_DLL #define DLL_PUBLIC __declspec(dllexport) #else #define DLL_PUBLIC __declspec(dllimport) #endif #else #define DLL_PUBLIC __attribute__ ((visibility ("default"))) #endif extern "C" int DLL_PUBLIC cppfunc(void); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/256 subproject extracted objects/subprojects/myobjects/meson.build0000644000175000017500000000011514516512250033113 0ustar00jpakkanejpakkaneproject('myobjects', 'cpp') sublib = static_library('sublib', 'cpplib.cpp') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/256 subproject extracted objects/test.json0000644000175000017500000000011514516515714026271 0ustar00jpakkanejpakkane{ "installed": [ { "type": "file", "file": "usr/lib/libfoo.a" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8786566 meson-1.3.2/test cases/common/257 generated header dep/0000755000175000017500000000000014562742415022566 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/257 generated header dep/foo.c0000644000175000017500000000002114516512250023475 0ustar00jpakkanejpakkane#include "foo.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421664.0 meson-1.3.2/test cases/common/257 generated header dep/meson.build0000644000175000017500000000140014516755640024726 0ustar00jpakkanejpakkaneproject('generated header dep', 'c') # Regression test case for a very specific case: # - Uses both_libraries(), or library() with default_library=both. # - A header file is generated by a custom_target() and passed as source. # - A C file that uses that header is passed as a declare_dependency() source. # Under those specific conditions, the static library used to miss an order # dependency on the header file. This happened in GLib: # https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2917. python = find_program('python3') header = custom_target( output: 'foo.h', capture: true, command: [python, '-c', 'print("#define FOO")'], ) sources_dep = declare_dependency(sources: files('foo.c')) both_libraries('foo', header, dependencies: sources_dep, ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8786566 meson-1.3.2/test cases/common/258 subsubproject inplace/0000755000175000017500000000000014562742415023155 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421664.0 meson-1.3.2/test cases/common/258 subsubproject inplace/meson.build0000644000175000017500000000004314516755640025317 0ustar00jpakkanejpakkaneproject('main') subproject('sub') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.9146268 meson-1.3.2/test cases/common/258 subsubproject inplace/subprojects/0000755000175000017500000000000014562742413025516 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8786566 meson-1.3.2/test cases/common/258 subsubproject inplace/subprojects/sub/0000755000175000017500000000000014562742415026311 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/258 subsubproject inplace/subprojects/sub/meson.build0000644000175000017500000000004514516512250030441 0ustar00jpakkanejpakkaneproject('sub') subproject('subsub') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8786566 meson-1.3.2/test cases/common/258 subsubproject inplace/subprojects/sub/subprojects/0000755000175000017500000000000014562742415030654 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8786566 meson-1.3.2/test cases/common/258 subsubproject inplace/subprojects/sub/subprojects/subsub-1.0/0000755000175000017500000000000014562742415032453 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000021200000000000010210 xustar00116 path=meson-1.3.2/test cases/common/258 subsubproject inplace/subprojects/sub/subprojects/subsub-1.0/meson.build 22 mtime=1698337960.0 meson-1.3.2/test cases/common/258 subsubproject inplace/subprojects/sub/subprojects/subsub-1.0/meson0000644000175000017500000000002214516512250033500 0ustar00jpakkanejpakkaneproject('subsub') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/258 subsubproject inplace/subprojects/sub/subprojects/subsub.wrap0000644000175000017500000000004314516512250033036 0ustar00jpakkanejpakkane[wrap-file] directory = subsub-1.0 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8826568 meson-1.3.2/test cases/common/259 preprocess/0000755000175000017500000000000014562742415021055 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0 meson-1.3.2/test cases/common/259 preprocess/bar.c0000644000175000017500000000006114562742373021765 0ustar00jpakkanejpakkaneint @BAR@(void) { return BAR + PLOP + BAZ; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/259 preprocess/foo.c0000644000175000017500000000002114516512250021764 0ustar00jpakkanejpakkane#include ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/test cases/common/259 preprocess/foo.h0000644000175000017500000000006614562742363022015 0ustar00jpakkanejpakkaneint bar(void); int main(void) { return FOO + bar(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/259 preprocess/math.c0000644000175000017500000000023114516512250022135 0ustar00jpakkanejpakkane// Verify we preprocess as C language, otherwise including math.h would fail. // See https://github.com/mesonbuild/meson/issues/11940. #include ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853051.0 meson-1.3.2/test cases/common/259 preprocess/meson.build0000644000175000017500000000124714562742373023226 0ustar00jpakkanejpakkaneproject('preprocess', 'c') cc = meson.get_compiler('c') add_project_arguments(['-DFOO=0', '-DBAR=0'], language: 'c') fs = import('fs') bar_content = fs.read('bar.c') bar_x = custom_target( input: 'bar.c', output: 'bar.x', command: ['python3', '-c', '''import sys;print(sys.argv[1].replace('@BAR@', 'bar'))''', bar_content], capture: true, ) dep = declare_dependency(compile_args: '-DPLOP=0') pp_files = cc.preprocess('foo.c', bar_x, 'math.c', output: '@PLAINNAME@.c', dependencies: dep, compile_args: ['-DBAZ=0'], ) foreach f : pp_files message(f.full_path()) endforeach subdir('src') test('test-foo', executable('app', pp_files, link_depends: file_map)) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8826568 meson-1.3.2/test cases/common/259 preprocess/src/0000755000175000017500000000000014562742415021644 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/259 preprocess/src/file.map.in0000644000175000017500000000003114516512250023650 0ustar00jpakkanejpakkane#if 1 Hello World #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/259 preprocess/src/meson.build0000644000175000017500000000010214516512250023766 0ustar00jpakkanejpakkanefile_map = cc.preprocess('file.map.in', output: '@BASENAME@', ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8826568 meson-1.3.2/test cases/common/26 find program/0000755000175000017500000000000014562742415021150 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421464.0 meson-1.3.2/test cases/common/26 find program/meson.build0000644000175000017500000000254014516755330023312 0ustar00jpakkanejpakkaneproject('find program') if build_machine.system() == 'windows' # Things Windows does not provide: # - an executable to copy files without prompting # - working command line quoting # - anything that you might actually need # Because of these reasons we only check that # the program can be found. cp = find_program('xcopy') else cp = find_program('donotfindme', 'cp') gen = generator(cp, \ output : '@BASENAME@.c', \ arguments : ['@INPUT@', '@OUTPUT@']) generated = gen.process('source.in') add_languages('c', required: true) e = executable('prog', generated) test('external exe', e) endif prog = find_program('print-version.py', version : '>=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.py') assert(prog.version() == '1.0', 'Program version should be detectable') 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 : ['/nonexistent', meson.current_source_dir() / 'scripts']) assert(prog.found(), 'Program should be found') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/26 find program/print-version-with-prefix.py0000644000175000017500000000017414516512250026576 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys if len(sys.argv) != 2 or sys.argv[1] != '--version': exit(1) print('Version: 1.0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/26 find program/print-version.py0000644000175000017500000000016314516512250024330 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys if len(sys.argv) != 2 or sys.argv[1] != '--version': exit(1) print('1.0') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8826568 meson-1.3.2/test cases/common/26 find program/scripts/0000755000175000017500000000000014562742415022637 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/26 find program/scripts/test_subdir.py0000644000175000017500000000004014516512250025521 0ustar00jpakkanejpakkane#!/usr/bin/env python3 exit(0) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/26 find program/source.in0000644000175000017500000000003714516512250022767 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8826568 meson-1.3.2/test cases/common/260 declare_dependency objects/0000755000175000017500000000000014562742415024067 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/260 declare_dependency objects/bar.c0000644000175000017500000000002214516512250024760 0ustar00jpakkanejpakkanevoid bar(void) {} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/260 declare_dependency objects/foo.c0000644000175000017500000000006214516512250025003 0ustar00jpakkanejpakkaneextern void bar(void); void foo(void) { bar(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421665.0 meson-1.3.2/test cases/common/260 declare_dependency objects/meson.build0000644000175000017500000000223714516755641026241 0ustar00jpakkanejpakkane# Test that declare_dependency(objects: ...) fixes issues with duplicated # objects in the final link line, thanks to deduplication of dependencies. # The commented declare_dependency() invocation using link_whole instead # fails thusly: # # ar csrDT libbar.a libfoo.a.p/foo.c.o libbar.a.p/bar.c.o # ar csrDT libfoo.a libfoo.a.p/foo.c.o # cc -o prog prog.p/prog.c.o -Wl,--as-needed -Wl,--no-undefined -Wl,--whole-archive -Wl,--start-group libfoo.a libbar.a -Wl,--end-group -Wl,--no-whole-archive # /usr/bin/ld: libfoo.a.p/foo.c.o: in function `foo': # ../foo.c:3: multiple definition of `foo'; libfoo.a.p/foo.c.o:../foo.c:3: first defined here project('Transitive declare_dependency(objects)', 'c') libfoo = static_library('foo', 'foo.c') #foo = declare_dependency(link_whole: libfoo) foo = declare_dependency(objects: libfoo.extract_all_objects(recursive: true)) libbar = static_library('bar', 'bar.c', dependencies: foo) #bar = declare_dependency(link_whole: libbar, dependencies: foo) bar = declare_dependency(objects: libbar.extract_all_objects(recursive: true), dependencies: foo) executable('prog', sources: files('prog.c'), dependencies: [foo, bar]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/260 declare_dependency objects/prog.c0000644000175000017500000000006214516512250025167 0ustar00jpakkanejpakkaneextern void foo(void); int main(void) { foo(); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8826568 meson-1.3.2/test cases/common/261 testcase clause/0000755000175000017500000000000014562742415021731 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421665.0 meson-1.3.2/test cases/common/261 testcase clause/meson.build0000644000175000017500000000204314516755641024076 0ustar00jpakkanejpakkaneproject('testcase clause') # To make sure unreachable code is not executed. unreachable = true # Verify assertion exception gets catched and dropped. testcase expect_error('Assert failed: false') assert(false) unreachable = false endtestcase assert(unreachable) # The inner testcase raises an exception because it did not receive the expected # error message. The outer testcase catches the inner testcase exception and # drop it. testcase expect_error('Expecting error \'something\' but got \'Assert failed: false\'') testcase expect_error('something') assert(false) unreachable = false endtestcase unreachable = false endtestcase assert(unreachable) # The inner testcase raises an exception because it did not receive an # exception. The outer testcase catches the inner testcase exception and # drop it. testcase expect_error('Expecting an error but code block succeeded') testcase expect_error('something') reached = true endtestcase unreachable = false endtestcase assert(reached) assert(unreachable) message('all good') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339788.0 meson-1.3.2/test cases/common/261 testcase clause/test.json0000644000175000017500000000014414516515714023601 0ustar00jpakkanejpakkane{ "stdout": [ { "line": ".*all good", "match": "re", "count": 1 } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8866568 meson-1.3.2/test cases/common/262 generator chain/0000755000175000017500000000000014562742415021713 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/262 generator chain/data.txt0000644000175000017500000000000714516512250023351 0ustar00jpakkanejpakkanestage1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421666.0 meson-1.3.2/test cases/common/262 generator chain/meson.build0000644000175000017500000000066414516755642024070 0ustar00jpakkanejpakkaneproject('Generator Chain', 'c') stage1_exe = find_program('stage1.py') stage2_exe = find_program('stage2.py') stage1_gen = generator(stage1_exe, output : '@PLAINNAME@.inter', arguments : ['@INPUT@', '@OUTPUT@']) stage2_gen = generator(stage2_exe, output : '@PLAINNAME@.c', arguments : ['@INPUT@', '@OUTPUT@']) out = stage2_gen.process(stage1_gen.process('data.txt')) hello = executable('hello', out) test('basic', hello) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/262 generator chain/stage1.py0000644000175000017500000000023114516512250023434 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys from pathlib import Path assert(Path(sys.argv[1]).read_text() == 'stage1\n') Path(sys.argv[2]).write_text('stage2\n') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/262 generator chain/stage2.py0000644000175000017500000000024314516512250023440 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys from pathlib import Path assert(Path(sys.argv[1]).read_text() == 'stage2\n') Path(sys.argv[2]).write_text('int main(void){}\n') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8866568 meson-1.3.2/test cases/common/263 internal dependency includes in checks/0000755000175000017500000000000014562742415026175 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8866568 meson-1.3.2/test cases/common/263 internal dependency includes in checks/include/0000755000175000017500000000000014562742415027620 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/common/263 internal dependency includes in checks/include/test_262_header.h0000644000175000017500000000001714516552205032642 0ustar00jpakkanejpakkaneint foo(void); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421666.0 meson-1.3.2/test cases/common/263 internal dependency includes in checks/meson.build0000644000175000017500000000032014516755642030337 0ustar00jpakkanejpakkaneproject('test 262', 'c') cc = meson.get_compiler('c') internal_dep = declare_dependency(include_directories: 'include') assert(cc.has_header_symbol('test_262_header.h', 'foo', dependencies: internal_dep)) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.8866568 meson-1.3.2/test cases/common/264 required keyword in has functions/0000755000175000017500000000000014562742415025265 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421666.0 meson-1.3.2/test cases/common/264 required keyword in has functions/meson.build0000644000175000017500000000500514516755642027434 0ustar00jpakkanejpakkaneproject('required keyword in has functions', 'c') cc = meson.get_compiler('c') opt = get_option('opt') cc.has_function('printf', prefix : '#include', required : true) cc.has_type('time_t', prefix : '#include', required : true) cc.has_member('struct tm', 'tm_sec', prefix : '#include', required : true) cc.has_members('struct tm', ['tm_sec', 'tm_min'], prefix : '#include', required : true) cc.has_header('time.h', required : true) cc.has_header_symbol('time.h', 'time', required : true) assert(not cc.has_function('printf', prefix : '#include', required : opt)) assert(not cc.has_type('time_t', prefix : '#include', required : opt)) assert(not cc.has_member('struct tm', 'tm_sec', prefix : '#include', required : opt)) assert(not cc.has_members('struct tm', ['tm_sec', 'tm_min'], prefix : '#include', required : opt)) assert(not cc.has_header('time.h', required : opt)) assert(not cc.has_header_symbol('time.h', 'time', required : opt)) # compiler.has_argument if cc.get_id() == 'msvc' is_arg = '/O2' else is_arg = '-O2' endif cc.has_argument(is_arg, required: true) assert(not cc.has_argument(is_arg, required: opt)) # compiler.has_multi_arguments if cc.get_id() == 'gcc' pre_arg = '-Wformat' arg = '-Werror=format-security' cc.has_multi_arguments([pre_arg, arg], required: true) assert(not cc.has_multi_arguments(pre_arg, arg, required: opt)) endif # compiler.has_link_argument if cc.get_argument_syntax() == 'msvc' is_arg = '/OPT:REF' else is_arg = '-Wl,-L/tmp' endif cc.has_link_argument(is_arg, required: true) assert(not cc.has_link_argument(is_arg, required: opt)) # compiler.has_function_attribute if not ['pgi', 'msvc', 'clang-cl', 'intel-cl'].contains(cc.get_id()) a = 'aligned' cc.has_function_attribute(a, required: true) assert(not cc.has_function_attribute(a, required: opt)) endif testcase expect_error('''compiler.has_function keyword argument 'required' was of type str but should have been one of: bool, UserFeatureOption''') cc.has_function('printf', required : 'not a bool') endtestcase testcase expect_error('''C function 'asdfkawlegsdiovapfjhkr' not usable''') cc.has_function('asdfkawlegsdiovapfjhkr', required : true) endtestcase testcase expect_error('''C header 'asdfkawlegsdiovapfjhkr.h' not found''') cc.has_header('asdfkawlegsdiovapfjhkr.h', required : true) endtestcase testcase expect_error('''C symbol time_not_found not found in header time.h''') cc.has_header_symbol('time.h', 'time_not_found', required : true) endtestcase ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/common/264 required keyword in has functions/meson_options.txt0000644000175000017500000000006214516552205030713 0ustar00jpakkanejpakkaneoption('opt', type: 'feature', value: 'disabled') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.890657 meson-1.3.2/test cases/common/265 default_options dict/0000755000175000017500000000000014562742415022770 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/common/265 default_options dict/lib.c0000644000175000017500000000004514516552205023674 0ustar00jpakkanejpakkane#warning Make sure this is not fatal ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421667.0 meson-1.3.2/test cases/common/265 default_options dict/meson.build0000644000175000017500000000101614516755643025136 0ustar00jpakkanejpakkaneproject('test default options', 'c', default_options: { 'bool': true, 'int': 42, 'str': 'foo', 'array': ['foo'], 'werror': true, }, ) assert(get_option('bool') == true) assert(get_option('int') == 42) assert(get_option('str') == 'foo') assert(get_option('array') == ['foo']) assert(get_option('werror') == true) cc = meson.get_compiler('c') # MSVC does not support #warning if cc.get_id() != 'msvc' static_library('foo', 'lib.c', override_options: {'werror': false}) endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/common/265 default_options dict/meson_options.txt0000644000175000017500000000026214516552205026420 0ustar00jpakkanejpakkaneoption('bool', type: 'boolean', value: false) option('int', type: 'integer', value: 0) option('str', type: 'string', value: 'bar') option('array', type: 'array', value: ['bar']) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.890657 meson-1.3.2/test cases/common/266 format string/0000755000175000017500000000000014562742415021445 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421667.0 meson-1.3.2/test cases/common/266 format string/meson.build0000644000175000017500000000117514516755643023621 0ustar00jpakkanejpakkaneproject('test format string') # Test all supported types in message(), format(), f-string. foreach t : [get_option('opt'), 42, true, false, 'str', ['list'], {'dict': 'value'}] message(t, '@0@'.format(t), f'@t@', [t], {'key': t}) endforeach # Deprecated but should work with str.format(). env = environment() message('@0@'.format(env)) # Should fail with f-string and message() error_msg = 'Value other than strings, integers, bools, options, dictionaries and lists thereof.' testcase expect_error('message(): ' + error_msg) message(env) endtestcase testcase expect_error('f-string: ' + error_msg) message(f'@env@') endtestcase ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/common/266 format string/meson_options.txt0000644000175000017500000000003714516552205025075 0ustar00jpakkanejpakkaneoption('opt', type: 'feature') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/common/266 format string/test.json0000644000175000017500000000135514516552205023316 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "Message: auto auto auto [auto] {'key' : auto}" }, { "line": "Message: 42 42 42 [42] {'key' : 42}" }, { "line": "Message: true true true [true] {'key' : true}" }, { "line": "Message: false false false [false] {'key' : false}" }, { "line": "Message: str str str ['str'] {'key' : 'str'}" }, { "line": "Message: ['list'] ['list'] ['list'] [['list']] {'key' : ['list']}" }, { "line": "Message: {'dict' : 'value'} {'dict' : 'value'} {'dict' : 'value'} [{'dict' : 'value'}] {'key' : {'dict' : 'value'}}" }, { "line": "Message: " } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.890657 meson-1.3.2/test cases/common/267 default_options in find_program/0000755000175000017500000000000014562742415025105 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421667.0 meson-1.3.2/test cases/common/267 default_options in find_program/meson.build0000644000175000017500000000023714516755643027257 0ustar00jpakkanejpakkaneproject('test default_options in find_program') dummy_exe = find_program('dummy', default_options: ['subproject_option=true']) test('test_dummy', dummy_exe) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.890657 meson-1.3.2/test cases/common/267 default_options in find_program/subprojects/0000755000175000017500000000000014562742415027450 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.894657 meson-1.3.2/test cases/common/267 default_options in find_program/subprojects/dummy/0000755000175000017500000000000014562742415030603 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/common/267 default_options in find_program/subprojects/dummy/dummy.c0000644000175000017500000000004014516552205032067 0ustar00jpakkanejpakkaneint main(void) { return 0; }././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/common/267 default_options in find_program/subprojects/dummy/meson.build0000644000175000017500000000024314516552205032737 0ustar00jpakkanejpakkaneproject('dummy', 'c') if get_option('subproject_option') dummy_exe = executable('dummy', 'dummy.c') meson.override_find_program('dummy', dummy_exe) endif ././@PaxHeader0000000000000000000000000000020500000000000010212 xustar00111 path=meson-1.3.2/test cases/common/267 default_options in find_program/subprojects/dummy/meson_options.txt 22 mtime=1698354309.0 meson-1.3.2/test cases/common/267 default_options in find_program/subprojects/dummy/meson_options.tx0000644000175000017500000000007314516552205034047 0ustar00jpakkanejpakkaneoption('subproject_option', type: 'boolean', value: false) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/common/267 default_options in find_program/subprojects/dummy.wrap0000644000175000017500000000007614516552205031474 0ustar00jpakkanejpakkane[wrap-file] directory = dummy [provide] program_names = dummy././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.894657 meson-1.3.2/test cases/common/268 install functions and follow symlinks/0000755000175000017500000000000014562742415026167 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.894657 meson-1.3.2/test cases/common/268 install functions and follow symlinks/foo/0000755000175000017500000000000014562742415026752 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1699814460.0 meson-1.3.2/test cases/common/268 install functions and follow symlinks/foo/file10000644000175000017500000000000514524216074027663 0ustar00jpakkanejpakkanetest ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1699814460.0 meson-1.3.2/test cases/common/268 install functions and follow symlinks/meson.build0000644000175000017500000000122114524216074030320 0ustar00jpakkanejpakkaneproject('install_data following symlinks') install_data( 'foo/link1', install_dir: get_option('datadir') / 'followed', follow_symlinks: true, ) install_headers( 'foo/link2.h', follow_symlinks: true, subdir: 'followed' ) install_data( 'foo/link1', install_dir: get_option('datadir'), follow_symlinks: false, ) install_headers( 'foo/link2.h', follow_symlinks: false, ) install_subdir( 'foo', install_dir: get_option('datadir') / 'subdir', strip_directory: true, follow_symlinks: false, ) install_subdir( 'foo', install_dir: get_option('datadir') / 'subdir_followed', strip_directory: true, follow_symlinks: true, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1699814460.0 meson-1.3.2/test cases/common/268 install functions and follow symlinks/test.json0000644000175000017500000000114514524216074030035 0ustar00jpakkanejpakkane{ "installed": [ {"type": "link", "file": "usr/share/link1"}, {"type": "link", "file": "usr/include/link2.h"}, {"type": "file", "file": "usr/share/followed/link1"}, {"type": "file", "file": "usr/include/followed/link2.h"}, {"type": "link", "file": "usr/share/subdir/link1"}, {"type": "link", "file": "usr/share/subdir/link2.h"}, {"type": "file", "file": "usr/share/subdir/file1"}, {"type": "file", "file": "usr/share/subdir_followed/link1"}, {"type": "file", "file": "usr/share/subdir_followed/link2.h"}, {"type": "file", "file": "usr/share/subdir_followed/file1"} ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.894657 meson-1.3.2/test cases/common/269 configure file output format/0000755000175000017500000000000014562742415024344 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/269 configure file output format/compare.py0000644000175000017500000000026714516512250026340 0ustar00jpakkanejpakkaneimport sys with open(sys.argv[1], 'r', encoding='utf-8') as f, open(sys.argv[2], 'r', encoding='utf-8') as g: if f.read() != g.read(): sys.exit('contents are not equal') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.898657 meson-1.3.2/test cases/common/269 configure file output format/expected/0000755000175000017500000000000014562742415026145 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/269 configure file output format/expected/config.h0000644000175000017500000000046114516512250027553 0ustar00jpakkanejpakkane/* * Autogenerated by the Meson build system. * Do not edit, your changes will be lost. */ #pragma once #define bool #undef false /* ultimate question of life, the universe, and everything */ #define int 42 /* This is a multiline description */ #define str "hello world!" #define unquoted float ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/269 configure file output format/expected/config.json0000644000175000017500000000013114516512250030267 0ustar00jpakkanejpakkane{"bool": true, "false": false, "int": 42, "str": "\"hello world!\"", "unquoted": "float"}././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/269 configure file output format/expected/config.mg0000644000175000017500000000054114516512250027726 0ustar00jpakkanejpakkane/* * Autogenerated by the Meson build system. * Do not edit, your changes will be lost. */ #ifndef CONFIG_MAGNESIUM_H #define CONFIG_MAGNESIUM_H #define bool #undef false /* ultimate question of life, the universe, and everything */ #define int 42 /* This is a multiline description */ #define str "hello world!" #define unquoted float #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/269 configure file output format/expected/config.nasm0000644000175000017500000000042614516512250030263 0ustar00jpakkanejpakkane; Autogenerated by the Meson build system. ; Do not edit, your changes will be lost. %define bool %undef false ; ultimate question of life, the universe, and everything %define int 42 ; This is ; a multiline ; description %define str "hello world!" %define unquoted float ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421667.0 meson-1.3.2/test cases/common/269 configure file output format/meson.build0000644000175000017500000000252714516755643026522 0ustar00jpakkanejpakkaneproject('configure file output format') data = configuration_data() data.set_quoted('str', 'hello world!', description: '''This is a multiline description''') data.set('unquoted', 'float') data.set('int', 42, description: 'ultimate question of life, the universe, and everything') data.set('bool', true) data.set('false', false) config_h = configure_file( configuration: data, output_format: 'c', output: 'config.h' ) config_nasm = configure_file( configuration: data, output_format: 'nasm', output: 'config.nasm' ) config_json = configure_file( configuration: data, output_format: 'json', output: 'config.json' ) config_mg = configure_file( configuration: data, macro_name: 'CONFIG_MAGNESIUM_H', output_format: 'c', output: 'config_mg.h' ) py = find_program('python3') compare_py = files('compare.py') expected_config_h = files('expected/config.h') expected_config_nasm = files('expected/config.nasm') expected_config_json = files('expected/config.json') expected_config_mg = files('expected/config.mg') test('c_output', py, args: [compare_py, expected_config_h, config_h]) test('nasm_output', py, args: [compare_py, expected_config_nasm, config_nasm]) test('json_output', py, args: [compare_py, expected_config_json, config_json]) test('c_mg_output', py, args: [compare_py, expected_config_mg, config_mg]) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.898657 meson-1.3.2/test cases/common/27 multiline string/0000755000175000017500000000000014562742415022072 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421464.0 meson-1.3.2/test cases/common/27 multiline string/meson.build0000644000175000017500000000107114516755330024232 0ustar00jpakkanejpakkaneproject('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 = ''' #include int main(void) { int num = 1; printf("%d\n", num); return 0; }''' assert(cc.compiles(prog), 'multiline test compile failed') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.898657 meson-1.3.2/test cases/common/270 int_to_str_fill/0000755000175000017500000000000014562742415022053 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421668.0 meson-1.3.2/test cases/common/270 int_to_str_fill/meson.build0000644000175000017500000000030314516755644024220 0ustar00jpakkanejpakkaneproject('test_fill_in_int_to_string') n = 4 assert(n.to_string() == '4') assert(n.to_string(fill: 3) == '004') assert(n.to_string(fill: -3) == '4') n = -4 assert(n.to_string(fill: 3) == '-04') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.898657 meson-1.3.2/test cases/common/271 env in generator.process/0000755000175000017500000000000014562742415023465 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/common/271 env in generator.process/generate_main.py0000644000175000017500000000043614516552205026633 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import os import sys ENV_VAR_VALUE = os.environ.get('ENV_VAR_VALUE') assert ENV_VAR_VALUE is not None with open(sys.argv[1], 'r') as infile, \ open(sys.argv[2], 'w') as outfile: outfile.write(infile.read().replace('ENV_VAR_VALUE', ENV_VAR_VALUE)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/common/271 env in generator.process/main.template0000644000175000017500000000005414516552205026140 0ustar00jpakkanejpakkaneint main(void) { return ENV_VAR_VALUE; }././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421668.0 meson-1.3.2/test cases/common/271 env in generator.process/meson.build0000644000175000017500000000116714516755644025643 0ustar00jpakkanejpakkaneproject('test_env_in_generator_process', 'c') generate_main_py = find_program('generate_main.py') main_generator = generator(generate_main_py, arguments: ['@INPUT@', '@OUTPUT@'], output: '@BASENAME@' + '.c' ) main_template = files('main.template') # With explicit values my_executable = executable('myexecutable', main_generator.process(main_template, env: {'ENV_VAR_VALUE': '0'})) test('explicit_value', my_executable) # With env object env = environment() env.set('ENV_VAR_VALUE', '0') my_executable2 = executable('myexecutable2', main_generator.process(main_template, env: env)) test('env_object', my_executable2) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.898657 meson-1.3.2/test cases/common/272 unity/0000755000175000017500000000000014562742415020033 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1700415808.0 meson-1.3.2/test cases/common/272 unity/meson.build0000644000175000017500000000065714526444500022177 0ustar00jpakkanejpakkaneproject('unity', 'c', default_options : [ 'unity_size=2']) if get_option('unity') != 'on' error('MESON_SKIP_TEST: unity builds not enabled') endif slib_notinstalled = static_library('slib_notinstalled', # test depends on the number of files being divisible by unity_size ['slib1.c', 'slib2.c']) slib_installed = static_library('slib_installed', ['slib1.c', 'slib2.c'], link_with : slib_notinstalled, install : true) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1700415808.0 meson-1.3.2/test cases/common/272 unity/slib.c0000644000175000017500000000013714526444500021123 0ustar00jpakkanejpakkaneint func1(void); int func2(void); int static_lib_func(void) { return func1() + func2(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1700415808.0 meson-1.3.2/test cases/common/272 unity/slib1.c0000644000175000017500000000004214526444500021177 0ustar00jpakkanejpakkaneint func1(void) { return 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1700415808.0 meson-1.3.2/test cases/common/272 unity/slib2.c0000644000175000017500000000004214526444500021200 0ustar00jpakkanejpakkaneint func2(void) { return 2; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1700415808.0 meson-1.3.2/test cases/common/272 unity/test.json0000644000175000017500000000012514526444500021675 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/lib/libslib_installed.a"} ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.906657 meson-1.3.2/test cases/common/28 try compile/0000755000175000017500000000000014562742415021031 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/28 try compile/foo.h.in0000644000175000017500000000000014516512250022347 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/28 try compile/invalid.c0000644000175000017500000000011214516512250022604 0ustar00jpakkanejpakkane#include void func(void) { printf("This won't work.\n"); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421468.0 meson-1.3.2/test cases/common/28 try compile/meson.build0000644000175000017500000000441114516755334023176 0ustar00jpakkanejpakkaneproject('try compile', 'c', 'cpp') code = '''#include void func(void) { printf("Something.\n"); } ''' breakcode = '''#include void func(void) { printf("This won't work.\n"); } ''' warncode = '''#warning This is a warning int main(void) { return 0; } ''' configure_file( input: 'foo.h.in', output: 'foo.h', configuration: {}, ) header_code = '#include "foo.h"' foreach lang : ['c', 'cpp'] compiler = meson.get_compiler(lang) assert(not compiler.compiles(header_code, name: 'Should not include . by default')) assert(compiler.compiles(header_code, name: 'Should include builddir', include_directories: include_directories('.'), )) if compiler.compiles(code, name : 'code should succeed') == false error('Compiler ' + compiler.get_id() + ' is fail.') endif if compiler.compiles(files('valid.c'), name : 'file should succeed') == false error('Compiler ' + compiler.get_id() + ' is fail.') endif copied = configure_file(input: 'valid.c', output: lang + '-valid-copy.c', copy: true) if compiler.compiles(copied, name : 'built file should succeed') == false error('Compiler ' + compiler.get_id() + ' is fail.') endif if compiler.compiles(breakcode, name : 'code should fail') error('Compiler ' + compiler.get_id() + ' returned true on broken code.') endif if compiler.compiles(files('invalid.c'), name : 'file should fail') error('Compiler ' + compiler.get_id() + ' returned true on broken code.') endif # MSVC does not support #warning instruction if compiler.get_id() != 'msvc' # First check that all tests pass without werror, then check they fail with it. foreach with_werror : [false, true] expect_success = not with_werror assert(compiler.compiles(warncode, name: f'code with warning compiles with werror=@with_werror@', werror: with_werror) == expect_success) assert(compiler.links(warncode, name: f'code with warning links with werror=@with_werror@', werror: with_werror) == expect_success) if meson.can_run_host_binaries() assert((compiler.run(warncode, name: f'code with warning runs with werror=@with_werror@', werror: with_werror).returncode() == 0) == expect_success) endif endforeach endif endforeach ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/28 try compile/valid.c0000644000175000017500000000007614516512250022266 0ustar00jpakkanejpakkane#include void func(void) { printf("Something.\n"); } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.906657 meson-1.3.2/test cases/common/29 compiler id/0000755000175000017500000000000014562742415020772 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421468.0 meson-1.3.2/test cases/common/29 compiler id/meson.build0000644000175000017500000000047214516755334023142 0ustar00jpakkanejpakkaneproject('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()) endforeach././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.906657 meson-1.3.2/test cases/common/3 static/0000755000175000017500000000000014562742415020002 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336264.0 meson-1.3.2/test cases/common/3 static/lib3.c0000644000175000017500000000026514516507010020767 0ustar00jpakkanejpakkaneint func3(const int x) { return x + 1; } #ifndef WORK # error "did not get static only C args" #endif #ifdef BREAK # error "got shared only C args, but shouldn't have" #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/3 static/libfile.c0000644000175000017500000000004413716006331021540 0ustar00jpakkanejpakkaneint libfunc(void) { return 3; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/3 static/libfile2.c0000644000175000017500000000004513716006331021623 0ustar00jpakkanejpakkaneint libfunc2(void) { return 4; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421444.0 meson-1.3.2/test cases/common/3 static/meson.build0000644000175000017500000000127614516755304022152 0ustar00jpakkanejpakkaneproject('static library test', 'c', default_options : ['default_library=static']) lib = static_library('mylib', get_option('source'), link_args : '-THISMUSTNOBEUSED') # Static linker needs to ignore all link args. assert(lib.name() == 'mylib') 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.') if get_option('default_library') == 'static' library('lib2', 'lib3.c', c_static_args : ['-DWORK'], c_shared_args : ['-DBREAK']) endif build_target('lib4', 'lib3.c', c_static_args : ['-DWORK'], target_type : 'static_library') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/3 static/meson_options.txt0000644000175000017500000000013513716006331023424 0ustar00jpakkanejpakkaneoption('source', type : 'combo', choices : ['libfile.c', 'libfile2.c'], value : 'libfile.c') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.906657 meson-1.3.2/test cases/common/30 sizeof/0000755000175000017500000000000014562742415020072 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/30 sizeof/config.h.in0000644000175000017500000000007014516512250022101 0ustar00jpakkanejpakkane#define INTSIZE @INTSIZE@ #define WCHARSIZE @WCHARSIZE@ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421469.0 meson-1.3.2/test cases/common/30 sizeof/meson.build0000644000175000017500000000172614516755335022246 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/30 sizeof/prog.c.in0000644000175000017500000000065614516512250021610 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.906657 meson-1.3.2/test cases/common/31 define10/0000755000175000017500000000000014562742415020167 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/31 define10/config.h.in0000644000175000017500000000004314516512250022176 0ustar00jpakkanejpakkane#mesondefine ONE #mesondefine ZERO ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421469.0 meson-1.3.2/test cases/common/31 define10/meson.build0000644000175000017500000000036614516755335022342 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/31 define10/prog.c0000644000175000017500000000034514516512250021273 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.914657 meson-1.3.2/test cases/common/32 has header/0000755000175000017500000000000014562742415020561 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421473.0 meson-1.3.2/test cases/common/32 has header/meson.build0000644000175000017500000000417014516755341022726 0ustar00jpakkanejpakkaneproject('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 nonexistent header.') endforeach endforeach ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/32 has header/ouagadougou.h0000644000175000017500000000004314516512250023235 0ustar00jpakkanejpakkane#define OMG_THIS_SHOULDNT_BE_FOUND ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.914657 meson-1.3.2/test cases/common/33 run program/0000755000175000017500000000000014562742415021032 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/33 run program/check-env.py0000644000175000017500000000014414516512250023235 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import os assert os.environ['MY_PATH'] == os.pathsep.join(['0', '1', '2']) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/33 run program/get-version.py0000644000175000017500000000004514516512250023634 0ustar00jpakkanejpakkane#!/usr/bin/env python3 print('1.2') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421473.0 meson-1.3.2/test cases/common/33 run program/meson.build0000644000175000017500000000472114516755341023201 0ustar00jpakkanejpakkaneproject('run command', version : run_command('get-version.py', check : true).stdout().strip(), meson_version: '>=0.1.0') if build_machine.system() == 'windows' c = run_command('cmd', '/c', 'echo', 'hello', check: false) else c = run_command('echo', 'hello', check: false) 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', check: false) else cs = run_command('scripts/hello.sh', check: false) 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, check: false) else c = run_command('echo', f, check: false) 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")', check: false) 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")', check: false, 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, check: false) 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', check: false, 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 env = environment() env.append('MY_PATH', '1') env.append('MY_PATH', '2') env.prepend('MY_PATH', '0') run_command('check-env.py', env: env, check: true) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.914657 meson-1.3.2/test cases/common/33 run program/scripts/0000755000175000017500000000000014562742415022521 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/33 run program/scripts/hello.bat0000644000175000017500000000002514516512250024300 0ustar00jpakkanejpakkane@ECHO OFF ECHO hello ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/33 run program/scripts/hello.sh0000755000175000017500000000002614516512250024150 0ustar00jpakkanejpakkane#!/bin/sh echo hello ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339787.0 meson-1.3.2/test cases/common/33 run program/test.json0000644000175000017500000000043414516515713022703 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/common/33 run program/meson.build:1: WARNING: Project targets '>=0.1.0' but uses feature introduced in '0.47.0': check arg in run_command.", "comment": "This triggers on line 1 -- the line with the project() function" } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.914657 meson-1.3.2/test cases/common/34 logic ops/0000755000175000017500000000000014562742415020456 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421473.0 meson-1.3.2/test cases/common/34 logic ops/meson.build0000644000175000017500000000206714516755341022626 0ustar00jpakkanejpakkaneproject('logicopts') 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 ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.914657 meson-1.3.2/test cases/common/35 string operations/0000755000175000017500000000000014562742415022252 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421473.0 meson-1.3.2/test cases/common/35 string operations/meson.build0000644000175000017500000001314414516755341024420 0ustar00jpakkanejpakkaneproject('string formatting') 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[0] == 'a') assert(long[2] == 'c') assert(long.replace('b', 'd') == 'adcde') assert(long.replace('z', 'x') == long) assert(long.replace(prefix, suffix) == 'cdede') 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('@0@'.format(['one', 'two']) == '[\'one\', \'two\']', 'list 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') assert(' '.join(['a'], ['b', ['c']], 'd') == 'a b c d', 'varargs 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') mysubstring='foobarbaz' assert(mysubstring.substring() == 'foobarbaz', 'substring is broken') assert(mysubstring.substring(0) == 'foobarbaz', 'substring is broken') assert(mysubstring.substring(1) == 'oobarbaz', 'substring is broken') assert(mysubstring.substring(-5) == 'arbaz', 'substring is broken') assert(mysubstring.substring(1, 4) == 'oob', 'substring is broken') assert(mysubstring.substring(1,-5) == 'oob', 'substring is broken') assert(mysubstring.substring(1, 0) == '', 'substring is broken') assert(mysubstring.substring(0, 100) == 'foobarbaz', 'substring is broken') assert(mysubstring.substring(-1, -5) == '', 'substring is broken') assert(mysubstring.substring(10, -25) == '', 'substring is broken') assert(mysubstring.substring(-4, 2) == '', 'substring is broken') assert(mysubstring.substring(10, 9) == '', 'substring is broken') assert(mysubstring.substring(8, 10) == 'z', 'substring is broken') # str.splitlines() assert('foo\nbar\nbaz'.splitlines() == ['foo', 'bar', 'baz'], 'splitlines is broken') assert(''.splitlines() == [], 'splitlines with empty string is broken') assert('foo\rbar\nbaz\n'.splitlines() == ['foo', 'bar', 'baz'], 'splitlines trailing newline is broken') assert('hello\r\nworld'.splitlines() == ['hello', 'world']) assert( ' leading ws\nand trailing\t'.splitlines() == [' leading ws', 'and trailing\t'], 'splitlines leading/trailing whitespace is broken', ) assert('\n\r\n\r'.splitlines() == ['', '', ''], 'splitlines is broken') assert('foo'.splitlines() == ['foo'], 'splitlines is broken') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.914657 meson-1.3.2/test cases/common/36 has function/0000755000175000017500000000000014562742415021162 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421484.0 meson-1.3.2/test cases/common/36 has function/meson.build0000644000175000017500000001230614516755354023333 0ustar00jpakkanejpakkaneproject('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 nonexistent function "hfkerhisadf".') endif if cc.has_function('hfkerhisadf', args : unit_test_args) error('Found nonexistent function "hfkerhisadf".') endif # With glibc (before 2.32, see below) 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 the main # alternative Linux C library (musl) doesn't use glibc's stub mechanism; # also, it has implemented lchmod since 2013, so it should be safe to check # that lchmod is available on Linux when not using glibc. 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 ' has_lchmod = cc.has_function('lchmod', prefix : lchmod_prefix, args : unit_test_args) if host_system == 'linux' # __GLIBC__ macro can be retrieved by including almost any C library header glibc_major = cc.get_define('__GLIBC__', prefix: '#include ', args: unit_test_args) # __GLIBC__ will only be set for glibc if glibc_major != '' glibc_minor = cc.get_define('__GLIBC_MINOR__', prefix: '#include ', args: unit_test_args) glibc_vers = '@0@.@1@'.format(glibc_major, glibc_minor) message('GLIBC version:', glibc_vers) # lchmod was implemented in glibc 2.32 (https://sourceware.org/pipermail/libc-announce/2020/000029.html) if glibc_vers.version_compare('<2.32') assert (not has_lchmod, '"lchmod" check should have failed') else assert (has_lchmod, '"lchmod" check should have succeeded') endif else # Other C libraries for Linux should have lchmod assert (has_lchmod, '"lchmod" check should have succeeded') endif else # macOS and *BSD have lchmod assert (has_lchmod, '"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 # We should be able to find GCC and Clang __builtin functions if ['gcc', 'clang'].contains(cc.get_id()) # __builtin_constant_p is documented to exist at least as far back as # GCC 2.95.3 assert(cc.has_function('__builtin_constant_p', args : unit_test_args), '__builtin_constant_p must be found under gcc and clang') endif endforeach ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.914657 meson-1.3.2/test cases/common/37 has member/0000755000175000017500000000000014562742415020605 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421479.0 meson-1.3.2/test cases/common/37 has member/meson.build0000644000175000017500000000140114516755347022752 0ustar00jpakkanejpakkaneproject('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 ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.914657 meson-1.3.2/test cases/common/38 alignment/0000755000175000017500000000000014562742415020561 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421479.0 meson-1.3.2/test cases/common/38 alignment/meson.build0000644000175000017500000000154414516755347022736 0ustar00jpakkanejpakkaneproject('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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9186573 meson-1.3.2/test cases/common/39 library chain/0000755000175000017500000000000014562742415021313 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/39 library chain/main.c0000644000175000017500000000007114516512250022370 0ustar00jpakkanejpakkaneint libfun(void); int main(void) { return libfun(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421479.0 meson-1.3.2/test cases/common/39 library chain/meson.build0000644000175000017500000000017514516755347023467 0ustar00jpakkanejpakkaneproject('libchain', 'c') subdir('subdir') e = executable('prog', 'main.c', link_with : lib1, install : true) test('tst', e) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9186573 meson-1.3.2/test cases/common/39 library chain/subdir/0000755000175000017500000000000014562742415022603 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/39 library chain/subdir/lib1.c0000644000175000017500000000061414516512250023566 0ustar00jpakkanejpakkaneint 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(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/39 library chain/subdir/meson.build0000644000175000017500000000017014516512250024732 0ustar00jpakkanejpakkanesubdir('subdir2') subdir('subdir3') lib1 = shared_library('lib1', 'lib1.c', install : false, link_with : [lib2, lib3]) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9186573 meson-1.3.2/test cases/common/39 library chain/subdir/subdir2/0000755000175000017500000000000014562742415024155 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/39 library chain/subdir/subdir2/lib2.c0000644000175000017500000000052214516512250025137 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/39 library chain/subdir/subdir2/meson.build0000644000175000017500000000007114516512250026304 0ustar00jpakkanejpakkanelib2 = shared_library('lib2', 'lib2.c', install : false) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9186573 meson-1.3.2/test cases/common/39 library chain/subdir/subdir3/0000755000175000017500000000000014562742415024156 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/39 library chain/subdir/subdir3/lib3.c0000644000175000017500000000052314516512250025142 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/39 library chain/subdir/subdir3/meson.build0000644000175000017500000000007114516512250026305 0ustar00jpakkanejpakkanelib3 = shared_library('lib3', 'lib3.c', install : false) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339787.0 meson-1.3.2/test cases/common/39 library chain/test.json0000644000175000017500000000016214516515713023162 0ustar00jpakkanejpakkane{ "installed": [ {"type": "exe", "file": "usr/bin/prog"}, {"type": "pdb", "file": "usr/bin/prog"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9266574 meson-1.3.2/test cases/common/4 shared/0000755000175000017500000000000014562742415017762 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/4 shared/libfile.c0000644000175000017500000000052413716006331021523 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698336264.0 meson-1.3.2/test cases/common/4 shared/libfile2.c0000644000175000017500000000073714516507010021612 0ustar00jpakkanejpakkane#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 #ifndef WORK # error "Did not get shared only arguments" #endif #ifdef BREAK # error "got static only C args, but shouldn't have" #endif int DLL_PUBLIC libfunc(void) { return 3; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421444.0 meson-1.3.2/test cases/common/4 shared/meson.build0000644000175000017500000000122314516755304022122 0ustar00jpakkanejpakkaneproject('shared library test', 'c', default_options : ['default_library=shared']) 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.') if get_option('default_library') == 'shared' library('mylib5', 'libfile2.c', c_shared_args : ['-DWORK']) endif build_target('mylib4', 'libfile2.c', target_type: 'shared_library', c_shared_args : ['-DWORK'], c_static_args : ['-DBREAK']) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9266574 meson-1.3.2/test cases/common/40 options/0000755000175000017500000000000014562742415020267 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421483.0 meson-1.3.2/test cases/common/40 options/meson.build0000644000175000017500000000274114516755353022441 0ustar00jpakkanejpakkaneproject('options', 'c', meson_version : '>= 1.0.0') 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 if get_option('neg_int_opt') != -3 error('Incorrect value in negative integer option.') endif if get_option('CaseSenSiTivE') != 'Some CAPS' error('Incorrect value in mixed caps option.') endif if get_option('CASESENSITIVE') != 'ALL CAPS' error('Incorrect value in all caps option.') endif assert(get_option('wrap_mode') == 'default', 'Wrap mode option is broken.') assert(get_option('boolean_string') == false) assert(get_option('boolean_string2') == true) assert(get_option('integer_string') == 42) testcase expect_error('Invalid option name \'..invalid\'') get_option('..invalid') endtestcase testcase expect_error('Invalid option name \'this.is.also.invalid\'') get_option('this.is.also.invalid') endtestcase ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/40 options/meson_options.txt0000644000175000017500000000170514516512250023716 0ustar00jpakkanejpakkaneoption('testoption', type : 'string', value : 'optval', description : 'An option ' + 'to do something') option('other_one', type : 'boolean', value : not (not (not (not false)))) option('combo_opt', type : 'co' + 'mbo', 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) option('neg' + '_' + 'int' + '_' + 'opt', type : 'integer', min : -5, max : 5, value : -3) option('CaseSenSiTivE', type : 'string', value: 'Some CAPS', description : 'An option with mixed capitalization') option('CASESENSITIVE', type : 'string', value: 'ALL CAPS', description : 'An option with all caps') option('boolean_string', type : 'boolean', value : 'false') option('boolean_string2', type : 'boolean', value : 'true') option('integer_string', type : 'integer', value : '42') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339787.0 meson-1.3.2/test cases/common/40 options/test.json0000644000175000017500000000026714516515713022144 0ustar00jpakkanejpakkane{ "stdout": [ { "line": " * 1.1.0: {'\"boolean option\" keyword argument \"value\" of type str', '\"integer option\" keyword argument \"value\" of type str'}" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9306574 meson-1.3.2/test cases/common/41 test args/0000755000175000017500000000000014562742415020471 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/41 test args/cmd_args.c0000644000175000017500000000066114516512250022406 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/41 test args/copyfile.py0000644000175000017500000000013414516512250022642 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys import shutil shutil.copyfile(sys.argv[1], sys.argv[2]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/41 test args/env2vars.c0000644000175000017500000000117214516512250022373 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/41 test args/envvars.c0000644000175000017500000000116014516512250022306 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421484.0 meson-1.3.2/test cases/common/41 test args/meson.build0000644000175000017500000000250114516755354022636 0ustar00jpakkanejpakkaneproject('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, 'TEST_LIST_FLATTENING=1']) 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/41 test args/tester.c0000644000175000017500000000134014516512250022130 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/41 test args/tester.py0000755000175000017500000000034414516512250022344 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys import os assert os.environ['MESONTESTING'] == 'picklerror' assert os.environ['TEST_LIST_FLATTENING'] == '1' with open(sys.argv[1]) as f: if f.read() != 'contents\n': sys.exit(1) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/41 test args/testfile.txt0000644000175000017500000000001114516512250023030 0ustar00jpakkanejpakkanecontents ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9306574 meson-1.3.2/test cases/common/42 subproject/0000755000175000017500000000000014562742415020756 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421484.0 meson-1.3.2/test cases/common/42 subproject/meson.build0000644000175000017500000000152214516755354023125 0ustar00jpakkanejpakkaneproject('subproj user', 'c', version : '2.3.4', license : 'mylicense', license_files: 'mylicense.txt', ) 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 ('unexpected fallback value for subproject.get_variable()') endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/42 subproject/mylicense.txt0000644000175000017500000000000014516512250023464 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853066.922627 meson-1.3.2/test cases/common/42 subproject/subprojects/0000755000175000017500000000000014562742413023317 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9306574 meson-1.3.2/test cases/common/42 subproject/subprojects/sublib/0000755000175000017500000000000014562742415024601 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9306574 meson-1.3.2/test cases/common/42 subproject/subprojects/sublib/include/0000755000175000017500000000000014562742415026224 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/42 subproject/subprojects/sublib/include/subdefs.h0000644000175000017500000000070314516512250030017 0ustar00jpakkanejpakkane#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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/42 subproject/subprojects/sublib/meson.build0000644000175000017500000000125214516512250026732 0ustar00jpakkanejpakkaneproject('subproject', 'c', version : '1.0.0', license : ['sublicense1', 'sublicense2'], license_files: ['sublicense1.txt', 'sublicense2.txt'], ) 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/42 subproject/subprojects/sublib/simpletest.c0000644000175000017500000000011414516512250027121 0ustar00jpakkanejpakkane#include int main(void) { return subfunc() == 42 ? 0 : 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/42 subproject/subprojects/sublib/sublib.c0000644000175000017500000000010514516512250026210 0ustar00jpakkanejpakkane#include int DLL_PUBLIC subfunc(void) { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/42 subproject/subprojects/sublib/sublicense1.txt0000644000175000017500000000000014516512250027534 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/42 subproject/subprojects/sublib/sublicense2.txt0000644000175000017500000000000014516512250027535 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339787.0 meson-1.3.2/test cases/common/42 subproject/test.json0000644000175000017500000000063314516515713022630 0ustar00jpakkanejpakkane{ "installed": [ {"type": "exe", "file": "usr/bin/user"}, {"type": "pdb", "file": "usr/bin/user"}, {"type": "file", "file": "usr/share/sublib/sublib.depmf"}, {"type": "file", "file": "usr/share/sublib/mylicense.txt"}, {"type": "file", "file": "usr/share/sublib/subprojects/sublib/sublicense1.txt"}, {"type": "file", "file": "usr/share/sublib/subprojects/sublib/sublicense2.txt"} ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/42 subproject/user.c0000644000175000017500000000044614516512250022073 0ustar00jpakkanejpakkane#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; } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9306574 meson-1.3.2/test cases/common/43 subproject options/0000755000175000017500000000000014562742415022433 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421486.0 meson-1.3.2/test cases/common/43 subproject options/meson.build0000644000175000017500000000017614516755356024610 0ustar00jpakkanejpakkaneproject('suboptions') subproject('subproject') if not get_option('opt') error('option unset when it should be set') endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/43 subproject options/meson_options.txt0000644000175000017500000000012314516512250026053 0ustar00jpakkanejpakkaneoption('opt', type : 'boolean', value : true, description : 'main project option') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853066.926627 meson-1.3.2/test cases/common/43 subproject options/subprojects/0000755000175000017500000000000014562742413024774 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9306574 meson-1.3.2/test cases/common/43 subproject options/subprojects/subproject/0000755000175000017500000000000014562742415027156 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/43 subproject options/subprojects/subproject/meson.build0000644000175000017500000000014114516512250031303 0ustar00jpakkanejpakkaneproject('subproject') if get_option('opt') error('option set when it should be unset.') endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/43 subproject options/subprojects/subproject/meson_options.txt0000644000175000017500000000012214516512250032575 0ustar00jpakkanejpakkaneoption('opt', type : 'boolean', value : false, description : 'subproject option') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9346576 meson-1.3.2/test cases/common/44 pkgconfig-gen/0000755000175000017500000000000014562742415021316 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/44 pkgconfig-gen/answer.c0000644000175000017500000000011014516512250022740 0ustar00jpakkanejpakkaneint answer_to_life_the_universe_and_everything(void) { return 42; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9386575 meson-1.3.2/test cases/common/44 pkgconfig-gen/dependencies/0000755000175000017500000000000014562742415023744 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/44 pkgconfig-gen/dependencies/custom.c0000644000175000017500000000005514516512250025411 0ustar00jpakkanejpakkaneint custom_function(void) { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/44 pkgconfig-gen/dependencies/dummy.c0000644000175000017500000000004214516512250025226 0ustar00jpakkanejpakkaneint dummy(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/44 pkgconfig-gen/dependencies/exposed.c0000644000175000017500000000005614516512250025547 0ustar00jpakkanejpakkaneint exposed_function(void) { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/44 pkgconfig-gen/dependencies/internal.c0000644000175000017500000000005714516512250025715 0ustar00jpakkanejpakkaneint internal_function(void) { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/44 pkgconfig-gen/dependencies/main.c0000644000175000017500000000025714516512250025027 0ustar00jpakkanejpakkane#include #ifndef LIBFOO #error LIBFOO should be defined in pkgconfig cflags #endif int main(int argc, char *argv[]) { return simple_function() == 42 ? 0 : 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/44 pkgconfig-gen/dependencies/meson.build0000644000175000017500000000575114516512250026105 0ustar00jpakkanejpakkaneproject('pkgconfig-gen-dependencies', 'c', version: '1.0') if find_program('pkg-config').version() == '2.0.1' error('MESON_SKIP_TEST: cannot test uninstalled.pc due to https://github.com/pkgconf/pkgconf/issues/310#issuecomment-1677844842') endif 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', 'dummy.c', 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']) exe = executable('test1', 'main.c', dependencies : [pc_dep]) test('Test1', exe) # 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', 'dummy.c', link_with : internal_lib) pkgg.generate(main_lib2, libraries : internal_lib, filebase : 'pub-lib-order', ) # This will be built against both simple7.pc and simple7-uninstalled.pc, check # that include directories works in both cases. simple7 = dependency('simple7') exe = executable('test2', 'test2.c', dependencies: simple7, ) test('Test2', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/44 pkgconfig-gen/dependencies/test2.c0000644000175000017500000000015214516512250025136 0ustar00jpakkanejpakkane#include #include int main(void) { if (INC1 + INC2 != 3) return 1; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/44 pkgconfig-gen/foo.c0000644000175000017500000000024314516512250022233 0ustar00jpakkanejpakkane#include"simple.h" int answer_to_life_the_universe_and_everything (void); int simple_function(void) { return answer_to_life_the_universe_and_everything(); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9386575 meson-1.3.2/test cases/common/44 pkgconfig-gen/inc1/0000755000175000017500000000000014562742415022150 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/44 pkgconfig-gen/inc1/inc1.h0000644000175000017500000000001714516512250023140 0ustar00jpakkanejpakkane#define INC1 1 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9386575 meson-1.3.2/test cases/common/44 pkgconfig-gen/inc2/0000755000175000017500000000000014562742415022151 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/44 pkgconfig-gen/inc2/inc2.h0000644000175000017500000000001714516512250023142 0ustar00jpakkanejpakkane#define INC2 2 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421490.0 meson-1.3.2/test cases/common/44 pkgconfig-gen/meson.build0000644000175000017500000001415114516755362023466 0ustar00jpakkanejpakkaneproject('pkgconfig-gen', 'c', meson_version: '>=0.60.0') # Some CI runners does not have zlib, just skip them as we need some common # external dependency. cc = meson.get_compiler('c') if not cc.find_library('z', required: false).found() error('MESON_SKIP_TEST: zlib missing') endif # First check we have pkg-config >= 0.29 pkgconfig = find_program('pkg-config', native: true, required: false) if not pkgconfig.found() error('MESON_SKIP_TEST: pkg-config not found') endif v = run_command(pkgconfig, '--version', check: true).stdout().strip() if v.version_compare('<0.29') error('MESON_SKIP_TEST: pkg-config version \'' + v + '\' too old') endif python = find_program('python3') fs = import('fs') 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'], ) env = environment() env.prepend('PKG_CONFIG_PATH', meson.current_build_dir() / 'meson-private') test( 'pkgconfig-validation', pkgconfig, args: ['--validate', 'simple'], env : env, ) answerlib = shared_library('answer', 'answer.c') pkgg.generate(answerlib, name : 'libanswer', description : 'An answer library.', extra_cflags : ['-DLIBFOO'], ) # Test that name_prefix='' and name='libfoo' results in '-lfoo' lib2 = shared_library('libfoo', 'foo.c', link_with: answerlib, name_prefix : '', version : libver) pkgg.generate(lib2, libraries : [lib2, answerlib], name : 'libfoo', version : libver, description : 'A foo library.', variables : ['foo=bar', 'datadir=${prefix}/data'], extra_cflags : ['-DLIBFOO'], ) pkgg.generate( name : 'libhello', description : 'A minimalistic pkgconfig file.', version : libver, ) pkgg.generate( name : 'libhello_nolib', description : 'A minimalistic pkgconfig file.', version : libver, dataonly: true, variables : { 'foo': 'bar', # prefix is not set by default for dataonly pc files, but it is allowed to # define it manually. 'prefix': get_option('prefix'), 'escaped_var': 'hello world', }, unescaped_variables: { 'unescaped_var': 'hello world', } ) # Regression test for 2 cases: # - link_whole from InternalDependency used to be ignored, but we should still # recurse to add libraries they link to. In this case it must add `-lsimple1` # in generated pc file. # - dependencies from InternalDependency used to be ignored. In this it must add # `-lz` in generated pc file. simple1 = shared_library('simple1', 'simple.c') stat1 = static_library('stat1', 'simple.c', link_with: simple1) dep = declare_dependency(link_whole: stat1, dependencies: cc.find_library('z')) simple2 = library('simple2', 'simple.c') pkgg.generate(simple2, libraries: dep) # Regression test: as_system() does a deepcopy() of the InternalDependency object # which caused `-lsimple3` to be duplicated because generator used to compare # Target instances instead of their id. simple3 = shared_library('simple3', 'simple.c') dep1 = declare_dependency(link_with: simple3) dep2 = dep1.as_system() pkgg.generate(libraries: [dep1, dep2], name: 'simple3', description: 'desc') # Regression test: stat2 is both link_with and link_whole, it should not appear # in generated pc file. stat2 = static_library('stat2', 'simple.c', install: true) simple4 = library('simple4', 'simple.c', link_with: stat2) simple5 = library('simple5', 'simple5.c', link_with: simple4, link_whole: stat2) pkgg.generate(simple5) # Test passing a linkable CustomTarget and CustomTargetIndex to generator. # Do this only with gcc/clang to not have to deal with other compiler command # line specificities. if cc.get_id() in ['gcc', 'clang'] ct = custom_target('ct', input: 'simple.c', output: 'libct.so', command: [cc.cmd_array(), '@INPUT@', '-shared', '-o', '@OUTPUT@'], ) pkgg.generate(libraries: ct, name: 'ct', description: 'custom target' ) pkgg.generate(libraries: ct[0], name: 'ct0', description: 'custom target index' ) endif # Regression test: A library linking to an uninstalled custom_target static # library used to crash when generating its pkgconfig file. # Copy libstat2.a to libstat3.a to have a static library as custom target. infile = stat2.full_path() outfile = meson.current_build_dir() / 'libstat3.a' script = 'import shutil ; shutil.copyfile("@0@", "@1@")'.format(infile, outfile) ct = custom_target('stat3', input: stat2, output: fs.name(outfile), command: [python, '-c', script], ) simple6 = library('simple6', 'dependencies/dummy.c', link_with: ct) pkgg.generate(simple6) # implicit variables pkgg.generate( name : 'libvartest', description : 'Check that implicit vars are created', version : libver, variables: ['datadir=${prefix}/data', 'foo=${datadir}/foo', 'bar=${bindir}/bar'] ) pkgg.generate( name : 'libvartest2', description : 'Check that libdir is not an implicit var', version : libver, variables: ['bar=${libdir}/bar'] ) # Regression test: variables kwarg should listify single string value pkgg.generate( name : 'libvartest3', description : 'Check that variables can be single string', variables: 'foo=bar', ) # without a mainlib, name/description are mandatory testcase expect_error('pkgconfig.generate: if a library is not passed as a positional argument, the \'name\' keyword argument is required.') pkgg.generate(description: 'empty data') endtestcase testcase expect_error('pkgconfig.generate: if a library is not passed as a positional argument, the \'description\' keyword argument is required.') pkgg.generate(name: 'foobar') endtestcase # Make sure the -uninstalled.pc file contains both include directories. # See dependencies/test2.c that gets built against both simple7.pc and # simple7-uninstalled.pc. simple7 = library('simple7', include_directories: 'inc1') dep = declare_dependency(include_directories: 'inc2') install_headers('inc1/inc1.h', 'inc2/inc2.h') pkgg.generate(simple7, libraries: dep) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/44 pkgconfig-gen/simple.c0000644000175000017500000000010114516512250022732 0ustar00jpakkanejpakkane#include"simple.h" int simple_function(void) { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/44 pkgconfig-gen/simple.h0000644000175000017500000000011014516512250022737 0ustar00jpakkanejpakkane#ifndef SIMPLE_H_ #define SIMPLE_H_ int simple_function(void); #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/44 pkgconfig-gen/simple5.c0000644000175000017500000000007014516512250023024 0ustar00jpakkanejpakkaneint simple5(void); int simple5(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339787.0 meson-1.3.2/test cases/common/44 pkgconfig-gen/test.json0000644000175000017500000000350514516515713023171 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/include/simple.h"}, {"type": "file", "file": "usr/include/inc1.h"}, {"type": "file", "file": "usr/include/inc2.h"}, {"type": "file", "file": "usr/lib/libstat2.a"}, {"type": "file", "file": "usr/lib/pkgconfig/simple.pc"}, {"type": "file", "file": "usr/lib/pkgconfig/libanswer.pc"}, {"type": "file", "file": "usr/lib/pkgconfig/libfoo.pc"}, {"type": "file", "file": "usr/lib/pkgconfig/libhello.pc"}, {"type": "file", "file": "usr/lib/pkgconfig/libvartest.pc"}, {"type": "file", "file": "usr/lib/pkgconfig/libvartest2.pc"}, {"type": "file", "file": "usr/lib/pkgconfig/libvartest3.pc"}, {"type": "file", "file": "usr/lib/pkgconfig/simple2.pc"}, {"type": "file", "file": "usr/lib/pkgconfig/simple3.pc"}, {"type": "file", "file": "usr/lib/pkgconfig/simple5.pc"}, {"type": "file", "file": "usr/lib/pkgconfig/simple6.pc"}, {"type": "file", "file": "usr/lib/pkgconfig/simple7.pc"}, {"type": "file", "file": "usr/lib/pkgconfig/ct.pc"}, {"type": "file", "file": "usr/lib/pkgconfig/ct0.pc"}, {"type": "file", "file": "usr/share/pkgconfig/libhello_nolib.pc"} ], "stdout": [ { "line": "test cases/common/44 pkgconfig-gen/meson.build:160: WARNING: Project targets '>=0.60.0' but uses feature introduced in '0.62.0': pkgconfig.generate implicit variable for builtin directories." }, { "line": "test cases/common/44 pkgconfig-gen/meson.build:170: WARNING: Project targets '>=0.60.0' but uses feature introduced in '0.62.0': pkgconfig.generate implicit variable for builtin directories.", "count": 0 }, { "comment": "This will either match in the future-deprecated notice summary, or match the warning summary", "line": " * 0.62.0: {'pkgconfig.generate variable for builtin directories'}" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9466577 meson-1.3.2/test cases/common/45 custom install dirs/0000755000175000017500000000000014562742415022464 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/45 custom install dirs/datafile.cat0000644000175000017500000000003414516512250024712 0ustar00jpakkanejpakkaneInstalled cat is installed. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421489.0 meson-1.3.2/test cases/common/45 custom install dirs/meson.build0000644000175000017500000000130014516755361024623 0ustar00jpakkanejpakkaneproject('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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/45 custom install dirs/prog.10000644000175000017500000000001514516512250023500 0ustar00jpakkanejpakkaneMan up, you. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/45 custom install dirs/prog.c0000644000175000017500000000004114516512250023561 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/45 custom install dirs/sample.h0000644000175000017500000000007414516512250024106 0ustar00jpakkanejpakkane#ifndef SAMPLE_H #define SAMPLE_H int wackiness(); #endif ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9466577 meson-1.3.2/test cases/common/45 custom install dirs/subdir/0000755000175000017500000000000014562742415023754 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/45 custom install dirs/subdir/datafile.dog0000644000175000017500000000003414516512250026204 0ustar00jpakkanejpakkaneInstalled dog is installed. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339787.0 meson-1.3.2/test cases/common/45 custom install dirs/test.json0000644000175000017500000000126014516515713024333 0ustar00jpakkanejpakkane{ "installed": [ {"type": "exe", "file": "usr/dib/dab/dub/prog"}, {"type": "pdb", "file": "usr/dib/dab/dub/prog"}, {"type": "exe", "file": "usr/dib/dab/dub2/prog2"}, {"type": "pdb", "file": "usr/dib/dab/dub2/prog2"}, {"type": "file", "file": "usr/some/dir/sample.h"}, {"type": "file", "file": "usr/some/dir2/sample.h"}, {"type": "file", "file": "usr/woman/prog.1"}, {"type": "file", "file": "usr/woman2/prog.1"}, {"type": "file", "file": "usr/meow/datafile.cat"}, {"type": "file", "file": "usr/meow2/datafile.cat"}, {"type": "file", "file": "usr/woof/subdir/datafile.dog"}, {"type": "file", "file": "usr/woof2/subdir/datafile.dog"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9466577 meson-1.3.2/test cases/common/46 subproject subproject/0000755000175000017500000000000014562742415023123 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421491.0 meson-1.3.2/test cases/common/46 subproject subproject/meson.build0000644000175000017500000000040714516755363025273 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/46 subproject subproject/prog.c0000644000175000017500000000010514516512250024221 0ustar00jpakkanejpakkaneint func(void); int main(void) { return func() == 42 ? 0 : 1; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853066.930627 meson-1.3.2/test cases/common/46 subproject subproject/subprojects/0000755000175000017500000000000014562742413025464 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9466577 meson-1.3.2/test cases/common/46 subproject subproject/subprojects/a/0000755000175000017500000000000014562742415025706 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/46 subproject subproject/subprojects/a/a.c0000644000175000017500000000054514516512250026265 0ustar00jpakkanejpakkaneint 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(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/46 subproject subproject/subprojects/a/meson.build0000644000175000017500000000015014516512250030033 0ustar00jpakkanejpakkaneproject('a', 'c') b = subproject('b') l = shared_library('a', 'a.c', link_with : b.get_variable('lb')) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9466577 meson-1.3.2/test cases/common/46 subproject subproject/subprojects/b/0000755000175000017500000000000014562742415025707 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/46 subproject subproject/subprojects/b/b.c0000644000175000017500000000052314516512250026263 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/46 subproject subproject/subprojects/b/meson.build0000644000175000017500000000006314516512250030037 0ustar00jpakkanejpakkaneproject('b', 'c') lb = shared_library('b', 'b.c') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9466577 meson-1.3.2/test cases/common/46 subproject subproject/subprojects/c/0000755000175000017500000000000014562742415025710 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/46 subproject subproject/subprojects/c/meson.build0000644000175000017500000000015014516512250030035 0ustar00jpakkanejpakkaneproject('not-found-dep-subproj', 'c', version : '1.0') notfound_dep = dependency('', required : false) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9466577 meson-1.3.2/test cases/common/47 same file name/0000755000175000017500000000000014562742415021331 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9466577 meson-1.3.2/test cases/common/47 same file name/d1/0000755000175000017500000000000014562742415021635 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/47 same file name/d1/file.c0000644000175000017500000000003714516512250022707 0ustar00jpakkanejpakkaneint func1(void) { return 42; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9546578 meson-1.3.2/test cases/common/47 same file name/d2/0000755000175000017500000000000014562742415021636 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/47 same file name/d2/file.c0000644000175000017500000000003714516512250022710 0ustar00jpakkanejpakkaneint func2(void) { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421490.0 meson-1.3.2/test cases/common/47 same file name/meson.build0000644000175000017500000000014014516755362023472 0ustar00jpakkanejpakkaneproject('samefile', 'c') test('basic', executable('prog', 'prog.c', 'd1/file.c', 'd2/file.c')) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/47 same file name/prog.c0000644000175000017500000000012414516512250022430 0ustar00jpakkanejpakkaneint func1(void); int func2(void); int main(void) { return func1() - func2(); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9546578 meson-1.3.2/test cases/common/48 file grabber/0000755000175000017500000000000014562742415021110 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/48 file grabber/a.c0000644000175000017500000000003614516512250021462 0ustar00jpakkanejpakkaneint funca(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/48 file grabber/b.c0000644000175000017500000000003614516512250021463 0ustar00jpakkanejpakkaneint funcb(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/48 file grabber/c.c0000644000175000017500000000003614516512250021464 0ustar00jpakkanejpakkaneint funcc(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/48 file grabber/grabber.bat0000644000175000017500000000006114516512250023170 0ustar00jpakkanejpakkane@ECHO OFF echo a.c echo b.c echo c.c echo prog.c ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/48 file grabber/grabber.sh0000755000175000017500000000005314516512250023040 0ustar00jpakkanejpakkane#!/bin/sh for i in *.c; do echo $i done ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/48 file grabber/grabber2.bat0000644000175000017500000000007514516512250023257 0ustar00jpakkanejpakkane@ECHO OFF echo suba.c echo subb.c echo subc.c echo subprog.c ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421492.0 meson-1.3.2/test cases/common/48 file grabber/meson.build0000644000175000017500000000173114516755364023262 0ustar00jpakkanejpakkaneproject('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', check: false) grabber = find_program('grabber2.bat') else c = run_command('grabber.sh', check: false) 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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/48 file grabber/prog.c0000644000175000017500000000015714516512250022215 0ustar00jpakkanejpakkaneint funca(void); int funcb(void); int funcc(void); int main(void) { return funca() + funcb() + funcc(); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9546578 meson-1.3.2/test cases/common/48 file grabber/subdir/0000755000175000017500000000000014562742415022400 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/48 file grabber/subdir/meson.build0000644000175000017500000000022714516512250024532 0ustar00jpakkanejpakkanesc = run_command(grabber, check: true) subsources = sc.stdout().strip().split(newline) se = executable('subprog', subsources) test('subgrabtest', se) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/48 file grabber/subdir/suba.c0000644000175000017500000000003614516512250023464 0ustar00jpakkanejpakkaneint funca(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/48 file grabber/subdir/subb.c0000644000175000017500000000003614516512250023465 0ustar00jpakkanejpakkaneint funcb(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/48 file grabber/subdir/subc.c0000644000175000017500000000003614516512250023466 0ustar00jpakkanejpakkaneint funcc(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/48 file grabber/subdir/subprog.c0000644000175000017500000000015714516512250024217 0ustar00jpakkanejpakkaneint funca(void); int funcb(void); int funcc(void); int main(void) { return funca() + funcb() + funcc(); } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.962658 meson-1.3.2/test cases/common/49 custom target/0000755000175000017500000000000014562742415021366 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/49 custom target/data_source.txt0000644000175000017500000000004014516512250024401 0ustar00jpakkanejpakkaneThis is a text only input file. ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.962658 meson-1.3.2/test cases/common/49 custom target/depfile/0000755000175000017500000000000014562742415022776 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/49 custom target/depfile/dep.py0000755000175000017500000000056714516512250024122 0ustar00jpakkanejpakkane#!/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('{}: {}\n'.format(output, ' '.join(quoted_depfiles))) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/49 custom target/depfile/meson.build0000644000175000017500000000026214516512250025127 0ustar00jpakkanejpakkane mytarget = custom_target('depfile', output : 'dep.dat', depfile : 'dep.dat.d', command : [find_program('dep.py'), meson.current_source_dir(), '@DEPFILE@', '@OUTPUT@'], ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421492.0 meson-1.3.2/test cases/common/49 custom target/meson.build0000644000175000017500000000361514516755364023543 0ustar00jpakkanejpakkaneproject('custom target') 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('test.json') mytarget = custom_target('bindat', output : 'data.dat', input : 'data_source.txt', command : [python, comp, '--input=@INPUT@', '--output=@OUTPUT@', useless], env: {'MY_COMPILER_ENV': 'value'}, 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_ci = custom_target('bindat_ci', output : 'data_ci.dat', input : 'data_source.txt', command : [python, comp, '--input=@INPUT@', '--output=@OUTPUT@', mytarget.to_list()], ) 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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/49 custom target/my_compiler.py0000755000175000017500000000122114516512250024245 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import os import sys assert os.path.exists(sys.argv[3]) args = sys.argv[:-1] if __name__ == '__main__': assert os.environ['MY_COMPILER_ENV'] == 'value' 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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339787.0 meson-1.3.2/test cases/common/49 custom target/test.json0000644000175000017500000000011514516515713023233 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/subdir/data.dat"} ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.966658 meson-1.3.2/test cases/common/5 linkstatic/0000755000175000017500000000000014562742415020662 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/5 linkstatic/libfile.c0000644000175000017500000000004113716006331022415 0ustar00jpakkanejpakkaneint func(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/5 linkstatic/libfile2.c0000644000175000017500000000004213716006331022500 0ustar00jpakkanejpakkaneint func2(void) { return 2; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/5 linkstatic/libfile3.c0000644000175000017500000000004213716006331022501 0ustar00jpakkanejpakkaneint func3(void) { return 3; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/5 linkstatic/libfile4.c0000644000175000017500000000004213716006331022502 0ustar00jpakkanejpakkaneint func4(void) { return 4; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/5 linkstatic/main.c0000644000175000017500000000006713716006331021743 0ustar00jpakkanejpakkaneint func(void); int main(void) { return func(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421446.0 meson-1.3.2/test cases/common/5 linkstatic/meson.build0000644000175000017500000000035214516755306023026 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.966658 meson-1.3.2/test cases/common/50 custom target chain/0000755000175000017500000000000014562742415022421 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/50 custom target chain/data_source.txt0000644000175000017500000000004014516512250025434 0ustar00jpakkanejpakkaneThis is a text only input file. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421494.0 meson-1.3.2/test cases/common/50 custom target chain/meson.build0000644000175000017500000000156314516755366024600 0ustar00jpakkanejpakkaneproject('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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/50 custom target chain/my_compiler.py0000755000175000017500000000065014516512250025305 0ustar00jpakkanejpakkane#!/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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/50 custom target chain/my_compiler2.py0000755000175000017500000000066014516512250025370 0ustar00jpakkanejpakkane#!/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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339787.0 meson-1.3.2/test cases/common/50 custom target chain/test.json0000644000175000017500000000020414516515713024265 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/subdir/data2.dat"}, {"type": "file", "file": "usr/subdir/data3.dat"} ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.966658 meson-1.3.2/test cases/common/50 custom target chain/usetarget/0000755000175000017500000000000014562742415024424 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/50 custom target chain/usetarget/meson.build0000644000175000017500000000026614516512250026561 0ustar00jpakkanejpakkanee = executable('myexe', 'myexe.c') subexe = find_program('subcomp.py') custom_target('use_exe', input : e, output : 'subout.res', command : [subexe, '@INPUT@', '@OUTPUT@'], ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/50 custom target chain/usetarget/myexe.c0000644000175000017500000000012114516512250025700 0ustar00jpakkanejpakkane#include int main(void) { printf("I am myexe.\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/50 custom target chain/usetarget/subcomp.py0000755000175000017500000000023514516512250026440 0ustar00jpakkanejpakkane#!/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') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.966658 meson-1.3.2/test cases/common/51 run target/0000755000175000017500000000000014562742415020651 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/51 run target/.clang-format0000644000175000017500000000002314516512250023206 0ustar00jpakkanejpakkaneBasedOnStyle: LLVM ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/51 run target/.clang-tidy0000644000175000017500000000000014516512250022662 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/51 run target/check-env.py0000644000175000017500000000204514516512250023056 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import os, sys from pathlib import Path assert 'MESON_SOURCE_ROOT' in os.environ assert 'MESON_BUILD_ROOT' in os.environ assert 'MESON_SUBDIR' in os.environ assert 'MESONINTROSPECT' in os.environ assert 'MY_ENV' in os.environ # Environment has absolute paths and argv has relative paths when using ninja # backend and absolute paths when using vs backend. What matters is once # resolved they point to same location. env_source_root = Path(os.environ['MESON_SOURCE_ROOT']).resolve() env_build_root = Path(os.environ['MESON_BUILD_ROOT']).resolve() env_current_source_dir = Path(env_source_root, os.environ['MESON_SUBDIR']).resolve() print(sys.argv) argv_paths = [Path(i).resolve() for i in sys.argv[1:]] source_root, build_root, current_source_dir = argv_paths print(f'{source_root} == {env_source_root}') assert source_root == env_source_root print(f'{build_root} == {env_build_root}') assert build_root == env_build_root print(f'{current_source_dir} == {env_current_source_dir}') assert current_source_dir == env_current_source_dir ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/51 run target/check_exists.py0000755000175000017500000000022014516512250023663 0ustar00jpakkanejpakkane#!/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])) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/51 run target/configure.in0000755000175000017500000000005014516512250023147 0ustar00jpakkanejpakkane#!/usr/bin/env python3 print('Success')././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/51 run target/converter.py0000644000175000017500000000021314516512250023215 0ustar00jpakkanejpakkane#!/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()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/51 run target/fakeburner.py0000755000175000017500000000054414516512250023344 0ustar00jpakkanejpakkane#!/usr/bin/env python3 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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/51 run target/helloprinter.c0000644000175000017500000000033714516512250023516 0ustar00jpakkanejpakkane#include int main(int argc, char **argv) { if(argc != 2) { printf("I cannot haz argument.\n"); return 1; } else { printf("I can haz argument: %s\n", argv[1]); } return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421495.0 meson-1.3.2/test cases/common/51 run target/meson.build0000644000175000017500000000627414516755367023035 0ustar00jpakkanejpakkaneproject('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') if not meson.is_cross_build() or meson.can_run_host_binaries() run_target('runhello', command : [exe, 'argument']) endif 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 ) custom_target('configure_script_ct', command: conf, output: 'dummy.txt', capture: true) # Target names that clash with potential builtin functionality. run_target('ctags', command : converter) clangf = run_target('clang-format', command : [converter, files('.clang-format'), meson.current_build_dir() / 'clang-format']) custom_target('clang-tidy', input: '.clang-tidy', output: 'clang-tidy', command : [converter, '@INPUT@', '@OUTPUT@']) alias_target('clang-format-check', clangf) # Check we can pass env to the program. Also check some string substitutions # that were added in 0.57.0 but not documented. This is documented behaviour # since 0.57.1. run_target('check-env', command: [find_program('check-env.py'), '@SOURCE_ROOT@', '@BUILD_ROOT@', '@CURRENT_SOURCE_DIR@'], env: {'MY_ENV': '1'}, ) # Check some string substitutions that has always been done but never documented. # Some projects have been relying on this implementation detail. This is # documented behaviour since 0.57.1. custom_target('check-env-ct', command: [find_program('check-env.py'), '@SOURCE_ROOT@', '@BUILD_ROOT@', '@CURRENT_SOURCE_DIR@'], env: {'MESON_SOURCE_ROOT': meson.source_root(), 'MESON_BUILD_ROOT': meson.build_root(), 'MESON_SUBDIR': meson.current_source_dir(), 'MESONINTROSPECT': 'fake value', 'MY_ENV': '1'}, output: 'check-env-ct', ) run_target('textprinter', command: ['subdir/textprinter.py']) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.974658 meson-1.3.2/test cases/common/51 run target/subdir/0000755000175000017500000000000014562742415022141 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/51 run target/subdir/textprinter.py0000644000175000017500000000007314516512250025072 0ustar00jpakkanejpakkane#!/usr/bin/env python3 print('I am a script. Being run.') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.974658 meson-1.3.2/test cases/common/52 object generator/0000755000175000017500000000000014562742415022014 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1702314114.0 meson-1.3.2/test cases/common/52 object generator/meson.build0000644000175000017500000000232414535640202024146 0ustar00jpakkanejpakkaneproject('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']) # Generate an object file ending with .o even on Windows. # The VS backend needs to handle .o objects differently from .obj objects. gen3 = generator(python, output : '@BASENAME@.o', arguments : [comp, cc, '@INPUT@', '@OUTPUT@']) generated3 = gen3.process(['source4.c']) e = executable('prog', 'prog.c', generated, generated2, generated3) test('objgen', e)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/52 object generator/obj_generator.py0000755000175000017500000000101314516512250025173 0ustar00jpakkanejpakkane#!/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)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1702314114.0 meson-1.3.2/test cases/common/52 object generator/prog.c0000644000175000017500000000030214535640202023111 0ustar00jpakkanejpakkaneint func1_in_obj(void); int func2_in_obj(void); int func3_in_obj(void); int func4_in_obj(void); int main(void) { return func1_in_obj() + func2_in_obj() + func3_in_obj() + func4_in_obj(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/52 object generator/source.c0000644000175000017500000000005114516512250023443 0ustar00jpakkanejpakkaneint func1_in_obj(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/52 object generator/source2.c0000644000175000017500000000005114516512250023525 0ustar00jpakkanejpakkaneint func2_in_obj(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/52 object generator/source3.c0000644000175000017500000000005114516512250023526 0ustar00jpakkanejpakkaneint func3_in_obj(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1702314114.0 meson-1.3.2/test cases/common/52 object generator/source4.c0000644000175000017500000000005114535640202023527 0ustar00jpakkanejpakkaneint func4_in_obj(void) { return 0; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853068.974658 meson-1.3.2/test cases/common/53 install script/0000755000175000017500000000000014562742415021533 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/53 install script/customtarget.py0000755000175000017500000000057614516512250024630 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import argparse import os def main() -> None: parser = argparse.ArgumentParser() parser.add_argument('dirname') args = parser.parse_args() with open(os.path.join(args.dirname, '1.txt'), 'w') as f: f.write('') with open(os.path.join(args.dirname, '2.txt'), 'w') as f: f.write('') if __name__ == "__main__": main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421497.0 meson-1.3.2/test cases/common/53 install script/meson.build0000644000175000017500000000234214516755371023702 0ustar00jpakkanejpakkaneproject('custom install script', 'c') meson.add_install_script('myinstall.py', 'diiba/daaba', 'file.dat', dry_run: true) meson.add_install_script('myinstall.py', 'this/should', 'also-work.dat') subdir('src') meson.add_install_script('myinstall.py', 'dir', afile, '--mode=copy') data = configuration_data() data.set10('foo', true) conf = configure_file( configuration : data, output : 'conf.txt' ) meson.add_install_script('myinstall.py', 'dir', conf, '--mode=copy') t = custom_target( 'ct', command : [find_program('customtarget.py'), '@OUTDIR@'], output : ['1.txt', '2.txt'], ) meson.add_install_script('myinstall.py', 'customtarget', t, '--mode=copy') meson.add_install_script('myinstall.py', 'customtargetindex', t[0], '--mode=copy') installer = configure_file( input : 'myinstall.py', output : 'myinstall_copy.py', copy : true, ) meson.add_install_script(installer, 'otherdir', afile, '--mode=copy') # This executable links on a library built in src/ directory. On Windows this # means meson must add src/ into $PATH to find the DLL when running it as # install script. myexe = executable('prog', 'prog.c', link_with: mylib, install : true, ) if meson.can_run_host_binaries() meson.add_install_script(myexe) endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/53 install script/myinstall.py0000755000175000017500000000216714516512250024121 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import argparse import os import shutil prefix = os.environ['MESON_INSTALL_DESTDIR_PREFIX'] dry_run = bool(os.environ.get('MESON_INSTALL_DRY_RUN')) def main() -> None: parser = argparse.ArgumentParser() parser.add_argument('dirname') parser.add_argument('files', nargs='+') parser.add_argument('--mode', action='store', default='create', choices=['create', 'copy']) args = parser.parse_args() dirname = os.path.join(prefix, args.dirname) if not os.path.exists(dirname): if dry_run: print(f"DRYRUN: Creating directory {dirname}") else: os.makedirs(dirname) if args.mode == 'create': for name in args.files: if dry_run: print(f'DRYRUN: Writing file {name}') else: with open(os.path.join(dirname, name), 'w') as f: f.write('') else: for name in args.files: if dry_run: print(f"DRYRUN: Copying file {name} to {dirname}") else: shutil.copy(name, dirname) if __name__ == "__main__": main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/53 install script/prog.c0000644000175000017500000000031314516512250022632 0ustar00jpakkanejpakkane#include #ifdef _WIN32 #define DO_IMPORT __declspec(dllimport) #else #define DO_IMPORT #endif DO_IMPORT int foo(void); int main(void) { printf("This is text.\n"); return foo(); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9826581 meson-1.3.2/test cases/common/53 install script/src/0000755000175000017500000000000014562742415022322 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/53 install script/src/a file.txt0000644000175000017500000000000014516512250024160 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/53 install script/src/foo.c0000644000175000017500000000020214516512250023232 0ustar00jpakkanejpakkane#ifdef _WIN32 #define DO_EXPORT __declspec(dllexport) #else #define DO_EXPORT #endif DO_EXPORT int foo(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/53 install script/src/meson.build0000644000175000017500000000023014516512250024446 0ustar00jpakkanejpakkanemeson.add_install_script('myinstall.py', 'this/does', 'something-different.dat') afile = files('a file.txt') mylib = shared_library('mylib', 'foo.c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/53 install script/src/myinstall.py0000644000175000017500000000043314516512250024677 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import os import sys prefix = os.environ['MESON_INSTALL_DESTDIR_PREFIX'] dirname = os.path.join(prefix, sys.argv[1]) if not os.path.exists(dirname): os.makedirs(dirname) with open(os.path.join(dirname, sys.argv[2] + '.in'), 'w') as f: f.write('') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339787.0 meson-1.3.2/test cases/common/53 install script/test.json0000644000175000017500000000120114516515713023375 0ustar00jpakkanejpakkane{ "installed": [ {"type": "exe", "file": "usr/bin/prog"}, {"type": "pdb", "file": "usr/bin/prog"}, {"type": "file", "file": "usr/diiba/daaba/file.dat"}, {"type": "file", "file": "usr/this/should/also-work.dat"}, {"type": "file", "file": "usr/this/does/something-different.dat.in"}, {"type": "file", "file": "usr/dir/a file.txt"}, {"type": "file", "file": "usr/dir/conf.txt"}, {"type": "file", "file": "usr/otherdir/a file.txt"}, {"type": "file", "file": "usr/customtarget/1.txt"}, {"type": "file", "file": "usr/customtarget/2.txt"}, {"type": "file", "file": "usr/customtargetindex/1.txt"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9826581 meson-1.3.2/test cases/common/54 custom target source output/0000755000175000017500000000000014562742415024164 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/54 custom target source output/generator.py0000755000175000017500000000047114516512250026520 0ustar00jpakkanejpakkane#!/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; } ''') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/54 custom target source output/main.c0000644000175000017500000000007114516512250025241 0ustar00jpakkanejpakkane#include"mylib.h" int main(void) { return func(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421498.0 meson-1.3.2/test cases/common/54 custom target source output/meson.build0000644000175000017500000000031714516755372026334 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9826581 meson-1.3.2/test cases/common/55 exe static shared/0000755000175000017500000000000014562742415022062 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421499.0 meson-1.3.2/test cases/common/55 exe static shared/meson.build0000644000175000017500000000121714516755373024233 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/55 exe static shared/prog.c0000644000175000017500000000025414516512250023165 0ustar00jpakkanejpakkaneint shlibfunc2(void); int statlibfunc(void); int main(void) { if (statlibfunc() != 42) return 1; if (shlibfunc2() != 24) return 1; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/55 exe static shared/shlib2.c0000644000175000017500000000023414516512250023377 0ustar00jpakkanejpakkane#include "subdir/exports.h" int statlibfunc(void); int statlibfunc2(void); int DLL_PUBLIC shlibfunc2(void) { return statlibfunc() - statlibfunc2(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/55 exe static shared/stat.c0000644000175000017500000000016014516512250023165 0ustar00jpakkanejpakkane#include "subdir/exports.h" int shlibfunc(void); int DLL_PUBLIC statlibfunc(void) { return shlibfunc(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/55 exe static shared/stat2.c0000644000175000017500000000005214516512250023247 0ustar00jpakkanejpakkaneint statlibfunc2(void) { return 18; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9866583 meson-1.3.2/test cases/common/55 exe static shared/subdir/0000755000175000017500000000000014562742415023352 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/55 exe static shared/subdir/exports.h0000644000175000017500000000046214516512250025220 0ustar00jpakkanejpakkane#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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/55 exe static shared/subdir/meson.build0000644000175000017500000000005214516512250025500 0ustar00jpakkanejpakkaneshlib = shared_library('shar', 'shlib.c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/55 exe static shared/subdir/shlib.c0000644000175000017500000000011014516512250024576 0ustar00jpakkanejpakkane#include "exports.h" int DLL_PUBLIC shlibfunc(void) { return 42; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9866583 meson-1.3.2/test cases/common/56 array methods/0000755000175000017500000000000014562742415021345 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/56 array methods/a.txt0000644000175000017500000000000014516512250022303 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/56 array methods/b.txt0000644000175000017500000000000014516512250022304 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/56 array methods/c.txt0000644000175000017500000000000014516512250022305 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421498.0 meson-1.3.2/test cases/common/56 array methods/meson.build0000644000175000017500000000253714516755372023523 0ustar00jpakkanejpakkaneproject('array methods') empty = [] one = ['abc'] two = ['def', 'ghi'] combined = [empty, one, two] file_list = files('a.txt', 'b.txt') file_a = files('a.txt') file_c = files('c.txt') if file_a[0] != file_list[0] error('Files are not equal') endif if not file_list.contains(file_a[0]) error('Contains with ObjectHolder lists does not work') endif if file_list.contains(file_c[0]) error('Contains with ObjectHolder lists found nonexistent object') endif 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(one) error('Combined claims not to contain [abc].') endif if not combined.contains(two) error('Combined claims not to contain [def, ghi].') endif if not combined.contains('ghi') error('Combined claims not to contain ghi.') endif ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9866583 meson-1.3.2/test cases/common/57 custom header generator/0000755000175000017500000000000014562742415023276 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421165.0 meson-1.3.2/test cases/common/57 custom header generator/input.def0000644000175000017500000000000214516754655025115 0ustar00jpakkanejpakkane0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421165.0 meson-1.3.2/test cases/common/57 custom header generator/makeheader.py0000644000175000017500000000050214516754655025743 0ustar00jpakkanejpakkane#!/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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421500.0 meson-1.3.2/test cases/common/57 custom header generator/meson.build0000644000175000017500000000153514516755374025453 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/57 custom header generator/prog.c0000644000175000017500000000007614516512250024403 0ustar00jpakkanejpakkane#include"myheader.lh" int main(void) { return RET_VAL; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421165.0 meson-1.3.2/test cases/common/57 custom header generator/somefile.txt0000644000175000017500000000000014516754655025640 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9906583 meson-1.3.2/test cases/common/58 multiple generators/0000755000175000017500000000000014562742415022572 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/58 multiple generators/data2.dat0000644000175000017500000000000214516512250024236 0ustar00jpakkanejpakkane2 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/58 multiple generators/main.cpp0000644000175000017500000000013214516512250024205 0ustar00jpakkanejpakkane#include"source1.h" #include"source2.h" int main(void) { return func1() + func2(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421501.0 meson-1.3.2/test cases/common/58 multiple generators/meson.build0000644000175000017500000000057714516755375024755 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/58 multiple generators/mygen.py0000755000175000017500000000066714516512250024266 0ustar00jpakkanejpakkane#!/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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9906583 meson-1.3.2/test cases/common/58 multiple generators/subdir/0000755000175000017500000000000014562742415024062 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/58 multiple generators/subdir/data.dat0000644000175000017500000000000214516512250025444 0ustar00jpakkanejpakkane1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/58 multiple generators/subdir/meson.build0000644000175000017500000000021414516512250026210 0ustar00jpakkanejpakkanegenerated = custom_target('generated', output : ['source1.h', 'source1.cpp'], input : 'data.dat', command : [comp, '@INPUT0@', '@OUTDIR@']) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9906583 meson-1.3.2/test cases/common/59 install subdir/0000755000175000017500000000000014562742415021525 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421500.0 meson-1.3.2/test cases/common/59 install subdir/meson.build0000644000175000017500000000164614516755374023705 0ustar00jpakkanejpakkaneproject('install a whole subdir', default_options : ['install_umask=preserve']) # A subdir with an exclusion: install_subdir('sub2', exclude_files : ['excluded-three.dat'], exclude_directories : ['excluded'], install_dir : 'share') # More exclusions install_subdir('sub3', exclude_files : ['data/excluded.txt'], exclude_directories : ['data/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) # Create new empty directory that doesn't exist in the source tree install_subdir('new_directory', install_dir : 'share') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.9426272 meson-1.3.2/test cases/common/59 install subdir/nested_elided/0000755000175000017500000000000014562742413024313 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9906583 meson-1.3.2/test cases/common/59 install subdir/nested_elided/sub/0000755000175000017500000000000014562742415025106 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9906583 meson-1.3.2/test cases/common/59 install subdir/nested_elided/sub/dircheck/0000755000175000017500000000000014562742415026662 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/59 install subdir/nested_elided/sub/dircheck/ninth.dat0000644000175000017500000000005314516512250030461 0ustar00jpakkanejpakkaneNested file under nested elided directory. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/59 install subdir/nested_elided/sub/eighth.dat0000644000175000017500000000004114516512250027032 0ustar00jpakkanejpakkaneFile in nested elided directory. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.9426272 meson-1.3.2/test cases/common/59 install subdir/sub/0000755000175000017500000000000014562742413022314 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9906583 meson-1.3.2/test cases/common/59 install subdir/sub/sub1/0000755000175000017500000000000014562742415023170 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/59 install subdir/sub/sub1/third.dat0000644000175000017500000000005014516512250024756 0ustar00jpakkanejpakkaneThis is a third data file for sub1 dir. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9906583 meson-1.3.2/test cases/common/59 install subdir/sub1/0000755000175000017500000000000014562742415022377 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/59 install subdir/sub1/second.dat0000644000175000017500000000006614516512250024335 0ustar00jpakkanejpakkaneTest that multiple install_subdirs meld their results.././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9946585 meson-1.3.2/test cases/common/59 install subdir/sub2/0000755000175000017500000000000014562742415022400 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9946585 meson-1.3.2/test cases/common/59 install subdir/sub2/dircheck/0000755000175000017500000000000014562742415024154 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/59 install subdir/sub2/dircheck/excluded-three.dat0000644000175000017500000000000014516512250027525 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9946585 meson-1.3.2/test cases/common/59 install subdir/sub2/excluded/0000755000175000017500000000000014562742415024175 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/59 install subdir/sub2/excluded/two.dat0000644000175000017500000000000014516512250025455 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/59 install subdir/sub2/excluded-three.dat0000644000175000017500000000000014516512250025751 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/59 install subdir/sub2/one.dat0000644000175000017500000000000014516512250023630 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.9466274 meson-1.3.2/test cases/common/59 install subdir/sub3/0000755000175000017500000000000014562742413022377 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9946585 meson-1.3.2/test cases/common/59 install subdir/sub3/data/0000755000175000017500000000000014562742415023312 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/59 install subdir/sub3/data/data.txt0000644000175000017500000000000514516512250024746 0ustar00jpakkanejpakkanedata ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9946585 meson-1.3.2/test cases/common/59 install subdir/sub3/data/excluded/0000755000175000017500000000000014562742415025107 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/59 install subdir/sub3/data/excluded/excluded.txt0000644000175000017500000000001114516512250027424 0ustar00jpakkanejpakkaneexcluded ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/59 install subdir/sub3/data/excluded.txt0000644000175000017500000000001114516512250025627 0ustar00jpakkanejpakkaneexcluded ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9946585 meson-1.3.2/test cases/common/59 install subdir/sub_elided/0000755000175000017500000000000014562742415023624 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9946585 meson-1.3.2/test cases/common/59 install subdir/sub_elided/dircheck/0000755000175000017500000000000014562742415025400 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/59 install subdir/sub_elided/dircheck/fifth.dat0000644000175000017500000000005314516512250027157 0ustar00jpakkanejpakkaneData file in a subdir of elided directory. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/59 install subdir/sub_elided/fourth.dat0000644000175000017500000000007414516512250025615 0ustar00jpakkanejpakkaneTest that this file is installed directly into install_dir. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9986584 meson-1.3.2/test cases/common/59 install subdir/subdir/0000755000175000017500000000000014562742415023015 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/59 install subdir/subdir/meson.build0000644000175000017500000000034614516512250025151 0ustar00jpakkanejpakkaneinstall_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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9986584 meson-1.3.2/test cases/common/59 install subdir/subdir/sub1/0000755000175000017500000000000014562742415023667 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/59 install subdir/subdir/sub1/data1.dat0000644000175000017500000000004114516512250025335 0ustar00jpakkanejpakkaneThis is a data file in a subdir. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9986584 meson-1.3.2/test cases/common/59 install subdir/subdir/sub1/sub2/0000755000175000017500000000000014562742415024542 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/59 install subdir/subdir/sub1/sub2/data2.dat0000644000175000017500000000005014516512250026211 0ustar00jpakkanejpakkaneThis is a data file in a deeper subdir. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9986584 meson-1.3.2/test cases/common/59 install subdir/subdir/sub_elided/0000755000175000017500000000000014562742415025114 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9986584 meson-1.3.2/test cases/common/59 install subdir/subdir/sub_elided/dircheck/0000755000175000017500000000000014562742415026670 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/59 install subdir/subdir/sub_elided/dircheck/seventh.dat0000644000175000017500000000003114516512250031017 0ustar00jpakkanejpakkaneNested file in a subdir. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/59 install subdir/subdir/sub_elided/sixth.dat0000644000175000017500000000003514516512250026732 0ustar00jpakkanejpakkaneElide test file in a subdir. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339787.0 meson-1.3.2/test cases/common/59 install subdir/test.json0000644000175000017500000000153514516515713023401 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/share/dircheck/fifth.dat"}, {"type": "file", "file": "usr/share/dircheck/seventh.dat"}, {"type": "file", "file": "usr/share/dircheck/ninth.dat"}, {"type": "file", "file": "usr/share/eighth.dat"}, {"type": "file", "file": "usr/share/fourth.dat"}, {"type": "file", "file": "usr/share/sixth.dat"}, {"type": "file", "file": "usr/share/sub1/data1.dat"}, {"type": "file", "file": "usr/share/sub1/second.dat"}, {"type": "file", "file": "usr/share/sub1/third.dat"}, {"type": "file", "file": "usr/share/sub1/sub2/data2.dat"}, {"type": "file", "file": "usr/share/sub2/one.dat"}, {"type": "file", "file": "usr/share/sub2/dircheck/excluded-three.dat"}, {"type": "file", "file": "usr/share/sub3/data/data.txt"}, {"type": "dir", "file": "usr/share/new_directory"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853068.9986584 meson-1.3.2/test cases/common/6 linkshared/0000755000175000017500000000000014562742415020642 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/common/6 linkshared/cpplib.cpp0000644000175000017500000000013214107166547022614 0ustar00jpakkanejpakkane#define BUILDING_DLL #include "cpplib.h" int DLL_PUBLIC cppfunc(void) { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/common/6 linkshared/cpplib.h0000644000175000017500000000056514107166547022273 0ustar00jpakkanejpakkane/* See http://gcc.gnu.org/wiki/Visibility#How_to_use_the_new_C.2B-.2B-_visibility_support */ #if defined(_WIN32) || defined(__CYGWIN__) #ifdef BUILDING_DLL #define DLL_PUBLIC __declspec(dllexport) #else #define DLL_PUBLIC __declspec(dllimport) #endif #else #define DLL_PUBLIC __attribute__ ((visibility ("default"))) #endif int DLL_PUBLIC cppfunc(void); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/common/6 linkshared/cppmain.cpp0000644000175000017500000000010414107166547022771 0ustar00jpakkanejpakkane#include "cpplib.h" int main(void) { return cppfunc() != 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421248.0 meson-1.3.2/test cases/common/6 linkshared/libfile.c0000644000175000017500000000052114516755000022403 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/6 linkshared/main.c0000644000175000017500000000027113716006331021720 0ustar00jpakkanejpakkane#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(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421447.0 meson-1.3.2/test cases/common/6 linkshared/meson.build0000644000175000017500000000075114516755307023012 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/6 linkshared/test.json0000644000175000017500000000016613716006331022505 0ustar00jpakkanejpakkane{ "installed": [ { "type": "exe", "file": "usr/bin/prog" }, { "type": "pdb", "file": "usr/bin/prog" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0026586 meson-1.3.2/test cases/common/60 foreach/0000755000175000017500000000000014562742415020205 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421502.0 meson-1.3.2/test cases/common/60 foreach/meson.build0000644000175000017500000000236014516755376022361 0ustar00jpakkanejpakkaneproject('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') items = [] iter = range(2) foreach i : iter items += i endforeach assert(items == [0, 1]) assert(iter[1] == 1) items = [] foreach i : range(1, 2) items += i endforeach assert(items == [1]) items = [] foreach i : range(1, 10, 2) items += i endforeach assert(items == [1, 3, 5, 7, 9]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/60 foreach/prog1.c0000644000175000017500000000012614516512250021367 0ustar00jpakkanejpakkane#include int main(void) { printf("This is test #1.\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/60 foreach/prog2.c0000644000175000017500000000012614516512250021370 0ustar00jpakkanejpakkane#include int main(void) { printf("This is test #2.\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/60 foreach/prog3.c0000644000175000017500000000012614516512250021371 0ustar00jpakkanejpakkane#include int main(void) { printf("This is test #3.\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339787.0 meson-1.3.2/test cases/common/60 foreach/test.json0000644000175000017500000000045414516515713022060 0ustar00jpakkanejpakkane{ "installed": [ {"type": "exe", "file": "usr/bin/prog1"}, {"type": "pdb", "file": "usr/bin/prog1"}, {"type": "exe", "file": "usr/bin/prog2"}, {"type": "pdb", "file": "usr/bin/prog2"}, {"type": "exe", "file": "usr/bin/prog3"}, {"type": "pdb", "file": "usr/bin/prog3"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0026586 meson-1.3.2/test cases/common/61 number arithmetic/0000755000175000017500000000000014562742415022201 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421502.0 meson-1.3.2/test cases/common/61 number arithmetic/meson.build0000644000175000017500000000363414516755376024362 0ustar00jpakkanejpakkaneproject('number arithmetic') 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.') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0026586 meson-1.3.2/test cases/common/62 string arithmetic/0000755000175000017500000000000014562742415022220 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421502.0 meson-1.3.2/test cases/common/62 string arithmetic/meson.build0000644000175000017500000000223214516755376024372 0ustar00jpakkanejpakkaneproject('string arithmetic', meson_version: '>=0.62.0') assert('foo' + 'bar' == 'foobar') assert('foo' + 'bar' + 'baz' == 'foobarbaz') a = 'a' b = 'b' assert(a + b + 'c' == 'abc') # ------------------------------------------------------------------------------ # format strings: # ------------------------------------------------------------------------------ sub1 = 'the' sub2 = ' quick\n' sub3 = ' brown' sub4 = '\nfox' x = f'@sub1@@sub2@@sub3@@sub4@' assert(x == sub1 + sub2 + sub3 + sub4) assert(x == 'the quick\n brown\nfox') # ------------------------------------------------------------------------------ # multi-line format strings # ------------------------------------------------------------------------------ y_actual = f'''This is a multi-line comment with string substitution: "@sub1@@sub2@@sub3@@sub4@" And I can even substitute the entry multiple times! @sub1@ @sub2@ @sub3@ ''' y_expect = '''This is a multi-line comment with string substitution: "the quick brown fox" And I can even substitute the entry multiple times! the quick brown ''' message('actual=' + y_actual) message('expect=' + y_expect) assert(y_actual == y_expect) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339787.0 meson-1.3.2/test cases/common/62 string arithmetic/test.json0000644000175000017500000000032014516515713024063 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/common/62 string arithmetic/meson.build:25: WARNING: Project targets '>=0.62.0' but uses feature introduced in '0.63.0': multiline format strings." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0026586 meson-1.3.2/test cases/common/63 array arithmetic/0000755000175000017500000000000014562742415022031 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421503.0 meson-1.3.2/test cases/common/63 array arithmetic/meson.build0000644000175000017500000000062114516755377024204 0ustar00jpakkanejpakkaneproject('array arithmetic') 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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0026586 meson-1.3.2/test cases/common/64 arithmetic bidmas/0000755000175000017500000000000014562742415022153 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421504.0 meson-1.3.2/test cases/common/64 arithmetic bidmas/meson.build0000644000175000017500000000057014516755400024314 0ustar00jpakkanejpakkaneproject('arithmetic bidmas') 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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0066586 meson-1.3.2/test cases/common/65 build always/0000755000175000017500000000000014562742415021163 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/65 build always/main.c0000644000175000017500000000017014516512250022240 0ustar00jpakkanejpakkane#include #include"version.h" int main(void) { printf("Version is %s.\n", version_string); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421504.0 meson-1.3.2/test cases/common/65 build always/meson.build0000644000175000017500000000046014516755400023322 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/65 build always/version.c.in0000644000175000017500000000007714516512250023414 0ustar00jpakkanejpakkane#include"version.h" const char *version_string = "@VERSION@"; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/65 build always/version.h0000644000175000017500000000006114516512250023005 0ustar00jpakkanejpakkane#pragma once extern const char *version_string; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/65 build always/version_gen.py0000755000175000017500000000147014516512250024047 0ustar00jpakkanejpakkane#!/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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0066586 meson-1.3.2/test cases/common/66 vcstag/0000755000175000017500000000000014562742415020073 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421506.0 meson-1.3.2/test cases/common/66 vcstag/meson.build0000644000175000017500000000261514516755402022240 0ustar00jpakkanejpakkaneproject('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_notfound_fallback = vcs_tag(input : 'vcstag.c.in', output : 'vcstag-notfound-fallback.c', command : ['git-but-not-found-sorry', 'show-ref', '-s', 'refs/heads/master'], fallback : '1.0.0') version_src_fallback = vcs_tag(input : 'vcstag.c.in', output : 'vcstag-fallback.c') git = find_program('git') version_src_git_program = vcs_tag(input : 'vcstag.c.in', output : 'vcstag-git-program.c', command : [git, 'rev-parse', 'HEAD'], fallback : '1.0.0') version_src_file = vcs_tag(input : 'vcstag.c.in', output : 'vcstag-file.c', command : files('version.py')) tagprog = executable('tagprog', 'tagprog.c', version_src) version_src_executable = vcs_tag(input : 'vcstag.c.in', output : 'vcstag-executable.c', command : [tagprog]) executable('tagprog-custom', 'tagprog.c', version_src_custom) executable('tagprog-fallback', 'tagprog.c', version_src_fallback) executable('tagprog-notfound-fallback', 'tagprog.c', version_src_notfound_fallback) executable('tagprog-git-program', 'tagprog.c', version_src_git_program) executable('tagprog-executable', 'tagprog.c', version_src_executable) executable('tagprog-file', 'tagprog.c', version_src_file) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/66 vcstag/tagprog.c0000644000175000017500000000016714516512250021675 0ustar00jpakkanejpakkane#include extern const char *vcstag; int main(void) { printf("Version is %s\n", vcstag); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/66 vcstag/vcstag.c.in0000644000175000017500000000004214516512250022116 0ustar00jpakkanejpakkaneconst char *vcstag = "@VCS_TAG@"; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/66 vcstag/version.py0000755000175000017500000000004614516512250022124 0ustar00jpakkanejpakkane#!/usr/bin/env python3 print('3.14') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0066586 meson-1.3.2/test cases/common/67 modules/0000755000175000017500000000000014562742415020255 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421505.0 meson-1.3.2/test cases/common/67 modules/meson.build0000644000175000017500000000055614516755401022423 0ustar00jpakkanejpakkaneproject('module test') modtest = import('modtest') modtest.print_hello() assert(modtest.found()) modtest = import('modtest', required : get_option('disabled')) assert(not modtest.found()) notfound = import('not-found', required : false) assert(not notfound.found()) disabled = import('not-found', required : false, disabler : true) assert(is_disabler(disabled)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/67 modules/meson_options.txt0000644000175000017500000000014214516512250023676 0ustar00jpakkanejpakkaneoption( 'disabled', type : 'feature', value : 'disabled', description : 'test disabled' ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0066586 meson-1.3.2/test cases/common/68 should fail/0000755000175000017500000000000014562742415021000 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/68 should fail/failing.c0000644000175000017500000000004114516512250022537 0ustar00jpakkanejpakkaneint main(void) { return 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421506.0 meson-1.3.2/test cases/common/68 should fail/meson.build0000644000175000017500000000015414516755402023141 0ustar00jpakkanejpakkaneproject('should fail', 'c') exe = executable('prog', 'failing.c') test('failing', exe, should_fail : true) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0146587 meson-1.3.2/test cases/common/69 configure file in custom target/0000755000175000017500000000000014562742415024621 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0146587 meson-1.3.2/test cases/common/69 configure file in custom target/inc/0000755000175000017500000000000014562742415025372 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/69 configure file in custom target/inc/confdata.in0000644000175000017500000000001014516512250027457 0ustar00jpakkanejpakkane@VALUE@ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/69 configure file in custom target/inc/meson.build0000644000175000017500000000022114516512250027516 0ustar00jpakkanejpakkanecdata = configuration_data() cdata.set('VALUE', '42') cfile = configure_file(input : 'confdata.in', output : 'confdata', configuration : cdata) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421507.0 meson-1.3.2/test cases/common/69 configure file in custom target/meson.build0000644000175000017500000000010314516755403026755 0ustar00jpakkanejpakkaneproject('conf file in custom target') subdir('inc') subdir('src') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0146587 meson-1.3.2/test cases/common/69 configure file in custom target/src/0000755000175000017500000000000014562742415025410 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/69 configure file in custom target/src/meson.build0000644000175000017500000000102514516512250027537 0ustar00jpakkanejpakkanecustom_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@']) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/69 configure file in custom target/src/mycompiler.py0000644000175000017500000000032214516512250030126 0ustar00jpakkanejpakkane#!/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') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0146587 meson-1.3.2/test cases/common/7 mixed/0000755000175000017500000000000014562742415017625 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/7 mixed/func.c0000644000175000017500000000007013716006331020707 0ustar00jpakkanejpakkaneint func(void) { int class = 0; return class; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/7 mixed/main.cc0000644000175000017500000000013213716006331021042 0ustar00jpakkanejpakkaneextern "C" int func(); class BreakPlainCCompiler; int main(void) { return func(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421447.0 meson-1.3.2/test cases/common/7 mixed/meson.build0000644000175000017500000000015214516755307021770 0ustar00jpakkanejpakkaneproject('mixed C and C++', 'c', 'cpp') exe = executable('prog', 'main.cc', 'func.c') test('mixtest', exe) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0146587 meson-1.3.2/test cases/common/70 external test program/0000755000175000017500000000000014562742415023011 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421507.0 meson-1.3.2/test cases/common/70 external test program/meson.build0000644000175000017500000000013514516755403025152 0ustar00jpakkanejpakkaneproject('test is external') test('external', find_program('mytest.py'), args : ['correct']) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/70 external test program/mytest.py0000755000175000017500000000025514516512250024704 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys if sys.argv[1] == 'correct': print('Argument is correct.') sys.exit(0) print('Argument is incorrect:', sys.argv[1]) sys.exit(1) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0146587 meson-1.3.2/test cases/common/71 ctarget dependency/0000755000175000017500000000000014562742415022330 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/71 ctarget dependency/gen1.py0000755000175000017500000000035014516512250023524 0ustar00jpakkanejpakkane#!/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]) as f: contents = f.read() with open(sys.argv[2], 'w') as f: f.write(contents) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/71 ctarget dependency/gen2.py0000755000175000017500000000034414516512250023530 0ustar00jpakkanejpakkane#!/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]) as ifile, open(sys.argv[2], 'w') as ofile: ofile.write(ifile.read()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/71 ctarget dependency/input.dat0000644000175000017500000000003114516512250024142 0ustar00jpakkanejpakkaneThis is a piece of text. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421508.0 meson-1.3.2/test cases/common/71 ctarget dependency/meson.build0000644000175000017500000000105114516755404024470 0ustar00jpakkanejpakkaneproject('custom target dependency') # 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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0146587 meson-1.3.2/test cases/common/72 shared subproject/0000755000175000017500000000000014562742415022210 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/72 shared subproject/a.c0000644000175000017500000000027714516512250022571 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421510.0 meson-1.3.2/test cases/common/72 shared subproject/meson.build0000644000175000017500000000025614516755406024360 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.9546275 meson-1.3.2/test cases/common/72 shared subproject/subprojects/0000755000175000017500000000000014562742413024551 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0146587 meson-1.3.2/test cases/common/72 shared subproject/subprojects/B/0000755000175000017500000000000014562742415024734 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/72 shared subproject/subprojects/B/b.c0000644000175000017500000000065514516512250025316 0ustar00jpakkanejpakkane#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'; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/72 shared subproject/subprojects/B/meson.build0000644000175000017500000000014514516512250027065 0ustar00jpakkanejpakkaneproject('B', 'c') C = subproject('C') c = C.get_variable('c') b = library('b', 'b.c', link_with : c) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0186589 meson-1.3.2/test cases/common/72 shared subproject/subprojects/C/0000755000175000017500000000000014562742415024735 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/72 shared subproject/subprojects/C/c.c0000644000175000017500000000052414516512250025313 0ustar00jpakkanejpakkane#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'; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/72 shared subproject/subprojects/C/meson.build0000644000175000017500000000015314516512250027065 0ustar00jpakkanejpakkaneproject('C', 'c') # libc.so cannot be used, it already exists as a reserved name c = library('cee', 'c.c') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0186589 meson-1.3.2/test cases/common/73 shared subproject 2/0000755000175000017500000000000014562742415022333 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/73 shared subproject 2/a.c0000644000175000017500000000027714516512250022714 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421510.0 meson-1.3.2/test cases/common/73 shared subproject 2/meson.build0000644000175000017500000000036414516755406024503 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.9546275 meson-1.3.2/test cases/common/73 shared subproject 2/subprojects/0000755000175000017500000000000014562742413024674 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0186589 meson-1.3.2/test cases/common/73 shared subproject 2/subprojects/B/0000755000175000017500000000000014562742415025057 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/73 shared subproject 2/subprojects/B/b.c0000644000175000017500000000065414516512250025440 0ustar00jpakkanejpakkane#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'; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/73 shared subproject 2/subprojects/B/meson.build0000644000175000017500000000014514516512250027210 0ustar00jpakkanejpakkaneproject('B', 'c') C = subproject('C') c = C.get_variable('c') b = library('b', 'b.c', link_with : c) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0186589 meson-1.3.2/test cases/common/73 shared subproject 2/subprojects/C/0000755000175000017500000000000014562742415025060 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/73 shared subproject 2/subprojects/C/c.c0000644000175000017500000000052414516512250025436 0ustar00jpakkanejpakkane#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'; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/73 shared subproject 2/subprojects/C/meson.build0000644000175000017500000000015314516512250027210 0ustar00jpakkanejpakkaneproject('C', 'c') # libc.so cannot be used, it already exists as a reserved name c = library('cee', 'c.c') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.026659 meson-1.3.2/test cases/common/74 file object/0000755000175000017500000000000014562742415020751 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/74 file object/lib.c0000644000175000017500000000004114516512250021645 0ustar00jpakkanejpakkaneint func(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/test cases/common/74 file object/meson.build0000644000175000017500000000023614562742363023116 0ustar00jpakkanejpakkaneproject('file object', 'c') prog0 = files('prog.c') lib0 = files('lib.c') test('fobj', executable('fobj', prog0, lib0)) subdir('subdir1') subdir('subdir2') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/74 file object/prog.c0000644000175000017500000000037114516512250022054 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.026659 meson-1.3.2/test cases/common/74 file object/subdir1/0000755000175000017500000000000014562742415022322 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/74 file object/subdir1/lib.c0000644000175000017500000000004114516512250023216 0ustar00jpakkanejpakkaneint func(void) { return 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/74 file object/subdir1/meson.build0000644000175000017500000000036314516512250024455 0ustar00jpakkanejpakkaneprog1 = 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))././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/74 file object/subdir1/prog.c0000644000175000017500000000027714516512250023432 0ustar00jpakkanejpakkane#include int func(void); int main(void) { if(func() == 1) { printf("Iz success.\n"); } else { printf("Iz fail.\n"); return 1; } return 0; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.026659 meson-1.3.2/test cases/common/74 file object/subdir2/0000755000175000017500000000000014562742415022323 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/74 file object/subdir2/lib.c0000644000175000017500000000004114516512250023217 0ustar00jpakkanejpakkaneint func(void) { return 2; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/74 file object/subdir2/meson.build0000644000175000017500000000036314516512250024456 0ustar00jpakkanejpakkaneprog2 = 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))././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/74 file object/subdir2/prog.c0000644000175000017500000000027714516512250023433 0ustar00jpakkanejpakkane#include int func(void); int main(void) { if(func() == 2) { printf("Iz success.\n"); } else { printf("Iz fail.\n"); return 1; } return 0; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.026659 meson-1.3.2/test cases/common/75 custom subproject dir/0000755000175000017500000000000014562742415023016 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/75 custom subproject dir/a.c0000644000175000017500000000027714516512250023377 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.9626276 meson-1.3.2/test cases/common/75 custom subproject dir/custom_subproject_dir/0000755000175000017500000000000014562742413027424 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.030659 meson-1.3.2/test cases/common/75 custom subproject dir/custom_subproject_dir/B/0000755000175000017500000000000014562742415027607 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/75 custom subproject dir/custom_subproject_dir/B/b.c0000644000175000017500000000065414516512250030170 0ustar00jpakkanejpakkane#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'; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/75 custom subproject dir/custom_subproject_dir/B/meson.build0000644000175000017500000000015414516512250031740 0ustar00jpakkanejpakkaneproject('B', 'c') C = subproject('C') c = C.get_variable('c') b = shared_library('b', 'b.c', link_with : c) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.030659 meson-1.3.2/test cases/common/75 custom subproject dir/custom_subproject_dir/C/0000755000175000017500000000000014562742415027610 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/75 custom subproject dir/custom_subproject_dir/C/c.c0000644000175000017500000000052414516512250030166 0ustar00jpakkanejpakkane#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'; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/75 custom subproject dir/custom_subproject_dir/C/meson.build0000644000175000017500000000016214516512250031740 0ustar00jpakkanejpakkaneproject('C', 'c') # libc.so cannot be used, it already exists as a reserved name c = shared_library('cee', 'c.c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421512.0 meson-1.3.2/test cases/common/75 custom subproject dir/meson.build0000644000175000017500000000032614516755410025157 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.030659 meson-1.3.2/test cases/common/76 has type/0000755000175000017500000000000014562742415020322 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421512.0 meson-1.3.2/test cases/common/76 has type/meson.build0000644000175000017500000000054114516755410022462 0ustar00jpakkanejpakkaneproject('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 ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.030659 meson-1.3.2/test cases/common/77 extract from nested subdir/0000755000175000017500000000000014562742415023720 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421512.0 meson-1.3.2/test cases/common/77 extract from nested subdir/meson.build0000644000175000017500000000024214516755410026056 0ustar00jpakkanejpakkaneproject('Extract objects from subdirs', 'c') if meson.is_unity() message('Unity build: skipping incompatible test') else subdir('src') subdir('tst') endif ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.030659 meson-1.3.2/test cases/common/77 extract from nested subdir/src/0000755000175000017500000000000014562742415024507 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.030659 meson-1.3.2/test cases/common/77 extract from nested subdir/src/first/0000755000175000017500000000000014562742415025636 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/77 extract from nested subdir/src/first/lib_first.c0000644000175000017500000000004514516512250027745 0ustar00jpakkanejpakkaneint first(void) { return 1001; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/77 extract from nested subdir/src/first/meson.build0000644000175000017500000000006714516512250027772 0ustar00jpakkanejpakkanefirst_lib = shared_library('first_lib', 'lib_first.c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/77 extract from nested subdir/src/meson.build0000644000175000017500000000002014516512250026630 0ustar00jpakkanejpakkanesubdir('first') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.030659 meson-1.3.2/test cases/common/77 extract from nested subdir/tst/0000755000175000017500000000000014562742415024532 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.030659 meson-1.3.2/test cases/common/77 extract from nested subdir/tst/first/0000755000175000017500000000000014562742415025661 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/77 extract from nested subdir/tst/first/exe_first.c0000644000175000017500000000010014516512250027773 0ustar00jpakkanejpakkaneint first(void); int main(void) { return first() - 1001; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/77 extract from nested subdir/tst/first/meson.build0000644000175000017500000000021014516512250030003 0ustar00jpakkanejpakkanefirst_exe = executable('first_exe', 'exe_first.c', objects : first_lib.extract_objects('lib_first.c')) test('first_test', first_exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/77 extract from nested subdir/tst/meson.build0000644000175000017500000000002014516512250026653 0ustar00jpakkanejpakkanesubdir('first') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.030659 meson-1.3.2/test cases/common/78 internal dependency/0000755000175000017500000000000014562742415022522 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421512.0 meson-1.3.2/test cases/common/78 internal dependency/meson.build0000644000175000017500000000010314516755410024654 0ustar00jpakkanejpakkaneproject('internal dependency', 'c') subdir('proj1') subdir('src') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.030659 meson-1.3.2/test cases/common/78 internal dependency/proj1/0000755000175000017500000000000014562742415023555 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.030659 meson-1.3.2/test cases/common/78 internal dependency/proj1/include/0000755000175000017500000000000014562742415025200 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/78 internal dependency/proj1/include/proj1.h0000644000175000017500000000012614516512250026372 0ustar00jpakkanejpakkane#pragma once void proj1_func1(void); void proj1_func2(void); void proj1_func3(void); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/78 internal dependency/proj1/meson.build0000644000175000017500000000043714516512250025712 0ustar00jpakkanejpakkaneincdirs = 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]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/78 internal dependency/proj1/proj1f1.c0000644000175000017500000000014114516512250025166 0ustar00jpakkanejpakkane#include #include void proj1_func1(void) { printf("In proj1_func1.\n"); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/78 internal dependency/proj1/proj1f2.c0000644000175000017500000000014114516512250025167 0ustar00jpakkanejpakkane#include #include void proj1_func2(void) { printf("In proj1_func2.\n"); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/78 internal dependency/proj1/proj1f3.c0000644000175000017500000000014114516512250025170 0ustar00jpakkanejpakkane#include #include void proj1_func3(void) { printf("In proj1_func3.\n"); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0346591 meson-1.3.2/test cases/common/78 internal dependency/src/0000755000175000017500000000000014562742415023311 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/78 internal dependency/src/main.c0000644000175000017500000000025214516512250024367 0ustar00jpakkanejpakkane#include #include int main(void) { printf("Now calling into library.\n"); proj1_func1(); proj1_func2(); proj1_func3(); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/78 internal dependency/src/meson.build0000644000175000017500000000012714516512250025442 0ustar00jpakkanejpakkaneexe = executable('projtest', 'main.c', dependencies : proj1_dep) test('projtest', exe) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0346591 meson-1.3.2/test cases/common/79 same basename/0000755000175000017500000000000014562742415021271 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/79 same basename/exe1.c0000644000175000017500000000006714516512250022271 0ustar00jpakkanejpakkaneint func(void); int main(void) { return func(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/79 same basename/exe2.c0000644000175000017500000000010414516512250022262 0ustar00jpakkanejpakkaneint func(void); int main(void) { return func() == 1 ? 0 : 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/79 same basename/lib.c0000644000175000017500000000070314516512250022172 0ustar00jpakkanejpakkane#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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421514.0 meson-1.3.2/test cases/common/79 same basename/meson.build0000644000175000017500000000060514516755412023434 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0346591 meson-1.3.2/test cases/common/79 same basename/sharedsub/0000755000175000017500000000000014562742415023251 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/79 same basename/sharedsub/meson.build0000644000175000017500000000007614516512250025405 0ustar00jpakkanejpakkaneshlib = shared_library('name', '../lib.c', c_args : '-DSHAR') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0346591 meson-1.3.2/test cases/common/79 same basename/staticsub/0000755000175000017500000000000014562742415023272 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/79 same basename/staticsub/meson.build0000644000175000017500000000025614516512250025426 0ustar00jpakkanejpakkane# 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') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.038659 meson-1.3.2/test cases/common/8 install/0000755000175000017500000000000014562742415020166 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1619506185.0 meson-1.3.2/test cases/common/8 install/gendir.py0000755000175000017500000000024514041732011021773 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys, os dirname = sys.argv[1] fname = os.path.join(dirname, 'file.txt') os.makedirs(dirname, exist_ok=True) open(fname, 'w').close() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421447.0 meson-1.3.2/test cases/common/8 install/meson.build0000644000175000017500000000052614516755307022336 0ustar00jpakkanejpakkaneproject('install test', 'c', default_options : ['libdir=libtest']) stlib = static_library('stat', 'stat.c', install : true) exe = executable('prog', 'prog.c', install : true) dirtarget = custom_target('dirtarget', output: ['dir'], install: true, command: [find_program('gendir.py'), '@OUTPUT@'], install_dir: get_option('datadir')) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/8 install/prog.c0000644000175000017500000000004113716006331021262 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/8 install/stat.c0000644000175000017500000000003713716006331021273 0ustar00jpakkanejpakkaneint func(void) { return 933; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1619506185.0 meson-1.3.2/test cases/common/8 install/test.json0000644000175000017500000000044114041732011022016 0ustar00jpakkanejpakkane{ "installed": [ { "type": "exe", "file": "usr/bin/prog" }, { "type": "pdb", "file": "usr/bin/prog" }, { "type": "file", "file": "usr/share/dir/file.txt" }, { "type": "file", "file": "usr/libtest/libstat.a" } ], "do_not_set_opts": ["libdir"] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.038659 meson-1.3.2/test cases/common/80 declare dep/0000755000175000017500000000000014562742415020730 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.042659 meson-1.3.2/test cases/common/80 declare dep/entity/0000755000175000017500000000000014562742415022244 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/80 declare dep/entity/entity.h0000644000175000017500000000007614516512250023723 0ustar00jpakkanejpakkane#pragma once int entity_func1(void); int entity_func2(void); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/80 declare dep/entity/entity1.c0000644000175000017500000000021714516512250023774 0ustar00jpakkanejpakkane#include"entity.h" #ifdef USING_ENT #error "Entity use flag leaked into entity compilation." #endif int entity_func1(void) { return 5; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/80 declare dep/entity/entity2.c0000644000175000017500000000007514516512250023777 0ustar00jpakkanejpakkane#include int entity_func2(void) { return 9; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/80 declare dep/entity/meson.build0000644000175000017500000000060714516512250024400 0ustar00jpakkanejpakkaneentity_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.') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/80 declare dep/main.c0000644000175000017500000000051214516512250022005 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421515.0 meson-1.3.2/test cases/common/80 declare dep/meson.build0000644000175000017500000000130114516755413023066 0ustar00jpakkanejpakkaneproject('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]) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0466592 meson-1.3.2/test cases/common/81 extract all/0000755000175000017500000000000014562742415021004 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/81 extract all/extractor.h0000644000175000017500000000012214516512250023152 0ustar00jpakkanejpakkane#pragma once int func1(void); int func2(void); int func3(void); int func4(void); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/81 extract all/four.c0000644000175000017500000000007114516512250022110 0ustar00jpakkanejpakkane#include"extractor.h" int func4(void) { return 4; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421515.0 meson-1.3.2/test cases/common/81 extract all/meson.build0000644000175000017500000000110414516755413023143 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/81 extract all/one.c0000644000175000017500000000007114516512250021716 0ustar00jpakkanejpakkane#include"extractor.h" int func1(void) { return 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/81 extract all/prog.c0000644000175000017500000000031214516512250022102 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/81 extract all/three.c0000644000175000017500000000007114516512250022244 0ustar00jpakkanejpakkane#include"extractor.h" int func3(void) { return 3; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/81 extract all/two.c0000644000175000017500000000007114516512250021746 0ustar00jpakkanejpakkane#include"extractor.h" int func2(void) { return 2; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0466592 meson-1.3.2/test cases/common/82 add language/0000755000175000017500000000000014562742415021076 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421516.0 meson-1.3.2/test cases/common/82 add language/meson.build0000644000175000017500000000052314516755414023242 0ustar00jpakkanejpakkaneproject('add language', 'c') test('C', executable('cprog', 'prog.c')) assert(add_languages('cpp', native: false), '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')) add_languages('c', native: false) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/82 add language/prog.c0000644000175000017500000000012314516512250022174 0ustar00jpakkanejpakkane#include int main(void) { printf("I am plain C.\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/82 add language/prog.cc0000644000175000017500000000013414516512250022341 0ustar00jpakkanejpakkane#include int main(int, char**) { std::cout << "I am C++.\n"; return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0506592 meson-1.3.2/test cases/common/83 identical target name in subproject/0000755000175000017500000000000014562742415025437 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/83 identical target name in subproject/bar.c0000644000175000017500000000013514516512250026335 0ustar00jpakkanejpakkane#include int main(void) { printf("I'm a main project bar.\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421517.0 meson-1.3.2/test cases/common/83 identical target name in subproject/meson.build0000644000175000017500000000032614516755415027605 0ustar00jpakkanejpakkaneproject('toplevel bar', 'c') subproject('foo') true_cmd = find_program('true.py') executable('bar', 'bar.c') run_target('nop', command : [true_cmd]) custom_target('cus', output: ['cus.c'], command : [true_cmd]) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.9666276 meson-1.3.2/test cases/common/83 identical target name in subproject/subprojects/0000755000175000017500000000000014562742413030000 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0506592 meson-1.3.2/test cases/common/83 identical target name in subproject/subprojects/foo/0000755000175000017500000000000014562742415030565 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/83 identical target name in subproject/subprojects/foo/bar.c0000644000175000017500000000013314516512250031461 0ustar00jpakkanejpakkane#include int main(void) { printf("I'm a subproject bar.\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/83 identical target name in subproject/subprojects/foo/meson.build0000644000175000017500000000027514516512250032722 0ustar00jpakkanejpakkaneproject('subfoo', 'c') true_cmd = find_program('true.py') executable('bar', 'bar.c') run_target('nop', command : [true_cmd]) custom_target('cus', output: ['cus.c'], command : [true_cmd]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/83 identical target name in subproject/subprojects/foo/true.py0000644000175000017500000000007414516512250032106 0ustar00jpakkanejpakkane#!/usr/bin/env python3 if __name__ == '__main__': pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/83 identical target name in subproject/true.py0000644000175000017500000000007414516512250026760 0ustar00jpakkanejpakkane#!/usr/bin/env python3 if __name__ == '__main__': pass ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0506592 meson-1.3.2/test cases/common/84 plusassign/0000755000175000017500000000000014562742415020774 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421516.0 meson-1.3.2/test cases/common/84 plusassign/meson.build0000644000175000017500000000225214516755414023141 0ustar00jpakkanejpakkaneproject('plusassign') 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"') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0506592 meson-1.3.2/test cases/common/85 skip subdir/0000755000175000017500000000000014562742415021024 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421516.0 meson-1.3.2/test cases/common/85 skip subdir/meson.build0000644000175000017500000000005214516755414023165 0ustar00jpakkanejpakkaneproject('foo') subdir('subdir1/subdir2') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0506592 meson-1.3.2/test cases/common/85 skip subdir/subdir1/0000755000175000017500000000000014562742415022375 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/85 skip subdir/subdir1/meson.build0000644000175000017500000000004414516512250024524 0ustar00jpakkanejpakkaneerror('This should not be called.') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0506592 meson-1.3.2/test cases/common/85 skip subdir/subdir1/subdir2/0000755000175000017500000000000014562742415023747 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/85 skip subdir/subdir1/subdir2/meson.build0000644000175000017500000000004214516512250026074 0ustar00jpakkanejpakkanemessage('I\'m in subdir subdir.') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0506592 meson-1.3.2/test cases/common/86 private include/0000755000175000017500000000000014562742415021664 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421518.0 meson-1.3.2/test cases/common/86 private include/meson.build0000644000175000017500000000007714516755416024036 0ustar00jpakkanejpakkaneproject('access private', 'c') subdir('stlib') subdir('user') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0586593 meson-1.3.2/test cases/common/86 private include/stlib/0000755000175000017500000000000014562742415023001 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/86 private include/stlib/compiler.py0000755000175000017500000000101714516512250025156 0ustar00jpakkanejpakkane#!/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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/86 private include/stlib/foo1.def0000644000175000017500000000000014516512250024302 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/86 private include/stlib/foo2.def0000644000175000017500000000000014516512250024303 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/86 private include/stlib/meson.build0000644000175000017500000000045214516512250025133 0ustar00jpakkanejpakkanegenbin = 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() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0586593 meson-1.3.2/test cases/common/86 private include/user/0000755000175000017500000000000014562742415022642 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/86 private include/user/libuser.c0000644000175000017500000000012214516512250024435 0ustar00jpakkanejpakkane#include"foo1.h" #include"foo2.h" int main(void) { return foo1() + foo2(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/86 private include/user/meson.build0000644000175000017500000000017114516512250024772 0ustar00jpakkanejpakkaneexe = executable('libuser', 'libuser.c', link_with : stlib, include_directories : st_priv_inc) test('libuser', exe) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0586593 meson-1.3.2/test cases/common/87 default options/0000755000175000017500000000000014562742415021707 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421519.0 meson-1.3.2/test cases/common/87 default options/meson.build0000644000175000017500000000234414516755417024061 0ustar00jpakkanejpakkaneproject('default options', 'cpp', 'c', default_options : [ 'prefix=/absoluteprefix', 'buildtype=debugoptimized', 'cpp_std=c++11', 'cpp_eh=none', 'warning_level=3', 'sub1:test_option=false', ]) 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 subproject('sub1') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.9746277 meson-1.3.2/test cases/common/87 default options/subprojects/0000755000175000017500000000000014562742413024250 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0586593 meson-1.3.2/test cases/common/87 default options/subprojects/sub1/0000755000175000017500000000000014562742415025124 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/87 default options/subprojects/sub1/meson.build0000644000175000017500000000007414516512250027256 0ustar00jpakkanejpakkaneproject('sub1') assert(get_option('test_option') == false) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/87 default options/subprojects/sub1/meson_options.txt0000644000175000017500000000017614516512250030554 0ustar00jpakkanejpakkaneoption('test_option', type : 'boolean', value : true, description : 'Test option. Superproject overrides default to "false"') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0586593 meson-1.3.2/test cases/common/88 dep fallback/0000755000175000017500000000000014562742415021100 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/88 dep fallback/gensrc.py0000644000175000017500000000013414516512250022720 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys import shutil shutil.copyfile(sys.argv[1], sys.argv[2]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421521.0 meson-1.3.2/test cases/common/88 dep fallback/meson.build0000644000175000017500000000266114516755421023247 0ustar00jpakkanejpakkaneproject('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 bobinc is not a dependency variable sita = dependency('sitalib', fallback : ['boblib', 'bobinc'], required: false) assert(not sita.found()) # boblib subproject exists, but sita_dep doesn't exist sita = dependency('sitalib', fallback : ['boblib', 'sita_dep'], required: false) assert(not sita.found()) # boblib has been configured so zlib cannot be searched on the system zlib = dependency('zlib', fallback : ['boblib', 'notfound_dep'], required: false) assert(not zlib.found()) # boblib has been configured so zlib cannot be searched on the system. # Not variable name provided and the subproject does not override zlib. zlib = dependency('zlib', fallback : 'boblib', required: false) assert(not zlib.found()) # 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) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853066.978628 meson-1.3.2/test cases/common/88 dep fallback/subprojects/0000755000175000017500000000000014562742413023441 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0626595 meson-1.3.2/test cases/common/88 dep fallback/subprojects/boblib/0000755000175000017500000000000014562742415024674 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/88 dep fallback/subprojects/boblib/bob.c0000644000175000017500000000015614516512250025573 0ustar00jpakkanejpakkane#include"bob.h" #ifdef _MSC_VER __declspec(dllexport) #endif const char* get_bob(void) { return "bob"; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/88 dep fallback/subprojects/boblib/bob.h0000644000175000017500000000012614516512250025575 0ustar00jpakkanejpakkane#pragma once #ifdef _MSC_VER __declspec(dllimport) #endif const char* get_bob(void); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/88 dep fallback/subprojects/boblib/genbob.py0000644000175000017500000000012614516512250026470 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys with open(sys.argv[1], 'w') as f: f.write('') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/88 dep fallback/subprojects/boblib/meson.build0000644000175000017500000000074714516512250027035 0ustar00jpakkanejpakkaneproject('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) notfound_dep = dependency('', required: false) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0626595 meson-1.3.2/test cases/common/88 dep fallback/subprojects/dummylib/0000755000175000017500000000000014562742415025265 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/88 dep fallback/subprojects/dummylib/meson.build0000644000175000017500000000014714516512250027420 0ustar00jpakkanejpakkaneproject('dummylib', 'c') dummy_dep = declare_dependency() error('this subproject fails to configure') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/88 dep fallback/tester.c0000644000175000017500000000041314516512250022537 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0666595 meson-1.3.2/test cases/common/89 default library/0000755000175000017500000000000014562742415021662 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/89 default library/ef.cpp0000644000175000017500000000014414516512250022746 0ustar00jpakkanejpakkane#include"ef.h" DLL_PUBLIC Ef::Ef() : x(99) { } int DLL_PUBLIC Ef::get_x() const { return x; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/89 default library/ef.h0000644000175000017500000000062614516512250022420 0ustar00jpakkanejpakkane#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; }; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/89 default library/eftest.cpp0000644000175000017500000000036514516512250023653 0ustar00jpakkanejpakkane#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; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421520.0 meson-1.3.2/test cases/common/89 default library/meson.build0000644000175000017500000000051614516755420024025 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0666595 meson-1.3.2/test cases/common/9 header install/0000755000175000017500000000000014562742415021400 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0666595 meson-1.3.2/test cases/common/9 header install/child/0000755000175000017500000000000014562742415022463 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/common/9 header install/child/childdir.h0000644000175000017500000000026514253672217024420 0ustar00jpakkanejpakkane/* This file goes, depending on the state of `preserve_path` into subdirectory of include root or into the `child` dir of the subdirectory of include root. */ int childdir_func(); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421448.0 meson-1.3.2/test cases/common/9 header install/meson.build0000644000175000017500000000051714516755310023542 0ustar00jpakkanejpakkaneproject('header install') as_array = ['subdir.h', 'child/childdir.h'] subdir('vanishing_subdir') subdir('sub') h1 = install_headers('rootdir.h') h2 = install_headers(as_array, subdir : 'subdir') h3 = install_headers(as_array, subdir : 'subdir', preserve_path : true) h4 = install_headers(subheader) h5 = install_headers(disabler()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/9 header install/rootdir.h0000644000175000017500000000007613716006331023224 0ustar00jpakkanejpakkane/* This header goes to include dir root. */ int root_func(); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0666595 meson-1.3.2/test cases/common/9 header install/sub/0000755000175000017500000000000014562742415022171 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/9 header install/sub/fileheader.h0000644000175000017500000000007113716006331024416 0ustar00jpakkanejpakkane#pragma once #define LIFE "Is life! Na naa, naa-na na." ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/common/9 header install/sub/meson.build0000644000175000017500000000004214140314117024311 0ustar00jpakkanejpakkanesubheader = files('fileheader.h') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/9 header install/subdir.h0000644000175000017500000000011213716006331023021 0ustar00jpakkanejpakkane/* This file goes to subdirectory of include root. */ int subdir_func(); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/common/9 header install/test.json0000644000175000017500000000063414253672217023254 0ustar00jpakkanejpakkane{ "installed": [ { "type": "file", "file": "usr/include/rootdir.h" }, { "type": "file", "file": "usr/include/subdir/subdir.h" }, { "type": "file", "file": "usr/include/subdir/childdir.h" }, { "type": "file", "file": "usr/include/subdir/child/childdir.h" }, { "type": "file", "file": "usr/include/vanished.h" }, { "type": "file", "file": "usr/include/fileheader.h" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0666595 meson-1.3.2/test cases/common/9 header install/vanishing_subdir/0000755000175000017500000000000014562742415024736 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/9 header install/vanishing_subdir/meson.build0000644000175000017500000000003613716006331027065 0ustar00jpakkanejpakkaneinstall_headers('vanished.h') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/common/9 header install/vanishing_subdir/vanished.h0000644000175000017500000000022113716006331026671 0ustar00jpakkanejpakkane#pragma once /* This is a header in a subdirectory. Make sure it installs into * /prefix/include and not /prefix/include/vanishing_subdir. */ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0706596 meson-1.3.2/test cases/common/90 gen extra/0000755000175000017500000000000014562742415020456 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421521.0 meson-1.3.2/test cases/common/90 gen extra/meson.build0000644000175000017500000000217514516755421022625 0ustar00jpakkanejpakkaneproject('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)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/90 gen extra/name.dat0000644000175000017500000000001214516512250022050 0ustar00jpakkanejpakkanebob_mcbob ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/90 gen extra/name.l0000644000175000017500000000003514516512250021540 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/90 gen extra/plain.c0000644000175000017500000000010114516512250021704 0ustar00jpakkanejpakkaneint bob_mcbob(void); int main(void) { return bob_mcbob(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421271.0 meson-1.3.2/test cases/common/90 gen extra/srcgen.py0000755000175000017500000000124614516755027022321 0ustar00jpakkanejpakkane#!/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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/90 gen extra/srcgen2.py0000644000175000017500000000130314516512250022357 0ustar00jpakkanejpakkane#!/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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/90 gen extra/srcgen3.py0000644000175000017500000000043114516512250022361 0ustar00jpakkanejpakkane#!/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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/90 gen extra/upper.c0000644000175000017500000000010114516512250021734 0ustar00jpakkanejpakkaneint BOB_MCBOB(void); int main(void) { return BOB_MCBOB(); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0706596 meson-1.3.2/test cases/common/91 benchmark/0000755000175000017500000000000014562742415020534 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/91 benchmark/delayer.c0000644000175000017500000000056014516512250022315 0ustar00jpakkanejpakkane/* 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421522.0 meson-1.3.2/test cases/common/91 benchmark/meson.build0000644000175000017500000000020014516755422022667 0ustar00jpakkanejpakkaneproject('benchmark', 'c') delayer = executable('delayer', 'delayer.c', c_args : '-D_GNU_SOURCE') benchmark('delayer', delayer) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0706596 meson-1.3.2/test cases/common/92 test workdir/0000755000175000017500000000000014562742415021224 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421524.0 meson-1.3.2/test cases/common/92 test workdir/meson.build0000644000175000017500000000026614516755424023375 0ustar00jpakkanejpakkaneproject('test workdir', 'c') exe = executable('opener', 'opener.c') test('basic', exe, workdir : meson.source_root()) test('shouldfail', exe, should_fail : true) subdir('subdir') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/92 test workdir/opener.c0000644000175000017500000000031414516512250022645 0ustar00jpakkanejpakkane// 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; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0706596 meson-1.3.2/test cases/common/92 test workdir/subdir/0000755000175000017500000000000014562742415022514 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/92 test workdir/subdir/checker.py0000755000175000017500000000011214516512250024456 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys data = open(sys.argv[1], 'rb').read() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/92 test workdir/subdir/meson.build0000644000175000017500000000020614516512250024643 0ustar00jpakkanejpakkaneexe2 = executable('dummy', '../opener.c') test('subdir', find_program('checker.py'), workdir : meson.source_root(), args: [exe2]) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0786598 meson-1.3.2/test cases/common/93 suites/0000755000175000017500000000000014562742415020120 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/93 suites/exe1.c0000644000175000017500000000012514516512250021113 0ustar00jpakkanejpakkane#include int main(void) { printf("I am test exe1.\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/93 suites/exe2.c0000644000175000017500000000012514516512250021114 0ustar00jpakkanejpakkane#include int main(void) { printf("I am test exe2.\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421525.0 meson-1.3.2/test cases/common/93 suites/meson.build0000644000175000017500000000031714516755425022267 0ustar00jpakkanejpakkaneproject('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']]) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853066.978628 meson-1.3.2/test cases/common/93 suites/subprojects/0000755000175000017500000000000014562742413022461 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0786598 meson-1.3.2/test cases/common/93 suites/subprojects/sub/0000755000175000017500000000000014562742415023254 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/93 suites/subprojects/sub/meson.build0000644000175000017500000000025114516512250025403 0ustar00jpakkanejpakkaneproject('subproject test suites', 'c') sub1 = executable('sub1', 'sub1.c') sub2 = executable('sub2', 'sub2.c') test('sub1', sub1) test('sub2', sub2, suite : 'suite2') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/93 suites/subprojects/sub/sub1.c0000644000175000017500000000012514516512250024257 0ustar00jpakkanejpakkane#include int main(void) { printf("I am test sub1.\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/93 suites/subprojects/sub/sub2.c0000644000175000017500000000012514516512250024260 0ustar00jpakkanejpakkane#include int main(void) { printf("I am test sub2.\n"); return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0786598 meson-1.3.2/test cases/common/94 threads/0000755000175000017500000000000014562742415020237 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421526.0 meson-1.3.2/test cases/common/94 threads/meson.build0000644000175000017500000000067214516755426022413 0ustar00jpakkanejpakkaneproject('threads', 'cpp', 'c', default_options : ['cpp_std=c++11']) cc = meson.get_compiler('c') if cc.has_function_attribute('unused') add_project_arguments('-DHAVE_UNUSED', language: 'c') endif threaddep = dependency('threads') test('cppthreadtest', executable('cppthreadprog', 'threadprog.cpp', dependencies : threaddep ) ) test('cthreadtest', executable('cthreadprog', 'threadprog.c', dependencies : threaddep ) ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/94 threads/threadprog.c0000644000175000017500000000155014516512250022532 0ustar00jpakkanejpakkane#if defined _WIN32 #include #include DWORD WINAPI thread_func(void *arg) { 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 #ifdef HAVE_UNUSED #define UNUSED_ATTR __attribute__((unused)) #else #define UNUSED_ATTR #endif void* main_func(void UNUSED_ATTR *arg) { 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/94 threads/threadprog.cpp0000644000175000017500000000156014516512250023073 0ustar00jpakkanejpakkane/* 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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0786598 meson-1.3.2/test cases/common/95 manygen/0000755000175000017500000000000014562742415020244 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/95 manygen/depuser.c0000644000175000017500000000035314516512250022047 0ustar00jpakkanejpakkane#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); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421525.0 meson-1.3.2/test cases/common/95 manygen/meson.build0000644000175000017500000000046014516755425022412 0ustar00jpakkanejpakkaneproject('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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0786598 meson-1.3.2/test cases/common/95 manygen/subdir/0000755000175000017500000000000014562742415021534 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/95 manygen/subdir/funcinfo.def0000644000175000017500000000001114516512250024002 0ustar00jpakkanejpakkanegen_func ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/95 manygen/subdir/manygen.py0000755000175000017500000000347414516512250023546 0ustar00jpakkanejpakkane#!/usr/bin/env python3 # 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"{}.h" int {}_in_src(void) {{ return 0; }} '''.format(funcname, funcname)) with open(outh, 'w') as f: f.write('''#pragma once int {}_in_lib(void); int {}_in_obj(void); int {}_in_src(void); '''.format(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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/95 manygen/subdir/meson.build0000644000175000017500000000163114516512250023666 0ustar00jpakkanejpakkanegen = 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()], ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0786598 meson-1.3.2/test cases/common/96 stringdef/0000755000175000017500000000000014562742415020574 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421527.0 meson-1.3.2/test cases/common/96 stringdef/meson.build0000644000175000017500000000015514516755427022745 0ustar00jpakkanejpakkaneproject('stringdef', 'c') test('stringdef', executable('stringdef', 'stringdef.c', c_args : '-DFOO="bar"')) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/96 stringdef/stringdef.c0000644000175000017500000000025314516512250022714 0ustar00jpakkanejpakkane#include #include int main(void) { if(strcmp(FOO, "bar")) { printf("FOO is misquoted: %s\n", FOO); return 1; } return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0786598 meson-1.3.2/test cases/common/97 find program path/0000755000175000017500000000000014562742415022075 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421528.0 meson-1.3.2/test cases/common/97 find program path/meson.build0000644000175000017500000000151114516755430024235 0ustar00jpakkanejpakkaneproject('find program') 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, check: false) 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, check: false) assert(ret.returncode() == 0, 'can\'t run @0@'.format(prog.path())) assert(ret.stdout().strip() == 'Found', 'wrong output from @0@'.format(prog.path())) endforeach ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/97 find program path/program.py0000755000175000017500000000004714516512250024111 0ustar00jpakkanejpakkane#!/usr/bin/env python3 print("Found") ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0826597 meson-1.3.2/test cases/common/98 subproject subdir/0000755000175000017500000000000014562742415022242 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421531.0 meson-1.3.2/test cases/common/98 subproject subdir/meson.build0000644000175000017500000000756314516755433024422 0ustar00jpakkanejpakkaneproject('proj', 'c') subproject('sub') libSub = dependency('sub', fallback: ['sub', 'libSub']) exe = executable('prog', 'prog.c', dependencies: libSub) test('subproject subdir', exe) # Verify the subproject has placed dependency override. dependency('sub-1.0') # Verify we can now take 'sub' dependency without fallback, but only version 1.0. dependency('sub') d = dependency('sub', version : '>=2.0', required : false) assert(not d.found(), 'version should not match') # Verify that not-found does not get cached, we can still fallback afterward. dependency('sub2', required : false) d = dependency('sub2', fallback: ['sub', 'libSub']) assert(d.found(), 'Should fallback even if a previous call returned not-found') # Verify we can get a fallback dependency without specifying the variable name, # because the subproject overridden 'sub-novar'. dependency('sub-novar', fallback : 'sub_novar') # Verify a subproject can force a dependency to be not-found d = dependency('sub-notfound', fallback : 'sub_novar', required : false) assert(not d.found(), 'Dependency should be not-found') # Verify that implicit fallback works because subprojects/sub_implicit directory exists d = dependency('sub_implicit', default_options: 'opt=overridden') assert(d.found(), 'Should implicitly fallback') # Verify that implicit fallback works because sub_implicit.wrap has # `dependency_names=sub_implicit_provide1` and the subproject overrides sub_implicit_provide1. d = dependency('sub_implicit_provide1') assert(d.found(), 'Should implicitly fallback') # Verify that implicit fallback works because sub_implicit.wrap has # `sub_implicit_provide2=sub_implicit_provide2_dep` and does not override # sub_implicit_provide2. d = dependency('sub_implicit_provide2') assert(d.found(), 'Should implicitly fallback') # sub_implicit.wrap provides glib-2.0 and we already configured that subproject, # so we must not return the system dependency here. Using glib-2.0 here because # some CI runners have it installed. d = dependency('glib-2.0', required : false) assert(d.found()) assert(d.type_name() == 'internal') # sub_implicit.wrap provides gobject-2.0 and we already configured that subproject, # so we must not return the system dependency here. But since the subproject did # not override that dependency and its not required, not-found should be returned. # Using gobject-2.0 here because some CI runners have it installed. d = dependency('gobject-2.0', required : false) assert(not d.found()) # Verify that implicit fallback works because subprojects/sub_implicit/subprojects/subsub # directory exists. d = dependency('subsub') assert(d.found(), 'Should be able to fallback to sub-subproject') # Verify that implicit fallback works because # subprojects/sub_implicit/subprojects/subsub/subprojects/subsubsub.wrap # file exists. d = dependency('subsubsub') assert(d.found(), 'Should be able to fallback to sub-sub-subproject') # Verify that `static: true` implies 'default_library=static'. d = dependency('sub_static', static: true) assert(d.found()) # Verify that when not specifying static kwarg we can still get fallback dep. d = dependency('sub_static') assert(d.found()) # But when asking for shared library explicitly, it is not found. d = dependency('sub_static', static: false, required: false) assert(not d.found()) # The subproject also overrides sub_static2 with `static: true` d = dependency('sub_static2') assert(d.found()) d = dependency('sub_static2', static: true) assert(d.found()) d = dependency('sub_static2', static: false, required: false) assert(not d.found()) # sub_static3 is overridden twice with `static: true` and `static: false` d = dependency('sub_static3') assert(d.found()) assert(d.get_variable('static') == 'true') d = dependency('sub_static3', static: true) assert(d.found()) assert(d.get_variable('static') == 'true') d = dependency('sub_static3', static: false) assert(d.found()) assert(d.get_variable('static') == 'false') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/98 subproject subdir/prog.c0000644000175000017500000000006714516512250023347 0ustar00jpakkanejpakkane#include int main(void) { return sub(); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0826597 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/0000755000175000017500000000000014562742415024605 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0826597 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub/0000755000175000017500000000000014562742415025376 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.0826597 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub/lib/0000755000175000017500000000000014562742415026144 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub/lib/meson.build0000644000175000017500000000025514516512250030277 0ustar00jpakkanejpakkanelib = static_library('sub', 'sub.c') libSub = declare_dependency(include_directories: include_directories('.'), link_with: lib) meson.override_dependency('sub-1.0', libSub) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub/lib/sub.c0000644000175000017500000000006214516512250027066 0ustar00jpakkanejpakkane#include "sub.h" int sub(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub/lib/sub.h0000644000175000017500000000006414516512250027075 0ustar00jpakkanejpakkane#ifndef SUB_H #define SUB_H int sub(void); #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub/meson.build0000644000175000017500000000006314516512250027526 0ustar00jpakkanejpakkaneproject('sub', 'c', version : '1.0') subdir('lib') ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1707853069.08666 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub_implicit/0000755000175000017500000000000014562742415027270 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub_implicit/meson.build0000644000175000017500000000065314516512250031425 0ustar00jpakkanejpakkaneproject('sub_implicit', 'c', version : '1.0') dep = declare_dependency() meson.override_dependency('sub_implicit', dep) meson.override_dependency('sub_implicit_provide1', dep) # This one is not overridden but the wrap file tells the variable name to use. sub_implicit_provide2_dep = dep # This one is not overridden but the wrap file tells the variable name to use. glib_dep = dep assert(get_option('opt') == 'overridden') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub_implicit/meson_options.txt0000644000175000017500000000005714516512250032716 0ustar00jpakkanejpakkaneoption('opt', type: 'string', value: 'default')././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853066.978628 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub_implicit/subprojects/0000755000175000017500000000000014562742413031631 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1707853069.08666 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub_implicit/subprojects/subsub/0000755000175000017500000000000014562742415033136 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub_implicit/subprojects/subsub/foo.h0000644000175000017500000000002114516512250034052 0ustar00jpakkanejpakkane#define DUMMY 42 ././@PaxHeader0000000000000000000000000000021200000000000010210 xustar00116 path=meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub_implicit/subprojects/subsub/meson.build 22 mtime=1698337960.0 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub_implicit/subprojects/subsub/meson0000644000175000017500000000040714516512250034172 0ustar00jpakkanejpakkaneproject('subsub') meson.override_dependency('subsub', declare_dependency()) # Regression test: Installing a header from nested sub-subproject used to raise: # ERROR: Sandbox violation: Tried to grab file foo.h from a nested subproject. install_headers('foo.h') ././@PaxHeader0000000000000000000000000000021700000000000010215 xustar00117 path=meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub_implicit/subprojects/subsub/subprojects/ 26 mtime=1707853069.08666 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub_implicit/subprojects/subsub/subpr0000755000175000017500000000000014562742415034212 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000023400000000000010214 xustar00130 path=meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub_implicit/subprojects/subsub/subprojects/packagefiles/ 26 mtime=1707853069.08666 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub_implicit/subprojects/subsub/subpr0000755000175000017500000000000014562742415034212 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000025100000000000010213 xustar00147 path=meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub_implicit/subprojects/subsub/subprojects/packagefiles/subsubsub-1.0.zip 22 mtime=1698337960.0 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub_implicit/subprojects/subsub/subpr0000644000175000017500000000070714516512250034207 0ustar00jpakkanejpakkanePKī{P subsubsub-1.0/UT ¾”^¾”^¾”^ux ččPKī{PS subsubsub-1.0/meson.buildUT ¾”^¾”^¾”^ux čč+(ŹĻJM.ŃP/.M‚ uM.®ÜŌāü<½ü²Ō¢¢Ģ”Ōų”Ō‚Ō¼”Ō¼äJdu: )©É9‰E(ņšš\PK}šŪy;SPKī{P ķAsubsubsub-1.0/UT ¾”^¾”^¾”^ux ččPKī{P}šŪy;S ¤Lsubsubsub-1.0/meson.buildUT ¾”^¾”^¾”^ux ččPKĆī././@PaxHeader0000000000000000000000000000023100000000000010211 xustar00131 path=meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub_implicit/subprojects/subsub/subprojects/subsubsub.wrap 22 mtime=1698337960.0 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub_implicit/subprojects/subsub/subpr0000644000175000017500000000023114516512250034177 0ustar00jpakkanejpakkane[wrap-file] directory = subsubsub-1.0 source_filename = subsubsub-1.0.zip source_hash = c073a96b7251937e53216578f6f03d91b84816618a0f1ce3ecfb867beddf1498 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub_implicit.wrap0000644000175000017500000000022314516512250030147 0ustar00jpakkanejpakkane[wrap-file] [provide] glib-2.0 = glib_dep dependency_names = sub_implicit_provide1, gobject-2.0 sub_implicit_provide2 = sub_implicit_provide2_dep ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1707853069.08666 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub_novar/0000755000175000017500000000000014562742415026603 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub_novar/meson.build0000644000175000017500000000026514516512250030737 0ustar00jpakkanejpakkaneproject('sub-novar', 'c', version : '1.0') meson.override_dependency('sub-novar', declare_dependency()) meson.override_dependency('sub-notfound', dependency('', required : false)) ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1707853069.09466 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub_static/0000755000175000017500000000000014562742415026745 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/98 subproject subdir/subprojects/sub_static/meson.build0000644000175000017500000000065314516512250031102 0ustar00jpakkanejpakkaneproject('sub_static') assert(get_option('default_library') == 'static') meson.override_dependency('sub_static', declare_dependency()) meson.override_dependency('sub_static2', declare_dependency(), static: true) meson.override_dependency('sub_static3', declare_dependency(variables: {'static': 'true'}), static: true) meson.override_dependency('sub_static3', declare_dependency(variables: {'static': 'false'}), static: false) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698339787.0 meson-1.3.2/test cases/common/98 subproject subdir/test.json0000644000175000017500000000011514516515713024107 0ustar00jpakkanejpakkane{ "installed": [ { "type": "file", "file": "usr/include/foo.h" } ] } ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1707853069.09466 meson-1.3.2/test cases/common/99 postconf/0000755000175000017500000000000014562742415020445 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421529.0 meson-1.3.2/test cases/common/99 postconf/meson.build0000644000175000017500000000016614516755431022613 0ustar00jpakkanejpakkaneproject('postconf script', 'c') meson.add_postconf_script('postconf.py') test('post', executable('prog', 'prog.c')) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/99 postconf/postconf.py0000644000175000017500000000062014516512250022637 0ustar00jpakkanejpakkane#!/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, encoding='utf-8') as f: data = f.readline().strip() with open(output_file, 'w', encoding='utf-8') as f: f.write(template.format(data)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/99 postconf/prog.c0000644000175000017500000000010614516512250021544 0ustar00jpakkanejpakkane#include"generated.h" int main(void) { return THE_NUMBER != 9; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698337960.0 meson-1.3.2/test cases/common/99 postconf/raw.dat0000644000175000017500000000000214516512250021707 0ustar00jpakkanejpakkane9 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853066.9866278 meson-1.3.2/test cases/csharp/0000755000175000017500000000000014562742413016356 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1707853069.09866 meson-1.3.2/test cases/csharp/1 basic/0000755000175000017500000000000014562742415017562 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421704.0 meson-1.3.2/test cases/csharp/1 basic/meson.build0000644000175000017500000000015214516755710021723 0ustar00jpakkanejpakkaneproject('simple c#', 'cs') e = executable('prog', 'prog.cs', 'text.cs', install : true) test('basic', e) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/csharp/1 basic/prog.cs0000644000175000017500000000023713716006331021050 0ustar00jpakkanejpakkaneusing System; public class Prog { static public void Main () { TextGetter tg = new TextGetter(); Console.WriteLine(tg.getText()); } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/csharp/1 basic/test.json0000644000175000017500000000016713716006331021426 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/bin/prog.exe"}, {"type": "pdb", "file": "usr/bin/prog"} ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/csharp/1 basic/text.cs0000644000175000017500000000016013716006331021060 0ustar00jpakkanejpakkaneusing System; public class TextGetter { public String getText() { return "C# is working."; } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1026602 meson-1.3.2/test cases/csharp/2 library/0000755000175000017500000000000014562742415020146 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/csharp/2 library/helper.cs0000644000175000017500000000017313716006331021743 0ustar00jpakkanejpakkaneusing System; public class Helper { public void print() { Console.WriteLine("Library class called."); } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421707.0 meson-1.3.2/test cases/csharp/2 library/meson.build0000644000175000017500000000070214516755713022313 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/csharp/2 library/prog.cs0000644000175000017500000000020013716006331021422 0ustar00jpakkanejpakkaneusing System; public class Prog { static public void Main () { Helper h = new Helper(); h.print(); } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/csharp/2 library/test.json0000644000175000017500000000046513716006331022013 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/bin/prog.exe"}, {"type": "pdb", "file": "usr/bin/prog"}, {"type": "file", "platform": "msvc", "file": "usr/bin/helper.dll"}, {"type": "pdb", "file": "usr/bin/helper"}, {"type": "file", "platform": "gcc", "file": "usr/lib/helper.dll"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1026602 meson-1.3.2/test cases/csharp/3 resource/0000755000175000017500000000000014562742415020332 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/csharp/3 resource/TestRes.resx0000644000175000017500000000360213716006331022615 0ustar00jpakkanejpakkane 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! ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421708.0 meson-1.3.2/test cases/csharp/3 resource/meson.build0000644000175000017500000000016614516755714022504 0ustar00jpakkanejpakkaneproject('C# resource', 'cs') e = executable('resprog', 'resprog.cs', resources : 'TestRes.resx') test('restest', e) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/csharp/3 resource/resprog.cs0000644000175000017500000000040213716006331022324 0ustar00jpakkanejpakkaneusing 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 { } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1026602 meson-1.3.2/test cases/csharp/4 external dep/0000755000175000017500000000000014562742415021057 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/csharp/4 external dep/hello.txt0000644000175000017500000000001513716006331022705 0ustar00jpakkanejpakkaneHello World! ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421709.0 meson-1.3.2/test cases/csharp/4 external dep/meson.build0000644000175000017500000000052114516755715023225 0ustar00jpakkanejpakkaneproject('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')]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/csharp/4 external dep/prog.cs0000644000175000017500000000025113716006331022341 0ustar00jpakkanejpakkaneusing System; using GLib; public class Prog { static public void Main (string[] args) { Console.WriteLine(GLib.FileUtils.GetFileContents(args[0])); } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/csharp/4 external dep/test.json0000644000175000017500000000011213716006331022711 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/bin/prog.exe"} ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853066.994628 meson-1.3.2/test cases/cuda/0000755000175000017500000000000014562742413016012 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1026602 meson-1.3.2/test cases/cuda/1 simple/0000755000175000017500000000000014562742415017426 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/cuda/1 simple/meson.build0000644000175000017500000000015014140314117021546 0ustar00jpakkanejpakkaneproject('simple', 'cuda', version : '1.0.0') exe = executable('prog', 'prog.cu') test('cudatest', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/cuda/1 simple/prog.cu0000644000175000017500000000244414140314117020714 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1026602 meson-1.3.2/test cases/cuda/10 cuda dependency/0000755000175000017500000000000014562742415021230 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1026602 meson-1.3.2/test cases/cuda/10 cuda dependency/c/0000755000175000017500000000000014562742415021452 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/10 cuda dependency/c/meson.build0000644000175000017500000000013313716006331023577 0ustar00jpakkanejpakkaneexe = executable('prog', 'prog.c', dependencies: dependency('cuda')) test('cudatest', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/10 cuda dependency/c/prog.c0000644000175000017500000000053313716006331022554 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1026602 meson-1.3.2/test cases/cuda/10 cuda dependency/cpp/0000755000175000017500000000000014562742415022012 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/10 cuda dependency/cpp/meson.build0000644000175000017500000000013413716006331024140 0ustar00jpakkanejpakkaneexe = executable('prog', 'prog.cc', dependencies: dependency('cuda')) test('cudatest', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/10 cuda dependency/cpp/prog.cc0000644000175000017500000000055413716006331023262 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/10 cuda dependency/meson.build0000644000175000017500000000015313716006331023357 0ustar00jpakkanejpakkaneproject('cuda dependency', 'c', 'cpp') subdir('c') subdir('cpp') subdir('modules') subdir('version_reqs') ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1707853069.11066 meson-1.3.2/test cases/cuda/10 cuda dependency/modules/0000755000175000017500000000000014562742415022700 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/10 cuda dependency/modules/meson.build0000644000175000017500000000016113716006331025026 0ustar00jpakkanejpakkaneexe = executable('prog', 'prog.cc', dependencies: dependency('cuda', modules: ['cublas'])) test('cudatest', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/10 cuda dependency/modules/prog.cc0000644000175000017500000000136513716006331024151 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1707853069.11066 meson-1.3.2/test cases/cuda/10 cuda dependency/version_reqs/0000755000175000017500000000000014562742415023747 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/10 cuda dependency/version_reqs/meson.build0000644000175000017500000000023013716006331026072 0ustar00jpakkanejpakkaneexe = executable('prog', 'prog.cc', dependencies: dependency('cuda', version: ['>=8.5', '<10'], required: false, disabler: true)) test('cudatest', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/10 cuda dependency/version_reqs/prog.cc0000644000175000017500000000135513716006331025217 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1707853069.11066 meson-1.3.2/test cases/cuda/11 cuda dependency (nvcc)/0000755000175000017500000000000014562742415022264 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/11 cuda dependency (nvcc)/meson.build0000644000175000017500000000011513716006331024411 0ustar00jpakkanejpakkaneproject('cuda dependency', 'cuda') subdir('modules') subdir('version_reqs') ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1707853069.11066 meson-1.3.2/test cases/cuda/11 cuda dependency (nvcc)/modules/0000755000175000017500000000000014562742415023734 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/11 cuda dependency (nvcc)/modules/meson.build0000644000175000017500000000016113716006331026062 0ustar00jpakkanejpakkaneexe = executable('prog', 'prog.cu', dependencies: dependency('cuda', modules: ['cublas'])) test('cudatest', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/11 cuda dependency (nvcc)/modules/prog.cu0000644000175000017500000000136513716006331025227 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1707853069.11066 meson-1.3.2/test cases/cuda/11 cuda dependency (nvcc)/version_reqs/0000755000175000017500000000000014562742415025003 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/11 cuda dependency (nvcc)/version_reqs/meson.build0000644000175000017500000000022213716006331027127 0ustar00jpakkanejpakkaneexe = executable('prog', 'prog.cu', dependencies: dependency('cuda', version: ['>=10.1'], required: false, disabler: true)) test('cudatest', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/11 cuda dependency (nvcc)/version_reqs/prog.cu0000644000175000017500000000147113716006331026274 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1707853069.11066 meson-1.3.2/test cases/cuda/12 cuda dependency (mixed)/0000755000175000017500000000000014562742415022442 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/12 cuda dependency (mixed)/kernel.cu0000644000175000017500000000015713716006331024244 0ustar00jpakkanejpakkane#include __global__ void kernel (void){ } void do_cuda_stuff(void) { kernel<<<1,1>>>(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/12 cuda dependency (mixed)/meson.build0000644000175000017500000000025213716006331024571 0ustar00jpakkanejpakkaneproject('cuda dependency', 'cpp', 'cuda') exe = executable('prog', 'prog.cpp', 'kernel.cu', dependencies: dependency('cuda', modules: ['cublas'])) test('cudatest', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/12 cuda dependency (mixed)/prog.cpp0000644000175000017500000000144613716006331024110 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1707853069.11066 meson-1.3.2/test cases/cuda/13 cuda compiler setting/0000755000175000017500000000000014562742415022365 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/cuda/13 cuda compiler setting/meson.build0000644000175000017500000000015014140314117024505 0ustar00jpakkanejpakkaneproject('simple', 'cuda', version : '1.0.0') exe = executable('prog', 'prog.cu') test('cudatest', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/cuda/13 cuda compiler setting/nativefile.ini0000644000175000017500000000003214140314117025171 0ustar00jpakkanejpakkane[binaries] cuda = 'nvcc' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/cuda/13 cuda compiler setting/prog.cu0000644000175000017500000000244414140314117023653 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1707853069.11066 meson-1.3.2/test cases/cuda/14 cuda has header symbol/0000755000175000017500000000000014562742415022370 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/cuda/14 cuda has header symbol/meson.build0000644000175000017500000000317314140314117024520 0ustar00jpakkanejpakkaneproject('cuda has header symbol', 'cuda') cuda = meson.get_compiler('cuda') # C checks assert (cuda.has_header_symbol('stdio.h', 'int'), 'base types should always be available') assert (cuda.has_header_symbol('stdio.h', 'printf'), 'printf function not found') assert (cuda.has_header_symbol('stdio.h', 'FILE'), 'FILE structure not found') assert (cuda.has_header_symbol('limits.h', 'INT_MAX'), 'INT_MAX define not found') assert (not cuda.has_header_symbol('limits.h', 'guint64'), 'guint64 is not defined in limits.h') assert (not cuda.has_header_symbol('stdlib.h', 'FILE'), 'FILE structure is defined in stdio.h, not stdlib.h') assert (not cuda.has_header_symbol('stdlol.h', 'printf'), 'stdlol.h shouldn\'t exist') assert (not cuda.has_header_symbol('stdlol.h', 'int'), 'shouldn\'t be able to find "int" with invalid header') # C++ checks assert (cuda.has_header_symbol('iostream', 'std::iostream'), 'iostream not found in iostream.h') assert (cuda.has_header_symbol('vector', 'std::vector'), 'vector not found in vector.h') assert (not cuda.has_header_symbol('limits.h', 'std::iostream'), 'iostream should not be defined in limits.h') # CUDA checks assert (cuda.has_header_symbol('cuda.h', 'CUDA_VERSION'), 'CUDA_VERSION not found in cuda.h') assert (not cuda.has_header_symbol('cuda.h', 'cublasSaxpy'), 'cublasSaxpy is defined in cublas.h, not cuda.h') if cuda.version().version_compare('>=4.0') assert (cuda.has_header_symbol('thrust/device_vector.h', 'thrust::device_vector'), 'thrust::device_vector not found') assert (not cuda.has_header_symbol('thrust/fill.h', 'thrust::sort'), 'thrust::sort should not be defined in thrust/fill.h') endif ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1186602 meson-1.3.2/test cases/cuda/15 sanitizer/0000755000175000017500000000000014562742415020232 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1618046534.0 meson-1.3.2/test cases/cuda/15 sanitizer/meson.build0000644000175000017500000000022714034267106022366 0ustar00jpakkanejpakkaneproject('simple', 'cuda', version : '1.0.0', default_options: ['b_sanitize=address,undefined']) libtests = shared_library('tests', 'prog.cu') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/cuda/15 sanitizer/prog.cu0000644000175000017500000000245114140314117021516 0ustar00jpakkanejpakkane#include int run_tests(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; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1186602 meson-1.3.2/test cases/cuda/16 multistd/0000755000175000017500000000000014562742415020070 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883093.0 meson-1.3.2/test cases/cuda/16 multistd/lib.cu0000644000175000017500000000004414140314125021146 0ustar00jpakkanejpakkaneint do_cuda_stuff() { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883093.0 meson-1.3.2/test cases/cuda/16 multistd/main.cu0000644000175000017500000000062014140314125021324 0ustar00jpakkanejpakkane#include #include auto cuda_devices(void) { int result = 0; cudaGetDeviceCount(&result); return result; } int do_cuda_stuff(); 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 do_cuda_stuff(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883093.0 meson-1.3.2/test cases/cuda/16 multistd/meson.build0000644000175000017500000000077314140314125022222 0ustar00jpakkanejpakkaneproject('C++-CUDA multi-std', 'cpp', 'cuda', version : '1.0.0', default_options : ['cpp_std=c++17', 'cuda_std=c++14']) # Regression test: Passing override_options used to cause a crash. # See https://github.com/mesonbuild/meson/issues/9448. libcpp11 = static_library('testcpp11', 'lib.cu', override_options: ['cpp_std=c++11'] ) exe = executable('prog', 'main.cu', link_with: libcpp11) # The runtimes leak memory, so ignore it. test('cudatest', exe, env: ['ASAN_OPTIONS=detect_leaks=0']) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1186602 meson-1.3.2/test cases/cuda/2 split/0000755000175000017500000000000014562742415017271 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/cuda/2 split/lib.cu0000644000175000017500000000024514140314117020353 0ustar00jpakkanejpakkane#include #include __global__ void kernel (void){ } int do_cuda_stuff(void) { kernel<<<1,1>>>(); printf("Hello, World!\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/2 split/main.cpp0000644000175000017500000000013313716006331020704 0ustar00jpakkanejpakkane#include int do_cuda_stuff(void); int main(void) { return do_cuda_stuff(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/cuda/2 split/meson.build0000644000175000017500000000017114140314117021414 0ustar00jpakkanejpakkaneproject('simple', 'cuda', 'cpp') exe = executable('prog', 'main.cpp', 'lib.cu') test('cudatest', exe) subdir('static') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1186602 meson-1.3.2/test cases/cuda/2 split/static/0000755000175000017500000000000014562742415020560 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/cuda/2 split/static/lib.cu0000644000175000017500000000024114140314117021636 0ustar00jpakkanejpakkane#include #include __global__ void kernel (void){ } int do_cuda_stuff() { kernel<<<1,1>>>(); printf("Hello, World!\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/cuda/2 split/static/libsta.cu0000644000175000017500000000024114140314117022346 0ustar00jpakkanejpakkane#include #include __global__ void kernel (void){ } int do_cuda_stuff() { kernel<<<1,1>>>(); printf("Hello, World!\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/2 split/static/main_static.cpp0000644000175000017500000000013313716006331023542 0ustar00jpakkanejpakkane#include int do_cuda_stuff(void); int main(void) { return do_cuda_stuff(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/2 split/static/meson.build0000644000175000017500000000020213716006331022702 0ustar00jpakkanejpakkanel = static_library('clib', 'lib.cu') exe = executable('staexe', 'main_static.cpp', link_with : l) test('static Cuda test', exe) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1186602 meson-1.3.2/test cases/cuda/3 cudamodule/0000755000175000017500000000000014562742415020261 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/cuda/3 cudamodule/meson.build0000644000175000017500000000537014140314117022412 0ustar00jpakkanejpakkaneproject('cudamodule', 'cuda', version : '1.0.0') nvcc = meson.get_compiler('cuda') cuda = import('unstable-cuda') arch_flags = cuda.nvcc_arch_flags(nvcc.version(), 'Auto', detected: ['6.0']) arch_readable = cuda.nvcc_arch_readable(nvcc.version(), 'Auto', detected: ['6.0']) driver_version = cuda.min_driver_version(nvcc.version()) 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) # # Assert Series # # Sanity test. assert(' '.join(cuda.nvcc_arch_flags('11.1', '8.6')) == '-gencode arch=compute_86,code=sm_86') # CUDA Toolkit too old, flag filtered out. assert(' '.join(cuda.nvcc_arch_flags('11.0', '8.6')) == '') # Named architectures. assert(' '.join(cuda.nvcc_arch_flags('11.0', 'Ampere')) == '-gencode arch=compute_80,code=sm_80') # Splitting & deduplication. assert(' '.join(cuda.nvcc_arch_flags('11.0', 'Ampere;8.0,8.0')) == '-gencode arch=compute_80,code=sm_80') # Same, but list supplied as list. assert(' '.join(cuda.nvcc_arch_flags('11.0', ['Ampere', '8.0', '8.0'])) == '-gencode arch=compute_80,code=sm_80') # Same, but mode set to Auto with detected set to a string with a variety of separators. assert(' '.join(cuda.nvcc_arch_flags('11.0', 'Auto', detected: 'Ampere;8.0,8.0')) == '-gencode arch=compute_80,code=sm_80') # Same, but detected set to a list. assert(' '.join(cuda.nvcc_arch_flags('11.0', 'Auto', detected: ['Ampere', '8.0', '8.0'])) == '-gencode arch=compute_80,code=sm_80') # Ask for 8.6 binary with 8.0-level PTX. assert(' '.join(cuda.nvcc_arch_flags('11.1', '8.6(8.0)')) == '-gencode arch=compute_80,code=sm_86') # Same, but keep the 8.0 PTX. assert(' '.join(cuda.nvcc_arch_flags('11.1', '8.6(8.0)+PTX')) == '-gencode arch=compute_80,code=sm_86 -gencode arch=compute_80,code=compute_80') # Detected Ampere RTX 3090 on CUDA 10.2, saturate to 7.5+PTX assert(' '.join(cuda.nvcc_arch_flags('10.2', 'Auto', detected: ['8.0'])) == '-gencode arch=compute_75,code=sm_75 -gencode arch=compute_75,code=compute_75') # Failed to auto-detect with CUDA 10.2, default to common GPUs (3.0;3.5;5.0;5.2;6.0;6.1;7.0;7.5+PTX) assert(' '.join(cuda.nvcc_arch_flags('10.2', 'Auto', detected: [])) == '-gencode arch=compute_30,code=sm_30 -gencode arch=compute_35,code=sm_35 '+ '-gencode arch=compute_50,code=sm_50 -gencode arch=compute_52,code=sm_52 '+ '-gencode arch=compute_60,code=sm_60 -gencode arch=compute_61,code=sm_61 '+ '-gencode arch=compute_70,code=sm_70 -gencode arch=compute_75,code=sm_75 '+ '-gencode arch=compute_75,code=compute_75') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/cuda/3 cudamodule/prog.cu0000644000175000017500000000244414140314117021547 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1186602 meson-1.3.2/test cases/cuda/4 shared/0000755000175000017500000000000014562742415017406 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/4 shared/main.cu0000644000175000017500000000057413716006331020657 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/4 shared/meson.build0000644000175000017500000000022413716006331021534 0ustar00jpakkanejpakkaneproject('simple', 'cuda', version : '1.0.0') subdir('shared') exe = executable('prog', 'main.cu', dependencies: libkernels) test('cudatest', exe) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1186602 meson-1.3.2/test cases/cuda/4 shared/shared/0000755000175000017500000000000014562742415020654 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/cuda/4 shared/shared/kernels.cu0000644000175000017500000000032114140314117022626 0ustar00jpakkanejpakkane#include #include #include "kernels.h" TAG_HIDDEN __global__ void kernel (void){ } TAG_PUBLIC int run_tests(void) { kernel<<<1,1>>>(); return (int)cudaDeviceSynchronize(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/4 shared/shared/kernels.h0000644000175000017500000000423213716006331022457 0ustar00jpakkanejpakkane/* 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/cuda/4 shared/shared/meson.build0000644000175000017500000000064014140314117023000 0ustar00jpakkanejpakkanelibkernels = shared_library('kernels', 'kernels.cu', cuda_args: ['-DTAG_IS_SHARED=1', '-DTAG_IS_BUILDING=1'], gnu_symbol_visibility: 'hidden', soversion : 1, version : '1.2.3') libkernels = declare_dependency(compile_args: ['-DTAG_IS_SHARED=1'], link_with: libkernels) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1266603 meson-1.3.2/test cases/cuda/5 threads/0000755000175000017500000000000014562742415017573 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/5 threads/main.cu0000644000175000017500000000057413716006331021044 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/5 threads/meson.build0000644000175000017500000000030513716006331021721 0ustar00jpakkanejpakkaneproject('simple', 'cuda', version : '1.0.0') subdir('shared') thread_dep = dependency('threads') exe = executable('prog', 'main.cu', dependencies: [libkernels, thread_dep]) test('cudatest', exe) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1266603 meson-1.3.2/test cases/cuda/5 threads/shared/0000755000175000017500000000000014562742415021041 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/cuda/5 threads/shared/kernels.cu0000644000175000017500000000032114140314117023013 0ustar00jpakkanejpakkane#include #include #include "kernels.h" TAG_HIDDEN __global__ void kernel (void){ } TAG_PUBLIC int run_tests(void) { kernel<<<1,1>>>(); return (int)cudaDeviceSynchronize(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/5 threads/shared/kernels.h0000644000175000017500000000423213716006331022644 0ustar00jpakkanejpakkane/* 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/5 threads/shared/meson.build0000644000175000017500000000050613716006331023172 0ustar00jpakkanejpakkanelibkernels = 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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1266603 meson-1.3.2/test cases/cuda/6 std/0000755000175000017500000000000014562742415016734 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/6 std/main.cu0000644000175000017500000000055513716006331020204 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/6 std/meson.build0000644000175000017500000000021713716006331021064 0ustar00jpakkanejpakkaneproject('C++ std', 'cuda', version : '1.0.0', default_options : ['cuda_std=c++14']) exe = executable('prog', 'main.cu') test('cudatest', exe) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1306605 meson-1.3.2/test cases/cuda/7 static vs runtime/0000755000175000017500000000000014562742415021507 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/7 static vs runtime/main.cu0000644000175000017500000000055413716006331022756 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/7 static vs runtime/meson.build0000644000175000017500000000023013716006331023632 0ustar00jpakkanejpakkaneproject('static msvc runtime', 'cuda', version : '1.0.0', default_options : ['b_vscrt=mtd']) exe = executable('prog', 'main.cu') test('cudatest', exe) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1306605 meson-1.3.2/test cases/cuda/8 release/0000755000175000017500000000000014562742415017564 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/cuda/8 release/main.cu0000644000175000017500000000066414140314117021031 0ustar00jpakkanejpakkane#include #include #ifndef NDEBUG #error "NDEBUG not defined, this is a Meson bug" #endif 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/cuda/8 release/meson.build0000644000175000017500000000105214140314117021706 0ustar00jpakkanejpakkaneproject('release', 'cpp', 'cuda', version : '1.0.0', default_options : ['buildtype=release', 'b_ndebug=if-release']) # We don't actually need boost, but it serves as a common dependency # that has the potential to add "-isystem/usr/include" to the compile # line. By making it optional, we test that system search paths get # removed without unnecessarily failing the test if boost is absent. boost_dep = dependency('boost', include_type : 'system', required : false) exe = executable('prog', 'main.cu', dependencies : boost_dep) test('cudatest', exe) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1306605 meson-1.3.2/test cases/cuda/9 optimize for space/0000755000175000017500000000000014562742415021630 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/9 optimize for space/main.cu0000644000175000017500000000055413716006331023077 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/cuda/9 optimize for space/meson.build0000644000175000017500000000023213716006331023755 0ustar00jpakkanejpakkaneproject('optimize for space', 'cuda', version : '1.0.0', default_options : ['optimization=s']) exe = executable('prog', 'main.cu') test('cudatest', exe) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853066.994628 meson-1.3.2/test cases/cython/0000755000175000017500000000000014562742413016402 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1346605 meson-1.3.2/test cases/cython/1 basic/0000755000175000017500000000000014562742415017606 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/cython/1 basic/cytest.py0000755000175000017500000000054214107166547021500 0ustar00jpakkanejpakkane#!/usr/bin/env python3 from storer import Storer s = Storer() if s.get_value() != 0: raise SystemExit('Initial value incorrect.') s.set_value(42) if s.get_value() != 42: raise SystemExit('Setting value failed.') try: s.set_value('not a number') raise SystemExit('Using wrong argument type did not fail.') except TypeError: pass ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1346605 meson-1.3.2/test cases/cython/1 basic/libdir/0000755000175000017500000000000014562742415021053 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/cython/1 basic/libdir/cstorer.pxd0000644000175000017500000000033014107166547023246 0ustar00jpakkanejpakkane cdef extern from "storer.h": ctypedef struct Storer: pass Storer* storer_new(); void storer_destroy(Storer *s); int storer_get_value(Storer *s); void storer_set_value(Storer *s, int v); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/cython/1 basic/libdir/meson.build0000644000175000017500000000020514107166547023213 0ustar00jpakkanejpakkaneslib = py3.extension_module( 'storer', 'storer.pyx', 'storer.c', dependencies : py3_dep ) pydir = meson.current_build_dir() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/cython/1 basic/libdir/storer.c0000644000175000017500000000053614107166547022542 0ustar00jpakkanejpakkane#include"storer.h" #include struct _Storer { int value; }; Storer* storer_new() { Storer *s = malloc(sizeof(struct _Storer)); s->value = 0; return s; } void storer_destroy(Storer *s) { free(s); } int storer_get_value(Storer *s) { return s->value; } void storer_set_value(Storer *s, int v) { s->value = v; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/cython/1 basic/libdir/storer.h0000644000175000017500000000036314140314117022526 0ustar00jpakkanejpakkane#pragma once #ifdef __cplusplus extern "C" { #endif typedef struct _Storer Storer; Storer* storer_new(); void storer_destroy(Storer *s); int storer_get_value(Storer *s); void storer_set_value(Storer *s, int v); #ifdef __cplusplus } #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/cython/1 basic/libdir/storer.pyx0000644000175000017500000000062114107166547023133 0ustar00jpakkanejpakkanecimport cstorer cdef class Storer: cdef cstorer.Storer* _c_storer def __cinit__(self): self._c_storer = cstorer.storer_new() def __dealloc__(self): cstorer.storer_destroy(self._c_storer) cpdef int get_value(self): return cstorer.storer_get_value(self._c_storer) cpdef set_value(self, int value): cstorer.storer_set_value(self._c_storer, value) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855209.0 meson-1.3.2/test cases/cython/1 basic/meson.build0000644000175000017500000000074714433154651021754 0ustar00jpakkanejpakkaneproject( 'basic cython project', ['cython', 'c'], default_options : ['warning_level=3', 'buildtype=release'], ) if meson.backend() != 'ninja' error('MESON_SKIP_TEST: Ninja backend required') endif py3 = import('python').find_installation() py3_dep = py3.dependency(required : false) if not py3_dep.found() error('MESON_SKIP_TEST: Python library not found.') endif subdir('libdir') test('cython tester', py3, args : files('cytest.py'), env : ['PYTHONPATH=' + pydir] ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/cython/1 basic/test.json0000644000175000017500000000020314140314117021435 0ustar00jpakkanejpakkane{ "matrix": { "options": { "cython_language": [ { "val": "c" }, { "val": "cpp" } ] } } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1386607 meson-1.3.2/test cases/cython/2 generated sources/0000755000175000017500000000000014562742415022130 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/cython/2 generated sources/configure.pyx.in0000644000175000017500000000005114107166547025255 0ustar00jpakkanejpakkanecpdef func(): return "Hello, World!" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/cython/2 generated sources/g.in0000644000175000017500000000005114107166547022703 0ustar00jpakkanejpakkanecpdef func(): return "Hello, World!" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/cython/2 generated sources/gen.py0000644000175000017500000000045714107166547023262 0ustar00jpakkanejpakkane# SPDX-License-Identifier: Apache-2.0 import argparse import textwrap parser = argparse.ArgumentParser() parser.add_argument('output') args = parser.parse_args() with open(args.output, 'w') as f: f.write(textwrap.dedent('''\ cpdef func(): return "Hello, World!" ''')) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/cython/2 generated sources/generator.py0000755000175000017500000000043014140314117024452 0ustar00jpakkanejpakkane#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 import argparse parser = argparse.ArgumentParser() parser.add_argument('input') parser.add_argument('output') args = parser.parse_args() with open(args.input) as i, open(args.output, 'w') as o: o.write(i.read()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1675287798.0 meson-1.3.2/test cases/cython/2 generated sources/includestuff.pyx0000644000175000017500000000002414366556366025373 0ustar00jpakkanejpakkaneinclude "stuff.pxi" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1386607 meson-1.3.2/test cases/cython/2 generated sources/libdir/0000755000175000017500000000000014562742415023375 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/cython/2 generated sources/libdir/gen.py0000644000175000017500000000045714107166547024527 0ustar00jpakkanejpakkane# SPDX-License-Identifier: Apache-2.0 import argparse import textwrap parser = argparse.ArgumentParser() parser.add_argument('output') args = parser.parse_args() with open(args.output, 'w') as f: f.write(textwrap.dedent('''\ cpdef func(): return "Hello, World!" ''')) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/cython/2 generated sources/libdir/meson.build0000644000175000017500000000033314107166547025537 0ustar00jpakkanejpakkanect2 = custom_target( 'ct2', input : 'gen.py', output : 'ct2.pyx', command : [py3, '@INPUT@', '@OUTPUT@'], ) ct2_ext = py3.extension_module('ct2', ct2, dependencies : py3_dep) pydir = meson.current_build_dir() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855209.0 meson-1.3.2/test cases/cython/2 generated sources/meson.build0000644000175000017500000000373714433154651024300 0ustar00jpakkanejpakkaneproject( 'generated cython sources', ['cython', 'c'], default_options : ['buildtype=release'], ) if meson.backend() != 'ninja' error('MESON_SKIP_TEST: Ninja backend required') endif fs = import('fs') py3 = import('python').find_installation('python3') py3_dep = py3.dependency(required : false) if not py3_dep.found() error('MESON_SKIP_TEST: Python library not found.') endif ct = custom_target( 'ct', input : 'gen.py', output : 'ct.pyx', command : [py3, '@INPUT@', '@OUTPUT@'], ) ct_ext = py3.extension_module('ct', ct) test( 'custom target', py3, args : [files('test.py'), 'ct'], env : ['PYTHONPATH=' + meson.current_build_dir()] ) # Test a CustomTargetIndex cti = custom_target( 'cti', input : 'gen.py', output : 'cti.pyx', command : [py3, '@INPUT@', '@OUTPUT@'], ) cti_ext = py3.extension_module('cti', cti[0]) cf = configure_file( input : 'configure.pyx.in', output : 'cf.pyx', copy : true, ) cf_ext = py3.extension_module('cf', cf) test( 'configure file', py3, args : [files('test.py'), 'cf'], env : ['PYTHONPATH=' + meson.current_build_dir()] ) gen = generator( find_program('generator.py'), arguments : ['@INPUT@', '@OUTPUT@'], output : '@BASENAME@.pyx', ) g_ext = py3.extension_module( 'g', gen.process('g.in'), ) test( 'generator', py3, args : [files('test.py'), 'g'], env : ['PYTHONPATH=' + meson.current_build_dir()] ) stuff_pxi = fs.copyfile( 'stuff.pxi.in', 'stuff.pxi' ) # Need to copy the cython source to the build directory # since meson can only generate the .pxi there includestuff_pyx = fs.copyfile( 'includestuff.pyx' ) stuff_pxi_dep = declare_dependency(sources: stuff_pxi) includestuff_ext = py3.extension_module( 'includestuff', includestuff_pyx, dependencies: stuff_pxi_dep ) simpleinclude_ext = py3.extension_module( 'simpleinclude', 'simpleinclude.pyx', ) subdir('libdir') test( 'custom target in subdir', py3, args : [files('test.py'), 'ct2'], env : ['PYTHONPATH=' + pydir] ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1676897923.0 meson-1.3.2/test cases/cython/2 generated sources/simpleinclude.pyx0000644000175000017500000000003214374667203025524 0ustar00jpakkanejpakkaneinclude "simplestuff.pxi" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421132.0 meson-1.3.2/test cases/cython/2 generated sources/simplestuff.pxi0000644000175000017500000000004614516754614025216 0ustar00jpakkanejpakkanedef func2(): print("Hello world") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1675287798.0 meson-1.3.2/test cases/cython/2 generated sources/stuff.pxi.in0000644000175000017500000000004514366556366024417 0ustar00jpakkanejpakkanedef func(): print("Hello world") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/cython/2 generated sources/test.py0000644000175000017500000000041014107166547023455 0ustar00jpakkanejpakkane#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 import argparse import importlib parser = argparse.ArgumentParser() parser.add_argument('mod') args = parser.parse_args() mod = importlib.import_module(args.mod) assert mod.func() == 'Hello, World!' ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1466608 meson-1.3.2/test cases/cython/3 cython_args/0000755000175000017500000000000014562742415021047 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1648239127.0 meson-1.3.2/test cases/cython/3 cython_args/cythonargs.pyx0000644000175000017500000000010614217421027023755 0ustar00jpakkanejpakkanedef test(): IF VALUE: return 1 ELSE: return 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855209.0 meson-1.3.2/test cases/cython/3 cython_args/meson.build0000644000175000017500000000140714433154651023207 0ustar00jpakkanejpakkaneproject('cython_args', ['cython', 'c'], # Needed because Windows Python builds are release-only and tend to be # unhappy with a debug build type. default_options : ['buildtype=release'] ) if meson.backend() != 'ninja' error('MESON_SKIP_TEST: Ninja backend required') endif python = import('python').find_installation('python3') python_dep = python.dependency() if not python_dep.found() error('MESON_SKIP_TEST: Python library not found.') endif mod = python.extension_module( 'cythonargs', files('cythonargs.pyx'), cython_args: [ '--compile-time-env', 'VALUE=1', '-3', ], ) test( 'test', python, args: [ 'test.py' ], workdir: meson.current_source_dir(), env: environment({ 'PYTHONPATH': meson.current_build_dir(), }) ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1648239127.0 meson-1.3.2/test cases/cython/3 cython_args/test.py0000644000175000017500000000006114217421027022363 0ustar00jpakkanejpakkaneimport cythonargs assert cythonargs.test() == 1 ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.002628 meson-1.3.2/test cases/d/0000755000175000017500000000000014562742413015321 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1466608 meson-1.3.2/test cases/d/1 simple/0000755000175000017500000000000014562742415016735 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/1 simple/app.d0000644000175000017500000000013113716006331017643 0ustar00jpakkanejpakkane import std.stdio; import utils; void main () { printGreeting ("a Meson D test"); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421763.0 meson-1.3.2/test cases/d/1 simple/meson.build0000644000175000017500000000016514516756003021076 0ustar00jpakkanejpakkaneproject('D Simple Test', 'd') e = executable('dsimpleapp', ['app.d', 'utils.d'], install : true) test('apptest', e) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/1 simple/test.json0000644000175000017500000000021713716006331020575 0ustar00jpakkanejpakkane{ "installed": [ {"type": "exe", "file": "usr/bin/dsimpleapp"}, {"type": "pdb", "file": "usr/bin/dsimpleapp", "language": "d"} ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/1 simple/utils.d0000644000175000017500000000020413716006331020224 0ustar00jpakkanejpakkane import std.stdio; import std.string : format; void printGreeting (string name) { writeln ("Hello, I am %s.".format (name)); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1466608 meson-1.3.2/test cases/d/10 d cpp/0000755000175000017500000000000014562742415016512 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/d/10 d cpp/cppmain.cpp0000644000175000017500000000053214140314117020627 0ustar00jpakkanejpakkaneextern "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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/10 d cpp/dmain.d0000644000175000017500000000011313716006331017730 0ustar00jpakkanejpakkaneextern (C++) void print_hello(int i); void main() { print_hello(1); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/10 d cpp/libfile.cpp0000644000175000017500000000017513716006331020615 0ustar00jpakkanejpakkane#include void print_hello(int i) { std::cout << "Hello. Here is a number printed with C++: " << i << ".\n"; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/10 d cpp/libfile.d0000644000175000017500000000017313716006331020254 0ustar00jpakkanejpakkaneimport std.stdio; extern (C++) void print_hello(int i) { writefln("Hello. Here is a number printed with D: %d", i); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421779.0 meson-1.3.2/test cases/d/10 d cpp/meson.build0000644000175000017500000000050314516756023020651 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1466608 meson-1.3.2/test cases/d/11 dub/0000755000175000017500000000000014562742415016277 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/d/11 dub/.gitignore0000644000175000017500000000001114253672217020256 0ustar00jpakkanejpakkanedub.json ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1685461376.0 meson-1.3.2/test cases/d/11 dub/meson.build0000644000175000017500000000155614435414600020437 0ustar00jpakkanejpakkaneproject('dub-example', 'd') error('MESON_SKIP_TEST: Dub support is broken at the moment (#11773)') 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 )././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/11 dub/test.d0000644000175000017500000000041313716006331017407 0ustar00jpakkanejpakkaneimport 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); }././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1506608 meson-1.3.2/test cases/d/12 root include directory/0000755000175000017500000000000014562742415022102 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421781.0 meson-1.3.2/test cases/d/12 root include directory/meson.build0000644000175000017500000000015214516756025024243 0ustar00jpakkanejpakkaneproject('some', 'd') project_dep = declare_dependency( include_directories: ['.'], ) subdir('some') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1506608 meson-1.3.2/test cases/d/12 root include directory/some/0000755000175000017500000000000014562742415023045 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1506608 meson-1.3.2/test cases/d/12 root include directory/some/dlang/0000755000175000017500000000000014562742415024132 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1646856884.0 meson-1.3.2/test cases/d/12 root include directory/some/dlang/code.d0000644000175000017500000000014014212205264025170 0ustar00jpakkanejpakkanevoid foo() {} version (Windows) { import core.sys.windows.dll; mixin SimpleDllMain; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1646856884.0 meson-1.3.2/test cases/d/12 root include directory/some/dlang/meson.build0000644000175000017500000000024414212205264026260 0ustar00jpakkanejpakkanecode_lib = library('code', ['code.d'], dependencies: [project_dep]) code_dep = declare_dependency( link_with: code_lib, dependencies: project_dep )././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1646856884.0 meson-1.3.2/test cases/d/12 root include directory/some/meson.build0000644000175000017500000000001714212205264025171 0ustar00jpakkanejpakkanesubdir('dlang')././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1506608 meson-1.3.2/test cases/d/13 declare dep/0000755000175000017500000000000014562742415017657 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421782.0 meson-1.3.2/test cases/d/13 declare dep/meson.build0000644000175000017500000000046114516756026022024 0ustar00jpakkanejpakkaneproject('meson-d-sample', 'd', version: '0.1.0', ) my_dep = declare_dependency( d_module_versions: ['TestVersion'], d_import_dirs: include_directories('views'), ) test_exe = executable('test-dep', 'test.d', dependencies: my_dep, ) test('test d features in declare_dependency', test_exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/d/13 declare dep/test.d0000644000175000017500000000031414253672217021000 0ustar00jpakkanejpakkanemodule test; int main() { version(TestVersion) { enum testPhrase = import("test.txt"); return testPhrase == "TEST PHRASE" ? 0 : 1; } else { return 1; } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1506608 meson-1.3.2/test cases/d/13 declare dep/views/0000755000175000017500000000000014562742415021014 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/d/13 declare dep/views/test.txt0000644000175000017500000000001314253672217022525 0ustar00jpakkanejpakkaneTEST PHRASE././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1506608 meson-1.3.2/test cases/d/14 dub with deps/0000755000175000017500000000000014562742415020152 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1685461376.0 meson-1.3.2/test cases/d/14 dub with deps/meson.build0000644000175000017500000000173214435414600022306 0ustar00jpakkanejpakkaneproject('dub-with-deps-example', ['d']) error('MESON_SKIP_TEST: Dub support is broken at the moment (#11773)') dub_exe = find_program('dub', required : false) if not dub_exe.found() error('MESON_SKIP_TEST: Dub not found') endif if meson.get_compiler('d').get_id() == 'gcc' error('MESON_SKIP_TEST: can\'t build dependencies with GDC') elif meson.get_compiler('d').get_id() == 'llvm' dc = 'ldc2' elif meson.get_compiler('d').get_id() == 'dmd' dc = 'dmd' endif arch = host_machine.cpu_family() if host_machine.system() == 'windows' # check if toolchain is 32bits sz = meson.get_compiler('d').sizeof('void*') if arch == 'x86' or sz == 4 arch = 'x86_mscoff' endif endif run_command('dub', 'run', 'dub-build-deep', '--yes', '--', 'xlsx', '--compiler', dc, '--arch', arch, check: true, ) xlsx_dep = dependency('xlsx', method: 'dub') test_exe = executable('test-test6', 'test.d', dependencies: xlsx_dep) test('test dub with deps', test_exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/d/14 dub with deps/test.d0000644000175000017500000000302714253672217021277 0ustar00jpakkanejpakkanemodule test; // testing import dirs import xlsx; // dependency of xlsx import dxml.dom; const xml = "\n" ~ "\n" ~ " some text\n" ~ " \n" ~ " \n" ~ ""; int main() { // testing versions version (Have_dxml) { import std.range.primitives : empty; auto dom = parseDOM(xml); assert(dom.type == EntityType.elementStart); assert(dom.name.empty); assert(dom.children.length == 2); assert(dom.children[0].type == EntityType.comment); assert(dom.children[0].text == " comment "); auto root = dom.children[1]; assert(root.type == EntityType.elementStart); assert(root.name == "root"); assert(root.children.length == 3); auto foo = root.children[0]; assert(foo.type == EntityType.elementStart); assert(foo.name == "foo"); assert(foo.children.length == 2); assert(foo.children[0].type == EntityType.text); assert(foo.children[0].text == "some text"); assert(foo.children[1].type == EntityType.elementEmpty); assert(foo.children[1].name == "whatever"); assert(root.children[1].type == EntityType.elementEmpty); assert(root.children[1].name == "bar"); assert(root.children[2].type == EntityType.elementStart); assert(root.children[2].name == "baz"); assert(root.children[2].children.length == 0); return 0; } else { return 1; } } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.158661 meson-1.3.2/test cases/d/15 compiler run checks/0000755000175000017500000000000014562742415021351 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421784.0 meson-1.3.2/test cases/d/15 compiler run checks/meson.build0000644000175000017500000000243514516756030023514 0ustar00jpakkanejpakkaneproject('test-d-run-checks', 'd') dc = meson.get_compiler('d') run_sizeof = dc.run('int main() { return (void*).sizeof; }') if run_sizeof.returncode() == 8 run_versions = ['Is64bits'] elif run_sizeof.returncode() == 4 run_versions = ['Is32bits'] endif run_sizeof_exe = executable('run_sizeof', 'test_sizeof.d', d_module_versions: run_versions, ) test('test D compiler run', run_sizeof_exe) sizeof_sizeof = dc.sizeof('void*') if sizeof_sizeof == 8 run_versions = ['Is64bits'] elif sizeof_sizeof == 4 run_versions = ['Is32bits'] endif sizeof_sizeof_exe = executable('sizeof_sizeof', 'test_sizeof.d', d_module_versions: run_versions, ) test('test D compiler sizeof', sizeof_sizeof_exe) if not dc.has_header('std.stdio') error('Could not find std.stdio import') endif if dc.has_header('not_a_d_module') error('has_header inconsistent result') endif # same checks as C/C++ alignments (D has same alignment requirements as C) # These tests should return the same value on all # platforms. If (and when) they don't, fix 'em up. if dc.alignment('char') != 1 error('Alignment of char misdetected.') endif dbl_alignment = dc.alignment('double') if dbl_alignment == 8 or dbl_alignment == 4 message('Alignment of double ok.') else error('Alignment of double misdetected.') endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/d/15 compiler run checks/test_sizeof.d0000644000175000017500000000043714253672217024057 0ustar00jpakkanejpakkanemodule test_sizeof; alias voidp = void*; int main() { version(Is64bits) { enum expectedSz = 8; } else version(Is32bits) { enum expectedSz = 4; } else { assert(false, "No version set!"); } return expectedSz == voidp.sizeof ? 0 : 1; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.158661 meson-1.3.2/test cases/d/16 code generation/0000755000175000017500000000000014562742415020560 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655666235.0 meson-1.3.2/test cases/d/16 code generation/exe.d0000644000175000017500000000022714253673073021507 0ustar00jpakkanejpakkanemodule exe; import generated; import std.stdio; int main() { return generatedString() == "Some text to be returned by generated code" ? 0 : 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655666235.0 meson-1.3.2/test cases/d/16 code generation/generator.d0000644000175000017500000000037614253673073022721 0ustar00jpakkanejpakkanemodule generator; import std.file; import std.stdio; import std.string; void main(string[] args) { const text = cast(string)read(args[1]); writeln("module generated;"); writefln!`string generatedString() { return "%s"; }`(text.strip()); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655666235.0 meson-1.3.2/test cases/d/16 code generation/input.txt0000644000175000017500000000005314253673073022456 0ustar00jpakkanejpakkaneSome text to be returned by generated code ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421784.0 meson-1.3.2/test cases/d/16 code generation/meson.build0000644000175000017500000000055614516756030022725 0ustar00jpakkanejpakkaneproject('meson-dep-test', 'd') generator = executable('generator', 'generator.d') generated = custom_target('generated', capture: true, output: 'generated.d', input: 'input.txt', command: [ generator, '@INPUT@' ] ) exe = executable('exe', generated, 'exe.d', include_directories: include_directories('.'), ) test('test exe', exe) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.158661 meson-1.3.2/test cases/d/2 static library/0000755000175000017500000000000014562742415020361 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/2 static library/app.d0000644000175000017500000000015313716006331021273 0ustar00jpakkanejpakkane import libstuff; void main () { immutable ret = printLibraryString ("foo"); assert (ret == 4); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/2 static library/libstuff.d0000644000175000017500000000023413716006331022331 0ustar00jpakkanejpakkane import std.stdio; import std.string : format; int printLibraryString (string str) { writeln ("Static Library says: %s".format (str)); return 4; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421764.0 meson-1.3.2/test cases/d/2 static library/meson.build0000644000175000017500000000030514516756004022517 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/2 static library/test.json0000644000175000017500000000027113716006331022221 0ustar00jpakkanejpakkane{ "installed": [ {"type": "exe", "file": "usr/bin/app_s"}, {"type": "pdb", "file": "usr/bin/app_s", "language": "d"}, {"type": "file", "file": "usr/lib/libstuff.a"} ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.158661 meson-1.3.2/test cases/d/3 shared library/0000755000175000017500000000000014562742415020341 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/3 shared library/app.d0000644000175000017500000000015313716006331021253 0ustar00jpakkanejpakkane import libstuff; void main () { immutable ret = printLibraryString ("foo"); assert (ret == 4); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/3 shared library/libstuff.d0000644000175000017500000000035413716006331022314 0ustar00jpakkanejpakkaneimport 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/3 shared library/libstuff.di0000644000175000017500000000006713716006331022466 0ustar00jpakkanejpakkanemodule libstuff; int printLibraryString (string str); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/3 shared library/lld-test.py0000644000175000017500000000077213716006331022437 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import argparse import subprocess def main(): parser = argparse.ArgumentParser() parser.add_argument('ldd') parser.add_argument('bin') args = parser.parse_args() p, o, _ = subprocess.run([args.ldd, args.bin], stdout=subprocess.PIPE) assert p == 0 o = o.decode() assert 'libstuff.so =>' in o, 'libstuff so not in linker path.' assert 'libstuff.so => not found' not in o, 'libstuff.so not found correctly' if __name__ == '__main__': main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421768.0 meson-1.3.2/test cases/d/3 shared library/meson.build0000644000175000017500000000124614516756010022501 0ustar00jpakkanejpakkaneproject('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 cannot build shared libraries') endif endif subdir('sub') 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'] ) ldd = find_program('ldd', required : false) if ldd.found() test('ldd-test.py', ed) endif ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.166661 meson-1.3.2/test cases/d/3 shared library/sub/0000755000175000017500000000000014562742415021132 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/3 shared library/sub/libstuff.d0000644000175000017500000000035413716006331023105 0ustar00jpakkanejpakkaneimport 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/d/3 shared library/sub/meson.build0000644000175000017500000000007514140314117023260 0ustar00jpakkanejpakkaneldyn = shared_library('stuff', 'libstuff.d', install : true) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/3 shared library/test.json0000644000175000017500000000072713716006331022207 0ustar00jpakkanejpakkane{ "installed": [ {"type": "exe", "file": "usr/bin/app_d"}, {"type": "pdb", "file": "usr/bin/app_d", "language": "d"}, {"type": "shared_lib", "platform": "msvc", "file": "usr/bin/stuff"}, {"type": "pdb", "file": "usr/bin/stuff", "language": "d"}, {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/stuff"}, {"type": "file", "platform": "msvc", "file": "usr/lib/stuff.lib"}, {"type": "file", "file": "usr/lib/pkgconfig/test.pc"} ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.166661 meson-1.3.2/test cases/d/4 library versions/0000755000175000017500000000000014562742415020744 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/4 library versions/lib.d0000644000175000017500000000036313716006331021647 0ustar00jpakkanejpakkane 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421769.0 meson-1.3.2/test cases/d/4 library versions/meson.build0000644000175000017500000000106414516756011023103 0ustar00jpakkanejpakkaneproject('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 cannot 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/4 library versions/test.json0000644000175000017500000000322213716006331022603 0ustar00jpakkanejpakkane{ "installed": [ {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/some"}, {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/some", "version": "0"}, {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/some", "version": "1.2.3"}, {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/noversion"}, {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/onlyversion"}, {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/onlyversion", "version": "1"}, {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/onlyversion", "version": "1.4.5"}, {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/onlysoversion"}, {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/onlysoversion", "version": "5"}, {"type": "shared_lib", "platform": "msvc", "file": "usr/bin/noversion"}, {"type": "pdb", "file": "usr/bin/noversion", "language": "d"}, {"type": "shared_lib", "platform": "msvc", "file": "usr/bin/onlysoversion", "version": "5"}, {"type": "pdb", "file": "usr/bin/onlysoversion", "version": "5", "language": "d"}, {"type": "shared_lib", "platform": "msvc", "file": "usr/bin/onlyversion", "version": "1"}, {"type": "pdb", "file": "usr/bin/onlyversion", "version": "1", "language": "d"}, {"type": "shared_lib", "platform": "msvc", "file": "usr/bin/some", "version": "0"}, {"type": "pdb", "file": "usr/bin/some", "version": "0", "language": "d"}, {"type": "implib", "file": "usr/lib/noversion"}, {"type": "implib", "file": "usr/lib/onlysoversion"}, {"type": "implib", "file": "usr/lib/onlyversion"}, {"type": "implib", "file": "usr/lib/some"} ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.166661 meson-1.3.2/test cases/d/5 mixed/0000755000175000017500000000000014562742415016556 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/5 mixed/app.d0000644000175000017500000000021713716006331017471 0ustar00jpakkanejpakkane extern(C) int printLibraryString(const char *str); void main () { immutable ret = printLibraryString ("C foo"); assert (ret == 3); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/5 mixed/libstuff.c0000644000175000017500000000064513716006331020533 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421768.0 meson-1.3.2/test cases/d/5 mixed/meson.build0000644000175000017500000000055114516756010020714 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/5 mixed/test.json0000644000175000017500000000110613716006331020414 0ustar00jpakkanejpakkane{ "installed": [ {"type": "exe", "file": "usr/bin/appdc_d"}, {"type": "pdb", "file": "usr/bin/appdc_d", "language": "d"}, {"type": "exe", "file": "usr/bin/appdc_s"}, {"type": "pdb", "file": "usr/bin/appdc_s", "language": "d"}, {"type": "file", "file": "usr/lib/libstuff.a"}, {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/stuff"}, {"type": "shared_lib", "platform": "msvc", "file": "usr/bin/stuff"}, {"type": "pdb", "file": "usr/bin/stuff", "language": "c"}, {"type": "file", "platform": "msvc", "file": "usr/lib/stuff.lib"} ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.166661 meson-1.3.2/test cases/d/6 unittest/0000755000175000017500000000000014562742415017330 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/6 unittest/app.d0000644000175000017500000000130213716006331020237 0ustar00jpakkanejpakkane 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); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421771.0 meson-1.3.2/test cases/d/6 unittest/meson.build0000644000175000017500000000036514516756013021474 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/6 unittest/second_unit.d0000644000175000017500000000022313716006331021772 0ustar00jpakkanejpakkane void secondModuleTestFunc () { import std.stdio : writeln; version (unittest) writeln ("Hello!"); else assert (0); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/6 unittest/test.json0000644000175000017500000000020313716006331021163 0ustar00jpakkanejpakkane{ "installed": [ {"type": "exe", "file": "usr/bin/dapp"}, {"type": "pdb", "file": "usr/bin/dapp", "language": "d"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1746612 meson-1.3.2/test cases/d/7 multilib/0000755000175000017500000000000014562742415017273 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/7 multilib/app.d0000644000175000017500000000017513716006331020211 0ustar00jpakkanejpakkane import say1; import say2; void main () { assert (sayHello1 ("Dave") == 4); assert (sayHello2 ("HAL 9000") == 8); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421776.0 meson-1.3.2/test cases/d/7 multilib/meson.build0000644000175000017500000000105414516756020021431 0ustar00jpakkanejpakkaneproject('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 cannot 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/7 multilib/say1.d0000644000175000017500000000035413716006331020305 0ustar00jpakkanejpakkane 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/7 multilib/say1.di0000644000175000017500000000003413716006331020451 0ustar00jpakkanejpakkaneint sayHello1 (string str); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/7 multilib/say2.d0000644000175000017500000000035413716006331020306 0ustar00jpakkanejpakkane 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/7 multilib/say2.di0000644000175000017500000000003413716006331020452 0ustar00jpakkanejpakkaneint sayHello2 (string str); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/7 multilib/test.json0000644000175000017500000000204313716006331021132 0ustar00jpakkanejpakkane{ "installed": [ {"type": "exe", "file": "usr/bin/app_d"}, {"type": "pdb", "file": "usr/bin/app_d", "language": "d"}, {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/say1"}, {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/say1", "version": "0"}, {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/say1", "version": "1.2.3"}, {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/say2"}, {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/say2", "version": "1"}, {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/say2", "version": "1.2.4"}, {"type": "shared_lib", "platform": "msvc", "file": "usr/bin/say1", "version": "0"}, {"type": "pdb", "file": "usr/bin/say1", "version": "0", "language": "d"}, {"type": "shared_lib", "platform": "msvc", "file": "usr/bin/say2", "version": "1"}, {"type": "pdb", "file": "usr/bin/say2", "version": "1", "language": "d"}, {"type": "implib", "file": "usr/lib/say1"}, {"type": "implib", "file": "usr/lib/say2"} ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1746612 meson-1.3.2/test cases/d/8 has multi arguments/0000755000175000017500000000000014562742415021327 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421773.0 meson-1.3.2/test cases/d/8 has multi arguments/meson.build0000644000175000017500000000101114516756015023462 0ustar00jpakkanejpakkaneproject('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()) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1746612 meson-1.3.2/test cases/d/9 features/0000755000175000017500000000000014562742415017272 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/d/9 features/app.d0000644000175000017500000000322214140314117020200 0ustar00jpakkanejpakkane 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); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1746612 meson-1.3.2/test cases/d/9 features/data/0000755000175000017500000000000014562742415020203 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/9 features/data/food.txt0000644000175000017500000000004513716006331021660 0ustar00jpakkanejpakkaneSpam Eggs Spam Baked Beans Spam Spam ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/9 features/data/people.txt0000644000175000017500000000003513716006331022214 0ustar00jpakkanejpakkaneRick Morty Summer Beth Jerry ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/d/9 features/extra.d0000644000175000017500000000020413716006331020544 0ustar00jpakkanejpakkane auto secondModulePeopleVersionSet () { version (With_People) { return true; } else { return false; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421778.0 meson-1.3.2/test cases/d/9 features/meson.build0000644000175000017500000000700714516756022021436 0ustar00jpakkanejpakkaneproject('D Features', 'd', default_options : ['debug=false']) dc = meson.get_compiler('d') # GDC 13 hard errors if options are given number values. # https://github.com/mesonbuild/meson/pull/11996 if dc.get_id() == 'gcc' and dc.version().version_compare('>=13') number_options_supported = false else number_options_supported = true endif # 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 if number_options_supported 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) endif # 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) if number_options_supported # 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 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']) endif # 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']) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.0786293 meson-1.3.2/test cases/failing/0000755000175000017500000000000014562742413016507 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1946614 meson-1.3.2/test cases/failing/1 project not first/0000755000175000017500000000000014562742415022171 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/1 project not first/meson.build0000644000175000017500000000016113716006331024317 0ustar00jpakkanejpakkanevar = 'assignment before project() call' project('no worky', 'c') test('not run', executable('prog', 'prog.c')) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/1 project not first/prog.c0000644000175000017500000000005613716006331023273 0ustar00jpakkanejpakkaneint main(int argc, char **argv) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/failing/1 project not first/test.json0000644000175000017500000000017214140314117024025 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "ERROR: Invalid source tree: first statement must be a call to project()" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1946614 meson-1.3.2/test cases/failing/10 out of bounds/0000755000175000017500000000000014562742415021361 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/10 out of bounds/meson.build0000644000175000017500000000005214316400150023500 0ustar00jpakkanejpakkaneproject('out of bounds') x = [] y = x[0] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/test cases/failing/10 out of bounds/test.json0000644000175000017500000000023014433154642023222 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/10 out of bounds/meson.build:4:6: ERROR: Index 0 out of bounds of array of size 0." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1946614 meson-1.3.2/test cases/failing/100 bool in combo/0000755000175000017500000000000014562742415021374 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/100 bool in combo/meson.build0000644000175000017500000000003114516552205023523 0ustar00jpakkanejpakkaneproject('bool in combo') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/100 bool in combo/meson_options.txt0000644000175000017500000000011114516552205025015 0ustar00jpakkanejpakkaneoption( 'opt', type : 'combo', choices : ['true', 'false'] ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/100 bool in combo/nativefile.ini0000644000175000017500000000003514516552205024214 0ustar00jpakkanejpakkane[project options] opt = true ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/100 bool in combo/test.json0000644000175000017500000000036514516552205023245 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/100 bool in combo/meson.build:1:0: ERROR: Value \"True\" (of type \"boolean\") for combo option \"opt\" is not one of the choices. Possible choices are (as string): \"true\", \"false\"." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2026615 meson-1.3.2/test cases/failing/101 compiler no lang/0000755000175000017500000000000014562742415022104 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/101 compiler no lang/meson.build0000644000175000017500000000007114516552205024237 0ustar00jpakkanejpakkaneproject('compiler without lang') meson.get_compiler('c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/101 compiler no lang/test.json0000644000175000017500000000027714516552205023757 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/101 compiler no lang/meson.build:2:6: ERROR: Tried to access compiler for language \"c\", not specified for host machine." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2026615 meson-1.3.2/test cases/failing/102 no fallback/0000755000175000017500000000000014562742415021130 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/102 no fallback/meson.build0000644000175000017500000000013414516552205023263 0ustar00jpakkanejpakkaneproject('no fallback') foob_dep = dependency('foob', allow_fallback: false, required: true) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.0066283 meson-1.3.2/test cases/failing/102 no fallback/subprojects/0000755000175000017500000000000014562742413023471 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2026615 meson-1.3.2/test cases/failing/102 no fallback/subprojects/foob/0000755000175000017500000000000014562742415024420 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/102 no fallback/subprojects/foob/meson.build0000644000175000017500000000011514516552205026552 0ustar00jpakkanejpakkaneproject('foob', 'c') meson.override_dependency('foob', declare_dependency()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/102 no fallback/test.json0000644000175000017500000000033414516552205022775 0ustar00jpakkanejpakkane{ "stdout": [ { "match": "re", "line": ".*/meson\\.build:2:11: ERROR: (Pkg-config binary for machine MachineChoice\\.HOST not found\\. Giving up\\.|Dependency \"foob\" not found, tried .*)" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2026615 meson-1.3.2/test cases/failing/103 feature require/0000755000175000017500000000000014562742415022065 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/103 feature require/meson.build0000644000175000017500000000016114516552205024220 0ustar00jpakkanejpakkaneproject('no fallback') foo = get_option('reqfeature').require(false, error_message: 'frobnicator not available') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/103 feature require/meson_options.txt0000644000175000017500000000013614516552205025515 0ustar00jpakkanejpakkaneoption('reqfeature', type : 'feature', value : 'enabled', description : 'A required feature') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/103 feature require/test.json0000644000175000017500000000024514516552205023733 0ustar00jpakkanejpakkane{ "stdout": [ { "match": "re", "line": ".*/meson\\.build:2:31: ERROR: Feature reqfeature cannot be enabled: frobnicator not available" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2026615 meson-1.3.2/test cases/failing/104 feature require.bis/0000755000175000017500000000000014562742415022642 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/104 feature require.bis/meson.build0000644000175000017500000000010514516552205024773 0ustar00jpakkanejpakkaneproject('no fallback') foo = get_option('reqfeature').require(false) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/104 feature require.bis/meson_options.txt0000644000175000017500000000013614516552205026272 0ustar00jpakkanejpakkaneoption('reqfeature', type : 'feature', value : 'enabled', description : 'A required feature') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/104 feature require.bis/test.json0000644000175000017500000000021214516552205024502 0ustar00jpakkanejpakkane{ "stdout": [ { "match": "re", "line": ".*/meson\\.build:2:31: ERROR: Feature reqfeature cannot be enabled" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2066617 meson-1.3.2/test cases/failing/105 no build get_external_property/0000755000175000017500000000000014562742415025101 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/105 no build get_external_property/meson.build0000644000175000017500000000014014516552205027231 0ustar00jpakkanejpakkaneproject('missing property') message(meson.get_external_property('nonexisting', native : true)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/105 no build get_external_property/test.json0000644000175000017500000000026114516552205026745 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/105 no build get_external_property/meson.build:3:14: ERROR: Unknown property for build machine: nonexisting" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2066617 meson-1.3.2/test cases/failing/106 enter subdir twice/0000755000175000017500000000000014562742415022462 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/106 enter subdir twice/meson.build0000644000175000017500000000005714516552205024621 0ustar00jpakkanejpakkaneproject('subdir2') subdir('sub') subdir('sub') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2066617 meson-1.3.2/test cases/failing/106 enter subdir twice/sub/0000755000175000017500000000000014562742415023253 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/106 enter subdir twice/sub/meson.build0000644000175000017500000000003114516552205025402 0ustar00jpakkanejpakkanemessage('Now in subdir') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/106 enter subdir twice/test.json0000644000175000017500000000026614516552205024333 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/106 enter subdir twice/meson.build:3:0: ERROR: Tried to enter directory \"sub\", which has already been visited." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2066617 meson-1.3.2/test cases/failing/107 invalid fstring/0000755000175000017500000000000014562742415022064 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2146618 meson-1.3.2/test cases/failing/107 invalid fstring/109 invalid fstring/0000755000175000017500000000000014562742415025441 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/107 invalid fstring/109 invalid fstring/meson.build0000644000175000017500000000012514516552205027574 0ustar00jpakkanejpakkaneproject('invalid-fstring', 'c') dict = {'key': true} s = f'invalid fstring: @dict@' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/107 invalid fstring/109 invalid fstring/test.json0000644000175000017500000000040414516552205027304 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/109 invalid fstring/meson.build:4:0: ERROR: Identifier \"dict\" does not name a formattable variable (has to be an integer, a string, a floating point number or a boolean)." } ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/107 invalid fstring/meson.build0000644000175000017500000000007214516552205024220 0ustar00jpakkanejpakkaneproject('invalid-fstring') z = f'invalid fstring: @foo@' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/107 invalid fstring/test.json0000644000175000017500000000026014516552205023727 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/107 invalid fstring/meson.build:3:4: ERROR: Identifier \"foo\" does not name a variable." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2146618 meson-1.3.2/test cases/failing/108 compiler argument checking/0000755000175000017500000000000014562742415024153 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/108 compiler argument checking/meson.build0000644000175000017500000000030614516552205026307 0ustar00jpakkanejpakkaneproject('compiler argument checking test', 'c') cc = meson.get_compiler('c') add_project_arguments(cc.get_supported_arguments('-meson-goober-arg-for-testing', checked : 'require'), language : 'c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/108 compiler argument checking/test.json0000644000175000017500000000030114516552205026012 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/108 compiler argument checking/meson.build:4:25: ERROR: Compiler for C does not support \"-meson-goober-arg-for-testing\"" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2146618 meson-1.3.2/test cases/failing/109 empty fallback/0000755000175000017500000000000014562742415021661 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/109 empty fallback/meson.build0000644000175000017500000000034314516552205024016 0ustar00jpakkanejpakkaneproject('empty fallback') # There is a subproject named 'foo' that overrides that dependency, # but `fallback: []` should not allow to use it. Same behaviour than with # `allow_fallback: false` dependency('foo', fallback: []) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.0106282 meson-1.3.2/test cases/failing/109 empty fallback/subprojects/0000755000175000017500000000000014562742413024222 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2186618 meson-1.3.2/test cases/failing/109 empty fallback/subprojects/foo/0000755000175000017500000000000014562742415025007 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/109 empty fallback/subprojects/foo/meson.build0000644000175000017500000000010714516552205027142 0ustar00jpakkanejpakkaneproject('foo') meson.override_dependency('foo', declare_dependency()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/109 empty fallback/test.json0000644000175000017500000000027414516552205023531 0ustar00jpakkanejpakkane{ "stdout": [ { "match": "re", "line": "test cases/failing/109 empty fallback/meson.build:6:0: ERROR: Dependency \"foo\" not found.*" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2186618 meson-1.3.2/test cases/failing/11 object arithmetic/0000755000175000017500000000000014562742415022273 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/11 object arithmetic/meson.build0000644000175000017500000000006014316400150024411 0ustar00jpakkanejpakkaneproject('object arithmetic') foo = '5' + meson ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/test cases/failing/11 object arithmetic/test.json0000644000175000017500000000032114433154642024135 0ustar00jpakkanejpakkane{ "stdout": [ { "match": "re", "line": "test cases/failing/11 object arithmetic/meson\\.build:3:12: ERROR: The `\\+` operator of str does not accept objects of type MesonMain .*" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2186618 meson-1.3.2/test cases/failing/110 cmake executable dependency/0000755000175000017500000000000014562742415024254 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/110 cmake executable dependency/meson.build0000644000175000017500000000036714516552205026417 0ustar00jpakkanejpakkaneproject('cmake-executable-dependency', 'c') if not find_program('cmake', required: false).found() error('MESON_SKIP_TEST CMake is not installed') endif cmake = import('cmake') cmlib = cmake.subproject('cmlib') maind = cmlib.dependency('main') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.0106282 meson-1.3.2/test cases/failing/110 cmake executable dependency/subprojects/0000755000175000017500000000000014562742413026615 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2186618 meson-1.3.2/test cases/failing/110 cmake executable dependency/subprojects/cmlib/0000755000175000017500000000000014562742415027705 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/110 cmake executable dependency/subprojects/cmlib/CMakeLists.txt0000644000175000017500000000012114516552205032432 0ustar00jpakkanejpakkanecmake_minimum_required(VERSION 3.5) project(cmlib) add_executable(main main.c) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/110 cmake executable dependency/subprojects/cmlib/main.c0000644000175000017500000000004114516552205030763 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/110 cmake executable dependency/test.json0000644000175000017500000000043214516552205026120 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/110 cmake executable dependency/meson.build:9:14: ERROR: main is an executable and does not support the dependency() method. Use target() instead." } ], "tools": { "cmake": ">=3.14" } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2186618 meson-1.3.2/test cases/failing/111 allow_fallback with fallback/0000755000175000017500000000000014562742415024405 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/111 allow_fallback with fallback/meson.build0000644000175000017500000000014214516552205026537 0ustar00jpakkanejpakkaneproject('fallback and allow_fallback') dependency('foo', fallback: 'foo', allow_fallback: false) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/111 allow_fallback with fallback/test.json0000644000175000017500000000032614516552205026253 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/111 allow_fallback with fallback/meson.build:3:0: ERROR: \"fallback\" and \"allow_fallback\" arguments are mutually exclusive" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2186618 meson-1.3.2/test cases/failing/112 nonsensical bindgen/0000755000175000017500000000000014562742415022700 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/112 nonsensical bindgen/meson.build0000644000175000017500000000073614516552205025043 0ustar00jpakkanejpakkane# SPDX-license-identifer: Apache-2.0 # Copyright Ā© 2021 Intel Corporation project('rustmod bindgen', 'c') if not add_languages('rust', required: false) error('MESON_SKIP_TEST test requires rust compiler') endif prog_bindgen = find_program('bindgen', required : false) if not prog_bindgen.found() error('MESON_SKIP_TEST bindgen not found') endif c_lib = static_library('clib', 'src/source.c') import('unstable-rust').bindgen( input : c_lib, output : 'header.rs', ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2186618 meson-1.3.2/test cases/failing/112 nonsensical bindgen/src/0000755000175000017500000000000014562742415023467 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/112 nonsensical bindgen/src/header.h0000644000175000017500000000023414516552205025062 0ustar00jpakkanejpakkane// SPDX-license-identifer: Apache-2.0 // Copyright Ā© 2021 Intel Corporation #pragma once #include int32_t add(const int32_t, const int32_t); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/112 nonsensical bindgen/src/source.c0000644000175000017500000000027114516552205025126 0ustar00jpakkanejpakkane// SPDX-license-identifer: Apache-2.0 // Copyright Ā© 2021 Intel Corporation #include "header.h" int32_t add(const int32_t first, const int32_t second) { return first + second; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/112 nonsensical bindgen/test.json0000644000175000017500000000032014516552205024540 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/112 nonsensical bindgen/meson.build:17:24: ERROR: bindgen source file must be a C header, not an object or build target" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2186618 meson-1.3.2/test cases/failing/113 run_target in test/0000755000175000017500000000000014562742415022477 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/113 run_target in test/meson.build0000644000175000017500000000031314516552205024631 0ustar00jpakkanejpakkaneproject('trivial test', 'c') python = find_program('python3') exe = executable('trivialprog', 'trivial.c') runt = run_target('invalid', command: [python, '--version']) test('runtest', exe, args: runt) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/113 run_target in test/test.json0000644000175000017500000000043114516552205024342 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/113 run_target in test/meson.build:7:0: ERROR: test keyword argument 'args' was of type array[RunTarget] but should have been array[str | File | BuildTarget | CustomTarget | CustomTargetIndex]" } ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/113 run_target in test/trivial.c0000644000175000017500000000013614516552205024310 0ustar00jpakkanejpakkane#include int main(void) { printf("Trivial test is working.\n"); return 0; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.222662 meson-1.3.2/test cases/failing/114 run_target in add_install_script/0000755000175000017500000000000014562742415025363 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/114 run_target in add_install_script/meson.build0000644000175000017500000000031614516552205027520 0ustar00jpakkanejpakkaneproject('trivial test', 'c') python = find_program('python3') exe = executable('trivialprog', 'trivial.c') runt = run_target('invalid', command: [python, '--version']) meson.add_install_script(exe, runt) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/114 run_target in add_install_script/test.json0000644000175000017500000000052114516552205027226 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/114 run_target in add_install_script/meson.build:7:6: ERROR: meson.add_install_script argument 2 was of type \"RunTarget\" but should have been one of: \"str\", \"File\", \"BuildTarget\", \"CustomTarget\", \"CustomTargetIndex\", \"ExternalProgram\"" } ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/114 run_target in add_install_script/trivial.c0000644000175000017500000000030114516552205027166 0ustar00jpakkanejpakkane#include int main(int argc, char **argv) { FILE *fp = fopen(argv[1], "r"); if (fp == NULL) { perror("fopen"); return 1; } else { return 0; } } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.222662 meson-1.3.2/test cases/failing/115 pathsep in install_symlink/0000755000175000017500000000000014562742415024230 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/115 pathsep in install_symlink/meson.build0000644000175000017500000000015114516552205026362 0ustar00jpakkanejpakkaneproject('symlink_pathsep') install_symlink('foo/bar', pointing_to: '/usr/baz/bar', install_dir: '/usr') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/115 pathsep in install_symlink/test.json0000644000175000017500000000037614516552205026103 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/115 pathsep in install_symlink/meson.build:3:0: ERROR: Link name is \"foo/bar\", but link names cannot contain path separators. The dir part should be in install_dir." } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.222662 meson-1.3.2/test cases/failing/116 subproject version conflict/0000755000175000017500000000000014562742415024411 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/116 subproject version conflict/meson.build0000644000175000017500000000022614516552205026546 0ustar00jpakkanejpakkaneproject('120 subproject version conflict') A_dep = subproject('A').get_variable('A_dep') B_dep = subproject('B', version: '1').get_variable('B_dep') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.0186284 meson-1.3.2/test cases/failing/116 subproject version conflict/subprojects/0000755000175000017500000000000014562742413026752 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.222662 meson-1.3.2/test cases/failing/116 subproject version conflict/subprojects/A/0000755000175000017500000000000014562742415027134 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/116 subproject version conflict/subprojects/A/meson.build0000644000175000017500000000015414516552205031271 0ustar00jpakkanejpakkaneproject('A') B_dep = subproject('B').get_variable('B_dep') A_dep = declare_dependency(dependencies: B_dep) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.226662 meson-1.3.2/test cases/failing/116 subproject version conflict/subprojects/B/0000755000175000017500000000000014562742415027135 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/116 subproject version conflict/subprojects/B/meson.build0000644000175000017500000000007314516552205031272 0ustar00jpakkanejpakkaneproject('B', version: '100') B_dep = declare_dependency() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/116 subproject version conflict/test.json0000644000175000017500000000027714516552205026264 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/116 subproject version conflict/meson.build:4:8: ERROR: Subproject B version is 100 but ['1'] required." } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.226662 meson-1.3.2/test cases/failing/117 structured source empty string/0000755000175000017500000000000014562742415025075 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/117 structured source empty string/main.rs0000644000175000017500000000000014516552205026350 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/117 structured source empty string/meson.build0000644000175000017500000000041714516552205027234 0ustar00jpakkanejpakkaneproject('structured_source with empty string key') if not add_languages(['rust'], required : false, native : false) error('MESON_SKIP_TEST: Rust is required but not found.') endif executable( 'main', structured_sources( 'main.rs', {'' : 'main.rs'}, ) ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/117 structured source empty string/test.json0000644000175000017500000000033614516552205026744 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/117 structured source empty string/meson.build:9:2: ERROR: structured_sources: keys to dictionary argument may not be an empty string." } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.226662 meson-1.3.2/test cases/failing/118 structured_sources conflicts/0000755000175000017500000000000014562742415024717 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/118 structured_sources conflicts/main.rs0000644000175000017500000000000014516552205026172 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/118 structured_sources conflicts/meson.build0000644000175000017500000000047114516552205027056 0ustar00jpakkanejpakkaneproject('structured_source with empty string key') if not add_languages(['rust'], required : false, native : false) error('MESON_SKIP_TEST: Rust is required but not found.') endif executable( 'main', [ structured_sources( 'main.rs', ), structured_sources( 'main.rs', ), ], ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/118 structured_sources conflicts/test.json0000644000175000017500000000030314516552205026560 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/118 structured_sources conflicts/meson.build:7:0: ERROR: Conflicting sources in structured sources: main.rs" } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.230662 meson-1.3.2/test cases/failing/119 missing compiler/0000755000175000017500000000000014562742415022250 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/119 missing compiler/meson.build0000644000175000017500000000006014516552205024401 0ustar00jpakkanejpakkaneproject('main project', 'c') subproject('sub') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.0186284 meson-1.3.2/test cases/failing/119 missing compiler/subprojects/0000755000175000017500000000000014562742413024611 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.230662 meson-1.3.2/test cases/failing/119 missing compiler/subprojects/sub/0000755000175000017500000000000014562742415025404 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/119 missing compiler/subprojects/sub/main.c0000644000175000017500000000005714516552205026471 0ustar00jpakkanejpakkaneint main(int argc, char *argv[]) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/119 missing compiler/subprojects/sub/meson.build0000644000175000017500000000017114516552205027540 0ustar00jpakkanejpakkaneproject('sub') # Should fail because we did not add C language, even if parent project did. executable('app', 'main.c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/119 missing compiler/test.json0000644000175000017500000000031214516552205024111 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/119 missing compiler/subprojects/sub/meson.build:4:0: ERROR: No host machine compiler for 'subprojects/sub/main.c'" } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.230662 meson-1.3.2/test cases/failing/12 string arithmetic/0000755000175000017500000000000014562742415022334 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/12 string arithmetic/meson.build0000644000175000017500000000005414316400150024455 0ustar00jpakkanejpakkaneproject('string arithmetic') foo = 'a' + 3 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/test cases/failing/12 string arithmetic/test.json0000644000175000017500000000026314433154642024203 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/12 string arithmetic/meson.build:3:12: ERROR: The `+` operator of str does not accept objects of type int (3)" } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.230662 meson-1.3.2/test cases/failing/120 cmake subproject error/0000755000175000017500000000000014562742415023327 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/120 cmake subproject error/meson.build0000644000175000017500000000032114516552205025460 0ustar00jpakkanejpakkaneproject('cmake-executable-dependency') if not find_program('cmake', required: false).found() error('MESON_SKIP_TEST CMake is not installed') endif cmake = import('cmake') cmlib = cmake.subproject('cmlib') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.0226285 meson-1.3.2/test cases/failing/120 cmake subproject error/subprojects/0000755000175000017500000000000014562742413025670 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.230662 meson-1.3.2/test cases/failing/120 cmake subproject error/subprojects/cmlib/0000755000175000017500000000000014562742415026760 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/120 cmake subproject error/subprojects/cmlib/CMakeLists.txt0000644000175000017500000000014014516552205031506 0ustar00jpakkanejpakkanecmake_minimum_required(VERSION 3.5) project(cmlib) message(FATAL_ERROR "Fancy error message") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/120 cmake subproject error/test.json0000644000175000017500000000037114516552205025175 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/120 cmake subproject error/meson.build:8:14: ERROR: Failed to configure the CMake subproject: Fancy error message" } ], "tools": { "cmake": ">=3.14" } } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.230662 meson-1.3.2/test cases/failing/121 pkgconfig not relocatable outside prefix/0000755000175000017500000000000014562742415026676 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/121 pkgconfig not relocatable outside prefix/meson.build0000644000175000017500000000075214516552205031037 0ustar00jpakkanejpakkaneproject( 'pkgconfig-not-relocatable-outside-prefix', version : '1.0', default_options: [ 'pkgconfig.relocatable=true', ]) pkgg = import('pkgconfig') # A drive letter is needed on windows for this to be an absolute path. if host_machine.system() == 'windows' install_dir = 'C:/opt/lib/pkgconfig' else install_dir = '/opt/lib/pkgconfig' endif pkgg.generate( name : 'libsimple', version : '1.0', description : 'A simple pkgconfig file.', install_dir: install_dir, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/121 pkgconfig not relocatable outside prefix/test.json0000644000175000017500000000044314516552205030544 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/121 pkgconfig not relocatable outside prefix/meson\\.build:17:5: ERROR: Pkgconfig prefix cannot be outside of the prefix when pkgconfig\\.relocatable=true. Pkgconfig prefix is (C:)?/opt/lib/pkgconfig.", "match": "re" } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.234662 meson-1.3.2/test cases/failing/122 subproject sandbox violation/0000755000175000017500000000000014562742415024562 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/122 subproject sandbox violation/meson.build0000644000175000017500000000160314516552205026717 0ustar00jpakkanejpakkaneproject('subproject-sandbox-violation') sub1_d = subproject('subproj1').get_variable('d') sub1_mustfail = sub1_d.get_variable('dir') / '..' / 'file.txt' sub2_d = subproject('subproj2').get_variable('d') sub2_mustfail = sub2_d.get_variable('dir') / 'file.txt' main_d = declare_dependency( variables: [ 'dir=@0@'.format(meson.current_source_dir()), ] ) main_mustfail = main_d.get_variable('dir') / 'subprojects/subproj3/file.txt' if get_option('failmode') == 'parent-dir' mustfail = sub1_mustfail elif get_option('failmode') == 'not-installed' mustfail = sub2_mustfail elif get_option('failmode') == 'root-subdir' mustfail = main_mustfail endif custom_target( 'mustfail', input: mustfail, output: 'file.txt', command: [ 'python3', '-c', 'import os; shutil.copy(sys.argv[1], sys.argv[2])', '@INPUT@', '@OUTPUT@' ], ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/122 subproject sandbox violation/meson_options.txt0000644000175000017500000000013314516552205030207 0ustar00jpakkanejpakkaneoption('failmode', type: 'combo', choices: ['parent-dir', 'not-installed', 'root-subdir']) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.0266285 meson-1.3.2/test cases/failing/122 subproject sandbox violation/subprojects/0000755000175000017500000000000014562742413027123 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.234662 meson-1.3.2/test cases/failing/122 subproject sandbox violation/subprojects/subproj1/0000755000175000017500000000000014562742415030672 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/122 subproject sandbox violation/subprojects/subproj1/file.txt0000644000175000017500000000000014516552205032333 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/122 subproject sandbox violation/subprojects/subproj1/meson.build0000644000175000017500000000007714516552205033033 0ustar00jpakkanejpakkaneproject('subproj1') install_data('file.txt') subdir('nested') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.234662 meson-1.3.2/test cases/failing/122 subproject sandbox violation/subprojects/subproj1/nested/0000755000175000017500000000000014562742415032154 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000020700000000000010214 xustar00113 path=meson-1.3.2/test cases/failing/122 subproject sandbox violation/subprojects/subproj1/nested/meson.build 22 mtime=1698354309.0 meson-1.3.2/test cases/failing/122 subproject sandbox violation/subprojects/subproj1/nested/meson.bu0000644000175000017500000000014714516552205033622 0ustar00jpakkanejpakkaned = declare_dependency( variables: [ 'dir=@0@'.format(meson.current_source_dir()), ] ) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.234662 meson-1.3.2/test cases/failing/122 subproject sandbox violation/subprojects/subproj2/0000755000175000017500000000000014562742415030673 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/122 subproject sandbox violation/subprojects/subproj2/file.txt0000644000175000017500000000000014516552205032334 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/122 subproject sandbox violation/subprojects/subproj2/meson.build0000644000175000017500000000017414516552205033032 0ustar00jpakkanejpakkaneproject('subproj1') d = declare_dependency( variables: [ 'dir=@0@'.format(meson.current_source_dir()), ] ) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.234662 meson-1.3.2/test cases/failing/122 subproject sandbox violation/subprojects/subproj2/nested/0000755000175000017500000000000014562742415032155 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000020700000000000010214 xustar00113 path=meson-1.3.2/test cases/failing/122 subproject sandbox violation/subprojects/subproj2/nested/meson.build 22 mtime=1698354309.0 meson-1.3.2/test cases/failing/122 subproject sandbox violation/subprojects/subproj2/nested/meson.bu0000644000175000017500000000000014516552205033607 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.234662 meson-1.3.2/test cases/failing/122 subproject sandbox violation/subprojects/subproj3/0000755000175000017500000000000014562742415030674 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/122 subproject sandbox violation/subprojects/subproj3/file.txt0000644000175000017500000000000014516552205032335 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/122 subproject sandbox violation/subprojects/subproj3/meson.build0000644000175000017500000000005614516552205033032 0ustar00jpakkanejpakkaneproject('subproj2') install_data('file.txt') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/122 subproject sandbox violation/test.json0000644000175000017500000000056414516552205026434 0ustar00jpakkanejpakkane{ "matrix": { "options": { "failmode": [ { "val": "not-installed" }, { "val": "parent-dir" }, { "val": "root-subdir" } ] } }, "stdout": [ { "line": "test cases/failing/122 subproject sandbox violation/meson.build:24:0: ERROR: Sandbox violation: Tried to grab file file.txt from a nested subproject." } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.238662 meson-1.3.2/test cases/failing/123 override and add_project_dependency/0000755000175000017500000000000014562742415025776 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.238662 meson-1.3.2/test cases/failing/123 override and add_project_dependency/inc/0000755000175000017500000000000014562742415026547 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/123 override and add_project_dependency/inc/lib.h0000644000175000017500000000003314516552205027455 0ustar00jpakkanejpakkane#pragma once void f(void); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/123 override and add_project_dependency/lib.c0000644000175000017500000000007614516552205026706 0ustar00jpakkanejpakkane#include #include "lib.h" void f() {puts("hello");} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/123 override and add_project_dependency/meson.build0000644000175000017500000000035714516552205030140 0ustar00jpakkanejpakkaneproject('super', 'c') inc = include_directories('inc') lib = static_library('sneaky', 'lib.c', include_directories: inc) meson.override_dependency('sneaky', declare_dependency(link_with: lib, include_directories: inc)) subproject('a') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.0306287 meson-1.3.2/test cases/failing/123 override and add_project_dependency/subprojects/0000755000175000017500000000000014562742413030337 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.238662 meson-1.3.2/test cases/failing/123 override and add_project_dependency/subprojects/a/0000755000175000017500000000000014562742415030561 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/123 override and add_project_dependency/subprojects/a/meson.build0000644000175000017500000000032714516552205032720 0ustar00jpakkanejpakkaneproject('a', 'c') dep = dependency('sneaky') # does not work add_project_dependencies(dep, language: 'c') executable('prog', 'prog.c') # this would work instead: # executable('prog', 'prog.c', dependencies: dep) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/123 override and add_project_dependency/subprojects/a/prog.c0000644000175000017500000000007014516552205031664 0ustar00jpakkanejpakkane#include "lib.h" int main() { f(); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/123 override and add_project_dependency/test.json0000644000175000017500000000027614516552205027650 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/123 override and add_project_dependency/subprojects/a/meson.build:6:0: ERROR: Dependencies must be external dependencies" } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.238662 meson-1.3.2/test cases/failing/124 targets before add_project_dependency/0000755000175000017500000000000014562742415026331 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.238662 meson-1.3.2/test cases/failing/124 targets before add_project_dependency/inc/0000755000175000017500000000000014562742415027102 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/124 targets before add_project_dependency/inc/lib.h0000644000175000017500000000003314516552205030010 0ustar00jpakkanejpakkane#pragma once void f(void); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/124 targets before add_project_dependency/lib.c0000644000175000017500000000007614516552205027241 0ustar00jpakkanejpakkane#include #include "lib.h" void f() {puts("hello");} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/124 targets before add_project_dependency/meson.build0000644000175000017500000000025414516552205030467 0ustar00jpakkanejpakkaneproject('test', 'c') static_library('lib', 'lib.c') inc = include_directories('inc') add_project_dependencies(declare_dependency(include_directories: inc), language: 'c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/124 targets before add_project_dependency/test.json0000644000175000017500000000032714516552205030200 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/124 targets before add_project_dependency/meson.build:5:0: ERROR: Tried to use 'add_project_dependencies' after a build target has been declared." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2466621 meson-1.3.2/test cases/failing/125 extract from unity/0000755000175000017500000000000014562742415022530 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/125 extract from unity/meson.build0000644000175000017500000000026414516552205024667 0ustar00jpakkanejpakkaneproject('extract nonexisting gen', 'c') lib1 = library('lib1', 'src1.c', 'src2.c', override_options: ['unity=on']) lib2 = library('lib2', objects: lib1.extract_objects('src1.c')) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/125 extract from unity/src1.c0000644000175000017500000000005314516552205023535 0ustar00jpakkanejpakkaneint sub_lib_method1() { return 1337; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/125 extract from unity/src2.c0000644000175000017500000000005314516552205023536 0ustar00jpakkanejpakkaneint sub_lib_method2() { return 1337; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/125 extract from unity/test.json0000644000175000017500000000036314516552205024377 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/125 extract from unity/meson.build:4:37: ERROR: Single object files cannot be extracted in Unity builds. You can only extract all the object files for each compiler at once." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2466621 meson-1.3.2/test cases/failing/126 subproject object as a dependency/0000755000175000017500000000000014562742415025275 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/126 subproject object as a dependency/main.c0000644000175000017500000000003514516552205026356 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/126 subproject object as a dependency/meson.build0000644000175000017500000000012714516552205027432 0ustar00jpakkanejpakkaneproject('test', 'c') executable( 'main', 'main.c', dependencies: subproject('sub')) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.0306287 meson-1.3.2/test cases/failing/126 subproject object as a dependency/subprojects/0000755000175000017500000000000014562742413027636 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2506623 meson-1.3.2/test cases/failing/126 subproject object as a dependency/subprojects/sub/0000755000175000017500000000000014562742415030431 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/126 subproject object as a dependency/subprojects/sub/meson.build0000644000175000017500000000001714516552205032564 0ustar00jpakkanejpakkaneproject('sub') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/126 subproject object as a dependency/test.json0000644000175000017500000000026314516552205027143 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/126 subproject object as a dependency/meson.build:3:0: ERROR: Tried to use subproject object as a dependency." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2506623 meson-1.3.2/test cases/failing/127 generator host binary/0000755000175000017500000000000014562742415023174 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/127 generator host binary/exe.c0000644000175000017500000000003514516552205024112 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/127 generator host binary/lib.in0000644000175000017500000000003414516552205024262 0ustar00jpakkanejpakkaneint foo(void) { return 7; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/127 generator host binary/meson.build0000644000175000017500000000061114516552205025327 0ustar00jpakkanejpakkaneproject('generator host binary no exe_wrapper') if meson.can_run_host_binaries() error('MESON_SKIP_TEST: test requires that build machine cannot run host binaries') endif add_languages('c', native : false) exe = executable('exe', 'exe.c', native : false) gen = generator(exe, output : '@BASENAME@.c', arguments : ['@INPUT@', '@OUTPUT@']) foo = gen.process('lib.in') library('foo', foo) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/127 generator host binary/test.json0000644000175000017500000000025014516552205025036 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "ERROR: An exe_wrapper is needed but was not found. Please define one in cross file and check the command and/or add it to PATH." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2506623 meson-1.3.2/test cases/failing/128 invalid ast/0000755000175000017500000000000014562742415021202 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/128 invalid ast/meson.build0000644000175000017500000000007414516552205023340 0ustar00jpakkanejpakkaneproject('invalid ast crash', meson_version: '0.1.0') = >%@ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/128 invalid ast/test.json0000644000175000017500000000030614516552205023046 0ustar00jpakkanejpakkane{ "stdout": [ { "match": "re", "line": "test cases/failing/128 invalid ast/meson.build:1:44: ERROR: Meson version is [0-9.]+(\\.rc[0-9]+)? but project requires 0.1.0" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2506623 meson-1.3.2/test cases/failing/129 invalid project function/0000755000175000017500000000000014562742415023670 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/129 invalid project function/meson.build0000644000175000017500000000014214516552205026022 0ustar00jpakkanejpakkaneproject('invalid project function with bad kwargs', meson_version: '0.1.0', unknown_kwarg: 'val') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/129 invalid project function/test.json0000644000175000017500000000032314516552205025533 0ustar00jpakkanejpakkane{ "stdout": [ { "match": "re", "line": "test cases/failing/129 invalid project function/meson.build:1:67: ERROR: Meson version is [0-9.]+(\\.rc[0-9]+)? but project requires 0.1.0" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2506623 meson-1.3.2/test cases/failing/13 array arithmetic/0000755000175000017500000000000014562742415022145 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/13 array arithmetic/meson.build0000644000175000017500000000006214316400150024265 0ustar00jpakkanejpakkaneproject('array arithmetic') foo = ['a', 'b'] * 3 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/test cases/failing/13 array arithmetic/test.json0000644000175000017500000000032314433154642024011 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/13 array arithmetic/meson.build:3:19: ERROR: Object <[ArrayHolder] holds [list]: ['a', 'b']> of type array does not support the `*` operator." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2506623 meson-1.3.2/test cases/failing/14 invalid option name/0000755000175000017500000000000014562742415022536 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/14 invalid option name/meson.build0000644000175000017500000000001714316400150024656 0ustar00jpakkanejpakkaneproject('foo') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/14 invalid option name/meson_options.txt0000644000175000017500000000007013716006331026156 0ustar00jpakkanejpakkaneoption('invalid:name', type : 'boolean', value : false) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/14 invalid option name/test.json0000644000175000017500000000026413716006331024400 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/14 invalid option name/meson_options.txt:1:0: ERROR: Option names can only contain letters, numbers or dashes." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2546623 meson-1.3.2/test cases/failing/15 kwarg before arg/0000755000175000017500000000000014562742415022007 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/15 kwarg before arg/meson.build0000644000175000017500000000011113716006331024130 0ustar00jpakkanejpakkaneproject('kwarg before arg', 'c') executable(sources : 'prog.c', 'prog') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/15 kwarg before arg/prog.c0000644000175000017500000000005613716006331023111 0ustar00jpakkanejpakkaneint main(int argc, char **argv) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/15 kwarg before arg/test.json0000644000175000017500000000025313716006331023647 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/15 kwarg before arg/meson.build:3:0: ERROR: All keyword arguments must be after positional arguments." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2546623 meson-1.3.2/test cases/failing/16 extract from subproject/0000755000175000017500000000000014562742415023457 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/16 extract from subproject/main.c0000644000175000017500000000012213716006331024530 0ustar00jpakkanejpakkaneint sub_lib_method(void); int main(void) { return 1337 - sub_lib_method(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/16 extract from subproject/meson.build0000644000175000017500000000033013716006331025603 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.0346286 meson-1.3.2/test cases/failing/16 extract from subproject/subprojects/0000755000175000017500000000000014562742413026020 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2626624 meson-1.3.2/test cases/failing/16 extract from subproject/subprojects/sub_project/0000755000175000017500000000000014562742415030341 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/failing/16 extract from subproject/subprojects/sub_project/meson.build0000644000175000017500000000013714107166547032505 0ustar00jpakkanejpakkaneproject('extract subproject object -- subproject', 'c') lib = library('sub_lib', 'sub_lib.c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/16 extract from subproject/subprojects/sub_project/sub_lib.c0000644000175000017500000000005213716006331032107 0ustar00jpakkanejpakkaneint sub_lib_method() { return 1337; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/test cases/failing/16 extract from subproject/test.json0000644000175000017500000000025714433154642025331 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/16 extract from subproject/meson.build:7:32: ERROR: Tried to extract objects from a different subproject." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2626624 meson-1.3.2/test cases/failing/17 same target/0000755000175000017500000000000014562742415021115 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/17 same target/file.c0000644000175000017500000000003113716006331022160 0ustar00jpakkanejpakkaneint func() { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/17 same target/meson.build0000644000175000017500000000013513716006331023244 0ustar00jpakkanejpakkaneproject('same target', 'c') static_library('foo', 'file.c') static_library('foo', 'file.c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/17 same target/test.json0000644000175000017500000000026613716006331022761 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/17 same target/meson.build:4:0: ERROR: Tried to create target \"foo\", but a target of that name already exists." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2666626 meson-1.3.2/test cases/failing/18 wrong plusassign/0000755000175000017500000000000014562742415022227 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/18 wrong plusassign/meson.build0000644000175000017500000000004414316400150024347 0ustar00jpakkanejpakkaneproject('false plusassign') 3 += 4 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/18 wrong plusassign/test.json0000644000175000017500000000022613716006331024067 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/18 wrong plusassign/meson.build:3:0: ERROR: Plusassignment target must be an id." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2666626 meson-1.3.2/test cases/failing/19 target clash/0000755000175000017500000000000014562742415021264 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/19 target clash/clash.c0000644000175000017500000000013713716006331022511 0ustar00jpakkanejpakkane#include int main(int argc, char **argv) { printf("Clash 2.\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/19 target clash/meson.build0000644000175000017500000000106213716006331023413 0ustar00jpakkanejpakkaneproject('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('MESON_SKIP_TEST test only works on platforms where executables have no suffix.') endif executable('clash', 'clash.c') run_target('clash', command: ['echo', 'clash 1']) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/19 target clash/test.json0000644000175000017500000000020413716006331023120 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "ERROR: Multiple producers for Ninja target \"clash\". Please rename your targets." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2666626 meson-1.3.2/test cases/failing/2 missing file/0000755000175000017500000000000014562742415021204 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/2 missing file/meson.build0000644000175000017500000000007613716006331023337 0ustar00jpakkanejpakkaneproject('missing file', 'c') executable('prog', 'missing.c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/2 missing file/test.json0000644000175000017500000000021313716006331023040 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/2 missing file/meson.build:3:0: ERROR: File missing.c does not exist." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2666626 meson-1.3.2/test cases/failing/20 version/0000755000175000017500000000000014562742415020400 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/20 version/meson.build0000644000175000017500000000007014316400150022517 0ustar00jpakkanejpakkaneproject('version mismatch', meson_version : '>100.0.0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/test cases/failing/20 version/test.json0000644000175000017500000000026614433154642022252 0ustar00jpakkanejpakkane{ "stdout": [ { "match": "re", "line": "test cases/failing/20 version/meson\\.build:1:44: ERROR: Meson version is .* but project requires >100\\.0\\.0" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2666626 meson-1.3.2/test cases/failing/21 subver/0000755000175000017500000000000014562742415020222 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/21 subver/meson.build0000644000175000017500000000007514316400150022346 0ustar00jpakkanejpakkaneproject('master') x = subproject('foo', version : '>1.0.0') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.0346286 meson-1.3.2/test cases/failing/21 subver/subprojects/0000755000175000017500000000000014562742413022563 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2666626 meson-1.3.2/test cases/failing/21 subver/subprojects/foo/0000755000175000017500000000000014562742415023350 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/21 subver/subprojects/foo/meson.build0000644000175000017500000000004214316400150025466 0ustar00jpakkanejpakkaneproject('foo', version : '1.0.0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/test cases/failing/21 subver/test.json0000644000175000017500000000024014433154642022064 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/21 subver/meson.build:3:4: ERROR: Subproject foo version is 1.0.0 but ['>1.0.0'] required." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2666626 meson-1.3.2/test cases/failing/22 assert/0000755000175000017500000000000014562742415020216 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/22 assert/meson.build0000644000175000017500000000006714316400150022343 0ustar00jpakkanejpakkaneproject('failing assert') assert(false, 'I am fail.') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/22 assert/test.json0000644000175000017500000000020113716006331022047 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/22 assert/meson.build:3:0: ERROR: Assert failed: I am fail." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2666626 meson-1.3.2/test cases/failing/23 rel testdir/0000755000175000017500000000000014562742415021137 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/23 rel testdir/meson.build0000644000175000017500000000015213716006331023265 0ustar00jpakkanejpakkaneproject('nonabs workdir', 'c') exe = executable('simple', 'simple.c') test('simple', exe, workdir : '.') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/23 rel testdir/simple.c0000644000175000017500000000006213716006331022560 0ustar00jpakkanejpakkaneint main(int argc, char **argv) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/failing/23 rel testdir/test.json0000644000175000017500000000024714140314117022776 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/23 rel testdir/meson.build:4:0: ERROR: test keyword argument \"workdir\" must be an absolute path" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2746627 meson-1.3.2/test cases/failing/24 int conversion/0000755000175000017500000000000014562742415021657 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/24 int conversion/meson.build0000644000175000017500000000006114316400150023776 0ustar00jpakkanejpakkaneproject('int conversion') 'notanumber'.to_int() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/24 int conversion/test.json0000644000175000017500000000023713716006331023521 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/24 int conversion/meson.build:3:13: ERROR: String 'notanumber' cannot be converted to int" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2746627 meson-1.3.2/test cases/failing/25 badlang/0000755000175000017500000000000014562742415020310 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/25 badlang/meson.build0000644000175000017500000000006114316400150022427 0ustar00jpakkanejpakkaneproject('badlang') add_languages('nonexisting') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/25 badlang/test.json0000644000175000017500000000022713716006331022151 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/25 badlang/meson.build:3:0: ERROR: Tried to use unknown language \"nonexisting\"." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2746627 meson-1.3.2/test cases/failing/26 output subdir/0000755000175000017500000000000014562742415021532 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/26 output subdir/foo.in0000644000175000017500000000001613716006331022630 0ustar00jpakkanejpakkaneNothing here. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/26 output subdir/meson.build0000644000175000017500000000014014316400150023647 0ustar00jpakkanejpakkaneproject('outdir path') configure_file(input : 'foo.in', output : 'subdir/foo', copy: true) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2746627 meson-1.3.2/test cases/failing/26 output subdir/subdir/0000755000175000017500000000000014562742415023022 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/failing/26 output subdir/subdir/dummy.txt0000644000175000017500000000006614140314117024702 0ustar00jpakkanejpakkaneI'm only here because Git is stupid about empty dirs. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/26 output subdir/test.json0000644000175000017500000000031614253672217023403 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/26 output subdir/meson.build:3:0: ERROR: configure_file keyword argument \"output\" Output 'subdir/foo' must not contain a path segment." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2746627 meson-1.3.2/test cases/failing/27 noprog use/0000755000175000017500000000000014562742415021003 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/27 noprog use/meson.build0000644000175000017500000000030214316400150023120 0ustar00jpakkanejpakkaneproject('using not found exe') nope = find_program('nonexisting', required : false) custom_target( 'aa', input: 'meson.build', output: 'foobar', command: [nope, '@INPUT@', '@OUTPUT@'] ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/27 noprog use/test.json0000644000175000017500000000024213716006331022641 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/27 noprog use/meson.build:5:0: ERROR: Tried to use not-found external program in \"command\"" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2746627 meson-1.3.2/test cases/failing/28 no crossprop/0000755000175000017500000000000014562742415021352 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/28 no crossprop/meson.build0000644000175000017500000000011214316400150023466 0ustar00jpakkanejpakkaneproject('no crossprop') message(meson.get_cross_property('nonexisting')) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/test cases/failing/28 no crossprop/test.json0000644000175000017500000000023514433154642023220 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/28 no crossprop/meson.build:3:14: ERROR: Unknown property for host machine: nonexisting" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2826629 meson-1.3.2/test cases/failing/29 nested ternary/0000755000175000017500000000000014562742415021653 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/29 nested ternary/meson.build0000644000175000017500000000007214316400150023774 0ustar00jpakkanejpakkaneproject('nested ternary') x = true ? (false ? 1 : 0) : 2 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/29 nested ternary/test.json0000644000175000017500000000023213716006331023510 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/29 nested ternary/meson.build:3:12: ERROR: Nested ternary operators are not allowed." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2826629 meson-1.3.2/test cases/failing/3 missing subdir/0000755000175000017500000000000014562742415021556 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/3 missing subdir/meson.build0000644000175000017500000000004514316400150023677 0ustar00jpakkanejpakkaneproject('subdir') subdir('missing') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/test cases/failing/3 missing subdir/test.json0000644000175000017500000000042714433154642023427 0ustar00jpakkanejpakkane{ "stdout": [ { "comment": "'missing/meson.build' gets transformed with os.path.sep separators", "match": "re", "line": "test cases/failing/3 missing subdir/meson\\.build:3:0: ERROR: Nonexistent build file 'missing[\\\\/]meson\\.build'" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2826629 meson-1.3.2/test cases/failing/30 invalid man extension/0000755000175000017500000000000014562742415023073 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/30 invalid man extension/foo.a10000644000175000017500000000000013716006331024055 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/30 invalid man extension/meson.build0000644000175000017500000000006214316400150025213 0ustar00jpakkanejpakkaneproject('man install') m1 = install_man('foo.a1') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/test cases/failing/30 invalid man extension/test.json0000644000175000017500000000026614433154642024745 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/30 invalid man extension/meson.build:2:5: ERROR: Man file must have a file extension of a number between 1 and 9" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2826629 meson-1.3.2/test cases/failing/31 no man extension/0000755000175000017500000000000014562742415022062 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/31 no man extension/foo0000644000175000017500000000000013716006331022544 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/31 no man extension/meson.build0000644000175000017500000000005714316400150024206 0ustar00jpakkanejpakkaneproject('man install') m1 = install_man('foo') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/test cases/failing/31 no man extension/test.json0000644000175000017500000000026114433154642023727 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/31 no man extension/meson.build:2:5: ERROR: Man file must have a file extension of a number between 1 and 9" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2826629 meson-1.3.2/test cases/failing/32 exe static shared/0000755000175000017500000000000014562742415022176 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/32 exe static shared/meson.build0000644000175000017500000000057613716006331024336 0ustar00jpakkanejpakkaneproject('statchain', 'c') host_system = host_machine.system() if host_system == 'windows' or host_system == 'darwin' error('MESON_SKIP_TEST 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/32 exe static shared/prog.c0000644000175000017500000000026513716006331023302 0ustar00jpakkanejpakkaneint shlibfunc2(); int statlibfunc(); int main(int argc, char **argv) { if (statlibfunc() != 42) return 1; if (shlibfunc2() != 24) return 1; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/32 exe static shared/shlib2.c0000644000175000017500000000056013716006331023514 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/32 exe static shared/stat.c0000644000175000017500000000004513716006331023302 0ustar00jpakkanejpakkaneint statlibfunc() { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/test cases/failing/32 exe static shared/test.json0000644000175000017500000000036114433154642024044 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/32 exe static shared/meson.build:9:9: ERROR: Can't link non-PIC static library 'stat' into shared library 'shr2'. Use the 'pic' option to static_library to build with PIC." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2826629 meson-1.3.2/test cases/failing/33 non-root subproject/0000755000175000017500000000000014562742415022633 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/33 non-root subproject/meson.build0000644000175000017500000000005714316400150024757 0ustar00jpakkanejpakkaneproject('non-root subproject') subdir('some') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2866628 meson-1.3.2/test cases/failing/33 non-root subproject/some/0000755000175000017500000000000014562742415023576 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/33 non-root subproject/some/meson.build0000644000175000017500000000011313716006331025721 0ustar00jpakkanejpakkanedependency('definitely-doesnt-exist', fallback : ['someproj', 'some_dep']) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/failing/33 non-root subproject/test.json0000644000175000017500000000027414031433465024501 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/33 non-root subproject/some/meson.build:1:0: ERROR: Neither a subproject directory nor a someproj.wrap file was found." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2866628 meson-1.3.2/test cases/failing/34 dependency not-required then required/0000755000175000017500000000000014562742415026155 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/34 dependency not-required then required/meson.build0000644000175000017500000000021214316400150030272 0ustar00jpakkanejpakkaneproject('dep-test', version : '1.0') foo_dep = dependency('foo-bar-xyz-12.3', required : false) bar_dep = dependency('foo-bar-xyz-12.3') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/test cases/failing/34 dependency not-required then required/test.json0000644000175000017500000000036014433154642030022 0ustar00jpakkanejpakkane{ "stdout": [ { "match": "re", "line": ".*/meson\\.build:4:10: ERROR: (Pkg-config binary for machine MachineChoice\\.HOST not found\\. Giving up\\.|Dependency \"foo\\-bar\\-xyz\\-12\\.3\" not found, tried .*)" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2866628 meson-1.3.2/test cases/failing/35 project argument after target/0000755000175000017500000000000014562742415024523 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/35 project argument after target/exe.c0000644000175000017500000000006213716006331025434 0ustar00jpakkanejpakkaneint main(int argc, char **argv) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/35 project argument after target/meson.build0000644000175000017500000000036713716006331026661 0ustar00jpakkanejpakkaneproject('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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/35 project argument after target/test.json0000644000175000017500000000031313716006331026360 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/35 project argument after target/meson.build:7:0: ERROR: Tried to use 'add_project_arguments' after a build target has been declared." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2866628 meson-1.3.2/test cases/failing/36 pkgconfig dependency impossible conditions/0000755000175000017500000000000014562742415027251 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/36 pkgconfig dependency impossible conditions/meson.build0000644000175000017500000000031613716006331031401 0ustar00jpakkanejpakkaneproject('impossible-dep-test', 'c', version : '1.0') if not dependency('zlib', required: false).found() error('MESON_SKIP_TEST test requires zlib') endif dependency('zlib', version : ['>=1.0', '<1.0']) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/failing/36 pkgconfig dependency impossible conditions/test.json0000644000175000017500000000027014107166547031123 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/36 pkgconfig dependency impossible conditions/meson.build:7:0: ERROR: Dependency 'zlib' is required but not found." } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.294663 meson-1.3.2/test cases/failing/37 has function external dependency/0000755000175000017500000000000014562742415025206 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/37 has function external dependency/meson.build0000644000175000017500000000040013716006331027330 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/37 has function external dependency/mylib.c0000644000175000017500000000004113716006331026447 0ustar00jpakkanejpakkaneint testfunc(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/37 has function external dependency/test.json0000644000175000017500000000025413716006331027047 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/37 has function external dependency/meson.build:8:3: ERROR: Dependencies must be external dependencies" } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.294663 meson-1.3.2/test cases/failing/38 prefix absolute/0000755000175000017500000000000014562742415022020 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/38 prefix absolute/meson.build0000644000175000017500000000010714316400150024140 0ustar00jpakkanejpakkaneproject('prefix-abs', default_options : ['prefix=some/path/notabs']) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/38 prefix absolute/test.json0000644000175000017500000000050614253672217023672 0ustar00jpakkanejpakkane{ "do_not_set_opts": [ "prefix" ], "stdout": [ { "comment": "literal 'some/path/notabs' appears in output, irrespective of os.path.sep, as that's the prefix", "line": "test cases/failing/38 prefix absolute/meson.build:1:0: ERROR: prefix value 'some/path/notabs' must be an absolute path" } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.294663 meson-1.3.2/test cases/failing/39 kwarg assign/0000755000175000017500000000000014562742415021305 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/39 kwarg assign/dummy.c0000644000175000017500000000006414253672217022603 0ustar00jpakkanejpakkaneconst char* dummy() { return "I do nothing."; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/39 kwarg assign/meson.build0000644000175000017500000000012014253672217023437 0ustar00jpakkanejpakkaneproject('assign in kwarg', 'c') executable('prog', 'dummy.c', args = 'prog.c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/39 kwarg assign/prog.c0000644000175000017500000000006214253672217022415 0ustar00jpakkanejpakkaneint main(int argc, char **argv) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/test cases/failing/39 kwarg assign/test.json0000644000175000017500000000023614433154642023154 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/39 kwarg assign/meson.build:3:30: ERROR: Tried to assign values inside an argument list." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2986631 meson-1.3.2/test cases/failing/4 missing meson.build/0000755000175000017500000000000014562742415022506 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/4 missing meson.build/meson.build0000644000175000017500000000006114316400150024625 0ustar00jpakkanejpakkaneproject('missing meson.build') subdir('subdir') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2986631 meson-1.3.2/test cases/failing/4 missing meson.build/subdir/0000755000175000017500000000000014562742415023776 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/4 missing meson.build/subdir/dummy.txt0000644000175000017500000000007313716006331025660 0ustar00jpakkanejpakkaneThis needs to be here because Git can't handle empty dirs. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/test cases/failing/4 missing meson.build/test.json0000644000175000017500000000042614433154642024356 0ustar00jpakkanejpakkane{ "stdout": [ { "match": "re", "comment": "'subdir/meson.build' gets transformed with os.path.sep separators", "line": "test cases/failing/4 missing meson\\.build/meson\\.build:3:0: ERROR: Nonexistent build file 'subdir[\\\\/]meson\\.build'" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2986631 meson-1.3.2/test cases/failing/40 custom target plainname many inputs/0000755000175000017500000000000014562742415025653 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/40 custom target plainname many inputs/1.txt0000644000175000017500000000000214253672217026543 0ustar00jpakkanejpakkane1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/40 custom target plainname many inputs/2.txt0000644000175000017500000000000214253672217026544 0ustar00jpakkanejpakkane2 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/40 custom target plainname many inputs/catfiles.py0000644000175000017500000000027014253672217030015 0ustar00jpakkanejpakkane#!/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()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/40 custom target plainname many inputs/meson.build0000644000175000017500000000033014316400150027771 0ustar00jpakkanejpakkaneproject('plain name many inputs') catfiles = find_program('catfiles.py') custom_target('plainname-inputs', input : ['1.txt', '2.txt'], output : '@PLAINNAME@.dat', command : [catfiles, '@INPUT@', '@OUTPUT@']) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1670690299.0 meson-1.3.2/test cases/failing/40 custom target plainname many inputs/test.json0000644000175000017500000000041214345132773027521 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/40 custom target plainname many inputs/meson.build:5:0: ERROR: custom_target: output cannot contain \"@PLAINNAME@\" or \"@BASENAME@\" when there is more than one input (we can't know which to use)" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.2986631 meson-1.3.2/test cases/failing/41 custom target outputs not matching install_dirs/0000755000175000017500000000000014562742415030207 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/41 custom target outputs not matching install_dirs/generator.py0000755000175000017500000000066614253672217032561 0ustar00jpakkanejpakkane#!/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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/41 custom target outputs not matching install_dirs/meson.build0000644000175000017500000000063514316400150032335 0ustar00jpakkanejpakkaneproject('outputs not matching install_dirs') gen = find_program('generator.py') if meson.backend() != 'ninja' error('MESON_SKIP_TEST 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]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/41 custom target outputs not matching install_dirs/test.json0000644000175000017500000000113414253672217032057 0ustar00jpakkanejpakkane{ "installed": [ { "type": "file", "file": "usr/include/diff.h" }, { "type": "file", "file": "usr/include/first.h" }, { "type": "file", "file": "usr/bin/diff.sh" }, { "type": "file", "file": "usr/bin/second.sh" }, { "type": "file", "file": "opt/same.h" }, { "type": "file", "file": "opt/same.sh" } ], "stdout": [ { "line": "ERROR: Target 'too-few-install-dirs' has 3 outputs: ['toofew.h', 'toofew.c', 'toofew.sh'], but only 2 \"install_dir\"s were found." } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.302663 meson-1.3.2/test cases/failing/42 project name colon/0000755000175000017500000000000014562742415022361 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/42 project name colon/meson.build0000644000175000017500000000002714253672217024521 0ustar00jpakkanejpakkaneproject('name with :') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/42 project name colon/test.json0000644000175000017500000000024314253672217024231 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/42 project name colon/meson.build:1:0: ERROR: Project name 'name with :' must not contain ':'" } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.302663 meson-1.3.2/test cases/failing/43 abs subdir/0000755000175000017500000000000014562742415020736 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.302663 meson-1.3.2/test cases/failing/43 abs subdir/bob/0000755000175000017500000000000014562742415021500 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/43 abs subdir/bob/meson.build0000644000175000017500000000004414253672217023637 0ustar00jpakkanejpakkane# This file is never reached. x = 3 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/43 abs subdir/meson.build0000644000175000017500000000027014316400150023057 0ustar00jpakkanejpakkaneproject('abs subdir') # 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')) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/43 abs subdir/test.json0000644000175000017500000000022414253672217022605 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/43 abs subdir/meson.build:5:0: ERROR: Subdir argument must be a relative path." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3106632 meson-1.3.2/test cases/failing/44 abspath to srcdir/0000755000175000017500000000000014562742415022215 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/44 abspath to srcdir/meson.build0000644000175000017500000000010214316400150024330 0ustar00jpakkanejpakkaneproject('meson') include_directories(meson.current_source_dir()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1666639513.0 meson-1.3.2/test cases/failing/44 abspath to srcdir/test.json0000644000175000017500000000025614325563231024064 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/44 abspath to srcdir/meson.build:3:0: ERROR: Tried to form an absolute path to a dir in the source tree." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3146632 meson-1.3.2/test cases/failing/45 pkgconfig variables reserved/0000755000175000017500000000000014562742415024422 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/45 pkgconfig variables reserved/meson.build0000644000175000017500000000057214253672217026567 0ustar00jpakkanejpakkaneproject('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/' ] ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/45 pkgconfig variables reserved/simple.c0000644000175000017500000000007514253672217026060 0ustar00jpakkanejpakkane#include"simple.h" int simple_function() { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/45 pkgconfig variables reserved/simple.h0000644000175000017500000000010414253672217026056 0ustar00jpakkanejpakkane#ifndef SIMPLE_H_ #define SIMPLE_H_ int simple_function(); #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/45 pkgconfig variables reserved/test.json0000644000175000017500000000023514253672217026273 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/45 pkgconfig variables reserved/meson.build:8:5: ERROR: Variable \"prefix\" is reserved" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3146632 meson-1.3.2/test cases/failing/46 pkgconfig variables zero length/0000755000175000017500000000000014562742415025025 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/46 pkgconfig variables zero length/meson.build0000644000175000017500000000056714253672217027176 0ustar00jpakkanejpakkaneproject('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' ] ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/46 pkgconfig variables zero length/simple.c0000644000175000017500000000007514253672217026463 0ustar00jpakkanejpakkane#include"simple.h" int simple_function() { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/46 pkgconfig variables zero length/simple.h0000644000175000017500000000010414253672217026461 0ustar00jpakkanejpakkane#ifndef SIMPLE_H_ #define SIMPLE_H_ int simple_function(); #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1666639513.0 meson-1.3.2/test cases/failing/46 pkgconfig variables zero length/test.json0000644000175000017500000000030614325563231026670 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/46 pkgconfig variables zero length/meson.build:8:5: ERROR: pkgconfig.generate keyword argument \"variables\" empty variable name" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3146632 meson-1.3.2/test cases/failing/47 pkgconfig variables zero length value/0000755000175000017500000000000014562742415026123 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/47 pkgconfig variables zero length value/meson.build0000644000175000017500000000057314253672217030271 0ustar00jpakkanejpakkaneproject('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=' ] ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/47 pkgconfig variables zero length value/simple.c0000644000175000017500000000007514253672217027561 0ustar00jpakkanejpakkane#include"simple.h" int simple_function() { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/47 pkgconfig variables zero length value/simple.h0000644000175000017500000000010414253672217027557 0ustar00jpakkanejpakkane#ifndef SIMPLE_H_ #define SIMPLE_H_ int simple_function(); #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1666639513.0 meson-1.3.2/test cases/failing/47 pkgconfig variables zero length value/test.json0000644000175000017500000000031514325563231027766 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/47 pkgconfig variables zero length value/meson.build:8:5: ERROR: pkgconfig.generate keyword argument \"variables\" empty variable value" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3186634 meson-1.3.2/test cases/failing/48 pkgconfig variables not key value/0000755000175000017500000000000014562742415025254 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/48 pkgconfig variables not key value/meson.build0000644000175000017500000000061314253672217027415 0ustar00jpakkanejpakkaneproject('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' ] ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/48 pkgconfig variables not key value/simple.c0000644000175000017500000000007514253672217026712 0ustar00jpakkanejpakkane#include"simple.h" int simple_function() { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/48 pkgconfig variables not key value/simple.h0000644000175000017500000000010414253672217026710 0ustar00jpakkanejpakkane#ifndef SIMPLE_H_ #define SIMPLE_H_ int simple_function(); #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1666639513.0 meson-1.3.2/test cases/failing/48 pkgconfig variables not key value/test.json0000644000175000017500000000040414325563231027116 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/48 pkgconfig variables not key value/meson.build:8:5: ERROR: pkgconfig.generate keyword argument \"variables\" variable 'this_should_be_key_value' must have a value separated by equals sign." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3226633 meson-1.3.2/test cases/failing/49 executable comparison/0000755000175000017500000000000014562742415023202 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/49 executable comparison/meson.build0000644000175000017500000000025114253672217025341 0ustar00jpakkanejpakkaneproject('executable comparison', 'c') exe1 = executable('prog1', sources : 'prog.c') exe2 = executable('prog2', sources : 'prog.c') assert(exe1 < exe2, 'should fail') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/49 executable comparison/prog.c0000644000175000017500000000005614253672217024315 0ustar00jpakkanejpakkaneint main(int argc, char **argv) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/test cases/failing/49 executable comparison/test.json0000644000175000017500000000036414433154642025053 0ustar00jpakkanejpakkane{ "stdout": [ { "match": "re", "line": "test cases/failing/49 executable comparison/meson.build:6:14: ERROR: Object of type Executable does not support the `<` operator." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3226633 meson-1.3.2/test cases/failing/5 misplaced option/0000755000175000017500000000000014562742415022070 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/5 misplaced option/meson.build0000644000175000017500000000007614316400150024215 0ustar00jpakkanejpakkaneproject('misplaced option') option('dummy', type : 'string') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/5 misplaced option/test.json0000644000175000017500000000031213716006331023724 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/5 misplaced option/meson.build:3:0: ERROR: Tried to call option() in build description file. All options must be in the option file." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3306634 meson-1.3.2/test cases/failing/50 inconsistent comparison/0000755000175000017500000000000014562742415023571 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/50 inconsistent comparison/meson.build0000644000175000017500000000034614316400150025716 0ustar00jpakkanejpakkaneproject('kwarg before arg') # 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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/test cases/failing/50 inconsistent comparison/test.json0000644000175000017500000000032214433154642025434 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/50 inconsistent comparison/meson.build:5:12: ERROR: Object <[ArrayHolder] holds [list]: []> of type array does not support the `<` operator." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3306634 meson-1.3.2/test cases/failing/51 slashname/0000755000175000017500000000000014562742415020672 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/51 slashname/meson.build0000644000175000017500000000050214253672217023030 0ustar00jpakkanejpakkaneproject('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.') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3306634 meson-1.3.2/test cases/failing/51 slashname/sub/0000755000175000017500000000000014562742415021463 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/51 slashname/sub/meson.build0000644000175000017500000000002514253672217023621 0ustar00jpakkanejpakkanepf = files('prog.c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/51 slashname/sub/prog.c0000644000175000017500000000016014253672217022572 0ustar00jpakkanejpakkane#include int main(int argc, char **argv) { printf("I should not be run ever.\n"); return 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/51 slashname/test.json0000644000175000017500000000030214253672217022536 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/51 slashname/meson.build:9:0: ERROR: Target \"sub/prog\" has a path segment pointing to directory \"sub\". This is an error." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3306634 meson-1.3.2/test cases/failing/52 reserved meson prefix/0000755000175000017500000000000014562742415023117 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3306634 meson-1.3.2/test cases/failing/52 reserved meson prefix/meson-foo/0000755000175000017500000000000014562742415025021 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/52 reserved meson prefix/meson-foo/meson.build0000644000175000017500000000000014253672217027150 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/52 reserved meson prefix/meson.build0000644000175000017500000000004514253672217025257 0ustar00jpakkanejpakkaneproject('test') subdir('meson-foo') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing/52 reserved meson prefix/test.json0000644000175000017500000000030314253672217024764 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/52 reserved meson prefix/meson.build:3:0: ERROR: The \"meson-\" prefix is reserved and cannot be used for top-level subdir()." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3386636 meson-1.3.2/test cases/failing/53 or on new line/0000755000175000017500000000000014562742415021420 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/53 or on new line/meson.build0000644000175000017500000000032714516552205023557 0ustar00jpakkanejpakkaneproject('silent_or') 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/53 or on new line/meson_options.txt0000644000175000017500000000012014516552205025041 0ustar00jpakkanejpakkaneoption('foo', type: 'combo', choices: ['true', 'false', 'auto'], value: 'auto') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/53 or on new line/test.json0000644000175000017500000000020214516552205023257 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/53 or on new line/meson.build:4:8: ERROR: Invalid or clause." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3386636 meson-1.3.2/test cases/failing/54 link with executable/0000755000175000017500000000000014562742415022715 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/54 link with executable/meson.build0000644000175000017500000000016614516552205025055 0ustar00jpakkanejpakkaneproject('link with exe', 'c') e = executable('prog', 'prog.c') m = shared_module('module', 'module.c', link_with: e) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/54 link with executable/module.c0000644000175000017500000000004214516552205024335 0ustar00jpakkanejpakkane int func(void) { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/54 link with executable/prog.c0000644000175000017500000000006114516552205024020 0ustar00jpakkanejpakkaneint main (int argc, char **argv) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/54 link with executable/test.json0000644000175000017500000000023114516552205024556 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/54 link with executable/meson.build:4:4: ERROR: Link target 'prog' is not linkable." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3386636 meson-1.3.2/test cases/failing/55 assign custom target index/0000755000175000017500000000000014562742415024041 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/55 assign custom target index/meson.build0000644000175000017500000000151414516552205026177 0ustar00jpakkanejpakkane# 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' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/55 assign custom target index/test.json0000644000175000017500000000023514516552205025706 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/55 assign custom target index/meson.build:24:0: ERROR: Assignment target must be an id." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3426638 meson-1.3.2/test cases/failing/56 getoption prefix/0000755000175000017500000000000014562742415022212 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/56 getoption prefix/meson.build0000644000175000017500000000010314516552205024341 0ustar00jpakkanejpakkaneproject('getopt prefix') subproject('abc') get_option('abc:foo') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.050629 meson-1.3.2/test cases/failing/56 getoption prefix/subprojects/0000755000175000017500000000000014562742413024553 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3426638 meson-1.3.2/test cases/failing/56 getoption prefix/subprojects/abc/0000755000175000017500000000000014562742415025302 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/56 getoption prefix/subprojects/abc/meson.build0000644000175000017500000000002414516552205027433 0ustar00jpakkanejpakkaneproject('abc', 'c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/56 getoption prefix/subprojects/abc/meson_options.txt0000644000175000017500000000004014516552205030724 0ustar00jpakkanejpakkaneoption('foo', type : 'boolean') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/56 getoption prefix/test.json0000644000175000017500000000034714516552205024063 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/56 getoption prefix/meson.build:5:0: ERROR: Having a colon in option name is forbidden, projects are not allowed to directly access options of other subprojects." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3426638 meson-1.3.2/test cases/failing/57 bad option argument/0000755000175000017500000000000014562742415022547 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/57 bad option argument/meson.build0000644000175000017500000000005214516552205024701 0ustar00jpakkanejpakkaneproject('bad option') get_option('name') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/57 bad option argument/meson_options.txt0000644000175000017500000000006014516552205026173 0ustar00jpakkanejpakkaneoption('name', type : 'string', value_ : 'foo') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/57 bad option argument/test.json0000644000175000017500000000026114516552205024413 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/57 bad option argument/meson_options.txt:1:0: ERROR: string option got unknown keyword arguments \"value_\"" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3426638 meson-1.3.2/test cases/failing/58 subproj filegrab/0000755000175000017500000000000014562742415022146 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/58 subproj filegrab/meson.build0000644000175000017500000000012214516552205024276 0ustar00jpakkanejpakkaneproject('mainproj') # Try to grab a file from a parent project. subproject('a') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/58 subproj filegrab/prog.c0000644000175000017500000000005614516552205023255 0ustar00jpakkanejpakkaneint main(int argc, char **argv) { return 0; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.050629 meson-1.3.2/test cases/failing/58 subproj filegrab/subprojects/0000755000175000017500000000000014562742413024507 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3426638 meson-1.3.2/test cases/failing/58 subproj filegrab/subprojects/a/0000755000175000017500000000000014562742415024731 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/58 subproj filegrab/subprojects/a/meson.build0000644000175000017500000000006614516552205027070 0ustar00jpakkanejpakkaneproject('a', 'c') executable('prog', '../../prog.c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/58 subproj filegrab/test.json0000644000175000017500000000031214516552205024007 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/58 subproj filegrab/subprojects/a/meson.build:3:0: ERROR: Sandbox violation: Tried to grab file prog.c outside current (sub)project." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3426638 meson-1.3.2/test cases/failing/59 grab subproj/0000755000175000017500000000000014562742415021307 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/59 grab subproj/meson.build0000644000175000017500000000020614516552205023442 0ustar00jpakkanejpakkaneproject('grabber', 'c') # Try to grab a file from a child subproject. subproject('foo') executable('foo', 'subprojects/foo/sub.c') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.050629 meson-1.3.2/test cases/failing/59 grab subproj/subprojects/0000755000175000017500000000000014562742413023650 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3466637 meson-1.3.2/test cases/failing/59 grab subproj/subprojects/foo/0000755000175000017500000000000014562742415024435 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/59 grab subproj/subprojects/foo/meson.build0000644000175000017500000000005614516552205026573 0ustar00jpakkanejpakkaneproject('foo', 'c') message('I do nothing.') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/59 grab subproj/subprojects/foo/sub.c0000644000175000017500000000017114516552205025364 0ustar00jpakkanejpakkane#include int main(int argc, char **argv) { printf("I am a subproject executable file.\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/59 grab subproj/test.json0000644000175000017500000000026314516552205023155 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/59 grab subproj/meson.build:7:0: ERROR: Sandbox violation: Tried to grab file sub.c from a nested subproject." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3466637 meson-1.3.2/test cases/failing/6 missing incdir/0000755000175000017500000000000014562742415021541 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/6 missing incdir/meson.build0000644000175000017500000000010214316400150023654 0ustar00jpakkanejpakkaneproject('missing incdir') inc = include_directories('nosuchdir') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/test cases/failing/6 missing incdir/test.json0000644000175000017500000000022414433154642023405 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/6 missing incdir/meson.build:3:6: ERROR: Include dir nosuchdir does not exist." } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.350664 meson-1.3.2/test cases/failing/60 grab sibling/0000755000175000017500000000000014562742415021242 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/60 grab sibling/meson.build0000644000175000017500000000004314516552205023374 0ustar00jpakkanejpakkaneproject('master') subproject('a') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.054629 meson-1.3.2/test cases/failing/60 grab sibling/subprojects/0000755000175000017500000000000014562742413023603 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.350664 meson-1.3.2/test cases/failing/60 grab sibling/subprojects/a/0000755000175000017500000000000014562742415024025 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/60 grab sibling/subprojects/a/meson.build0000644000175000017500000000007114516552205026160 0ustar00jpakkanejpakkaneproject('a', 'c') executable('sneaky', '../b/sneaky.c') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.350664 meson-1.3.2/test cases/failing/60 grab sibling/subprojects/b/0000755000175000017500000000000014562742415024026 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/60 grab sibling/subprojects/b/meson.build0000644000175000017500000000004714516552205026164 0ustar00jpakkanejpakkaneprojecT('b') message('I do nothing.') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/60 grab sibling/subprojects/b/sneaky.c0000644000175000017500000000020314516552205025452 0ustar00jpakkanejpakkane#include int main(int argc, char **argv) { printf("I can only come into existence via trickery.\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/60 grab sibling/test.json0000644000175000017500000000031014516552205023101 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/60 grab sibling/subprojects/a/meson.build:3:0: ERROR: Sandbox violation: Tried to grab file sneaky.c outside current (sub)project." } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.358664 meson-1.3.2/test cases/failing/61 string as link target/0000755000175000017500000000000014562742415022777 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/61 string as link target/meson.build0000644000175000017500000000013214516552205025130 0ustar00jpakkanejpakkaneproject('string as link argument', 'c') executable('myprog', 'prog.c', link_with: [ '' ]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/61 string as link target/prog.c0000644000175000017500000000005614516552205024106 0ustar00jpakkanejpakkaneint main(int argc, char **argv) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/61 string as link target/test.json0000644000175000017500000000021214516552205024637 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/61 string as link target/meson.build:2:0: ERROR: '' is not a target." } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.358664 meson-1.3.2/test cases/failing/62 dependency not-found and required/0000755000175000017500000000000014562742415025255 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/62 dependency not-found and required/meson.build0000644000175000017500000000007014516552205027407 0ustar00jpakkanejpakkaneproject('dep-test') dep = dependency('', required:true) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/62 dependency not-found and required/test.json0000644000175000017500000000026014516552205027120 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/62 dependency not-found and required/meson.build:2:6: ERROR: Dependency is required but has no candidates." } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.358664 meson-1.3.2/test cases/failing/63 subproj different versions/0000755000175000017500000000000014562742415024166 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/63 subproj different versions/main.c0000644000175000017500000000024014516552205025245 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/63 subproj different versions/meson.build0000644000175000017500000000042314516552205026322 0ustar00jpakkanejpakkaneproject('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]) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.054629 meson-1.3.2/test cases/failing/63 subproj different versions/subprojects/0000755000175000017500000000000014562742413026527 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.358664 meson-1.3.2/test cases/failing/63 subproj different versions/subprojects/a/0000755000175000017500000000000014562742415026751 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/63 subproj different versions/subprojects/a/a.c0000644000175000017500000000006414516552205027330 0ustar00jpakkanejpakkane#include "c.h" int a_fun() { return c_fun(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/63 subproj different versions/subprojects/a/a.h0000644000175000017500000000001514516552205027331 0ustar00jpakkanejpakkaneint a_fun(); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/63 subproj different versions/subprojects/a/meson.build0000644000175000017500000000035014516552205031104 0ustar00jpakkanejpakkaneproject('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('.'), ) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.362664 meson-1.3.2/test cases/failing/63 subproj different versions/subprojects/b/0000755000175000017500000000000014562742415026752 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/63 subproj different versions/subprojects/b/b.c0000644000175000017500000000005714516552205027334 0ustar00jpakkanejpakkane#include "c.h" int b_fun(){ return c_fun(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/63 subproj different versions/subprojects/b/b.h0000644000175000017500000000001514516552205027333 0ustar00jpakkanejpakkaneint b_fun(); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/63 subproj different versions/subprojects/b/meson.build0000644000175000017500000000035014516552205031105 0ustar00jpakkanejpakkaneproject('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('.'), ) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.362664 meson-1.3.2/test cases/failing/63 subproj different versions/subprojects/c/0000755000175000017500000000000014562742415026753 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/63 subproj different versions/subprojects/c/c.h0000644000175000017500000000004414516552205027337 0ustar00jpakkanejpakkanestatic int c_fun(){ return 3; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/63 subproj different versions/subprojects/c/meson.build0000644000175000017500000000015614516552205031112 0ustar00jpakkanejpakkaneproject('c', 'c', version:'1') c_dep = declare_dependency( include_directories: include_directories('.') ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/63 subproj different versions/test.json0000644000175000017500000000026314516552205026034 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/63 subproj different versions/subprojects/b/meson.build:3:8: ERROR: Dependency 'c' is required but not found." } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.366664 meson-1.3.2/test cases/failing/64 wrong boost module/0000755000175000017500000000000014562742415022434 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/64 wrong boost module/meson.build0000644000175000017500000000041714516552205024573 0ustar00jpakkanejpakkaneproject('boosttest', 'cpp', default_options : ['cpp_std=c++11']) if not dependency('boost', required: false).found() error('MESON_SKIP_TEST test requires boost') endif # abc doesn't exist linkdep = dependency('boost', modules : ['thread', 'system', 'test', 'abc']) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/64 wrong boost module/test.json0000644000175000017500000000024114516552205024276 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/64 wrong boost module/meson.build:9:10: ERROR: Dependency \"boost\" not found, tried system" } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.366664 meson-1.3.2/test cases/failing/65 install_data rename bad size/0000755000175000017500000000000014562742415024255 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/65 install_data rename bad size/file1.txt0000644000175000017500000000000014516552205025777 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/65 install_data rename bad size/file2.txt0000644000175000017500000000000014516552205026000 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/65 install_data rename bad size/meson.build0000644000175000017500000000014114516552205026406 0ustar00jpakkanejpakkaneproject('data install test') install_data(['file1.txt', 'file2.txt'], rename : 'just one name') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/65 install_data rename bad size/test.json0000644000175000017500000000040014516552205026114 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/65 install_data rename bad size/meson.build:3:0: ERROR: \"rename\" and \"sources\" argument lists must be the same length if \"rename\" is given. Rename has 1 elements and sources has 2." } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.366664 meson-1.3.2/test cases/failing/66 skip only subdir/0000755000175000017500000000000014562742415022106 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/66 skip only subdir/meson.build0000644000175000017500000000033414516552205024243 0ustar00jpakkanejpakkane# 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') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.366664 meson-1.3.2/test cases/failing/66 skip only subdir/subdir/0000755000175000017500000000000014562742415023376 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/66 skip only subdir/subdir/meson.build0000644000175000017500000000004414516552205025531 0ustar00jpakkanejpakkanesubdir_done() error('Unreachable') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/66 skip only subdir/test.json0000644000175000017500000000021714516552205023753 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/66 skip only subdir/meson.build:8:0: ERROR: File main.cpp does not exist." } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.366664 meson-1.3.2/test cases/failing/67 dual override/0000755000175000017500000000000014562742415021453 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/67 dual override/meson.build0000644000175000017500000000021314516552205023604 0ustar00jpakkanejpakkaneproject('yo dawg') p = find_program('overrides.py') meson.override_find_program('override', p) meson.override_find_program('override', p) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/67 dual override/overrides.py0000644000175000017500000000020214516552205024014 0ustar00jpakkanejpakkane#!/usr/bin/env python3 print('Yo dawg, we put overrides in your overrides,') print('so now you can override when you override.') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/67 dual override/test.json0000644000175000017500000000027314516552205023322 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/67 dual override/meson.build:5:6: ERROR: Tried to override executable \"override\" which has already been overridden." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3706641 meson-1.3.2/test cases/failing/68 override used/0000755000175000017500000000000014562742415021467 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/68 override used/meson.build0000644000175000017500000000025514516552205023626 0ustar00jpakkanejpakkaneproject('override an already found exe') old = find_program('something.py') replacement = find_program('other.py') meson.override_find_program('something.py', replacement) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/68 override used/other.py0000755000175000017500000000006714516552205023163 0ustar00jpakkanejpakkane#!/usr/bin/env python3 print('Doing something else.') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/68 override used/something.py0000755000175000017500000000006214516552205024032 0ustar00jpakkanejpakkane#!/usr/bin/env python3 print('Doing something.') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/68 override used/test.json0000644000175000017500000000030514516552205023332 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/68 override used/meson.build:5:6: ERROR: Tried to override finding of executable \"something.py\" which has already been found." } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.374664 meson-1.3.2/test cases/failing/69 run_command unclean exit/0000755000175000017500000000000014562742415023572 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/69 run_command unclean exit/meson.build0000644000175000017500000000016514516552205025731 0ustar00jpakkanejpakkaneproject('run_command unclean exit') rcprog = find_program('./returncode.py') run_command(rcprog, '1', check : true) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/69 run_command unclean exit/returncode.py0000755000175000017500000000007214516552205026313 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys exit(int(sys.argv[1])) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/69 run_command unclean exit/test.json0000644000175000017500000000044414516552205025441 0ustar00jpakkanejpakkane{ "stdout": [ { "match": "re", "line": "test cases/failing/69 run_command unclean exit/meson\\.build:4:0: ERROR: Command `.*['\"].*[\\\\/]test cases[\\\\/]failing[\\\\/]69 run_command unclean exit[\\\\/]\\.[\\\\/]returncode\\.py['\"] 1` failed with status 1\\." } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.374664 meson-1.3.2/test cases/failing/7 go to subproject/0000755000175000017500000000000014562742415022011 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/7 go to subproject/meson.build0000644000175000017500000000004614316400150024133 0ustar00jpakkanejpakkaneproject('fff') subdir('subprojects') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.374664 meson-1.3.2/test cases/failing/7 go to subproject/subprojects/0000755000175000017500000000000014562742415024354 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/7 go to subproject/subprojects/meson.build0000644000175000017500000000001013716006331026473 0ustar00jpakkanejpakkanex = 'x' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/7 go to subproject/test.json0000644000175000017500000000027213716006331023652 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/7 go to subproject/meson.build:3:0: ERROR: Must not go into subprojects dir with subdir(), use subproject() instead." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3826642 meson-1.3.2/test cases/failing/70 int literal leading zero/0000755000175000017500000000000014562742415023453 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/70 int literal leading zero/meson.build0000644000175000017500000000013014516552205025602 0ustar00jpakkanejpakkane # This should fail. # Decimal syntax is 123. # Octal syntax is 0o123. fail_0123 = 0123 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/70 int literal leading zero/test.json0000644000175000017500000000032314516552205025316 0ustar00jpakkanejpakkane{ "stdout": [ { "comment": "this error message is not very informative", "line": "test cases/failing/70 int literal leading zero/meson.build:5:13: ERROR: Expecting eof got number." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3826642 meson-1.3.2/test cases/failing/71 configuration immutable/0000755000175000017500000000000014562742415023530 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/71 configuration immutable/input0000644000175000017500000000000014516552205024573 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/71 configuration immutable/meson.build0000644000175000017500000000032614516552205025666 0ustar00jpakkanejpakkaneproject('configuration_data is immutable') a = configuration_data() configure_file( configuration : a, input : 'input', output : 'output', ) still_immutable = a still_immutable.set('hello', 'world') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/71 configuration immutable/test.json0000644000175000017500000000027114516552205025375 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/71 configuration immutable/meson.build:12:16: ERROR: Can not set values on configuration object that has been used." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3826642 meson-1.3.2/test cases/failing/72 link with shared module on osx/0000755000175000017500000000000014562742415024477 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/72 link with shared module on osx/meson.build0000644000175000017500000000034114516552205026632 0ustar00jpakkanejpakkaneproject('link with shared module', 'c') if host_machine.system() != 'darwin' error('MESON_SKIP_TEST test only fails on OSX') endif m = shared_module('mymodule', 'module.c') e = executable('prog', 'prog.c', link_with : m) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/72 link with shared module on osx/module.c0000644000175000017500000000004414516552205026121 0ustar00jpakkanejpakkaneint func(void) { return 1496; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/72 link with shared module on osx/prog.c0000644000175000017500000000007014516552205025602 0ustar00jpakkanejpakkane int main(int argc, char **argv) { return func(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/72 link with shared module on osx/test.json0000644000175000017500000000031614516552205026344 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/72 link with shared module on osx/meson.build:8:4: ERROR: target prog links against shared module mymodule. This is not permitted on OSX" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3866644 meson-1.3.2/test cases/failing/73 non-ascii in ascii encoded configure file/0000755000175000017500000000000014562742415026467 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/73 non-ascii in ascii encoded configure file/config9.h.in0000644000175000017500000000003014516552205030567 0ustar00jpakkanejpakkane#define MESSAGE "@var@" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/73 non-ascii in ascii encoded configure file/meson.build0000644000175000017500000000042014516552205030620 0ustar00jpakkanejpakkaneproject('non-ascii to ascii encoding') # 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 ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/73 non-ascii in ascii encoded configure file/test.json0000644000175000017500000000046214516552205030336 0ustar00jpakkanejpakkane{ "stdout": [ { "match": "re", "line": "test cases/failing/73 non-ascii in ascii encoded configure file/meson\\.build:5:0: ERROR: Could not write output file .*[\\\\/]config9\\.h: 'ascii' codec can't encode character '\\\\u0434' in position 17: ordinal not in range\\(128\\)" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3866644 meson-1.3.2/test cases/failing/74 subproj dependency not-found and required/0000755000175000017500000000000014562742415026725 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/74 subproj dependency not-found and required/meson.build0000644000175000017500000000014314516552205031060 0ustar00jpakkanejpakkaneproject('dep-test') missing = dependency('', fallback: ['missing', 'missing_dep'], required: true) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/74 subproj dependency not-found and required/test.json0000644000175000017500000000031514516552205030571 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/74 subproj dependency not-found and required/meson.build:2:10: ERROR: Neither a subproject directory nor a missing.wrap file was found." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3866644 meson-1.3.2/test cases/failing/75 unfound run/0000755000175000017500000000000014562742415021170 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/75 unfound run/meson.build0000644000175000017500000000020214516552205023317 0ustar00jpakkanejpakkaneproject('unfound runtarget') exe = find_program('nonexisting_prog', required : false) run_target('invoke_fail', command : [exe]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/75 unfound run/test.json0000644000175000017500000000024414516552205023035 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/75 unfound run/meson.build:4:0: ERROR: Tried to use non-existing executable 'nonexisting_prog'" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3946645 meson-1.3.2/test cases/failing/76 framework dependency with version/0000755000175000017500000000000014562742415025424 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/76 framework dependency with version/meson.build0000644000175000017500000000051514516552205027562 0ustar00jpakkanejpakkaneproject('framework dependency with version', 'c') if host_machine.system() != 'darwin' error('MESON_SKIP_TEST test only applicable on darwin') endif # do individual frameworks have a meaningful version to test? And multiple frameworks might be listed... dep = dependency('appleframeworks', modules: 'Foundation', version: '>0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/76 framework dependency with version/test.json0000644000175000017500000000035214516552205027271 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/76 framework dependency with version/meson.build:8:6: ERROR: Dependency lookup for appleframeworks with method 'framework' failed: Unknown version, but need ['>0']." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3986645 meson-1.3.2/test cases/failing/77 override exe config/0000755000175000017500000000000014562742415022536 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/77 override exe config/foo.c0000644000175000017500000000003714516552205023460 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/77 override exe config/meson.build0000644000175000017500000000023014516552205024666 0ustar00jpakkanejpakkaneproject('myexe', 'c') foo = executable('foo', 'foo.c') meson.override_find_program('bar', foo) bar = find_program('bar') run_command(bar, check: true) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/77 override exe config/test.json0000644000175000017500000000034614516552205024406 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/77 override exe config/meson.build:6:0: ERROR: Program 'bar' was overridden with the compiled executable 'foo' and therefore cannot be used during configuration" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3986645 meson-1.3.2/test cases/failing/78 gl dependency with version/0000755000175000017500000000000014562742415024033 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/78 gl dependency with version/meson.build0000644000175000017500000000053114516552205026167 0ustar00jpakkanejpakkaneproject('gl dependency with version', 'c') host_system = host_machine.system() if host_system != 'windows' and host_system != 'darwin' error('MESON_SKIP_TEST: 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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/78 gl dependency with version/test.json0000644000175000017500000000032314516552205025676 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/78 gl dependency with version/meson.build:9:6: ERROR: Dependency lookup for gl with method 'system' failed: Unknown version, but need ['>0']." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3986645 meson-1.3.2/test cases/failing/79 threads dependency with version/0000755000175000017500000000000014562742415025064 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/79 threads dependency with version/meson.build0000644000175000017500000000023314516552205027217 0ustar00jpakkanejpakkaneproject('threads dependency with version', 'c') # threads dependency doesn't have a meaningful version to check dep = dependency('threads', version: '>0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/79 threads dependency with version/test.json0000644000175000017500000000033514516552205026732 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/79 threads dependency with version/meson.build:3:6: ERROR: Dependency lookup for threads with method 'system' failed: Unknown version, but need ['>0']." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3986645 meson-1.3.2/test cases/failing/8 recursive/0000755000175000017500000000000014562742415020650 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/8 recursive/meson.build0000644000175000017500000000005214316400150022767 0ustar00jpakkanejpakkaneproject('recursive') a = subproject('a') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853067.062629 meson-1.3.2/test cases/failing/8 recursive/subprojects/0000755000175000017500000000000014562742413023211 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3986645 meson-1.3.2/test cases/failing/8 recursive/subprojects/a/0000755000175000017500000000000014562742415023433 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/8 recursive/subprojects/a/meson.build0000644000175000017500000000004214316400150025551 0ustar00jpakkanejpakkaneproject('a') b = subproject('b') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.3986645 meson-1.3.2/test cases/failing/8 recursive/subprojects/b/0000755000175000017500000000000014562742415023434 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664745576.0 meson-1.3.2/test cases/failing/8 recursive/subprojects/b/meson.build0000644000175000017500000000004214316400150025552 0ustar00jpakkanejpakkaneproject('b') a = subproject('a') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/test cases/failing/8 recursive/test.json0000644000175000017500000000024614433154642022520 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/8 recursive/subprojects/b/meson.build:3:4: ERROR: Recursive include of subprojects: a => b => a." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4026647 meson-1.3.2/test cases/failing/80 gtest dependency with version/0000755000175000017500000000000014562742415024550 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/80 gtest dependency with version/meson.build0000644000175000017500000000043414516552205026706 0ustar00jpakkanejpakkaneproject('gtest dependency with version', 'cpp') if not dependency('gtest', method: 'system', required: false).found() error('MESON_SKIP_TEST test requires gtest') endif # discovering gtest version is not yet implemented dep = dependency('gtest', method: 'system', version: '>0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/80 gtest dependency with version/test.json0000644000175000017500000000025414516552205026416 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/80 gtest dependency with version/meson.build:8:6: ERROR: Dependency 'gtest' is required but not found." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4026647 meson-1.3.2/test cases/failing/81 dub library/0000755000175000017500000000000014562742415021121 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/81 dub library/meson.build0000644000175000017500000000043714516552205023262 0ustar00jpakkanejpakkaneproject('dub') if not add_languages('d', required: false) error('MESON_SKIP_TEST test requires D compiler') endif if not find_program('dub', required: false).found() error('MESON_SKIP_TEST test requires dub') endif dependency('dubtestproject', method: 'dub') # Not library (none) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/81 dub library/test.json0000644000175000017500000000022514516552205022765 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/81 dub library/meson.build:11:0: ERROR: Dependency \"dubtestproject\" not found" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4026647 meson-1.3.2/test cases/failing/82 dub executable/0000755000175000017500000000000014562742415021577 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/82 dub executable/meson.build0000644000175000017500000000045314516552205023736 0ustar00jpakkanejpakkaneproject('dub') if not add_languages('d', required: false) error('MESON_SKIP_TEST test requires D compiler') endif if not find_program('dub', required: false).found() error('MESON_SKIP_TEST test requires dub') endif dependency('dubtestproject:test1', method: 'dub') # Not library (executable) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/82 dub executable/test.json0000644000175000017500000000023614516552205023445 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/82 dub executable/meson.build:11:0: ERROR: Dependency \"dubtestproject:test1\" not found" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4106648 meson-1.3.2/test cases/failing/83 dub compiler/0000755000175000017500000000000014562742415021271 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/83 dub compiler/meson.build0000644000175000017500000000077714516552205023441 0ustar00jpakkanejpakkaneproject('dub') if not add_languages('d', required: false) error('MESON_SKIP_TEST test requires D compiler') endif 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 if not find_program('dub', required: false).found() error('MESON_SKIP_TEST test requires dub') endif dependency('dubtestproject:test2', method: 'dub') # Compiler mismatch ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/83 dub compiler/test.json0000644000175000017500000000053214516552205023136 0ustar00jpakkanejpakkane{ "matrix": { "options": { "warning_level": [ { "val": "1", "skip_on_env": [ "SINGLE_DUB_COMPILER" ] } ] } }, "stdout": [ { "line": "test cases/failing/83 dub compiler/meson.build:17:0: ERROR: Dependency \"dubtestproject:test2\" not found" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4106648 meson-1.3.2/test cases/failing/84 subproj not-found dep/0000755000175000017500000000000014562742415023034 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/84 subproj not-found dep/meson.build0000644000175000017500000000015014516552205025165 0ustar00jpakkanejpakkaneproject('dep-test') missing = dependency('', fallback: ['somesubproj', 'notfound_dep'], required: true) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.0666292 meson-1.3.2/test cases/failing/84 subproj not-found dep/subprojects/0000755000175000017500000000000014562742413025375 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4106648 meson-1.3.2/test cases/failing/84 subproj not-found dep/subprojects/somesubproj/0000755000175000017500000000000014562742415027747 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/84 subproj not-found dep/subprojects/somesubproj/meson.build0000644000175000017500000000010514516552205032100 0ustar00jpakkanejpakkaneproject('dep', 'c') notfound_dep = dependency('', required : false) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/84 subproj not-found dep/test.json0000644000175000017500000000025314516552205024701 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/84 subproj not-found dep/meson.build:2:10: ERROR: Dependency '(anonymous)' is required but not found." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4106648 meson-1.3.2/test cases/failing/85 invalid configure file/0000755000175000017500000000000014562742415023216 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/85 invalid configure file/input0000644000175000017500000000000014516552205024261 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/85 invalid configure file/meson.build0000644000175000017500000000026514516552205025356 0ustar00jpakkanejpakkaneproject('invalid configura file') configure_file( configuration : configuration_data(), input : 'input', output : 'output', install_dir : '', install : true, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/85 invalid configure file/test.json0000644000175000017500000000030614516552205025062 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/85 invalid configure file/meson.build:3:0: ERROR: \"install_dir\" must be specified when \"install\" in a configure_file is true" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4106648 meson-1.3.2/test cases/failing/86 kwarg dupe/0000755000175000017500000000000014562742415020760 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/86 kwarg dupe/meson.build0000644000175000017500000000017214516552205023115 0ustar00jpakkanejpakkaneproject('dupe kwarg', 'c') dupedict = {'install': true} executable('prog', 'prog.c', install: true, kwargs: dupedict) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/86 kwarg dupe/prog.c0000644000175000017500000000020214516552205022060 0ustar00jpakkanejpakkane#include int main(int argc, char **argv) { printf("I don't get built. It makes me saaaaaad. :(\n"); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/86 kwarg dupe/test.json0000644000175000017500000000027214516552205022626 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/86 kwarg dupe/meson.build:6:2: ERROR: Entry \"install\" defined both as a keyword argument and in a \"kwarg\" entry." } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.418665 meson-1.3.2/test cases/failing/87 missing pch file/0000755000175000017500000000000014562742415022034 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/87 missing pch file/meson.build0000644000175000017500000000014614516552205024172 0ustar00jpakkanejpakkaneproject('pch test', 'c') exe = executable('prog', 'prog.c', c_pch : ['pch/prog_pch.c', 'pch/prog.h']) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/87 missing pch file/prog.c0000644000175000017500000000006214516552205023140 0ustar00jpakkanejpakkaneint main(int argc, char **argv) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/87 missing pch file/test.json0000644000175000017500000000037214516552205023703 0ustar00jpakkanejpakkane{ "stdout": [ { "comment": "literal 'pch/prog.h' from meson.build appears in output, irrespective of os.path.sep", "line": "test cases/failing/87 missing pch file/meson.build:2:6: ERROR: File pch/prog.h does not exist." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4226649 meson-1.3.2/test cases/failing/88 pch source different folder/0000755000175000017500000000000014562742415024147 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4226649 meson-1.3.2/test cases/failing/88 pch source different folder/include/0000755000175000017500000000000014562742415025572 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/88 pch source different folder/include/pch.h0000644000175000017500000000000014516552205026476 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/88 pch source different folder/meson.build0000644000175000017500000000027514516552205026310 0ustar00jpakkanejpakkaneproject('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']) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/88 pch source different folder/prog.c0000644000175000017500000000002114516552205025246 0ustar00jpakkanejpakkaneint main(void) {}././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4226649 meson-1.3.2/test cases/failing/88 pch source different folder/src/0000755000175000017500000000000014562742415024736 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/88 pch source different folder/src/pch.c0000644000175000017500000000000014516552205025635 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/88 pch source different folder/test.json0000644000175000017500000000025114516552205026012 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/88 pch source different folder/meson.build:4:6: ERROR: PCH files must be stored in the same folder." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4226649 meson-1.3.2/test cases/failing/89 unknown config tool/0000755000175000017500000000000014562742415022615 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/89 unknown config tool/meson.build0000644000175000017500000000012714516552205024752 0ustar00jpakkanejpakkaneproject('no-such-config-tool') dependency('no-such-config-tool', method:'config-tool') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/89 unknown config tool/test.json0000644000175000017500000000024114516552205024457 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/89 unknown config tool/meson.build:2:0: ERROR: Dependency \"no-such-config-tool\" not found" } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.426665 meson-1.3.2/test cases/failing/9 missing extra file/0000755000175000017500000000000014562742415022317 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/9 missing extra file/meson.build0000644000175000017500000000014013716006331024442 0ustar00jpakkanejpakkaneproject('missing extra file', 'c') executable('myprog', 'prog.c', extra_files : 'missing.txt') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/9 missing extra file/prog.c0000644000175000017500000000006213716006331023416 0ustar00jpakkanejpakkaneint main(int argc, char **argv) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing/9 missing extra file/test.json0000644000175000017500000000022313716006331024154 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/9 missing extra file/meson.build:3:0: ERROR: File missing.txt does not exist." } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.426665 meson-1.3.2/test cases/failing/90 custom target install data/0000755000175000017500000000000014562742415024024 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/90 custom target install data/Info.plist.cpp0000644000175000017500000000006314516552205026547 0ustar00jpakkanejpakkaneSome data which gets processed before installation ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/90 custom target install data/meson.build0000644000175000017500000000034614516552205026164 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/90 custom target install data/preproc.py0000644000175000017500000000034514516552205026045 0ustar00jpakkanejpakkane#!/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()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/90 custom target install data/test.json0000644000175000017500000000034014516552205025666 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/90 custom target install data/meson.build:11:0: ERROR: install_data argument 1 was of type \"CustomTarget\" but should have been one of: \"str\", \"File\"" } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.426665 meson-1.3.2/test cases/failing/91 add dict non string key/0000755000175000017500000000000014562742415023172 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/91 add dict non string key/meson.build0000644000175000017500000000030714516552205025327 0ustar00jpakkanejpakkaneproject('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'}././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/91 add dict non string key/test.json0000644000175000017500000000021514516552205025035 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/91 add dict non string key/meson.build:9:9: ERROR: Key must be a string" } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.426665 meson-1.3.2/test cases/failing/92 add dict duplicate keys/0000755000175000017500000000000014562742415023247 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/92 add dict duplicate keys/meson.build0000644000175000017500000000032014516552205025377 0ustar00jpakkanejpakkaneproject('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'}././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/92 add dict duplicate keys/test.json0000644000175000017500000000023114516552205025110 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/92 add dict duplicate keys/meson.build:9:27: ERROR: Duplicate dictionary key: myKey" } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.426665 meson-1.3.2/test cases/failing/93 no host get_external_property/0000755000175000017500000000000014562742415024705 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/93 no host get_external_property/meson.build0000644000175000017500000000012114516552205027034 0ustar00jpakkanejpakkaneproject('missing property') message(meson.get_external_property('nonexisting')) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/93 no host get_external_property/test.json0000644000175000017500000000025614516552205026555 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/93 no host get_external_property/meson.build:3:14: ERROR: Unknown property for host machine: nonexisting" } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.426665 meson-1.3.2/test cases/failing/94 no native compiler/0000755000175000017500000000000014562742415022404 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/94 no native compiler/main.c0000644000175000017500000000004114516552205023462 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/94 no native compiler/meson.build0000644000175000017500000000053014516552205024537 0ustar00jpakkanejpakkaneproject('no native compiler') if not meson.is_cross_build() error('MESON_SKIP_TEST test only applicable when cross building.') endif if add_languages('c', required: false, native: true) error('MESON_SKIP_TEST test only applicable when native compiler not available.') endif add_languages('c') executable('main', 'main.c', native: true) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/94 no native compiler/test.json0000644000175000017500000000023414516552205024250 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/94 no native compiler/meson.build:12:0: ERROR: No host machine compiler for \"main.c\"" } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.430665 meson-1.3.2/test cases/failing/95 subdir parse error/0000755000175000017500000000000014562742415022424 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/95 subdir parse error/meson.build0000644000175000017500000000006414516552205024561 0ustar00jpakkanejpakkaneproject('subdir false plusassign') subdir('subdir') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.430665 meson-1.3.2/test cases/failing/95 subdir parse error/subdir/0000755000175000017500000000000014562742415023714 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/95 subdir parse error/subdir/meson.build0000644000175000017500000000000714516552205026046 0ustar00jpakkanejpakkane3 += 4 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/95 subdir parse error/test.json0000644000175000017500000000023714516552205024273 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/95 subdir parse error/subdir/meson.build:1:0: ERROR: Plusassignment target must be an id." } ] } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.430665 meson-1.3.2/test cases/failing/96 invalid option file/0000755000175000017500000000000014562742415022547 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/96 invalid option file/meson.build0000644000175000017500000000003714516552205024704 0ustar00jpakkanejpakkaneproject('invalid option file') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/96 invalid option file/meson_options.txt0000644000175000017500000000000214516552205026167 0ustar00jpakkanejpakkane' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/96 invalid option file/test.json0000644000175000017500000000020014516552205024404 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/96 invalid option file/meson_options.txt:1:0: ERROR: lexer" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4386652 meson-1.3.2/test cases/failing/97 no lang/0000755000175000017500000000000014562742415020247 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/97 no lang/main.c0000644000175000017500000000004114516552205021325 0ustar00jpakkanejpakkaneint main(void) { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/97 no lang/meson.build0000644000175000017500000000007414516552205022405 0ustar00jpakkanejpakkaneproject('target without lang') executable('main', 'main.c') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/97 no lang/test.json0000644000175000017500000000021614516552205022113 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/97 no lang/meson.build:2:0: ERROR: No host machine compiler for 'main.c'" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4386652 meson-1.3.2/test cases/failing/98 no glib-compile-resources/0000755000175000017500000000000014562742415023702 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/98 no glib-compile-resources/meson.build0000644000175000017500000000044414516552205026041 0ustar00jpakkanejpakkaneproject('no glib-compile-resources') if find_program('glib-compile-resources', required: false).found() error('MESON_SKIP_TEST test only applicable when glib-compile-resources is missing.') endif gnome = import('gnome') res = gnome.compile_resources('resources', 'trivial.gresource.xml') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/98 no glib-compile-resources/test.json0000644000175000017500000000027014516552205025546 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/98 no glib-compile-resources/meson.build:8:12: ERROR: Program 'glib-compile-resources' not found or not executable" } ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/98 no glib-compile-resources/trivial.gresource.xml0000644000175000017500000000010214516552205030057 0ustar00jpakkanejpakkane ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4386652 meson-1.3.2/test cases/failing/99 number in combo/0000755000175000017500000000000014562742415021672 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/99 number in combo/meson.build0000644000175000017500000000003314516552205024023 0ustar00jpakkanejpakkaneproject('number in combo') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/99 number in combo/nativefile.ini0000644000175000017500000000004414516552205024512 0ustar00jpakkanejpakkane[built-in options] optimization = 1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698354309.0 meson-1.3.2/test cases/failing/99 number in combo/test.json0000644000175000017500000000044114516552205023536 0ustar00jpakkanejpakkane{ "stdout": [ { "line": "test cases/failing/99 number in combo/meson.build:1:0: ERROR: Value \"1\" (of type \"number\") for combo option \"Optimization level\" is not one of the choices. Possible choices are (as string): \"plain\", \"0\", \"g\", \"1\", \"2\", \"3\", \"s\"." } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.0066283 meson-1.3.2/test cases/failing build/0000755000175000017500000000000014562742413017567 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1746612 meson-1.3.2/test cases/failing build/1 vala c werror/0000755000175000017500000000000014562742415022341 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/test cases/failing build/1 vala c werror/meson.build0000644000175000017500000000060514562742363024506 0ustar00jpakkanejpakkaneproject('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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/test cases/failing build/1 vala c werror/prog.vala0000644000175000017500000000022314562742363024154 0ustar00jpakkanejpakkaneclass MainProg : GLib.Object { public static int main(string[] args) { stdout.printf("Vala is working.\n"); return 0; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707853043.0 meson-1.3.2/test cases/failing build/1 vala c werror/unused-var.c0000644000175000017500000000011314562742363024573 0ustar00jpakkanejpakkane#warning "something" int somelib(void) { int unused_var; return 33; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.178661 meson-1.3.2/test cases/failing build/2 hidden symbol/0000755000175000017500000000000014562742415022434 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing build/2 hidden symbol/bob.c0000644000175000017500000000007113716006331023326 0ustar00jpakkanejpakkane#include"bob.h" int hidden_function() { return 7; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing build/2 hidden symbol/bob.h0000644000175000017500000000004513716006331023334 0ustar00jpakkanejpakkane#pragma once int hidden_function(); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing build/2 hidden symbol/bobuser.c0000644000175000017500000000012313716006331024223 0ustar00jpakkanejpakkane#include"bob.h" int main(int argc, char **argv) { return hidden_function(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing build/2 hidden symbol/meson.build0000644000175000017500000000046613716006331024572 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.178661 meson-1.3.2/test cases/failing build/3 pch disabled/0000755000175000017500000000000014562742415022216 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.178661 meson-1.3.2/test cases/failing build/3 pch disabled/c/0000755000175000017500000000000014562742415022440 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing build/3 pch disabled/c/meson.build0000644000175000017500000000011513716006331024565 0ustar00jpakkanejpakkaneexe = executable('prog', 'prog.c', c_pch : ['pch/prog_pch.c', 'pch/prog.h']) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1826613 meson-1.3.2/test cases/failing build/3 pch disabled/c/pch/0000755000175000017500000000000014562742415023212 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing build/3 pch disabled/c/pch/prog.h0000644000175000017500000000002213716006331024312 0ustar00jpakkanejpakkane#include ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing build/3 pch disabled/c/pch/prog_pch.c0000644000175000017500000000013713716006331025146 0ustar00jpakkanejpakkane#if !defined(_MSC_VER) #error "This file is only for use with MSVC." #endif #include "prog.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/failing build/3 pch disabled/c/prog.c0000644000175000017500000000031314140314117023532 0ustar00jpakkanejpakkane// 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing build/3 pch disabled/meson.build0000644000175000017500000000036713716006331024354 0ustar00jpakkanejpakkane# 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') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1826613 meson-1.3.2/test cases/failing build/4 cmake subproject isolation/0000755000175000017500000000000014562742415025120 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1826613 meson-1.3.2/test cases/failing build/4 cmake subproject isolation/incDir/0000755000175000017500000000000014562742415026330 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing build/4 cmake subproject isolation/incDir/fileA.hpp0000644000175000017500000000005313716006331030045 0ustar00jpakkanejpakkane#pragma once #define SOME_DEFINE " World" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing build/4 cmake subproject isolation/main.cpp0000644000175000017500000000023213716006331026533 0ustar00jpakkanejpakkane#include #include using namespace std; int main(void) { cmModClass obj("Hello"); cout << obj.getStr() << endl; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing build/4 cmake subproject isolation/meson.build0000644000175000017500000000111113716006331027242 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.0066283 meson-1.3.2/test cases/failing build/4 cmake subproject isolation/subprojects/0000755000175000017500000000000014562742413027461 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1826613 meson-1.3.2/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/0000755000175000017500000000000014562742415030522 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000037613716006331033256 0ustar00jpakkanejpakkanecmake_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++) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/cmMod.cpp0000644000175000017500000000027013716006331032252 0ustar00jpakkanejpakkane#include "cmMod.hpp" #include "fileA.hpp" using namespace std; cmModClass::cmModClass(string foo) { str = foo + SOME_DEFINE; } string cmModClass::getStr() const { return str; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/cmMod.hpp0000644000175000017500000000031313716006331032255 0ustar00jpakkanejpakkane#pragma once #include "cmmodlib++_export.h" #include class CMMODLIB___EXPORT cmModClass { private: std::string str; public: cmModClass(std::string foo); std::string getStr() const; }; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/failing build/4 cmake subproject isolation/test.json0000644000175000017500000000006314253672217026770 0ustar00jpakkanejpakkane{ "tools": { "cmake": ">=3.14" } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1826613 meson-1.3.2/test cases/failing build/5 failed pickled/0000755000175000017500000000000014562742415022536 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1619506185.0 meson-1.3.2/test cases/failing build/5 failed pickled/false.py0000644000175000017500000000005714041732011024163 0ustar00jpakkanejpakkane#!/usr/bin/env python3 import sys sys.exit(1) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1619506185.0 meson-1.3.2/test cases/failing build/5 failed pickled/meson.build0000644000175000017500000000023514041732011024657 0ustar00jpakkanejpakkaneproject('failed pickled command') custom_target('failure', command: [find_program('false.py'), '\n'], output: 'output.txt', build_by_default: true, ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.0066283 meson-1.3.2/test cases/failing test/0000755000175000017500000000000014562742413017447 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1826613 meson-1.3.2/test cases/failing test/1 trivial/0000755000175000017500000000000014562742415021244 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing test/1 trivial/main.c0000644000175000017500000000004113716006331022315 0ustar00jpakkanejpakkaneint main(void) { return 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421678.0 meson-1.3.2/test cases/failing test/1 trivial/meson.build0000644000175000017500000000010714516755656023416 0ustar00jpakkanejpakkaneproject('trivial', 'c') test('My Test', executable('main', 'main.c')) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1906614 meson-1.3.2/test cases/failing test/2 signal/0000755000175000017500000000000014562742415021050 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing test/2 signal/main.c0000644000175000017500000000013113716006331022121 0ustar00jpakkanejpakkane#include #include int main(void) { kill(getpid(), SIGSEGV); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421678.0 meson-1.3.2/test cases/failing test/2 signal/meson.build0000644000175000017500000000031014516755656023216 0ustar00jpakkanejpakkaneproject('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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1906614 meson-1.3.2/test cases/failing test/3 ambiguous/0000755000175000017500000000000014562742415021567 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing test/3 ambiguous/main.c0000644000175000017500000000013113716006331022640 0ustar00jpakkanejpakkane#include #include int main(void) { kill(getpid(), SIGSEGV); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421678.0 meson-1.3.2/test cases/failing test/3 ambiguous/meson.build0000644000175000017500000000046714516755656023752 0ustar00jpakkanejpakkaneproject('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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing test/3 ambiguous/test_runner.sh0000755000175000017500000000033513716006331024465 0ustar00jpakkanejpakkane#!/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" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1906614 meson-1.3.2/test cases/failing test/4 hard error/0000755000175000017500000000000014562742415021625 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing test/4 hard error/main.c0000644000175000017500000000004213716006331022677 0ustar00jpakkanejpakkaneint main(void) { return 99; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421678.0 meson-1.3.2/test cases/failing test/4 hard error/meson.build0000644000175000017500000000020414516755656023775 0ustar00jpakkanejpakkaneproject('trivial', 'c') # Exit code 99 even overrides should_fail test('My Test', executable('main', 'main.c'), should_fail: true) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1906614 meson-1.3.2/test cases/failing test/5 tap tests/0000755000175000017500000000000014562742415021505 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421679.0 meson-1.3.2/test cases/failing test/5 tap tests/meson.build0000644000175000017500000000101014516755657023652 0ustar00jpakkanejpakkaneproject('test features', 'c') tester = executable('tester', 'tester.c') test_with_status = executable('test-with-status', 'tester_with_status.c') test('nonzero return code no tests', tester, args : [], protocol: 'tap') test('nonzero return code with tests', test_with_status, protocol: 'tap') test('missing test', tester, args : ['1..1'], protocol: 'tap') test('incorrect skip', tester, args : ['1..1 # skip\nok 1'], protocol: 'tap') test('partially skipped', tester, args : ['not ok 1\nok 2 # skip'], protocol: 'tap') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing test/5 tap tests/tester.c0000644000175000017500000000032013716006331023140 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311619.0 meson-1.3.2/test cases/failing test/5 tap tests/tester_with_status.c0000644000175000017500000000021614031433603025577 0ustar00jpakkanejpakkane#include #include int main(int argc, char **argv) { puts("1..1"); puts("not ok 1 - some test"); return 2; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.1946614 meson-1.3.2/test cases/failing test/6 xpass/0000755000175000017500000000000014562742415020735 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698421679.0 meson-1.3.2/test cases/failing test/6 xpass/meson.build0000644000175000017500000000017214516755657023112 0ustar00jpakkanejpakkaneproject('unexpected pass', 'c') test('should_fail_but_does_not', executable('xpass', 'xpass.c'), should_fail: true) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/failing test/6 xpass/xpass.c0000644000175000017500000000005613716006331022226 0ustar00jpakkanejpakkaneint main(int argc, char **argv) { return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.0946295 meson-1.3.2/test cases/fortran/0000755000175000017500000000000014562742413016551 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4386652 meson-1.3.2/test cases/fortran/1 basic/0000755000175000017500000000000014562742415017755 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345087.0 meson-1.3.2/test cases/fortran/1 basic/meson.build0000644000175000017500000000056014516530177022117 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635006971.0 meson-1.3.2/test cases/fortran/1 basic/simple.f900000644000175000017500000000010414135034773021556 0ustar00jpakkanejpakkaneprogram main print *, "Fortran compilation is working." end program ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4386652 meson-1.3.2/test cases/fortran/10 find library/0000755000175000017500000000000014562742415021321 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/10 find library/gzip.f900000644000175000017500000000123113716006331022575 0ustar00jpakkanejpakkanemodule 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635006971.0 meson-1.3.2/test cases/fortran/10 find library/main.f900000644000175000017500000000172414135034773022566 0ustar00jpakkanejpakkaneprogram main 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345093.0 meson-1.3.2/test cases/fortran/10 find library/meson.build0000644000175000017500000000050214516530205023447 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4466653 meson-1.3.2/test cases/fortran/11 compiles links runs/0000755000175000017500000000000014562742415022641 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345093.0 meson-1.3.2/test cases/fortran/11 compiles links runs/meson.build0000644000175000017500000000053614516530205024776 0ustar00jpakkanejpakkaneproject('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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4466653 meson-1.3.2/test cases/fortran/12 submodule/0000755000175000017500000000000014562742415020755 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/12 submodule/a1.f900000644000175000017500000000047413716006331021571 0ustar00jpakkanejpakkanemodule 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/12 submodule/a2.f900000644000175000017500000000022213716006331021561 0ustar00jpakkanejpakkane! testing no space between submodule() submodule(a1) a2 contains module procedure pi2tau pi2tau = 2*pi end procedure pi2tau end submodule a2 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/12 submodule/a3.f900000644000175000017500000000032513716006331021566 0ustar00jpakkanejpakkane! 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/fortran/12 submodule/child.f900000644000175000017500000000026114140314117022341 0ustar00jpakkanejpakkanesubmodule (parent) child contains module procedure pi2tau pi2tau = 2*pi end procedure pi2tau module procedure good print *, 'Good!' end procedure good end submodule child ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345095.0 meson-1.3.2/test cases/fortran/12 submodule/meson.build0000644000175000017500000000070414516530207023111 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635006971.0 meson-1.3.2/test cases/fortran/12 submodule/parent.f900000644000175000017500000000052414135034773022564 0ustar00jpakkanejpakkanemodule 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 program main use parent tau = pi2tau(pi) print *,'pi=',pi, 'tau=', tau call good() end program ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4466653 meson-1.3.2/test cases/fortran/13 coarray/0000755000175000017500000000000014562742415020417 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635006971.0 meson-1.3.2/test cases/fortran/13 coarray/main.f900000644000175000017500000000033714135034773021663 0ustar00jpakkanejpakkaneprogram main implicit 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629287610.0 meson-1.3.2/test cases/fortran/13 coarray/meson.build0000644000175000017500000000167214107172272022560 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4466653 meson-1.3.2/test cases/fortran/14 fortran links c/0000755000175000017500000000000014562742415021737 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/14 fortran links c/clib.c0000644000175000017500000000010613716006331022777 0ustar00jpakkanejpakkane#include void hello(void){ printf("hello from C\n"); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/14 fortran links c/clib.def0000644000175000017500000000001713716006331023314 0ustar00jpakkanejpakkaneEXPORTS hello ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635006971.0 meson-1.3.2/test cases/fortran/14 fortran links c/f_call_c.f900000644000175000017500000000020114135034773023767 0ustar00jpakkanejpakkaneprogram main implicit none interface subroutine hello() bind (c) end subroutine hello end interface call hello() end program ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345096.0 meson-1.3.2/test cases/fortran/14 fortran links c/meson.build0000644000175000017500000000103214516530210024060 0ustar00jpakkanejpakkaneproject('Fortran calling C', 'fortran', 'c', meson_version: '>= 0.51.0', default_options : ['default_library=static']) ccid = meson.get_compiler('c').get_id() fcid = meson.get_compiler('fortran').get_id() if fcid == 'gcc' and ccid in ['msvc', '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) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4546654 meson-1.3.2/test cases/fortran/15 include/0000755000175000017500000000000014562742415020404 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/15 include/inc1.f900000644000175000017500000000012413716006331021541 0ustar00jpakkanejpakkane real :: pi = 4.*atan(1.) real :: tau include "inc2.f90" ! testing inline comment ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/15 include/inc2.f900000644000175000017500000000001413716006331021540 0ustar00jpakkanejpakkane tau = 2*pi ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/fortran/15 include/include_hierarchy.f900000644000175000017500000000014114031433465024372 0ustar00jpakkanejpakkaneprogram test_include_hier implicit none include "inc1.f90" print *, '2*pi:', tau end program ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/fortran/15 include/include_syntax.f900000644000175000017500000000075114031433465023751 0ustar00jpakkanejpakkaneprogram test_include_syntax implicit 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 program ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345097.0 meson-1.3.2/test cases/fortran/15 include/meson.build0000644000175000017500000000151314516530211022532 0ustar00jpakkanejpakkaneproject('Inclusive', 'fortran', meson_version: '>= 0.51.1') cm = import('cmake') 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) # older CI runs into problems with too-old Ninja and CMake and Fortran ninja_version = run_command('ninja', '--version', check: true).stdout().strip() cmake_version = run_command('cmake', '--version', check: true).stdout().split()[2] if ninja_version.version_compare('>=1.10.0') and cmake_version.version_compare('>=3.17.0') cm.subproject('cmake_inc') else message('SKIP: CMake Fortran subproject with include. Ninja >= 1.10 and CMake >= 3.17 needed. You have Ninja ' + ninja_version + ' and CMake ' + cmake_version) endif ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.0866294 meson-1.3.2/test cases/fortran/15 include/subprojects/0000755000175000017500000000000014562742413022745 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4546654 meson-1.3.2/test cases/fortran/15 include/subprojects/cmake_inc/0000755000175000017500000000000014562742415024660 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/fortran/15 include/subprojects/cmake_inc/CMakeLists.txt0000644000175000017500000000015114031433465027406 0ustar00jpakkanejpakkanecmake_minimum_required(VERSION 3.17) project(cmake_inc LANGUAGES Fortran) add_executable(main main.f90) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/fortran/15 include/subprojects/cmake_inc/main.f900000644000175000017500000000021514031433465026113 0ustar00jpakkanejpakkaneprogram test_subproject_inc implicit none include 'thousand.f90' if (thousand /= 1000) error stop 'did not include properly' end program ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311541.0 meson-1.3.2/test cases/fortran/15 include/subprojects/cmake_inc/thousand.f900000644000175000017500000000004614031433465027016 0ustar00jpakkanejpakkaneinteger, parameter :: thousand = 1000 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/15 include/timestwo.f900000644000175000017500000000001713716006331022563 0ustar00jpakkanejpakkanex = 2*x y = y+1././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4546654 meson-1.3.2/test cases/fortran/16 openmp/0000755000175000017500000000000014562742415020260 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635006971.0 meson-1.3.2/test cases/fortran/16 openmp/main.f900000644000175000017500000000104114135034773021515 0ustar00jpakkanejpakkaneprogram main use, 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345096.0 meson-1.3.2/test cases/fortran/16 openmp/meson.build0000644000175000017500000000175014516530210022410 0ustar00jpakkanejpakkane# 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())) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4546654 meson-1.3.2/test cases/fortran/17 add_languages/0000755000175000017500000000000014562742415021541 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345097.0 meson-1.3.2/test cases/fortran/17 add_languages/meson.build0000644000175000017500000000034214516530211023666 0ustar00jpakkanejpakkaneproject('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')././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4546654 meson-1.3.2/test cases/fortran/18 first_arg/0000755000175000017500000000000014562742415020744 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635006971.0 meson-1.3.2/test cases/fortran/18 first_arg/main.f900000644000175000017500000000003714135034773022205 0ustar00jpakkanejpakkaneprogram main i = 3 end program ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345098.0 meson-1.3.2/test cases/fortran/18 first_arg/meson.build0000644000175000017500000000306214516530212023074 0ustar00jpakkanejpakkaneproject('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.') # --- test with an actual program, here for implicit none in0 = fc.first_supported_argument('-fimplicit-none', '-Mdclchk', '/warn:declarations', '-warn').get(0, '') impnone = { 'intel-cl': '/warn:declarations', 'intel': '-warn', 'gcc': '-fimplicit-none', 'pgi': '-Mdclchk', } arg = impnone.get(fc.get_id(), '') if arg != '' assert(in0 == arg, 'implicit none argument ' + arg + ' not matching ' + in0) endif in1 = fc.get_supported_arguments('-fimplicit-none', '/warn:declarations', '/warn:errors', '-Mdclchk') if in1.length() > 0 assert(not fc.compiles(files('main.f90'), args: in1, name:'will fail implicit none'), 'implicit none should have failed') endif ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4626656 meson-1.3.2/test cases/fortran/19 fortran_std/0000755000175000017500000000000014562742415021312 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635006971.0 meson-1.3.2/test cases/fortran/19 fortran_std/legacy.f0000644000175000017500000000023514135034773022722 0ustar00jpakkanejpakkane program main ! non-integer loop indices are deleted in Fortran 95 standard real a do 10 a=0,0.5,0.1 10 continue end program ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345099.0 meson-1.3.2/test cases/fortran/19 fortran_std/meson.build0000644000175000017500000000215214516530213023442 0ustar00jpakkanejpakkaneproject('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']) endif././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635006971.0 meson-1.3.2/test cases/fortran/19 fortran_std/std2003.f900000644000175000017500000000123314135034773022725 0ustar00jpakkanejpakkaneprogram main use, 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 program ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635006971.0 meson-1.3.2/test cases/fortran/19 fortran_std/std2008.f900000644000175000017500000000112214135034773022727 0ustar00jpakkanejpakkaneprogram main use, 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 program ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635006971.0 meson-1.3.2/test cases/fortran/19 fortran_std/std2018.f900000644000175000017500000000122614135034773022735 0ustar00jpakkanejpakkaneprogram main use, 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 program ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635006971.0 meson-1.3.2/test cases/fortran/19 fortran_std/std95.f900000644000175000017500000000023014135034773022572 0ustar00jpakkanejpakkaneprogram main implicit 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 program ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4626656 meson-1.3.2/test cases/fortran/2 modules/0000755000175000017500000000000014562742415020345 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/2 modules/comment_mod.f900000644000175000017500000000011413716006331023150 0ustar00jpakkanejpakkanemodule line ! inline comment implicit none real :: length end module line ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345087.0 meson-1.3.2/test cases/fortran/2 modules/meson.build0000644000175000017500000000043014516530177022503 0ustar00jpakkanejpakkaneproject('modules', 'fortran', default_options : ['default_library=static']) commented = library('commented', 'comment_mod.f90') # Have one file with an upper case file extension. e = executable('modprog', 'mymod.F90', 'prog.f90', link_with: commented) test('moduletest', e) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1618046534.0 meson-1.3.2/test cases/fortran/2 modules/mymod.F900000644000175000017500000000025414034267106021744 0ustar00jpakkanejpakkane! 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/fortran/2 modules/prog.f900000644000175000017500000000020314140314117021611 0ustar00jpakkanejpakkaneprogram main use circle, only: pi use line, only: length implicit none print *,'pi=',pi length = pi print *, length end program ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4626656 meson-1.3.2/test cases/fortran/20 buildtype/0000755000175000017500000000000014562742415020756 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635006971.0 meson-1.3.2/test cases/fortran/20 buildtype/main.f900000644000175000017500000000003114135034773022211 0ustar00jpakkanejpakkaneprogram main end program ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345099.0 meson-1.3.2/test cases/fortran/20 buildtype/meson.build0000644000175000017500000000032214516530213023103 0ustar00jpakkanejpakkane# 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') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4666655 meson-1.3.2/test cases/fortran/21 install static/0000755000175000017500000000000014562742415021674 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635006971.0 meson-1.3.2/test cases/fortran/21 install static/main.f900000644000175000017500000000010614135034773023132 0ustar00jpakkanejpakkaneprogram main use main_lib implicit none call main_hello() end program ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/fortran/21 install static/main_lib.f900000644000175000017500000000036414140314117023753 0ustar00jpakkanejpakkanemodule main_lib use static_hello implicit none private public :: main_hello contains subroutine main_hello call static_say_hello() print *, "Main hello routine finished." end subroutine main_hello end module main_lib ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345103.0 meson-1.3.2/test cases/fortran/21 install static/meson.build0000644000175000017500000000152414516530217024032 0ustar00jpakkanejpakkane# Based on 'fortran/5 static', but: # - Uses a subproject dependency # - Is an install:true static library to trigger certain codepath (promotion to link_whole) # - Does fortran code 'generation' with configure_file # - Uses .F90 ext (capital F typically denotes a dependence on preprocessor treatment, which however is not used) project('try-static-subproject-dependency', 'fortran') static_dep = dependency('static_hello', fallback: ['static_hello', 'static_hello_dep']) mainsrc = 'main_lib.f90' mainsrc = configure_file( copy: true, input: mainsrc, output: 'main_lib_output.F90' ) main_lib = library('mainstatic', mainsrc, dependencies: static_dep, install: true) main_dep = declare_dependency(link_with: main_lib) main_exe = executable('main_exe', 'main.f90', dependencies: main_dep) test('static_subproject_test', main_exe) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.0906296 meson-1.3.2/test cases/fortran/21 install static/subprojects/0000755000175000017500000000000014562742413024235 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4666655 meson-1.3.2/test cases/fortran/21 install static/subprojects/static_hello/0000755000175000017500000000000014562742415026711 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/fortran/21 install static/subprojects/static_hello/meson.build0000644000175000017500000000053414107166547031056 0ustar00jpakkanejpakkaneproject('static-hello', 'fortran') # staticlibsource = 'static_hello.f90' staticlibsource = configure_file( copy: true, input: 'static_hello.f90', output: 'static_hello_output.F90' ) static_hello_lib = static_library('static_hello', staticlibsource, install: false) static_hello_dep = declare_dependency(link_with: static_hello_lib) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311580.0 meson-1.3.2/test cases/fortran/21 install static/subprojects/static_hello/static_hello.f900000644000175000017500000000042414031433534031671 0ustar00jpakkanejpakkanemodule 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629285735.0 meson-1.3.2/test cases/fortran/21 install static/test.json0000644000175000017500000000030614107166547023546 0ustar00jpakkanejpakkane{ "installed": [ {"file": "usr/lib/libmainstatic.a", "type": "file"} ], "matrix": { "options": { "default_library": [ { "val": "static" } ] } } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4666655 meson-1.3.2/test cases/fortran/22 extract_objects/0000755000175000017500000000000014562742415022142 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855209.0 meson-1.3.2/test cases/fortran/22 extract_objects/bar.f900000644000175000017500000000000014433154651023210 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855209.0 meson-1.3.2/test cases/fortran/22 extract_objects/foo1.f900000644000175000017500000000000014433154651023310 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855209.0 meson-1.3.2/test cases/fortran/22 extract_objects/foo2.f900000644000175000017500000000000014433154651023311 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345101.0 meson-1.3.2/test cases/fortran/22 extract_objects/meson.build0000644000175000017500000000054014516530215024273 0ustar00jpakkanejpakkaneproject('test_project', 'fortran') if get_option('unity') == 'on' error('MESON_SKIP_TEST: extract_objects does not work in unity builds') endif libfoo = static_library( 'foo', sources : ['foo1.f90', 'foo2.f90']) foo1_object = libfoo.extract_objects('foo1.f90') libfinal = library( 'final', sources : 'bar.f90', objects : foo1_object, ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4706657 meson-1.3.2/test cases/fortran/23 preprocess/0000755000175000017500000000000014562742415021145 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1687963700.0 meson-1.3.2/test cases/fortran/23 preprocess/main.f900000644000175000017500000000011614447044064022404 0ustar00jpakkanejpakkane#define MYDEF program MYDEF foo write (*,*) 'Hello, world!' end MYDEF foo ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345101.0 meson-1.3.2/test cases/fortran/23 preprocess/meson.build0000644000175000017500000000023414516530215023276 0ustar00jpakkanejpakkaneproject('preprocess', 'fortran') fc = meson.get_compiler('fortran') pp_files = fc.preprocess('main.f90', output: '@PLAINNAME@') library('foo', pp_files) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4706657 meson-1.3.2/test cases/fortran/3 module procedure/0000755000175000017500000000000014562742415022134 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345087.0 meson-1.3.2/test cases/fortran/3 module procedure/meson.build0000644000175000017500000000026014516530177024273 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/3 module procedure/use_syntax.f900000644000175000017500000000071313716006331024645 0ustar00jpakkanejpakkanemodule 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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4786658 meson-1.3.2/test cases/fortran/4 self dependency/0000755000175000017500000000000014562742415021727 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345089.0 meson-1.3.2/test cases/fortran/4 self dependency/meson.build0000644000175000017500000000023214516530201024051 0ustar00jpakkanejpakkaneproject('selfdep', 'fortran') e = executable('selfdep', 'selfdep.f90') test('selfdep', e) library('selfmod', 'src/selfdep_mod.f90') subproject('sub1') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/4 self dependency/selfdep.f900000644000175000017500000000032713716006331023661 0ustar00jpakkanejpakkaneMODULE 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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4786658 meson-1.3.2/test cases/fortran/4 self dependency/src/0000755000175000017500000000000014562742415022516 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/4 self dependency/src/selfdep_mod.f900000644000175000017500000000006313716006331025304 0ustar00jpakkanejpakkanemodule a end module a module b use a end module b ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.0906296 meson-1.3.2/test cases/fortran/4 self dependency/subprojects/0000755000175000017500000000000014562742413024270 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4786658 meson-1.3.2/test cases/fortran/4 self dependency/subprojects/sub1/0000755000175000017500000000000014562742415025144 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/4 self dependency/subprojects/sub1/main.f900000644000175000017500000000004413716006331026374 0ustar00jpakkanejpakkanemodule a end program b use a end ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/4 self dependency/subprojects/sub1/meson.build0000644000175000017500000000011213716006331027266 0ustar00jpakkanejpakkaneproject('subproject self-def', 'fortran') library('subself', 'main.f90') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4786658 meson-1.3.2/test cases/fortran/5 static/0000755000175000017500000000000014562742415020167 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635006971.0 meson-1.3.2/test cases/fortran/5 static/main.f900000644000175000017500000000012114135034773021422 0ustar00jpakkanejpakkaneprogram main use static_hello implicit none call static_say_hello() end program ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345090.0 meson-1.3.2/test cases/fortran/5 static/meson.build0000644000175000017500000000031414516530202022313 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/5 static/static_hello.f900000644000175000017500000000042413716006331023147 0ustar00jpakkanejpakkanemodule 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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.4786658 meson-1.3.2/test cases/fortran/6 dynamic/0000755000175000017500000000000014562742415020325 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/6 dynamic/dynamic.f900000644000175000017500000000033313716006331022256 0ustar00jpakkanejpakkanemodule 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635006971.0 meson-1.3.2/test cases/fortran/6 dynamic/main.f900000644000175000017500000000011614135034773021564 0ustar00jpakkanejpakkaneprogram main use dynamic, only: hello implicit none call hello() end program ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345090.0 meson-1.3.2/test cases/fortran/6 dynamic/meson.build0000644000175000017500000000116414516530202022455 0ustar00jpakkanejpakkaneproject('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) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.486666 meson-1.3.2/test cases/fortran/7 generated/0000755000175000017500000000000014562742415020640 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345090.0 meson-1.3.2/test cases/fortran/7 generated/meson.build0000644000175000017500000000233014516530202022764 0ustar00jpakkanejpakkane# Tests whether fortran sources files created during configuration are properly # scanned for dependency information project('generated', 'fortran', default_options : ['default_library=static']) conf_data = configuration_data() conf_data.set('ONE', 1) conf_data.set('TWO', 2) mod3_f = custom_target( 'mod3.f', input : 'mod3.f90', output : 'mod3.f90', # We need a platform agnostic way to do a copy a file, using a custom_target # and we need to use the @OUTDIR@, not @OUTPUT@ in order to exercise # https://github.com/mesonbuild/meson/issues/9258 command : [ find_program('python', 'python3'), '-c', 'import sys, shutil; shutil.copy(sys.argv[1], sys.argv[2])', '@INPUT@', '@OUTDIR@', ], ) three = library('mod3', mod3_f) 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, link_with: three) test('generated', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/7 generated/mod1.fpp0000644000175000017500000000012213716006331022170 0ustar00jpakkanejpakkanemodule mod1 implicit none integer, parameter :: modval1 = @ONE@ end module mod1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/7 generated/mod2.fpp0000644000175000017500000000015313716006331022175 0ustar00jpakkanejpakkanemodule mod2 use mod1, only : modval1 implicit none integer, parameter :: modval2 = @TWO@ end module mod2 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/fortran/7 generated/mod3.f900000644000175000017500000000011614140314117022002 0ustar00jpakkanejpakkanemodule mod3 implicit none integer, parameter :: modval3 = 3 end module mod3 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/7 generated/prog.f900000644000175000017500000000024413716006331022115 0ustar00jpakkanejpakkaneprogram generated use mod2, only : modval1, modval2 use mod3, only : modval3 implicit none if (modval1 + modval2 + modval3 /= 6) error stop end program generated ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.490666 meson-1.3.2/test cases/fortran/8 module names/0000755000175000017500000000000014562742415021254 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345092.0 meson-1.3.2/test cases/fortran/8 module names/meson.build0000644000175000017500000000023314516530204023402 0ustar00jpakkanejpakkaneproject('mod_name_case', 'fortran') sources = ['test.f90', 'mod1.f90', 'mod2.f90'] exe = executable('mod_name_case', sources) test('mod_name_case', exe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/8 module names/mod1.f900000644000175000017500000000012413716006331022417 0ustar00jpakkanejpakkanemodule MyMod1 implicit none integer, parameter :: myModVal1 = 1 end module MyMod1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/8 module names/mod2.f900000644000175000017500000000012413716006331022420 0ustar00jpakkanejpakkanemodule mymod2 implicit none integer, parameter :: myModVal2 = 2 end module mymod2 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635006971.0 meson-1.3.2/test cases/fortran/8 module names/test.f900000644000175000017500000000021514135034773022546 0ustar00jpakkanejpakkaneprogram main use mymod1 use MyMod2 ! test inline comment implicit none integer, parameter :: testVar = myModVal1 + myModVal2 end program ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.494666 meson-1.3.2/test cases/fortran/9 cpp/0000755000175000017500000000000014562742415017466 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/9 cpp/fortran.f0000644000175000017500000000034013716006331021273 0ustar00jpakkanejpakkane 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1617311619.0 meson-1.3.2/test cases/fortran/9 cpp/main.c0000644000175000017500000000021214031433603020534 0ustar00jpakkanejpakkane#include double fortran(void); int main(void) { printf("FORTRAN gave us this number: %lf.\n", fortran()); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fortran/9 cpp/main.cpp0000644000175000017500000000023313716006331021102 0ustar00jpakkanejpakkane#include extern "C" double fortran(); int main(void) { std::cout << "FORTRAN gave us this number: " << fortran() << '\n'; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345093.0 meson-1.3.2/test cases/fortran/9 cpp/meson.build0000644000175000017500000000114414516530205021617 0ustar00jpakkanejpakkaneproject('C, C++ and Fortran', 'c', 'cpp', 'fortran') cpp = meson.get_compiler('cpp') fc = meson.get_compiler('fortran') if build_machine.system() == 'windows' and fc.get_id() == 'gcc' and cpp.get_id() != 'gcc' 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( 'cfort', ['main.c', 'fortran.f'], dependencies : link_with, ) test('C and Fortran', e) e2 = executable( 'cppfort', ['main.cpp', 'fortran.f'], dependencies : link_with, ) test('C++ and Fortran', e2) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.0946295 meson-1.3.2/test cases/fpga/0000755000175000017500000000000014562742413016013 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.494666 meson-1.3.2/test cases/fpga/1 simple/0000755000175000017500000000000014562742415017427 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1666639513.0 meson-1.3.2/test cases/fpga/1 simple/meson.build0000644000175000017500000000017414325563231021565 0ustar00jpakkanejpakkaneproject('lattice', 'c') is = import('unstable-icestorm') is.project('spin', 'spin.v', constraint_file : 'spin.pcf', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/fpga/1 simple/spin.pcf0000644000175000017500000000013113716006331021053 0ustar00jpakkanejpakkaneset_io LED1 99 set_io LED2 98 set_io LED3 97 set_io LED4 96 set_io LED5 95 set_io clk 21 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/fpga/1 simple/spin.v0000644000175000017500000000127014140314117020551 0ustar00jpakkanejpakkane 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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.1506305 meson-1.3.2/test cases/frameworks/0000755000175000017500000000000014562742413017256 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.502666 meson-1.3.2/test cases/frameworks/1 boost/0000755000175000017500000000000014562742416020530 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/1 boost/extralib.cpp0000644000175000017500000000126113716006331023033 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/1 boost/linkexe.cc0000644000175000017500000000044513716006331022466 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345126.0 meson-1.3.2/test cases/frameworks/1 boost/meson.build0000644000175000017500000000714214516530246022671 0ustar00jpakkanejpakkane# this test requires the following on Ubuntu: libboost-{system,python,log,thread,test}-dev project('boosttest', 'cpp', default_options : ['cpp_std=c++14']) s = get_option('static') dep = dependency('boost', static: s, required: false) if not dep.found() error('MESON_SKIP_TEST boost not found.') 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', static: s, modules : ['thread', 'system', 'date_time']) testdep = dependency('boost', static: s, modules : ['unit_test_framework']) nomoddep = dependency('boost', static: s) extralibdep = dependency('boost', static: s, modules : ['thread', 'system', 'date_time', 'log_setup', 'log', 'filesystem', 'regex']) notfound = dependency('boost', static: s, modules : ['this_should_not_exist_on_any_system'], required: false) assert(not notfound.found()) require_bp = host_machine.system() in ['linux', 'darwin'] pymod = import('python') python2 = pymod.find_installation('python2', required: false , disabler: true) python3 = pymod.find_installation('python3', required: require_bp , disabler: true) python2dep = python2.dependency(required: false , embed: true, disabler: true) python3dep = python3.dependency(required: require_bp, embed: true, disabler: true) # compile python 2/3 modules only if we found a corresponding python version if(python2dep.found() and require_bp and not s) bpython2dep = dependency('boost', static: s, modules : ['python'], required: false, disabler: true) else python2dep = disabler() bpython2dep = disabler() endif if(python3dep.found() and require_bp and not s) bpython3dep = dependency('boost', static: s, modules : ['python3']) else python3dep = disabler() bpython3dep = disabler() endif linkexe = executable('linkedexe', 'linkexe.cc', dependencies : linkdep) 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 = python2.extension_module('python2_module', ['python_module.cpp'], dependencies: [python2dep, bpython2dep], cpp_args: ['-DMOD_NAME=python2_module']) python3module = python3.extension_module('python3_module', ['python_module.cpp'], dependencies: [python3dep, bpython3dep], cpp_args: ['-DMOD_NAME=python3_module']) test('Boost linktest', linkexe, timeout: 60) test('Boost UTF test', unitexe, timeout: 60) test('Boost nomod', nomodexe) if host_machine.system() != 'darwin' or s # Segfaults on macOS with dynamic linking since Boost 1.73 # https://github.com/mesonbuild/meson/issues/7535 test('Boost extralib test', extralibexe) endif # 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', static: s, version: '>=@0@'.format(dep.version())) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/1 boost/meson_options.txt0000644000175000017500000000006013716006331024146 0ustar00jpakkanejpakkaneoption('static', type: 'boolean', value: false) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/1 boost/nomod.cpp0000644000175000017500000000062013716006331022333 0ustar00jpakkanejpakkane#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; } } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.502666 meson-1.3.2/test cases/frameworks/1 boost/partial_dep/0000755000175000017500000000000014562742416023014 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/1 boost/partial_dep/foo.cpp0000644000175000017500000000122613716006331024271 0ustar00jpakkanejpakkane/* 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/1 boost/partial_dep/foo.hpp0000644000175000017500000000144413716006331024300 0ustar00jpakkanejpakkane/* 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); }; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/frameworks/1 boost/partial_dep/main.cpp0000644000175000017500000000146714140314117024435 0ustar00jpakkanejpakkane/* 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/1 boost/partial_dep/meson.build0000644000175000017500000000164713716006331025153 0ustar00jpakkanejpakkane# 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/1 boost/python_module.cpp0000644000175000017500000000102313716006331024103 0ustar00jpakkanejpakkane#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) ; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/frameworks/1 boost/test.json0000644000175000017500000000113714140314117022365 0ustar00jpakkanejpakkane{ "matrix": { "options": { "static": [ { "val": "true", "skip_on_env": [ "SKIP_STATIC_BOOST" ] }, { "val": "false" } ], "b_vscrt": [ { "val": null }, { "val": "md", "compilers": { "cpp": "msvc" } }, { "val": "mdd", "compilers": { "cpp": "msvc" } }, { "val": "mt", "compilers": { "cpp": "msvc" } }, { "val": "mtd", "compilers": { "cpp": "msvc" } } ] }, "exclude": [ { "static": "false", "b_vscrt": "mt" }, { "static": "false", "b_vscrt": "mtd" } ] }, "skip_on_jobname": ["azure", "msys2"] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/frameworks/1 boost/test_python_module.py0000644000175000017500000000113614140314117025011 0ustar00jpakkanejpakkaneimport 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() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/1 boost/unit_test.cpp0000644000175000017500000000031113716006331023232 0ustar00jpakkanejpakkane#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); } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1707853069.502666 meson-1.3.2/test cases/frameworks/10 gtk-doc/0000755000175000017500000000000014562742416021012 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.5106661 meson-1.3.2/test cases/frameworks/10 gtk-doc/doc/0000755000175000017500000000000014562742416021557 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/doc/foobar-docs.sgml0000644000175000017500000000210513716006331024624 0ustar00jpakkanejpakkane ]> Foolib Reference Manual for Foobar &version; Jonny Example
unknown@example.com
2015 Foobar corporation holdings ltd
Foobar library This part documents Foobar libs.
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.5106661 meson-1.3.2/test cases/frameworks/10 gtk-doc/doc/foobar1/0000755000175000017500000000000014562742416023110 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1642416638.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/doc/foobar1/baz.jpg0000644000175000017500000000000014171244776024356 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1642416638.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/doc/foobar1/baz.png.in0000644000175000017500000000000014171244776024767 0ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1623087322.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/doc/foobar1/foobar-docs.sgml0000644000175000017500000000210714057454332026166 0ustar00jpakkanejpakkane ]> Foolib Reference Manual for Foobar &version; Jonny Example
unknown@example.com
2015 Foobar corporation holdings ltd
Foobar library This part documents Foobar libs.
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1635883087.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/doc/foobar1/foobar-sections.txt0000644000175000017500000000033014140314117026723 0ustar00jpakkanejpakkane
foo FooObj FooObj FooObjClass foo_do_something
version version FOO_MAJOR_VERSION FOO_MINOR_VERSION FOO_MICRO_VERSION
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1623087322.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/doc/foobar1/foobar.types0000644000175000017500000000021014057454332025433 0ustar00jpakkanejpakkane% This include is useless it's a regression test for https://github.com/mesonbuild/meson/issues/8744 #include foo_obj_get_type ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1642416638.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/doc/foobar1/meson.build0000644000175000017500000000066314171244776025261 0ustar00jpakkanejpakkanepng = configure_file(input: 'baz.png.in', output: 'baz.png', copy: true) gnome.gtkdoc('foobar', src_dir : [inc, '.'], main_sgml : 'foobar-docs.sgml', content_files : [docbook, version_xml], dependencies: foo_dep, html_assets: ['baz.jpg', png], # Manually written types file for regression test: # https://github.com/mesonbuild/meson/issues/8744 gobject_typesfile: 'foobar.types', install : true, check: false) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.5106661 meson-1.3.2/test cases/frameworks/10 gtk-doc/doc/foobar2/0000755000175000017500000000000014562742416023111 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/doc/foobar2/foobar-docs.sgml0000644000175000017500000000211313716006331026155 0ustar00jpakkanejpakkane ]> Foolib Reference Manual for Foobar &version; Jonny Example
unknown@example.com
2015 Foobar corporation holdings ltd
Foobar library This part documents Foobar libs.
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1642416638.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/doc/foobar2/meson.build0000644000175000017500000000047214171244776025260 0ustar00jpakkanejpakkanetypes = configure_file(input: '../foobar1/foobar.types', output: 'foobar.types', copy: true ) gnome.gtkdoc('foobar2', src_dir : inc, main_sgml : 'foobar-docs.sgml', content_files : [docbook, version_xml], gobject_typesfile: types, dependencies: foo_dep, install : true, install_dir : 'foobar2') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.5106661 meson-1.3.2/test cases/frameworks/10 gtk-doc/doc/foobar3/0000755000175000017500000000000014562742416023112 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/doc/foobar3/foobar-docs.sgml0000644000175000017500000000211313716006331026156 0ustar00jpakkanejpakkane ]> Foolib Reference Manual for Foobar &version; Jonny Example
unknown@example.com
2015 Foobar corporation holdings ltd
Foobar library This part documents Foobar libs.
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/doc/foobar3/meson.build0000644000175000017500000000024013716006331025235 0ustar00jpakkanejpakkanegnome.gtkdoc('foobar', module_version : '3.0', src_dir : inc, main_sgml : 'foobar-docs.sgml', content_files : [docbook, version_xml], install : true) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.5186663 meson-1.3.2/test cases/frameworks/10 gtk-doc/doc/foobar4/0000755000175000017500000000000014562742416023113 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/doc/foobar4/foobar-docs.sgml0000644000175000017500000000211313716006331026157 0ustar00jpakkanejpakkane ]> Foolib Reference Manual for Foobar &version; Jonny Example
unknown@example.com
2015 Foobar corporation holdings ltd
Foobar library This part documents Foobar libs.
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/doc/foobar4/meson.build0000644000175000017500000000027413716006331025245 0ustar00jpakkanejpakkanegnome.gtkdoc('foobar2', module_version : '3.0', src_dir : inc, main_sgml : 'foobar-docs.sgml', content_files : [docbook, version_xml], install : true, install_dir : 'foobar3') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/doc/meson.build0000644000175000017500000000044213716006331023706 0ustar00jpakkanejpakkanecdata = 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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/doc/version.xml.in0000644000175000017500000000001213716006331024351 0ustar00jpakkanejpakkane@VERSION@ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1623087322.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/foo.c0000644000175000017500000000054514057454332021741 0ustar00jpakkanejpakkane#include struct _FooObj { GObject parent; int dummy; }; G_DEFINE_TYPE(FooObj, foo_obj, G_TYPE_OBJECT) static void foo_obj_init (FooObj *self) { } static void foo_obj_class_init (FooObjClass *klass) { } /** * foo_do_something: * @self: self * * Useless function. * * Returns: 0. */ int foo_do_something(FooObj *self) { return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.5186663 meson-1.3.2/test cases/frameworks/10 gtk-doc/include/0000755000175000017500000000000014562742416022435 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/include/foo-version.h.in0000644000175000017500000000074613716006331025455 0ustar00jpakkanejpakkane#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@) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1623087322.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/include/foo.h0000644000175000017500000000070014057454332023362 0ustar00jpakkanejpakkane#pragma once #include /** * FooIndecision: * @FOO_MAYBE: Something maybe * @FOO_POSSIBLY: Something possible * * The indecision type. **/ typedef enum { FOO_MAYBE, FOO_POSSIBLY, } FooIndecision; /** * FooObjClass: * * The class */ /** * FooObj: * * The instance */ #define FOO_TYPE_OBJ foo_obj_get_type() G_DECLARE_FINAL_TYPE(FooObj, foo_obj, FOO, OBJ, GObject) int foo_do_something(FooObj *self); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/include/generate-enums-docbook.py0000644000175000017500000000376413716006331027343 0ustar00jpakkanejpakkane#!/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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/include/meson.build0000644000175000017500000000111513716006331024562 0ustar00jpakkanejpakkanecdata = 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345154.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/meson.build0000644000175000017500000000217414516530302023144 0ustar00jpakkanejpakkaneproject('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'], check: true) 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 gobject = dependency('gobject-2.0') libfoo = shared_library('foo', 'foo.c', include_directories: inc, dependencies: gobject, ) deps = [] if host_machine.system() == 'darwin' deps += dependency('appleframeworks', modules : ['Foundation', 'CoreFoundation']) endif foo_dep = declare_dependency( link_with: libfoo, include_directories: inc, dependencies: deps, ) subdir('doc') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1655665807.0 meson-1.3.2/test cases/frameworks/10 gtk-doc/test.json0000644000175000017500000001106514253672217022665 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/include/foo-version.h"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar/BAR.html"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar/baz.jpg"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar/baz.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar/foobar.devhelp2"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar/foobar.html"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar/FooObj.html"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar/foo-version.html"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar/home.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar/index.html"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar/left.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar/left-insensitive.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar/right.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar/right-insensitive.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar/style.css"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar/up.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar/up-insensitive.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar2/BAR.html"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar2/foobar2.devhelp2"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar2/foobar.html"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar2/foobar2-foo.html"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar2/foobar2-foo-version.html"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar2/home.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar2/index.html"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar2/left.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar2/left-insensitive.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar2/right.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar2/right-insensitive.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar2/style.css"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar2/up.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar2/up-insensitive.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar-3.0/BAR.html"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar-3.0/foobar-3.0.devhelp2"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar-3.0/foobar.html"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar-3.0/foobar-foo.html"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar-3.0/foobar-foo-version.html"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar-3.0/home.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar-3.0/index.html"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar-3.0/left.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar-3.0/left-insensitive.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar-3.0/right.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar-3.0/right-insensitive.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar-3.0/style.css"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar-3.0/up.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar-3.0/up-insensitive.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar3/BAR.html"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar3/foobar2-3.0.devhelp2"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar3/foobar.html"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar3/foobar2-foo.html"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar3/foobar2-foo-version.html"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar3/home.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar3/index.html"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar3/left.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar3/left-insensitive.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar3/right.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar3/right-insensitive.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar3/style.css"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar3/up.png"}, {"type": "file", "file": "usr/share/gtk-doc/html/foobar3/up-insensitive.png"} ], "skip_on_jobname": ["azure", "msys2"] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.5186663 meson-1.3.2/test cases/frameworks/11 gir subproject/0000755000175000017500000000000014562742416022405 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.5186663 meson-1.3.2/test cases/frameworks/11 gir subproject/gir/0000755000175000017500000000000014562742416023166 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/11 gir subproject/gir/meson-subsample.c0000644000175000017500000000540213716006331026432 0ustar00jpakkanejpakkane#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); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/11 gir subproject/gir/meson-subsample.h0000644000175000017500000000070413716006331026437 0ustar00jpakkanejpakkane#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 */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/11 gir subproject/gir/meson.build0000644000175000017500000000212613716006331025316 0ustar00jpakkanejpakkanelibsources = ['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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/11 gir subproject/gir/prog.c0000644000175000017500000000034513716006331024270 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/11 gir subproject/gir/prog.py0000755000175000017500000000024013716006331024473 0ustar00jpakkanejpakkane#!/usr/bin/env python3 from gi.repository import MesonSub if __name__ == "__main__": s = MesonSub.Sample.new("Hello, sub/meson/py!") s.print_message() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345159.0 meson-1.3.2/test cases/frameworks/11 gir subproject/meson.build0000644000175000017500000000107114516530307024537 0ustar00jpakkanejpakkaneproject('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;', check: false).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') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853067.1026297 meson-1.3.2/test cases/frameworks/11 gir subproject/subprojects/0000755000175000017500000000000014562742413024745 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.5226665 meson-1.3.2/test cases/frameworks/11 gir subproject/subprojects/mesongir/0000755000175000017500000000000014562742416026573 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/11 gir subproject/subprojects/mesongir/meson-sample.c0000644000175000017500000000556113716006331031333 0ustar00jpakkanejpakkane#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); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/11 gir subproject/subprojects/mesongir/meson-sample.h0000644000175000017500000000100013716006331031320 0ustar00jpakkanejpakkane#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 */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/11 gir subproject/subprojects/mesongir/meson.build0000644000175000017500000000126713716006331030730 0ustar00jpakkanejpakkaneproject('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, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1676897923.0 meson-1.3.2/test cases/frameworks/11 gir subproject/test.json0000644000175000017500000000122614374667203024261 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/lib/girepository-1.0/Meson-1.0.typelib"}, {"type": "file", "file": "usr/lib/girepository-1.0/MesonSub-1.0.typelib"}, {"type": "file", "file": "usr/share/gir-1.0/Meson-1.0.gir"}, {"type": "file", "file": "usr/share/gir-1.0/MesonSub-1.0.gir"}, {"type": "expr", "file": "usr/lib/?libgirsubproject.so"}, {"type": "file", "platform": "cygwin", "file": "usr/lib/libgirlib.dll.a"}, {"type": "expr", "file": "usr/lib/?libgirlib.so"}, {"type": "file", "platform": "cygwin", "file": "usr/lib/libgirsubproject.dll.a"} ], "skip_on_jobname": ["azure", "cygwin", "macos", "msys2", "pypy"] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.5226665 meson-1.3.2/test cases/frameworks/12 multiple gir/0000755000175000017500000000000014562742416022061 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.5226665 meson-1.3.2/test cases/frameworks/12 multiple gir/gir/0000755000175000017500000000000014562742416022642 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/12 multiple gir/gir/meson-subsample.c0000644000175000017500000000540213716006331026106 0ustar00jpakkanejpakkane#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); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/12 multiple gir/gir/meson-subsample.h0000644000175000017500000000060113716006331026107 0ustar00jpakkanejpakkane#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 */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1640535865.0 meson-1.3.2/test cases/frameworks/12 multiple gir/gir/meson.build0000644000175000017500000000123614162113471024773 0ustar00jpakkanejpakkanelibsources = ['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, install_dir_gir: false, ) message('TEST: ' + girsubproject.outdir()) test('gobject introspection/subproject/c', girexe) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/12 multiple gir/gir/prog.c0000644000175000017500000000034513716006331023744 0ustar00jpakkanejpakkane#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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345163.0 meson-1.3.2/test cases/frameworks/12 multiple gir/meson.build0000644000175000017500000000044714516530313024216 0ustar00jpakkanejpakkaneproject('multiple-gobject-introspection', 'c', meson_version: '>=0.50.0') 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') ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.5266664 meson-1.3.2/test cases/frameworks/12 multiple gir/mesongir/0000755000175000017500000000000014562742416023704 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/12 multiple gir/mesongir/meson-sample.c0000644000175000017500000000553413716006331026444 0ustar00jpakkanejpakkane#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); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/12 multiple gir/mesongir/meson-sample.h.in0000644000175000017500000000067013716006331027052 0ustar00jpakkanejpakkane#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 */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1640535865.0 meson-1.3.2/test cases/frameworks/12 multiple gir/mesongir/meson.build0000644000175000017500000000161514162113471026036 0ustar00jpakkanejpakkaneconf = 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, install_gir: false, ) 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, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1640535865.0 meson-1.3.2/test cases/frameworks/12 multiple gir/test.json0000644000175000017500000000137214162113471023723 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/lib/girepository-1.0/Meson-1.0.typelib"}, {"type": "file", "file": "usr/lib/girepository-1.0/MesonSub-1.0.typelib"}, {"type": "expr", "file": "usr/lib/?libgirlib.so"}, {"type": "file", "platform": "cygwin", "file": "usr/lib/libgirlib.dll.a"}, {"type": "expr", "file": "usr/lib/?libgirsubproject.so"}, {"type": "file", "platform": "cygwin", "file": "usr/lib/libgirsubproject.dll.a"} ], "skip_on_jobname": ["azure", "macos", "msys2"], "stdout": [ { "comment": "This will either match in the future-deprecated notice summary, or match the warning summary", "line": " * 0.61.0: {'\"gnome.generate_gir\" keyword argument \"install_dir_gir\" value \"False\"'}" } ] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.5266664 meson-1.3.2/test cases/frameworks/13 yelp/0000755000175000017500000000000014562742416020436 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.5266664 meson-1.3.2/test cases/frameworks/13 yelp/help/0000755000175000017500000000000014562742416021366 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.5346665 meson-1.3.2/test cases/frameworks/13 yelp/help/C/0000755000175000017500000000000014562742416021550 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/13 yelp/help/C/index.page0000644000175000017500000000025613716006331023505 0ustar00jpakkanejpakkane Hello! ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1641154352.0 meson-1.3.2/test cases/frameworks/13 yelp/help/C/index2.page0000644000175000017500000000025714164403460023572 0ustar00jpakkanejpakkane Hello! ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1641154352.0 meson-1.3.2/test cases/frameworks/13 yelp/help/C/index3.page0000644000175000017500000000025714164403460023573 0ustar00jpakkanejpakkane Hello! ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.5346665 meson-1.3.2/test cases/frameworks/13 yelp/help/C/media/0000755000175000017500000000000014562742416022627 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/13 yelp/help/C/media/test.txt0000644000175000017500000000000613716006331024330 0ustar00jpakkanejpakkanehello ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/13 yelp/help/LINGUAS0000644000175000017500000000000613716006331022374 0ustar00jpakkanejpakkanede es ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.5346665 meson-1.3.2/test cases/frameworks/13 yelp/help/de/0000755000175000017500000000000014562742416021756 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/13 yelp/help/de/de.po0000644000175000017500000000045613716006331022700 0ustar00jpakkanejpakkanemsgid "" 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!" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.5346665 meson-1.3.2/test cases/frameworks/13 yelp/help/es/0000755000175000017500000000000014562742416021775 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/13 yelp/help/es/es.po0000644000175000017500000000045713716006331022737 0ustar00jpakkanejpakkanemsgid "" 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!" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.5346665 meson-1.3.2/test cases/frameworks/13 yelp/help/es/media/0000755000175000017500000000000014562742416023054 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1597508825.0 meson-1.3.2/test cases/frameworks/13 yelp/help/es/media/test.txt0000644000175000017500000000000613716006331024555 0ustar00jpakkanejpakkaneHola. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1641154352.0 meson-1.3.2/test cases/frameworks/13 yelp/help/meson.build0000644000175000017500000000062314164403460023520 0ustar00jpakkanejpakkanegnome = import('gnome') gnome.yelp('meson', sources: 'index.page', media: 'media/test.txt', symlink_media: false, languages: ['de', 'es'], ) gnome.yelp('meson-symlink', sources: 'index2.page', media: 'media/test.txt', symlink_media: true, languages: ['de', 'es'], ) gnome.yelp('meson-linguas', sources: 'index3.page', media: 'media/test.txt', symlink_media: false, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698345162.0 meson-1.3.2/test cases/frameworks/13 yelp/meson.build0000644000175000017500000000024414516530312022565 0ustar00jpakkanejpakkaneproject('yelp', 'c') itstool = find_program('itstool', required: false) if not itstool.found() error('MESON_SKIP_TEST itstool not found.') endif subdir('help') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1641154352.0 meson-1.3.2/test cases/frameworks/13 yelp/test.json0000644000175000017500000000264014164403460022301 0ustar00jpakkanejpakkane{ "installed": [ {"type": "file", "file": "usr/share/help/C/meson/index.page"}, {"type": "file", "file": "usr/share/help/C/meson/media/test.txt"}, {"type": "file", "file": "usr/share/help/es/meson/index.page"}, {"type": "file", "file": "usr/share/help/es/meson/media/test.txt"}, {"type": "file", "file": "usr/share/help/de/meson/index.page"}, {"type": "file", "file": "usr/share/help/de/meson/media/test.txt"}, {"type": "file", "file": "usr/share/help/C/meson-symlink/index2.page"}, {"type": "file", "file": "usr/share/help/C/meson-symlink/media/test.txt"}, {"type": "file", "file": "usr/share/help/es/meson-symlink/index2.page"}, {"type": "file", "file": "usr/share/help/es/meson-symlink/media/test.txt"}, {"type": "file", "file": "usr/share/help/de/meson-symlink/index2.page"}, {"type": "file", "file": "usr/share/help/de/meson-symlink/media/test.txt"}, {"type": "file", "file": "usr/share/help/C/meson-linguas/index3.page"}, {"type": "file", "file": "usr/share/help/C/meson-linguas/media/test.txt"}, {"type": "file", "file": "usr/share/help/es/meson-linguas/index3.page"}, {"type": "file", "file": "usr/share/help/es/meson-linguas/media/test.txt"}, {"type": "file", "file": "usr/share/help/de/meson-linguas/index3.page"}, {"type": "file", "file": "usr/share/help/de/meson-linguas/media/test.txt"} ], "skip_on_jobname": ["azure", "cygwin", "macos", "msys2"] } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.5346665 meson-1.3.2/test cases/frameworks/14 doxygen/0000755000175000017500000000000014562742416021143 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707853069.5346665 meson-1.3.2/test cases/frameworks/14 doxygen/doc/0000755000175000017500000000000014562742416021710 5ustar00jpakkanejpakkane././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1684855202.0 meson-1.3.2/test cases/frameworks/14 doxygen/doc/Doxyfile.in0000644000175000017500000032215014433154642024021 0ustar00jpakkanejpakkane# 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 = "@TOP_BUILDDIR@/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 # , /