aboutsummaryrefslogtreecommitdiff
BranchCommit messageAuthorAge
0.35.1Update version number for release.Jussi Pakkanen9 years
0.41Update all versions to 0.41.2Nirbheek Chauhan8 years
0.42Updated version number for 0.42.1 release.Jussi Pakkanen8 years
0.42-msiMake all functionality invokable via the main Meson binary,Jussi Pakkanen8 years
0.44Bump version to 0.44.1 for releaseNirbheek Chauhan7 years
0.45Fix appveyor failures: do not use PowerShell since it triggers NativeCommandE...Aleksey Filippov7 years
0.46Update versions to 0.46.1 for stable releaseNirbheek Chauhan7 years
0.47Test + fix for not-found dependency fallback version comparisonNirbheek Chauhan7 years
0.48Update version number for release.Jussi Pakkanen7 years
0.49Bump version to 0.49.2 for releaseNirbheek Chauhan7 years
0.50Update version numbers for release.Jussi Pakkanen6 years
0.51Bump versions to 0.51.2 for releaseNirbheek Chauhan6 years
0.52Update version numbers for 0.52.1 stable releaseNirbheek Chauhan6 years
0.53azure ci: Test x86 Visual Studio builds againNirbheek Chauhan5 years
0.54Bump versions to 0.54.3 for releaseNirbheek Chauhan5 years
0.55Bump versions to 0.55.3 for releaseNirbheek Chauhan5 years
0.56Bump to 0.56.2 for releaseNirbheek Chauhan5 years
0.57Bump to 0.57.2 for releaseNirbheek Chauhan4 years
0.58Bump versions to 0.58.1 for stable releaseNirbheek Chauhan4 years
0.59Bump versions to 0.59.1 for releaseNirbheek Chauhan4 years
0.60Revert use of thin archives in 0.60 branch.Olexa Bilaniuk4 years
0.61Bump versions to 0.61.3 for releaseNirbheek Chauhan3 years
0.62Bump versions to 0.62.1 for releaseNirbheek Chauhan3 years
0.63Bump versions to 0.63.2 for releaseNirbheek Chauhan3 years
0.63.0-ifortCI: install ifort on WindowsEli Schwartz3 years
0.64Bump versions to 0.64.1 for releaseNirbheek Chauhan3 years
0.pypy-testpypy debugEli Schwartz3 years
0.pypy-test-2python module: windows dll name for pypy needs special casingMatti Picus3 years
0.trymedebugEli Schwartz2 years
1.0set default install_tag of python.install_sources() to "python-runtime"Peter Urban3 years
1.0000000000000000000000001check CI issuesEli Schwartz2 years
1.1Bump versions for 1.1.1 releaseNirbheek Chauhan2 years
1.2Bump versions to 1.2.1 for releaseNirbheek Chauhan2 years
1.87654321unittests: fix test_scripts_loaded_modules matching exactly our own modulesCharles Brunet2 years
1.trymeazure pipelines: force python2 to be installedEli Schwartz2 years
58rc1Bump version number for rc1.Jussi Pakkanen4 years
add-configuration-configure_FileUpdate configure_file.yamlDylan Baker4 years
appleldFix Xcode 15 beta linker detection. Closes #11958.Jussi Pakkanen2 years
asmfixDo not test aarch64 as the assembly has not been written.Jussi Pakkanen5 years
biggenAdd support for opaque build targets. Closes #10627.Jussi Pakkanen3 years
builddirupgradeCan upgrade build directory from an old version.Jussi Pakkanen7 years
buildtyperemainsKeep buildtype the same even if user changes debug and/or optimization.Jussi Pakkanen5 years
capitalizationCapitalize "Meson" consistently as it is a proper name. [skip ci]Jussi Pakkanen5 years
cfortfixFix combining C and Fortran. Closes #8377.Jussi Pakkanen4 years
checknetworkdSkip wrapdb test if there is no connectivity.Jussi Pakkanen3 years
cigreenDocument new rules for green CI.Jussi Pakkanen4 years
clangclrustDisable Rust + clangcl.Jussi Pakkanen4 years
clangformatcheckDo not accidentally format files when only checking if they are formatted.Jussi Pakkanen4 years
clangsanitizeFix Clang windows linker detection.Jussi Pakkanen6 years
cleandeadDelete old outputs that are no longer in the Ninja file.Jussi Pakkanen4 years
cleanstrayPurge persistent Ninja state when doing a full reconfigure.Jussi Pakkanen2 years
corporationsAdd page listing Meson usage in proprietary projects.Jussi Pakkanen3 years
cpp23Add c++23 to the list of C++ standards.Jussi Pakkanen2 years
cppmodulesGenerate dependency scanning hooks in the Ninja file.Jussi Pakkanen5 years
cppnorthAdd CppNorth talk.Jussi Pakkanen2 years
crossargfixStore global and project arguments separately for cross and native compilation.Jussi Pakkanen7 years
crossenvvarProperly error out when cross file is missing a compiler.Jussi Pakkanen3 years
cudacustomAdd custom entyr to cuda buildtype dict. Closes #8336.Jussi Pakkanen4 years
cudafix0572Strip host-compiler -std flag from NVCC line.Olexa Bilaniuk4 years
cudamemDisable asan memory leak checks on a Cuda test.Jussi Pakkanen4 years
cygwindisableagainDisable broken asm test on Cygwin as nobody knows how to fix it.Jussi Pakkanen4 years
cygwindisabletestDisable failing Cygwin GIR test.Jussi Pakkanen4 years
darwin_archmacos: detect old OS/cpu 64-bit CPU in 32-bit MacOS kernelMichael Hirsch, Ph.D6 years
dcbAdd detection code for powerpc64le.Jussi Pakkanen2 years
debcrossfixesAdd CMake to cross file.Jussi Pakkanen3 years
debianfixRemove installation scheme tweaking hack.Jussi Pakkanen3 years
debpy310String "local" bits from system paths.Jussi Pakkanen3 years
delghwtDelete ghwt.py as it is no longer needed or even works.Jussi Pakkanen4 years
deterministichashMake environment objects hash deterministically.Jussi Pakkanen4 years
dimpdirUse include_directories for D impdirs.Jussi Pakkanen7 years
dirc2One more dircondensation for rc1.Jussi Pakkanen3 years
dircondenseCondense test directory names in preparation for rc1.Jussi Pakkanen5 years
dircondense2Condense test directory names again.Jussi Pakkanen5 years
dircondense64Condense test directory names.Jussi Pakkanen3 years
disable32rustwinDisable vs2017 + 32bit Rust combo as it is broken.Jussi Pakkanen4 years
docbuildGenerated docs if hotdoc is installed.Jussi Pakkanen8 years
docdelghwtRemove docs for ghwt that got deleted ages ago.Jussi Pakkanen4 years
docimagelinksFix image link names.Jussi Pakkanen4 years
docrewrapRewrap long text lines in docs. [skip ci]Jussi Pakkanen5 years
dolphinRenamed test dir.Jussi Pakkanen8 years
dotincludeAdd option to disable implicit include directories. Closes #2139.Jussi Pakkanen8 years
dverfixFix D module version declaration.Jussi Pakkanen2 years
eli/ci-shellCI: cygwin coverage uploader needs to run in bash tooEli Schwartz2 years
eli/submit/doc-no-pr-publishAdd kernel and userland properties to machine objects.Jussi Pakkanen2 years
emptysubdirGuard against empty string in subdir().Jussi Pakkanen4 years
endmessageAdd end_message to print status messages on successfull exit.Jussi Pakkanen7 years
env2crossAdd new env2cross command.Jussi Pakkanen3 years
env2mfileAdd new env2mfile command.Jussi Pakkanen3 years
env2mfilefixFix writing single strings in env2mfile.Jussi Pakkanen3 years
envvarfixupSplit environment variable and command line cflagsDylan Baker4 years
es/0.61-plus-cythonBump versions to 0.61.4 for releaseNirbheek Chauhan3 years
eschwartz/python-lib-install-dirtests: python module should install files correctlyEli Schwartz4 years
exewrapfixFix exe wrapper detection for run targets.Jussi Pakkanen4 years
failcheckFix validation regexes to handle rc version numbers.Jussi Pakkanen2 years
fatalhotdocEnable fatal warnings in HotDoc when building website.Jussi Pakkanen4 years
fedoraSplit generator @BASENAME@ at the first extension.Elliott Sales de Andrade9 years
fgetcfixMake generator exe more resilient.Jussi Pakkanen2 years
filecleanupDelete leftover files from some tests.Jussi Pakkanen4 years
fix7611Make MSVC accept gnu11 as a language standard version. Closes: #7611.Jussi Pakkanen5 years
fix7920Do not store config parser object in Wrap object. Closes: #7920.Jussi Pakkanen5 years
fix7975The version kwarg must be a string. Closes #7975.Jussi Pakkanen5 years
fixciFix mypy CI.Jussi Pakkanen3 years
fixlintFix pylint.Jussi Pakkanen2 years
fixmacciDisable D test on macOS as it fails mysteriously.Jussi Pakkanen4 years
fixplainwinReplace Unix shell commands with scripts.Jussi Pakkanen4 years
flexfixPass a test file to flex test.Jussi Pakkanen4 years
flexunityForce unity builds off in Flex test.Jussi Pakkanen4 years
flobadded cuda test caseBeau Johnston7 years
fortrancaseFix Fortran dep scanner for upper case file extensions. Closes #8395.Jussi Pakkanen4 years
fortranmodscanExtend the C++ module scanner to handle Fortran, too.Jussi Pakkanen5 years
fromlongmsgStrip out garbage debug text.Jussi Pakkanen2 years
gccmodulesAdd some scaffolding needed for C++ modules in GCC.Jussi Pakkanen3 years
gencustomGenerators can depend on custom targets as well as build targets.Jussi Pakkanen5 years
gentargetAdd just enough backend to make the simple case work.Jussi Pakkanen5 years
gh-pagesMade this a redirect.Jussi Pakkanen10 years
gnuobjcAdd gnuXX stds to Objective C.Jussi Pakkanen4 years
ignorebuilddirAdd VCS ignore files to build dir on creation. Closes #6509.Jussi Pakkanen5 years
ignoreencodingerrorsIgnore encoding errors when scanning. Closes #10571.Jussi Pakkanen3 years
immufixMark even empty confs used appropriately.Jussi Pakkanen7 years
implicitcustomDo not add custom target dir automatically when implicit false. Closes #8562.Jussi Pakkanen4 years
includeviolationWarn when grabbing internals of subprojects with include_directories.Jussi Pakkanen4 years
installdirAllow for missing install_dir in install_data()Peter Hutterer7 years
installdocDescribe array values in install_dir. [skip ci]Jussi Pakkanen6 years
intrcmdUse a temp file to invoke the introspection command.Jussi Pakkanen3 years
ioscrossUpdate iphone cross building.Jussi Pakkanen4 years
javacrossAlways generate Java rule, it is platform agnostic.Jussi Pakkanen4 years
joinelseMerge if and else tests to a single project.Jussi Pakkanen4 years
jslibsAdd support for finding Javascript source libraries with Emscripten.Jussi Pakkanen4 years
keepbackendPrevent changing backend during reconfigure.Jussi Pakkanen2 years
killhfsRemove HFS workaround as everyone should use APFS by now.Jussi Pakkanen4 years
killpy3Convert all test from the python3 module to python.Jussi Pakkanen3 years
lang-enumMerge remote-tracking branch 'upstream/master' into lang-enumJohn Ericson5 years
limitparLimit parallelism to hopefully work on machines with 160 cores.Jussi Pakkanen3 years
linkmsgImprove linker detection failure error message.Jussi Pakkanen4 years
macfixesHandle macOS filesystem sometimes setting lower digits to zero.Jussi Pakkanen4 years
macfixes2Fix building framework test.Jussi Pakkanen4 years
macfixes3Allow gettext test to skip on macOS.Jussi Pakkanen4 years
macinstallUpdate macOS installation instructions.Jussi Pakkanen4 years
macinstallerAdd a script to create macOS installer packages.Jussi Pakkanen4 years
macpkgcleanRemove temp files that the macOS installer builder leaves hanging.Jussi Pakkanen4 years
masterAdjust kernel detection to support Solaris 5.10 or earlierCorrodedCoder22 months
mensinda_temp_fixMerge branch 'refactorFix' into tmp_mergerDaniel Mensinger4 years
mingwdisableDisable asm test on Windows because it is blocking all CI.Jussi Pakkanen8 years
modulestricterOnly do module scanning if C++ version is latest.Jussi Pakkanen5 years
msifixRequire Windows 10 or newer for the MSI package. [skip ci]Jussi Pakkanen4 years
msifixpy39Delete extra data dirs that cause problems for WiX.Jussi Pakkanen4 years
msipkgfixOnly exclude _bootlocale with Python >= 3.10. Closes #9548.Jussi Pakkanen4 years
mtesttempmtest: do not process zero byte reads in read_decode()Hemmo Nieminen3 years
ninjabumpBump Ninja requirement to 1.8.Jussi Pakkanen5 years
ninjalinkAdd option to limit maximum number of concurrent link processes.Jussi Pakkanen8 years
ninjarestatRefresh Ninja cache files on regeneration.Jussi Pakkanen4 years
ninjarevertRemove workaround now that we have a new Ninja.Jussi Pakkanen4 years
ninjaverUse currently detected Ninja version as the minimum required.Jussi Pakkanen5 years
ninjaverdownFix version requirement on Ninja feature.Jussi Pakkanen4 years
nirbheek-vacation-nolife-typo-fixesFix typos in release notes for 0.60.0Nirbheek Chauhan4 years
nirbheek/deprecate-get-option-buildtypeDeprecate get_option('buildtype'), use optimization/debug insteadNirbheek Chauhan5 years
nirbheek/fix-giscannergnome: Always pass absolute -L paths to g-ir-scannerNirbheek Chauhan4 years
nirbheek/fix-x86-vs2017-cici: Use 32-bit Rust and Python on vs2017 x86Nirbheek Chauhan4 years
nirbheek/gnome-mkenums-rspfilegnome.mkenums: Use rspfiles when possibleNirbheek Chauhan6 years
nirbheek/more-buildtype-changesWarn when detecting debug with get_option('buildtype')Nirbheek Chauhan5 years
nirbheek/un-disable-rust-clang-clrust targets: lld-link is the same as link for static libsNirbheek Chauhan4 years
nirbheek/un-disable-rust-vs2017Revert "Disable vs2017 + 32bit Rust combo as it is broken."Nirbheek Chauhan4 years
nirbheek/valac-clang-int-conversiontest cases/vala: Fix clang error during int to pointer coercionNirbheek Chauhan3 years
no_buildNo need to reserve build_ because we use build. instead.Jussi Pakkanen6 years
noechoDo not use 'echo' as it is not available on plain cmd.exeJussi Pakkanen3 years
nopipeRemove -pipe from default list of args. Closes #8508.Jussi Pakkanen4 years
objversionsMake objective C use C standard version. Closes #5495.Jussi Pakkanen4 years
onemoreOne more unixy fix.Jussi Pakkanen4 years
ongoingxcodeXcode: can generate object files with generators.Jussi Pakkanen4 years
openmpitimeoutIncrease OpenMPI timeout to see if it fixes macOS CI test hangs.Jussi Pakkanen4 years
optionlookupUse toplevel key when sp-specific one does not exist.Jussi Pakkanen4 years
optiontreePut subproject options in their own submenus.Jussi Pakkanen9 years
overridesAdd general override functionality. Closes #3001.Jussi Pakkanen4 years
pipdocUpdate instructions on installing with Pip. Closes #9034.Jussi Pakkanen4 years
pkgfixAutodetect installer path location.Jussi Pakkanen2 years
ppcfixImport cpu detection fix from Debian.Jussi Pakkanen2 years
pr8895-oldfix: adapt option-contructior called by buildin-option, added missing argumen...Martin Friedrich4 years
prelinkAdd prelinking support for static libraries.Jussi Pakkanen5 years
progrefactorUse find_program also in add_*_script for consistency.Jussi Pakkanen4 years
providedocAdd doc on how to add the [provide] entry to wrapdb entries. [skip ci]Jussi Pakkanen5 years
py310msiFix MSI creation with Python 3.10.Jussi Pakkanen4 years
pydisttestAdd regression test for Python dist.Jussi Pakkanen3 years
pylogfixValidate that introspection command exited cleanly.Jussi Pakkanen3 years
pym3fixFix purelib and platlib validation in Python3 module.Jussi Pakkanen3 years
pyrefixReplace freezing regex with plain text operations.Jussi Pakkanen3 years
pythonbumpBump minimum supported Python version to 3.6. Closes #6297.Jussi Pakkanen5 years
rcdircondenseCondense test directories for rc1.Jussi Pakkanen2 years
regrfixNon-working fix and test. Closes #8361.Jussi Pakkanen4 years
remove-parse_cmd_line_optionsRemove uneeded `parse_cmd_line_options`John Ericson5 years
removednumbersDo not run tests that use integers in versions with compiler that do not supp...Jussi Pakkanen2 years
rename61rc1Condense test directory numbers for rc1.Jussi Pakkanen4 years
renamesubdirsCondense test directory names for release.Jussi Pakkanen2 years
renumberCondense test directory numbers.Jussi Pakkanen3 years
renumberingFix test case numbers.Jussi Pakkanen3 years
revert-10041-wayland-pkgconfigRevert "wayland: Also lookup scanner in pkgconfig"Eli Schwartz3 years
revert-10757-llvm-configRevert "Add LLVM_CONFIG support"Dylan Baker3 years
revert5323Revert "Merge pull request #5323 from scivision/pgiflang"Jussi Pakkanen6 years
revertoverrideAdd tests for std usage. Closes #5097.Jussi Pakkanen6 years
revertsRevert "interpreter: Fix holder_map not being updated when subproject fails"Jussi Pakkanen4 years
revertthinltoRevert "Add thinlto support. Closes #7493."Jussi Pakkanen5 years
reviewtoolDocument how to run the wrap valídator. [skip ci]Jussi Pakkanen4 years
runsubdirFix run_targets running scripts from different subdirs.Jussi Pakkanen4 years
scanbuildtempdirDo not delete workdir in case scan-build fails.Jussi Pakkanen4 years
sccacheAdd sccache support.Jussi Pakkanen4 years
sdldocAdd tutorial for building an SDL app from scratch.Jussi Pakkanen4 years
sharedwithrustAdd test to build a mixed C/Rust shared library.Jussi Pakkanen4 years
simdixFix alignment with MSVC.Jussi Pakkanen7 years
simplestartAdd simple start page for beginners. [skip ci]Jussi Pakkanen5 years
stricternamesBe more strict about target names with slashes.Jussi Pakkanen4 years
subdirrefacRefactor subdir visitation to track files instead of dirs.Jussi Pakkanen4 years
swiftxcodeAdd swift executable support in Xcode.Jussi Pakkanen4 years
symlinkinreleaseOnly run symlink test from git checkout.Jussi Pakkanen6 years
syspropsAdd kernel and userland properties to machine objects.Jussi Pakkanen2 years
targetbatchCan introspect the whole project in a single batch.Jussi Pakkanen7 years
testcommandAdded documentation.Jussi Pakkanen7 years
testsilencingFix cases where text leaks to stdout in unit tests.Jussi Pakkanen5 years
thinltoAdd thinlto support. Closes #7493.Jussi Pakkanen5 years
timeoutfixHandle freezing tests. Fixes #10752.Jussi Pakkanen3 years
tingping/test-gir-programtests: Test generating gir from programPatrick Griffis9 years
tingping/test-profileAdd profile kwarg to test()Patrick Griffis8 years
tingping/xdg-moduleCreate new xdg modulePatrick Griffis9 years
trigger-ciimage-builderCI: coerce a new image builder run outside the scheduleEli Schwartz2 years
typofixFix typo that breaks g++ cross detection on Debian.Jussi Pakkanen3 years
unittestargSet unittest backend with an argument rather than an envvar.Jussi Pakkanen4 years
useargsintestsUse option args in find_library.Jussi Pakkanen7 years
verfixFix last mention of Python 3.5. [skip ci]Jussi Pakkanen5 years
versionfileRenamed test directory.Jussi Pakkanen6 years
versionfromfileCan read project version from a file.Jussi Pakkanen5 years
vs22Use VS 2022 release version for packaging.Jussi Pakkanen4 years
vs_pch_fixAdd regression test for pch link_whole bug.Jussi Pakkanen3 years
vsasanAdd address sanitizer support for Visual Studio.Jussi Pakkanen4 years
vsenvSet up VS environment automatically when run.Jussi Pakkanen4 years
vsenvfixAlso skip VS activation if gcc is found.Jussi Pakkanen4 years
vsmodfixFix VS C++ module support.Jussi Pakkanen4 years
vsmodtestQ&D experiment to scan and build C++ modules with VS.Jussi Pakkanen6 years
vsmodverUpdate VS module version check.Jussi Pakkanen4 years
wasmthreadcountFix WASM thread count option. Closes #7921.Jussi Pakkanen5 years
wip/default-directoriesExpose a way for distributors to override default directoriesPatrick Griffis8 years
wip/ignatenko/gtesteradd GTest testIgor Gnatenko10 years
wip/tingping/xdg-auto-post-installWIPPatrick Griffis8 years
wip/xclaesse/pr-10714docs: Fix many build_target based issuesDylan Baker2 years
wip/xclaesse/pr-12097backend: Stop converting all "\" to "/" in commandXavier Claessens2 years
wix4Upgrade MSI builder from WiX3 to WiX 4.Jussi Pakkanen2 years
wrapcaseHandle uppercase dependency names in wraps.Jussi Pakkanen5 years
wrapdocsAdded some wrap review docs. [skip ci]Jussi Pakkanen4 years
xclaesse/pr11561-origpkg-config: Allow system program if pkg_config_libdir is setXavier Claessens2 years
xcode1234Xcode: do not link shared modules against executables.Jussi Pakkanen4 years
xcode200Xcode: some more skips.Jussi Pakkanen4 years
xcodecleanXcode: fix project cleaning.Jussi Pakkanen4 years
xcodeeeeeeXcode: one more whole-archive skip.Jussi Pakkanen4 years
xcodeevenmoreFix Xcode targets in subdirs.Jussi Pakkanen4 years
xcodefFix object extraction in the Xcode backend.Jussi Pakkanen4 years
xcodefixFix typos in Xcode backend.Jussi Pakkanen3 years
xcodeforeverWrite include directory names with the correct amount of quoting.Jussi Pakkanen4 years
xcodegalleyXcode: one more skip.Jussi Pakkanen4 years
xcodegodotFix duplicated frameworks in the Xcode backend.Jussi Pakkanen4 years
xcodehalfwayXcode: regenerato project file when build conf changes.Jussi Pakkanen4 years
xcodelibsFix shared libs and using one source in multiple targets.Jussi Pakkanen4 years
xcodeminorHandle same Framework multiple times in Xcode.Jussi Pakkanen3 years
xcodeobjcXcode: make Swift projects work.Jussi Pakkanen4 years
xcodepartnXcode: Fix source generation.Jussi Pakkanen4 years
xcodepoopXcode: handle CustomTargetIndexes.Jussi Pakkanen4 years
xcodeprojecttreeRemove unnecessary hierarchical layer.Jussi Pakkanen4 years
xcoderefactorFix LGTM issues.Jussi Pakkanen4 years
xcodesloggingXcode: fix file objects in various places.Jussi Pakkanen4 years
xcodetunkkiXcode: fix generators that take custom targets as inputs.Jussi Pakkanen4 years
xcodewarnoptLGTM fix.Jussi Pakkanen4 years
xcodexUse correct key for file id lookup.Jussi Pakkanen4 years
xcodezXcode: this is what happens when you do not treat command lines as arrays.Jussi Pakkanen4 years
xcode🥃Xcode: make the test target depend on build_all target.Jussi Pakkanen4 years
 
TagDownloadAuthorAge
1.2.1meson-1.2.1.zip  meson-1.2.1.tar.gz  meson-1.2.1.tar.bz2  Jussi Pakkanen2 years
1.2.0meson-1.2.0.zip  meson-1.2.0.tar.gz  meson-1.2.0.tar.bz2  Jussi Pakkanen2 years
1.2.0rc3meson-1.2.0rc3.zip  meson-1.2.0rc3.tar.gz  meson-1.2.0rc3.tar.bz2  Jussi Pakkanen2 years
1.2.0rc2meson-1.2.0rc2.zip  meson-1.2.0rc2.tar.gz  meson-1.2.0rc2.tar.bz2  Jussi Pakkanen2 years
1.2.0rc1meson-1.2.0rc1.zip  meson-1.2.0rc1.tar.gz  meson-1.2.0rc1.tar.bz2  Jussi Pakkanen2 years
1.1.1meson-1.1.1.zip  meson-1.1.1.tar.gz  meson-1.1.1.tar.bz2  Jussi Pakkanen2 years
1.0.2meson-1.0.2.zip  meson-1.0.2.tar.gz  meson-1.0.2.tar.bz2  Jussi Pakkanen2 years
1.1.0meson-1.1.0.zip  meson-1.1.0.tar.gz  meson-1.1.0.tar.bz2  Jussi Pakkanen2 years
1.1.0rc2meson-1.1.0rc2.zip  meson-1.1.0rc2.tar.gz  meson-1.1.0rc2.tar.bz2  Jussi Pakkanen2 years
1.1.0rc1meson-1.1.0rc1.zip  meson-1.1.0rc1.tar.gz  meson-1.1.0rc1.tar.bz2  Jussi Pakkanen2 years
1.0.1meson-1.0.1.zip  meson-1.0.1.tar.gz  meson-1.0.1.tar.bz2  Jussi Pakkanen2 years
1.0.0meson-1.0.0.zip  meson-1.0.0.tar.gz  meson-1.0.0.tar.bz2  Jussi Pakkanen3 years
1.0.0rc2meson-1.0.0rc2.zip  meson-1.0.0rc2.tar.gz  meson-1.0.0rc2.tar.bz2  Jussi Pakkanen3 years
1.0.0rc1meson-1.0.0rc1.zip  meson-1.0.0rc1.tar.gz  meson-1.0.0rc1.tar.bz2  Jussi Pakkanen3 years
0.64.1meson-0.64.1.zip  meson-0.64.1.tar.gz  meson-0.64.1.tar.bz2  Jussi Pakkanen3 years
0.64.0meson-0.64.0.zip  meson-0.64.0.tar.gz  meson-0.64.0.tar.bz2  Jussi Pakkanen3 years
0.64.0rc2meson-0.64.0rc2.zip  meson-0.64.0rc2.tar.gz  meson-0.64.0rc2.tar.bz2  Jussi Pakkanen3 years
0.64.0rc1meson-0.64.0rc1.zip  meson-0.64.0rc1.tar.gz  meson-0.64.0rc1.tar.bz2  Jussi Pakkanen3 years
0.63.3meson-0.63.3.zip  meson-0.63.3.tar.gz  meson-0.63.3.tar.bz2  Jussi Pakkanen3 years
0.63.2meson-0.63.2.zip  meson-0.63.2.tar.gz  meson-0.63.2.tar.bz2  Jussi Pakkanen3 years
0.63.1meson-0.63.1.zip  meson-0.63.1.tar.gz  meson-0.63.1.tar.bz2  Jussi Pakkanen3 years
0.63.0meson-0.63.0.zip  meson-0.63.0.tar.gz  meson-0.63.0.tar.bz2  Jussi Pakkanen3 years
0.63.0.rc2meson-0.63.0.rc2.zip  meson-0.63.0.rc2.tar.gz  meson-0.63.0.rc2.tar.bz2  Jussi Pakkanen3 years
0.63.0rc1meson-0.63.0rc1.zip  meson-0.63.0rc1.tar.gz  meson-0.63.0rc1.tar.bz2  Jussi Pakkanen3 years
0.61.5meson-0.61.5.zip  meson-0.61.5.tar.gz  meson-0.61.5.tar.bz2  Jussi Pakkanen3 years
0.62.2meson-0.62.2.zip  meson-0.62.2.tar.gz  meson-0.62.2.tar.bz2  Jussi Pakkanen3 years
0.62.1meson-0.62.1.zip  meson-0.62.1.tar.gz  meson-0.62.1.tar.bz2  Jussi Pakkanen3 years
0.61.4meson-0.61.4.zip  meson-0.61.4.tar.gz  meson-0.61.4.tar.bz2  Jussi Pakkanen3 years
0.62.0meson-0.62.0.zip  meson-0.62.0.tar.gz  meson-0.62.0.tar.bz2  Jussi Pakkanen3 years
0.62.0rc2meson-0.62.0rc2.zip  meson-0.62.0rc2.tar.gz  meson-0.62.0rc2.tar.bz2  Jussi Pakkanen3 years
0.61.3meson-0.61.3.zip  meson-0.61.3.tar.gz  meson-0.61.3.tar.bz2  Jussi Pakkanen3 years
0.62.0rc1meson-0.62.0rc1.zip  meson-0.62.0rc1.tar.gz  meson-0.62.0rc1.tar.bz2  Jussi Pakkanen3 years
0.61.2meson-0.61.2.zip  meson-0.61.2.tar.gz  meson-0.61.2.tar.bz2  Jussi Pakkanen3 years
0.61.1meson-0.61.1.zip  meson-0.61.1.tar.gz  meson-0.61.1.tar.bz2  Jussi Pakkanen4 years
0.61.0meson-0.61.0.zip  meson-0.61.0.tar.gz  meson-0.61.0.tar.bz2  Jussi Pakkanen4 years
0.61.0rc1meson-0.61.0rc1.zip  meson-0.61.0rc1.tar.gz  meson-0.61.0rc1.tar.bz2  Jussi Pakkanen4 years
0.60.3meson-0.60.3.zip  meson-0.60.3.tar.gz  meson-0.60.3.tar.bz2  Jussi Pakkanen4 years
0.60.2meson-0.60.2.zip  meson-0.60.2.tar.gz  meson-0.60.2.tar.bz2  Jussi Pakkanen4 years
0.60.1meson-0.60.1.zip  meson-0.60.1.tar.gz  meson-0.60.1.tar.bz2  Jussi Pakkanen4 years
0.59.4meson-0.59.4.zip  meson-0.59.4.tar.gz  meson-0.59.4.tar.bz2  Jussi Pakkanen4 years
0.60.0meson-0.60.0.zip  meson-0.60.0.tar.gz  meson-0.60.0.tar.bz2  Jussi Pakkanen4 years
0.59.3meson-0.59.3.zip  meson-0.59.3.tar.gz  meson-0.59.3.tar.bz2  Jussi Pakkanen4 years
0.60.0rc2meson-0.60.0rc2.zip  meson-0.60.0rc2.tar.gz  meson-0.60.0rc2.tar.bz2  Jussi Pakkanen4 years
0.60.0.rc1meson-0.60.0.rc1.zip  meson-0.60.0.rc1.tar.gz  meson-0.60.0.rc1.tar.bz2  Jussi Pakkanen4 years
0.59.2meson-0.59.2.zip  meson-0.59.2.tar.gz  meson-0.59.2.tar.bz2  Jussi Pakkanen4 years
0.59.1meson-0.59.1.zip  meson-0.59.1.tar.gz  meson-0.59.1.tar.bz2  Jussi Pakkanen4 years
0.58.2meson-0.58.2.zip  meson-0.58.2.tar.gz  meson-0.58.2.tar.bz2  Jussi Pakkanen4 years
0.59.0meson-0.59.0.zip  meson-0.59.0.tar.gz  meson-0.59.0.tar.bz2  Jussi Pakkanen4 years
0.59.0.rc2meson-0.59.0.rc2.zip  meson-0.59.0.rc2.tar.gz  meson-0.59.0.rc2.tar.bz2  Jussi Pakkanen4 years
0.59.0.rc1meson-0.59.0.rc1.zip  meson-0.59.0.rc1.tar.gz  meson-0.59.0.rc1.tar.bz2  Jussi Pakkanen4 years
0.58.1meson-0.58.1.zip  meson-0.58.1.tar.gz  meson-0.58.1.tar.bz2  Jussi Pakkanen4 years
0.58.0meson-0.58.0.zip  meson-0.58.0.tar.gz  meson-0.58.0.tar.bz2  Jussi Pakkanen4 years
0.58.0.rc1meson-0.58.0.rc1.zip  meson-0.58.0.rc1.tar.gz  meson-0.58.0.rc1.tar.bz2  Jussi Pakkanen4 years
0.57.2meson-0.57.2.zip  meson-0.57.2.tar.gz  meson-0.57.2.tar.bz2  Jussi Pakkanen4 years
0.57.1meson-0.57.1.zip  meson-0.57.1.tar.gz  meson-0.57.1.tar.bz2  Jussi Pakkanen4 years
0.57.0meson-0.57.0.zip  meson-0.57.0.tar.gz  meson-0.57.0.tar.bz2  Jussi Pakkanen4 years
0.57.0.rc1meson-0.57.0.rc1.zip  meson-0.57.0.rc1.tar.gz  meson-0.57.0.rc1.tar.bz2  Jussi Pakkanen4 years
0.56.2meson-0.56.2.zip  meson-0.56.2.tar.gz  meson-0.56.2.tar.bz2  Jussi Pakkanen5 years
0.56.1meson-0.56.1.zip  meson-0.56.1.tar.gz  meson-0.56.1.tar.bz2  Jussi Pakkanen5 years
0.56.0meson-0.56.0.zip  meson-0.56.0.tar.gz  meson-0.56.0.tar.bz2  Jussi Pakkanen5 years
0.56.0.rc2meson-0.56.0.rc2.zip  meson-0.56.0.rc2.tar.gz  meson-0.56.0.rc2.tar.bz2  Jussi Pakkanen5 years
0.56.0.rc1meson-0.56.0.rc1.zip  meson-0.56.0.rc1.tar.gz  meson-0.56.0.rc1.tar.bz2  Jussi Pakkanen5 years
0.55.3meson-0.55.3.zip  meson-0.55.3.tar.gz  meson-0.55.3.tar.bz2  Jussi Pakkanen5 years
0.55.2meson-0.55.2.zip  meson-0.55.2.tar.gz  meson-0.55.2.tar.bz2  Jussi Pakkanen5 years
0.55.1meson-0.55.1.zip  meson-0.55.1.tar.gz  meson-0.55.1.tar.bz2  Jussi Pakkanen5 years
0.55.0meson-0.55.0.zip  meson-0.55.0.tar.gz  meson-0.55.0.tar.bz2  Jussi Pakkanen5 years
0.55.0.rc2meson-0.55.0.rc2.zip  meson-0.55.0.rc2.tar.gz  meson-0.55.0.rc2.tar.bz2  Jussi Pakkanen5 years
0.55.0.rc1meson-0.55.0.rc1.zip  meson-0.55.0.rc1.tar.gz  meson-0.55.0.rc1.tar.bz2  Jussi Pakkanen5 years
0.54.3meson-0.54.3.zip  meson-0.54.3.tar.gz  meson-0.54.3.tar.bz2  Jussi Pakkanen5 years
0.54.2meson-0.54.2.zip  meson-0.54.2.tar.gz  meson-0.54.2.tar.bz2  Jussi Pakkanen5 years
0.54.1meson-0.54.1.zip  meson-0.54.1.tar.gz  meson-0.54.1.tar.bz2  Jussi Pakkanen5 years
0.54.0meson-0.54.0.zip  meson-0.54.0.tar.gz  meson-0.54.0.tar.bz2  Jussi Pakkanen5 years
0.54.0.rc1meson-0.54.0.rc1.zip  meson-0.54.0.rc1.tar.gz  meson-0.54.0.rc1.tar.bz2  Jussi Pakkanen5 years
0.53.2meson-0.53.2.zip  meson-0.53.2.tar.gz  meson-0.53.2.tar.bz2  Jussi Pakkanen5 years
0.53.1meson-0.53.1.zip  meson-0.53.1.tar.gz  meson-0.53.1.tar.bz2  Jussi Pakkanen6 years
0.53.0meson-0.53.0.zip  meson-0.53.0.tar.gz  meson-0.53.0.tar.bz2  Jussi Pakkanen6 years
0.52.1meson-0.52.1.zip  meson-0.52.1.tar.gz  meson-0.52.1.tar.bz2  Jussi Pakkanen6 years
0.52.0meson-0.52.0.zip  meson-0.52.0.tar.gz  meson-0.52.0.tar.bz2  Jussi Pakkanen6 years
0.51.2meson-0.51.2.zip  meson-0.51.2.tar.gz  meson-0.51.2.tar.bz2  Jussi Pakkanen6 years
0.51.1meson-0.51.1.zip  meson-0.51.1.tar.gz  meson-0.51.1.tar.bz2  Jussi Pakkanen6 years
0.51.0meson-0.51.0.zip  meson-0.51.0.tar.gz  meson-0.51.0.tar.bz2  Jussi Pakkanen6 years
0.50.1meson-0.50.1.zip  meson-0.50.1.tar.gz  meson-0.50.1.tar.bz2  Jussi Pakkanen6 years
0.50.0meson-0.50.0.zip  meson-0.50.0.tar.gz  meson-0.50.0.tar.bz2  Jussi Pakkanen6 years
0.49.2meson-0.49.2.zip  meson-0.49.2.tar.gz  meson-0.49.2.tar.bz2  Jussi Pakkanen7 years
0.49.1meson-0.49.1.zip  meson-0.49.1.tar.gz  meson-0.49.1.tar.bz2  Jussi Pakkanen7 years
0.49.0meson-0.49.0.zip  meson-0.49.0.tar.gz  meson-0.49.0.tar.bz2  Jussi Pakkanen7 years
0.48.2meson-0.48.2.zip  meson-0.48.2.tar.gz  meson-0.48.2.tar.bz2  Jussi Pakkanen7 years
0.48.1meson-0.48.1.zip  meson-0.48.1.tar.gz  meson-0.48.1.tar.bz2  Jussi Pakkanen7 years
0.48.0meson-0.48.0.zip  meson-0.48.0.tar.gz  meson-0.48.0.tar.bz2  Jussi Pakkanen7 years
0.47.2meson-0.47.2.zip  meson-0.47.2.tar.gz  meson-0.47.2.tar.bz2  Jussi Pakkanen7 years
0.47.1meson-0.47.1.zip  meson-0.47.1.tar.gz  meson-0.47.1.tar.bz2  Jussi Pakkanen7 years
0.47.0meson-0.47.0.zip  meson-0.47.0.tar.gz  meson-0.47.0.tar.bz2  Jussi Pakkanen7 years
0.46.1meson-0.46.1.zip  meson-0.46.1.tar.gz  meson-0.46.1.tar.bz2  Jussi Pakkanen7 years
0.46.0meson-0.46.0.zip  meson-0.46.0.tar.gz  meson-0.46.0.tar.bz2  Jussi Pakkanen7 years
0.45.1meson-0.45.1.zip  meson-0.45.1.tar.gz  meson-0.45.1.tar.bz2  Jussi Pakkanen7 years
0.45.0meson-0.45.0.zip  meson-0.45.0.tar.gz  meson-0.45.0.tar.bz2  Jussi Pakkanen7 years
0.44.1meson-0.44.1.zip  meson-0.44.1.tar.gz  meson-0.44.1.tar.bz2  Jussi Pakkanen7 years
0.44.0meson-0.44.0.zip  meson-0.44.0.tar.gz  meson-0.44.0.tar.bz2  Jussi Pakkanen8 years
0.43.0meson-0.43.0.zip  meson-0.43.0.tar.gz  meson-0.43.0.tar.bz2  Jussi Pakkanen8 years
0.42.1meson-0.42.1.zip  meson-0.42.1.tar.gz  meson-0.42.1.tar.bz2  Jussi Pakkanen8 years
0.42.0meson-0.42.0.zip  meson-0.42.0.tar.gz  meson-0.42.0.tar.bz2  Jussi Pakkanen8 years
0.41.2meson-0.41.2.zip  meson-0.41.2.tar.gz  meson-0.41.2.tar.bz2  Nirbheek Chauhan8 years
0.41.1meson-0.41.1.zip  meson-0.41.1.tar.gz  meson-0.41.1.tar.bz2  Jussi Pakkanen8 years
0.41.0meson-0.41.0.zip  meson-0.41.0.tar.gz  meson-0.41.0.tar.bz2  Jussi Pakkanen8 years
0.40.1meson-0.40.1.zip  meson-0.40.1.tar.gz  meson-0.40.1.tar.bz2  Jussi Pakkanen8 years
0.40.0meson-0.40.0.zip  meson-0.40.0.tar.gz  meson-0.40.0.tar.bz2  Jussi Pakkanen8 years
0.39.1meson-0.39.1.zip  meson-0.39.1.tar.gz  meson-0.39.1.tar.bz2  Jussi Pakkanen8 years
0.39.0meson-0.39.0.zip  meson-0.39.0.tar.gz  meson-0.39.0.tar.bz2  Jussi Pakkanen8 years
0.38.1meson-0.38.1.zip  meson-0.38.1.tar.gz  meson-0.38.1.tar.bz2  Jussi Pakkanen9 years
0.38.0meson-0.38.0.zip  meson-0.38.0.tar.gz  meson-0.38.0.tar.bz2  Jussi Pakkanen9 years
0.37.1meson-0.37.1.zip  meson-0.37.1.tar.gz  meson-0.37.1.tar.bz2  Jussi Pakkanen9 years
0.37.0meson-0.37.0.zip  meson-0.37.0.tar.gz  meson-0.37.0.tar.bz2  Jussi Pakkanen9 years
0.36.0meson-0.36.0.zip  meson-0.36.0.tar.gz  meson-0.36.0.tar.bz2  Jussi Pakkanen9 years
0.35.1meson-0.35.1.zip  meson-0.35.1.tar.gz  meson-0.35.1.tar.bz2  Jussi Pakkanen9 years
0.35.0meson-0.35.0.zip  meson-0.35.0.tar.gz  meson-0.35.0.tar.bz2  Jussi Pakkanen9 years
0.34.0meson-0.34.0.zip  meson-0.34.0.tar.gz  meson-0.34.0.tar.bz2  Jussi Pakkanen9 years
0.33.0meson-0.33.0.zip  meson-0.33.0.tar.gz  meson-0.33.0.tar.bz2  Jussi Pakkanen9 years
0.32.0meson-0.32.0.zip  meson-0.32.0.tar.gz  meson-0.32.0.tar.bz2  Jussi Pakkanen9 years
0.31.0meson-0.31.0.zip  meson-0.31.0.tar.gz  meson-0.31.0.tar.bz2  Jussi Pakkanen9 years
0.30.0meson-0.30.0.zip  meson-0.30.0.tar.gz  meson-0.30.0.tar.bz2  Jussi Pakkanen9 years
0.29.0meson-0.29.0.zip  meson-0.29.0.tar.gz  meson-0.29.0.tar.bz2  Jussi Pakkanen10 years
0.28.0meson-0.28.0.zip  meson-0.28.0.tar.gz  meson-0.28.0.tar.bz2  Jussi Pakkanen10 years
0.27.0meson-0.27.0.zip  meson-0.27.0.tar.gz  meson-0.27.0.tar.bz2  Jussi Pakkanen10 years
0.26.0meson-0.26.0.zip  meson-0.26.0.tar.gz  meson-0.26.0.tar.bz2  Jussi Pakkanen10 years
0.25.0meson-0.25.0.zip  meson-0.25.0.tar.gz  meson-0.25.0.tar.bz2  Jussi Pakkanen10 years
0.24.0meson-0.24.0.zip  meson-0.24.0.tar.gz  meson-0.24.0.tar.bz2  Jussi Pakkanen10 years
0.23.0meson-0.23.0.zip  meson-0.23.0.tar.gz  meson-0.23.0.tar.bz2  Jussi Pakkanen10 years
0.22.0meson-0.22.0.zip  meson-0.22.0.tar.gz  meson-0.22.0.tar.bz2  Jussi Pakkanen11 years
0.21.0meson-0.21.0.zip  meson-0.21.0.tar.gz  meson-0.21.0.tar.bz2  Jussi Pakkanen11 years
0.20.0meson-0.20.0.zip  meson-0.20.0.tar.gz  meson-0.20.0.tar.bz2  Jussi Pakkanen11 years
0.19.0meson-0.19.0.zip  meson-0.19.0.tar.gz  meson-0.19.0.tar.bz2  Jussi Pakkanen11 years
0.18.0meson-0.18.0.zip  meson-0.18.0.tar.gz  meson-0.18.0.tar.bz2  Jussi Pakkanen11 years
0.17.0meson-0.17.0.zip  meson-0.17.0.tar.gz  meson-0.17.0.tar.bz2  Jussi Pakkanen11 years
0.16.0meson-0.16.0.zip  meson-0.16.0.tar.gz  meson-0.16.0.tar.bz2  Jussi Pakkanen11 years
0.15.0meson-0.15.0.zip  meson-0.15.0.tar.gz  meson-0.15.0.tar.bz2  Jussi Pakkanen11 years
0.14.0meson-0.14.0.zip  meson-0.14.0.tar.gz  meson-0.14.0.tar.bz2  Jussi Pakkanen11 years
0.13.0meson-0.13.0.zip  meson-0.13.0.tar.gz  meson-0.13.0.tar.bz2  Jussi Pakkanen11 years
0.12.0meson-0.12.0.zip  meson-0.12.0.tar.gz  meson-0.12.0.tar.bz2  Jussi Pakkanen12 years
0.11.0meson-0.11.0.zip  meson-0.11.0.tar.gz  meson-0.11.0.tar.bz2  Jussi Pakkanen12 years
0.10.0meson-0.10.0.zip  meson-0.10.0.tar.gz  meson-0.10.0.tar.bz2  Jussi Pakkanen12 years
0.9.0meson-0.9.0.zip  meson-0.9.0.tar.gz  meson-0.9.0.tar.bz2  Jussi Pakkanen12 years
0.8.0meson-0.8.0.zip  meson-0.8.0.tar.gz  meson-0.8.0.tar.bz2  Jussi Pakkanen12 years
0.7.0meson-0.7.0.zip  meson-0.7.0.tar.gz  meson-0.7.0.tar.bz2  Jussi Pakkanen12 years
0.6.0meson-0.6.0.zip  meson-0.6.0.tar.gz  meson-0.6.0.tar.bz2  Jussi Pakkanen12 years
0.5.0meson-0.5.0.zip  meson-0.5.0.tar.gz  meson-0.5.0.tar.bz2  Jussi Pakkanen12 years
0.4.1meson-0.4.1.zip  meson-0.4.1.tar.gz  meson-0.4.1.tar.bz2  Jussi Pakkanen12 years
0.4.0meson-0.4.0.zip  meson-0.4.0.tar.gz  meson-0.4.0.tar.bz2  Jussi Pakkanen12 years
0.2.0meson-0.2.0.zip  meson-0.2.0.tar.gz  meson-0.2.0.tar.bz2  Jussi Pakkanen12 years
0.1.0meson-0.1.0.zip  meson-0.1.0.tar.gz  meson-0.1.0.tar.bz2  Jussi Pakkanen12 years
kwa">if not is_ci() and subprocess.call(['pkg-config', '--exists', depname]) != 0: raise unittest.SkipTest('pkg-config dependency {} not found.'.format(depname)) return func(*args, **kwargs) return wrapped return wrapper def skip_if_not_language(lang): def wrapper(func): @functools.wraps(func) def wrapped(*args, **kwargs): try: env = get_fake_env('', '', '') f = getattr(env, 'detect_{}_compiler'.format(lang)) if lang in ['cs', 'vala', 'java', 'swift']: f() else: f(False) except EnvironmentException: raise unittest.SkipTest('No {} compiler found.'.format(lang)) return func(*args, **kwargs) return wrapped return wrapper def skip_if_env_value(value): def wrapper(func): @functools.wraps(func) def wrapped(*args, **kwargs): if value in os.environ: raise unittest.SkipTest( 'Environment variable "{}" set, skipping.'.format(value)) return func(*args, **kwargs) return wrapped return wrapper def skip_if_not_base_option(feature): """Skip tests if The compiler does not support a given base option. for example, ICC doesn't currently support b_sanitize. """ def actual(f): @functools.wraps(f) def wrapped(*args, **kwargs): env = get_fake_env('', '', '') cc = env.detect_c_compiler(False) if feature not in cc.base_options: raise unittest.SkipTest( '{} not available with {}'.format(feature, cc.id)) return f(*args, **kwargs) return wrapped return actual class PatchModule: ''' Fancy monkey-patching! Whee! Can't use mock.patch because it only patches in the local namespace. ''' def __init__(self, func, name, impl): self.func = func assert(isinstance(name, str)) self.func_name = name self.old_impl = None self.new_impl = impl def __enter__(self): self.old_impl = self.func exec('{} = self.new_impl'.format(self.func_name)) def __exit__(self, *args): exec('{} = self.old_impl'.format(self.func_name)) class InternalTests(unittest.TestCase): def test_version_number(self): searchfunc = mesonbuild.environment.search_version self.assertEqual(searchfunc('foobar 1.2.3'), '1.2.3') self.assertEqual(searchfunc('1.2.3'), '1.2.3') self.assertEqual(searchfunc('foobar 2016.10.28 1.2.3'), '1.2.3') self.assertEqual(searchfunc('2016.10.28 1.2.3'), '1.2.3') self.assertEqual(searchfunc('foobar 2016.10.128'), 'unknown version') self.assertEqual(searchfunc('2016.10.128'), 'unknown version') def test_mode_symbolic_to_bits(self): modefunc = mesonbuild.mesonlib.FileMode.perms_s_to_bits self.assertEqual(modefunc('---------'), 0) self.assertEqual(modefunc('r--------'), stat.S_IRUSR) self.assertEqual(modefunc('---r-----'), stat.S_IRGRP) self.assertEqual(modefunc('------r--'), stat.S_IROTH) self.assertEqual(modefunc('-w-------'), stat.S_IWUSR) self.assertEqual(modefunc('----w----'), stat.S_IWGRP) self.assertEqual(modefunc('-------w-'), stat.S_IWOTH) self.assertEqual(modefunc('--x------'), stat.S_IXUSR) self.assertEqual(modefunc('-----x---'), stat.S_IXGRP) self.assertEqual(modefunc('--------x'), stat.S_IXOTH) self.assertEqual(modefunc('--S------'), stat.S_ISUID) self.assertEqual(modefunc('-----S---'), stat.S_ISGID) self.assertEqual(modefunc('--------T'), stat.S_ISVTX) self.assertEqual(modefunc('--s------'), stat.S_ISUID | stat.S_IXUSR) self.assertEqual(modefunc('-----s---'), stat.S_ISGID | stat.S_IXGRP) self.assertEqual(modefunc('--------t'), stat.S_ISVTX | stat.S_IXOTH) self.assertEqual(modefunc('rwx------'), stat.S_IRWXU) self.assertEqual(modefunc('---rwx---'), stat.S_IRWXG) self.assertEqual(modefunc('------rwx'), stat.S_IRWXO) # We could keep listing combinations exhaustively but that seems # tedious and pointless. Just test a few more. self.assertEqual(modefunc('rwxr-xr-x'), stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH) self.assertEqual(modefunc('rw-r--r--'), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH) self.assertEqual(modefunc('rwsr-x---'), stat.S_IRWXU | stat.S_ISUID | stat.S_IRGRP | stat.S_IXGRP) def test_compiler_args_class(self): cargsfunc = mesonbuild.compilers.CompilerArgs cc = mesonbuild.compilers.CCompiler([], 'fake', False) # Test that bad initialization fails self.assertRaises(TypeError, cargsfunc, []) self.assertRaises(TypeError, cargsfunc, [], []) self.assertRaises(TypeError, cargsfunc, cc, [], []) # Test that empty initialization works a = cargsfunc(cc) self.assertEqual(a, []) # Test that list initialization works a = cargsfunc(['-I.', '-I..'], cc) self.assertEqual(a, ['-I.', '-I..']) # Test that there is no de-dup on initialization self.assertEqual(cargsfunc(['-I.', '-I.'], cc), ['-I.', '-I.']) ## Test that appending works a.append('-I..') self.assertEqual(a, ['-I..', '-I.']) a.append('-O3') self.assertEqual(a, ['-I..', '-I.', '-O3']) ## Test that in-place addition works a += ['-O2', '-O2'] self.assertEqual(a, ['-I..', '-I.', '-O3', '-O2', '-O2']) # Test that removal works a.remove('-O2') self.assertEqual(a, ['-I..', '-I.', '-O3', '-O2']) # Test that de-dup happens on addition a += ['-Ifoo', '-Ifoo'] self.assertEqual(a, ['-Ifoo', '-I..', '-I.', '-O3', '-O2']) # .extend() is just +=, so we don't test it ## Test that addition works # Test that adding a list with just one old arg works and yields the same array a = a + ['-Ifoo'] self.assertEqual(a, ['-Ifoo', '-I..', '-I.', '-O3', '-O2']) # Test that adding a list with one arg new and one old works a = a + ['-Ifoo', '-Ibaz'] self.assertEqual(a, ['-Ifoo', '-Ibaz', '-I..', '-I.', '-O3', '-O2']) # Test that adding args that must be prepended and appended works a = a + ['-Ibar', '-Wall'] self.assertEqual(a, ['-Ibar', '-Ifoo', '-Ibaz', '-I..', '-I.', '-O3', '-O2', '-Wall']) ## Test that reflected addition works # Test that adding to a list with just one old arg works and yields the same array a = ['-Ifoo'] + a self.assertEqual(a, ['-Ibar', '-Ifoo', '-Ibaz', '-I..', '-I.', '-O3', '-O2', '-Wall']) # Test that adding to a list with just one new arg that is not pre-pended works a = ['-Werror'] + a self.assertEqual(a, ['-Ibar', '-Ifoo', '-Ibaz', '-I..', '-I.', '-Werror', '-O3', '-O2', '-Wall']) # Test that adding to a list with two new args preserves the order a = ['-Ldir', '-Lbah'] + a self.assertEqual(a, ['-Ibar', '-Ifoo', '-Ibaz', '-I..', '-I.', '-Ldir', '-Lbah', '-Werror', '-O3', '-O2', '-Wall']) # Test that adding to a list with old args does nothing a = ['-Ibar', '-Ibaz', '-Ifoo'] + a self.assertEqual(a, ['-Ibar', '-Ifoo', '-Ibaz', '-I..', '-I.', '-Ldir', '-Lbah', '-Werror', '-O3', '-O2', '-Wall']) ## Test that adding libraries works l = cargsfunc(cc, ['-Lfoodir', '-lfoo']) self.assertEqual(l, ['-Lfoodir', '-lfoo']) # Adding a library and a libpath appends both correctly l += ['-Lbardir', '-lbar'] self.assertEqual(l, ['-Lbardir', '-Lfoodir', '-lfoo', '-lbar']) # Adding the same library again does nothing l += ['-lbar'] self.assertEqual(l, ['-Lbardir', '-Lfoodir', '-lfoo', '-lbar']) ## Test that 'direct' append and extend works l = cargsfunc(cc, ['-Lfoodir', '-lfoo']) self.assertEqual(l, ['-Lfoodir', '-lfoo']) # Direct-adding a library and a libpath appends both correctly l.extend_direct(['-Lbardir', '-lbar']) self.assertEqual(l, ['-Lfoodir', '-lfoo', '-Lbardir', '-lbar']) # Direct-adding the same library again still adds it l.append_direct('-lbar') self.assertEqual(l, ['-Lfoodir', '-lfoo', '-Lbardir', '-lbar', '-lbar']) # Direct-adding with absolute path deduplicates l.append_direct('/libbaz.a') self.assertEqual(l, ['-Lfoodir', '-lfoo', '-Lbardir', '-lbar', '-lbar', '/libbaz.a']) # Adding libbaz again does nothing l.append_direct('/libbaz.a') self.assertEqual(l, ['-Lfoodir', '-lfoo', '-Lbardir', '-lbar', '-lbar', '/libbaz.a']) def test_compiler_args_class_gnuld(self): cargsfunc = mesonbuild.compilers.CompilerArgs ## Test --start/end-group gcc = mesonbuild.compilers.GnuCCompiler([], 'fake', mesonbuild.compilers.CompilerType.GCC_STANDARD, False) ## Test that 'direct' append and extend works l = cargsfunc(gcc, ['-Lfoodir', '-lfoo']) self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Wl,--end-group']) # Direct-adding a library and a libpath appends both correctly l.extend_direct(['-Lbardir', '-lbar']) self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Lbardir', '-lbar', '-Wl,--end-group']) # Direct-adding the same library again still adds it l.append_direct('-lbar') self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Lbardir', '-lbar', '-lbar', '-Wl,--end-group']) # Direct-adding with absolute path deduplicates l.append_direct('/libbaz.a') self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Lbardir', '-lbar', '-lbar', '/libbaz.a', '-Wl,--end-group']) # Adding libbaz again does nothing l.append_direct('/libbaz.a') self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Lbardir', '-lbar', '-lbar', '/libbaz.a', '-Wl,--end-group']) # Adding a non-library argument doesn't include it in the group l += ['-Lfoo', '-Wl,--export-dynamic'] self.assertEqual(l.to_native(copy=True), ['-Lfoo', '-Lfoodir', '-Wl,--start-group', '-lfoo', '-Lbardir', '-lbar', '-lbar', '/libbaz.a', '-Wl,--end-group', '-Wl,--export-dynamic']) # -Wl,-lfoo is detected as a library and gets added to the group l.append('-Wl,-ldl') self.assertEqual(l.to_native(copy=True), ['-Lfoo', '-Lfoodir', '-Wl,--start-group', '-lfoo', '-Lbardir', '-lbar', '-lbar', '/libbaz.a', '-Wl,--export-dynamic', '-Wl,-ldl', '-Wl,--end-group']) def test_string_templates_substitution(self): dictfunc = mesonbuild.mesonlib.get_filenames_templates_dict substfunc = mesonbuild.mesonlib.substitute_values ME = mesonbuild.mesonlib.MesonException # Identity self.assertEqual(dictfunc([], []), {}) # One input, no outputs inputs = ['bar/foo.c.in'] outputs = [] ret = dictfunc(inputs, outputs) d = {'@INPUT@': inputs, '@INPUT0@': inputs[0], '@PLAINNAME@': 'foo.c.in', '@BASENAME@': 'foo.c'} # Check dictionary self.assertEqual(ret, d) # Check substitutions cmd = ['some', 'ordinary', 'strings'] self.assertEqual(substfunc(cmd, d), cmd) cmd = ['@INPUT@.out', 'ordinary', 'strings'] self.assertEqual(substfunc(cmd, d), [inputs[0] + '.out'] + cmd[1:]) cmd = ['@INPUT0@.out', '@PLAINNAME@.ok', 'strings'] self.assertEqual(substfunc(cmd, d), [inputs[0] + '.out'] + [d['@PLAINNAME@'] + '.ok'] + cmd[2:]) cmd = ['@INPUT@', '@BASENAME@.hah', 'strings'] self.assertEqual(substfunc(cmd, d), inputs + [d['@BASENAME@'] + '.hah'] + cmd[2:]) cmd = ['@OUTPUT@'] self.assertRaises(ME, substfunc, cmd, d) # One input, one output inputs = ['bar/foo.c.in'] outputs = ['out.c'] ret = dictfunc(inputs, outputs) d = {'@INPUT@': inputs, '@INPUT0@': inputs[0], '@PLAINNAME@': 'foo.c.in', '@BASENAME@': 'foo.c', '@OUTPUT@': outputs, '@OUTPUT0@': outputs[0], '@OUTDIR@': '.'} # Check dictionary self.assertEqual(ret, d) # Check substitutions cmd = ['some', 'ordinary', 'strings'] self.assertEqual(substfunc(cmd, d), cmd) cmd = ['@INPUT@.out', '@OUTPUT@', 'strings'] self.assertEqual(substfunc(cmd, d), [inputs[0] + '.out'] + outputs + cmd[2:]) cmd = ['@INPUT0@.out', '@PLAINNAME@.ok', '@OUTPUT0@'] self.assertEqual(substfunc(cmd, d), [inputs[0] + '.out', d['@PLAINNAME@'] + '.ok'] + outputs) cmd = ['@INPUT@', '@BASENAME@.hah', 'strings'] self.assertEqual(substfunc(cmd, d), inputs + [d['@BASENAME@'] + '.hah'] + cmd[2:]) # One input, one output with a subdir outputs = ['dir/out.c'] ret = dictfunc(inputs, outputs) d = {'@INPUT@': inputs, '@INPUT0@': inputs[0], '@PLAINNAME@': 'foo.c.in', '@BASENAME@': 'foo.c', '@OUTPUT@': outputs, '@OUTPUT0@': outputs[0], '@OUTDIR@': 'dir'} # Check dictionary self.assertEqual(ret, d) # Two inputs, no outputs inputs = ['bar/foo.c.in', 'baz/foo.c.in'] outputs = [] ret = dictfunc(inputs, outputs) d = {'@INPUT@': inputs, '@INPUT0@': inputs[0], '@INPUT1@': inputs[1]} # Check dictionary self.assertEqual(ret, d) # Check substitutions cmd = ['some', 'ordinary', 'strings'] self.assertEqual(substfunc(cmd, d), cmd) cmd = ['@INPUT@', 'ordinary', 'strings'] self.assertEqual(substfunc(cmd, d), inputs + cmd[1:]) cmd = ['@INPUT0@.out', 'ordinary', 'strings'] self.assertEqual(substfunc(cmd, d), [inputs[0] + '.out'] + cmd[1:]) cmd = ['@INPUT0@.out', '@INPUT1@.ok', 'strings'] self.assertEqual(substfunc(cmd, d), [inputs[0] + '.out', inputs[1] + '.ok'] + cmd[2:]) cmd = ['@INPUT0@', '@INPUT1@', 'strings'] self.assertEqual(substfunc(cmd, d), inputs + cmd[2:]) # Many inputs, can't use @INPUT@ like this cmd = ['@INPUT@.out', 'ordinary', 'strings'] self.assertRaises(ME, substfunc, cmd, d) # Not enough inputs cmd = ['@INPUT2@.out', 'ordinary', 'strings'] self.assertRaises(ME, substfunc, cmd, d) # Too many inputs cmd = ['@PLAINNAME@'] self.assertRaises(ME, substfunc, cmd, d) cmd = ['@BASENAME@'] self.assertRaises(ME, substfunc, cmd, d) # No outputs cmd = ['@OUTPUT@'] self.assertRaises(ME, substfunc, cmd, d) cmd = ['@OUTPUT0@'] self.assertRaises(ME, substfunc, cmd, d) cmd = ['@OUTDIR@'] self.assertRaises(ME, substfunc, cmd, d) # Two inputs, one output outputs = ['dir/out.c'] ret = dictfunc(inputs, outputs) d = {'@INPUT@': inputs, '@INPUT0@': inputs[0], '@INPUT1@': inputs[1], '@OUTPUT@': outputs, '@OUTPUT0@': outputs[0], '@OUTDIR@': 'dir'} # Check dictionary self.assertEqual(ret, d) # Check substitutions cmd = ['some', 'ordinary', 'strings'] self.assertEqual(substfunc(cmd, d), cmd) cmd = ['@OUTPUT@', 'ordinary', 'strings'] self.assertEqual(substfunc(cmd, d), outputs + cmd[1:]) cmd = ['@OUTPUT@.out', 'ordinary', 'strings'] self.assertEqual(substfunc(cmd, d), [outputs[0] + '.out'] + cmd[1:]) cmd = ['@OUTPUT0@.out', '@INPUT1@.ok', 'strings'] self.assertEqual(substfunc(cmd, d), [outputs[0] + '.out', inputs[1] + '.ok'] + cmd[2:]) # Many inputs, can't use @INPUT@ like this cmd = ['@INPUT@.out', 'ordinary', 'strings'] self.assertRaises(ME, substfunc, cmd, d) # Not enough inputs cmd = ['@INPUT2@.out', 'ordinary', 'strings'] self.assertRaises(ME, substfunc, cmd, d) # Not enough outputs cmd = ['@OUTPUT2@.out', 'ordinary', 'strings'] self.assertRaises(ME, substfunc, cmd, d) # Two inputs, two outputs outputs = ['dir/out.c', 'dir/out2.c'] ret = dictfunc(inputs, outputs) d = {'@INPUT@': inputs, '@INPUT0@': inputs[0], '@INPUT1@': inputs[1], '@OUTPUT@': outputs, '@OUTPUT0@': outputs[0], '@OUTPUT1@': outputs[1], '@OUTDIR@': 'dir'} # Check dictionary self.assertEqual(ret, d) # Check substitutions cmd = ['some', 'ordinary', 'strings'] self.assertEqual(substfunc(cmd, d), cmd) cmd = ['@OUTPUT@', 'ordinary', 'strings'] self.assertEqual(substfunc(cmd, d), outputs + cmd[1:]) cmd = ['@OUTPUT0@', '@OUTPUT1@', 'strings'] self.assertEqual(substfunc(cmd, d), outputs + cmd[2:]) cmd = ['@OUTPUT0@.out', '@INPUT1@.ok', '@OUTDIR@'] self.assertEqual(substfunc(cmd, d), [outputs[0] + '.out', inputs[1] + '.ok', 'dir']) # Many inputs, can't use @INPUT@ like this cmd = ['@INPUT@.out', 'ordinary', 'strings'] self.assertRaises(ME, substfunc, cmd, d) # Not enough inputs cmd = ['@INPUT2@.out', 'ordinary', 'strings'] self.assertRaises(ME, substfunc, cmd, d) # Not enough outputs cmd = ['@OUTPUT2@.out', 'ordinary', 'strings'] self.assertRaises(ME, substfunc, cmd, d) # Many outputs, can't use @OUTPUT@ like this cmd = ['@OUTPUT@.out', 'ordinary', 'strings'] self.assertRaises(ME, substfunc, cmd, d) def test_needs_exe_wrapper_override(self): config = ConfigParser() config['binaries'] = { 'c': '\'/usr/bin/gcc\'', } config['host_machine'] = { 'system': '\'linux\'', 'cpu_family': '\'arm\'', 'cpu': '\'armv7\'', 'endian': '\'little\'', } # Can not be used as context manager because we need to # open it a second time and this is not possible on # Windows. configfile = tempfile.NamedTemporaryFile(mode='w+', delete=False) configfilename = configfile.name config.write(configfile) configfile.flush() configfile.close() opts = get_fake_options('') opts.cross_file = configfilename env = get_fake_env('', '', '', opts) detected_value = env.need_exe_wrapper() os.unlink(configfilename) desired_value = not detected_value config['properties'] = { 'needs_exe_wrapper': 'true' if desired_value else 'false' } configfile = tempfile.NamedTemporaryFile(mode='w+', delete=False) configfilename = configfile.name config.write(configfile) configfile.close() opts = get_fake_options('') opts.cross_file = configfilename env = get_fake_env('', '', '', opts) forced_value = env.need_exe_wrapper() os.unlink(configfilename) self.assertEqual(forced_value, desired_value) def test_listify(self): listify = mesonbuild.mesonlib.listify # Test sanity self.assertEqual([1], listify(1)) self.assertEqual([], listify([])) self.assertEqual([1], listify([1])) # Test flattening self.assertEqual([1, 2, 3], listify([1, [2, 3]])) self.assertEqual([1, 2, 3], listify([1, [2, [3]]])) self.assertEqual([1, [2, [3]]], listify([1, [2, [3]]], flatten=False)) # Test flattening and unholdering holder1 = ObjectHolder(1) holder3 = ObjectHolder(3) self.assertEqual([holder1], listify(holder1)) self.assertEqual([holder1], listify([holder1])) self.assertEqual([holder1, 2], listify([holder1, 2])) self.assertEqual([holder1, 2, 3], listify([holder1, 2, [3]])) self.assertEqual([1], listify(holder1, unholder=True)) self.assertEqual([1], listify([holder1], unholder=True)) self.assertEqual([1, 2], listify([holder1, 2], unholder=True)) self.assertEqual([1, 2, 3], listify([holder1, 2, [holder3]], unholder=True)) # Unholding doesn't work recursively when not flattening self.assertEqual([1, [2], [holder3]], listify([holder1, [2], [holder3]], unholder=True, flatten=False)) def test_extract_as_list(self): extract = mesonbuild.mesonlib.extract_as_list # Test sanity kwargs = {'sources': [1, 2, 3]} self.assertEqual([1, 2, 3], extract(kwargs, 'sources')) self.assertEqual(kwargs, {'sources': [1, 2, 3]}) self.assertEqual([1, 2, 3], extract(kwargs, 'sources', pop=True)) self.assertEqual(kwargs, {}) # Test unholding holder3 = ObjectHolder(3) kwargs = {'sources': [1, 2, holder3]} self.assertEqual([1, 2, 3], extract(kwargs, 'sources', unholder=True)) self.assertEqual(kwargs, {'sources': [1, 2, holder3]}) self.assertEqual([1, 2, 3], extract(kwargs, 'sources', unholder=True, pop=True)) self.assertEqual(kwargs, {}) # Test listification kwargs = {'sources': [1, 2, 3], 'pch_sources': [4, 5, 6]} self.assertEqual([[1, 2, 3], [4, 5, 6]], extract(kwargs, 'sources', 'pch_sources')) def test_pkgconfig_module(self): class Mock: pass mock = Mock() mock.pcdep = Mock() mock.pcdep.name = "some_name" mock.version_reqs = [] # pkgconfig dependency as lib deps = mesonbuild.modules.pkgconfig.DependenciesHelper("thislib") deps.add_pub_libs([mock]) self.assertEqual(deps.format_reqs(deps.pub_reqs), "some_name") # pkgconfig dependency as requires deps = mesonbuild.modules.pkgconfig.DependenciesHelper("thislib") deps.add_pub_reqs([mock]) self.assertEqual(deps.format_reqs(deps.pub_reqs), "some_name") def _test_all_naming(self, cc, env, patterns, platform): shr = patterns[platform]['shared'] stc = patterns[platform]['static'] p = cc.get_library_naming(env, 'shared') self.assertEqual(p, shr) p = cc.get_library_naming(env, 'static') self.assertEqual(p, stc) p = cc.get_library_naming(env, 'static-shared') self.assertEqual(p, stc + shr) p = cc.get_library_naming(env, 'shared-static') self.assertEqual(p, shr + stc) p = cc.get_library_naming(env, 'default') self.assertEqual(p, shr + stc) # Test find library by mocking up openbsd if platform != 'openbsd': return with tempfile.TemporaryDirectory() as tmpdir: with open(os.path.join(tmpdir, 'libfoo.so.6.0'), 'w') as f: f.write('') with open(os.path.join(tmpdir, 'libfoo.so.5.0'), 'w') as f: f.write('') with open(os.path.join(tmpdir, 'libfoo.so.54.0'), 'w') as f: f.write('') with open(os.path.join(tmpdir, 'libfoo.so.66a.0b'), 'w') as f: f.write('') with open(os.path.join(tmpdir, 'libfoo.so.70.0.so.1'), 'w') as f: f.write('') found = cc.find_library_real('foo', env, [tmpdir], '', 'default') self.assertEqual(os.path.basename(found[0]), 'libfoo.so.54.0') def test_find_library_patterns(self): ''' Unit test for the library search patterns used by find_library() ''' unix_static = ('lib{}.a', '{}.a') msvc_static = ('lib{}.a', 'lib{}.lib', '{}.a', '{}.lib') # This is the priority list of pattern matching for library searching patterns = {'openbsd': {'shared': ('lib{}.so', '{}.so', 'lib{}.so.[0-9]*.[0-9]*'), 'static': unix_static}, 'linux': {'shared': ('lib{}.so', '{}.so'), 'static': unix_static}, 'darwin': {'shared': ('lib{}.dylib', 'lib{}.so', '{}.dylib', '{}.so'), 'static': unix_static}, 'cygwin': {'shared': ('cyg{}.dll', 'cyg{}.dll.a', 'lib{}.dll', 'lib{}.dll.a', '{}.dll', '{}.dll.a'), 'static': ('cyg{}.a',) + unix_static}, 'windows-msvc': {'shared': ('lib{}.lib', '{}.lib'), 'static': msvc_static}, 'windows-mingw': {'shared': ('lib{}.dll.a', 'lib{}.lib', 'lib{}.dll', '{}.dll.a', '{}.lib', '{}.dll'), 'static': msvc_static}} env = get_fake_env('', '', '') cc = env.detect_c_compiler(False) if is_osx(): self._test_all_naming(cc, env, patterns, 'darwin') elif is_cygwin(): self._test_all_naming(cc, env, patterns, 'cygwin') elif is_windows(): if cc.get_argument_syntax() == 'msvc': self._test_all_naming(cc, env, patterns, 'windows-msvc') else: self._test_all_naming(cc, env, patterns, 'windows-mingw') else: self._test_all_naming(cc, env, patterns, 'linux') # Mock OpenBSD since we don't have tests for it true = lambda x, y: True if not is_openbsd(): with PatchModule(mesonbuild.compilers.c.for_openbsd, 'mesonbuild.compilers.c.for_openbsd', true): self._test_all_naming(cc, env, patterns, 'openbsd') else: self._test_all_naming(cc, env, patterns, 'openbsd') with PatchModule(mesonbuild.compilers.c.for_darwin, 'mesonbuild.compilers.c.for_darwin', true): self._test_all_naming(cc, env, patterns, 'darwin') with PatchModule(mesonbuild.compilers.c.for_cygwin, 'mesonbuild.compilers.c.for_cygwin', true): self._test_all_naming(cc, env, patterns, 'cygwin') with PatchModule(mesonbuild.compilers.c.for_windows, 'mesonbuild.compilers.c.for_windows', true): self._test_all_naming(cc, env, patterns, 'windows-mingw') def test_pkgconfig_parse_libs(self): ''' Unit test for parsing of pkg-config output to search for libraries https://github.com/mesonbuild/meson/issues/3951 ''' with tempfile.TemporaryDirectory() as tmpdir: pkgbin = ExternalProgram('pkg-config', command=['pkg-config'], silent=True) env = get_fake_env('', '', '') compiler = env.detect_c_compiler(False) env.coredata.compilers = {'c': compiler} env.coredata.compiler_options['c_link_args'] = FakeCompilerOptions() p1 = Path(tmpdir) / '1' p2 = Path(tmpdir) / '2' p1.mkdir() p2.mkdir() # libfoo.a is in one prefix (p1 / 'libfoo.a').open('w').close() # libbar.a is in both prefixes (p1 / 'libbar.a').open('w').close() (p2 / 'libbar.a').open('w').close() # Ensure that we never statically link to these (p1 / 'libpthread.a').open('w').close() (p1 / 'libm.a').open('w').close() (p1 / 'libc.a').open('w').close() (p1 / 'libdl.a').open('w').close() (p1 / 'librt.a').open('w').close() def fake_call_pkgbin(self, args, env=None): if '--libs' not in args: return 0, '' if args[0] == 'foo': return 0, '-L{} -lfoo -L{} -lbar'.format(p2.as_posix(), p1.as_posix()) if args[0] == 'bar': return 0, '-L{} -lbar'.format(p2.as_posix()) if args[0] == 'internal': return 0, '-L{} -lpthread -lm -lc -lrt -ldl'.format(p1.as_posix()) old_call = PkgConfigDependency._call_pkgbin old_check = PkgConfigDependency.check_pkgconfig old_pkgbin = PkgConfigDependency.class_pkgbin PkgConfigDependency._call_pkgbin = fake_call_pkgbin PkgConfigDependency.check_pkgconfig = lambda x, _: pkgbin # Test begins kwargs = {'required': True, 'silent': True} foo_dep = PkgConfigDependency('foo', env, kwargs) self.assertEqual(foo_dep.get_link_args(), [(p1 / 'libfoo.a').as_posix(), (p2 / 'libbar.a').as_posix()]) bar_dep = PkgConfigDependency('bar', env, kwargs) self.assertEqual(bar_dep.get_link_args(), [(p2 / 'libbar.a').as_posix()]) internal_dep = PkgConfigDependency('internal', env, kwargs) if compiler.get_argument_syntax() == 'msvc': self.assertEqual(internal_dep.get_link_args(), []) else: link_args = internal_dep.get_link_args() for link_arg in link_args: for lib in ('pthread', 'm', 'c', 'dl', 'rt'): self.assertNotIn('lib{}.a'.format(lib), link_arg, msg=link_args) # Test ends PkgConfigDependency._call_pkgbin = old_call PkgConfigDependency.check_pkgconfig = old_check # Reset dependency class to ensure that in-process configure doesn't mess up PkgConfigDependency.pkgbin_cache = {} PkgConfigDependency.class_pkgbin = old_pkgbin def test_version_compare(self): comparefunc = mesonbuild.mesonlib.version_compare_many for (a, b, result) in [ ('0.99.beta19', '>= 0.99.beta14', True), ]: self.assertEqual(comparefunc(a, b)[0], result) for (a, b, result) in [ # examples from https://fedoraproject.org/wiki/Archive:Tools/RPM/VersionComparison ("1.0010", "1.9", 1), ("1.05", "1.5", 0), ("1.0", "1", 1), ("2.50", "2.5", 1), ("fc4", "fc.4", 0), ("FC5", "fc4", -1), ("2a", "2.0", -1), ("1.0", "1.fc4", 1), ("3.0.0_fc", "3.0.0.fc", 0), # from RPM tests ("1.0", "1.0", 0), ("1.0", "2.0", -1), ("2.0", "1.0", 1), ("2.0.1", "2.0.1", 0), ("2.0", "2.0.1", -1), ("2.0.1", "2.0", 1), ("2.0.1a", "2.0.1a", 0), ("2.0.1a", "2.0.1", 1), ("2.0.1", "2.0.1a", -1), ("5.5p1", "5.5p1", 0), ("5.5p1", "5.5p2", -1), ("5.5p2", "5.5p1", 1), ("5.5p10", "5.5p10", 0), ("5.5p1", "5.5p10", -1), ("5.5p10", "5.5p1", 1), ("10xyz", "10.1xyz", -1), ("10.1xyz", "10xyz", 1), ("xyz10", "xyz10", 0), ("xyz10", "xyz10.1", -1), ("xyz10.1", "xyz10", 1), ("xyz.4", "xyz.4", 0), ("xyz.4", "8", -1), ("8", "xyz.4", 1), ("xyz.4", "2", -1), ("2", "xyz.4", 1), ("5.5p2", "5.6p1", -1), ("5.6p1", "5.5p2", 1), ("5.6p1", "6.5p1", -1), ("6.5p1", "5.6p1", 1), ("6.0.rc1", "6.0", 1), ("6.0", "6.0.rc1", -1), ("10b2", "10a1", 1), ("10a2", "10b2", -1), ("1.0aa", "1.0aa", 0), ("1.0a", "1.0aa", -1), ("1.0aa", "1.0a", 1), ("10.0001", "10.0001", 0), ("10.0001", "10.1", 0), ("10.1", "10.0001", 0), ("10.0001", "10.0039", -1), ("10.0039", "10.0001", 1), ("4.999.9", "5.0", -1), ("5.0", "4.999.9", 1), ("20101121", "20101121", 0), ("20101121", "20101122", -1), ("20101122", "20101121", 1), ("2_0", "2_0", 0), ("2.0", "2_0", 0), ("2_0", "2.0", 0), ("a", "a", 0), ("a+", "a+", 0), ("a+", "a_", 0), ("a_", "a+", 0), ("+a", "+a", 0), ("+a", "_a", 0), ("_a", "+a", 0), ("+_", "+_", 0), ("_+", "+_", 0), ("_+", "_+", 0), ("+", "_", 0), ("_", "+", 0), # other tests ('0.99.beta19', '0.99.beta14', 1), ("1.0.0", "2.0.0", -1), (".0.0", "2.0.0", -1), ("alpha", "beta", -1), ("1.0", "1.0.0", -1), ("2.456", "2.1000", -1), ("2.1000", "3.111", -1), ("2.001", "2.1", 0), ("2.34", "2.34", 0), ("6.1.2", "6.3.8", -1), ("1.7.3.0", "2.0.0", -1), ("2.24.51", "2.25", -1), ("2.1.5+20120813+gitdcbe778", "2.1.5", 1), ("3.4.1", "3.4b1", 1), ("041206", "200090325", -1), ("0.6.2+git20130413", "0.6.2", 1), ("2.6.0+bzr6602", "2.6.0", 1), ("2.6.0", "2.6b2", 1), ("2.6.0+bzr6602", "2.6b2x", 1), ("0.6.7+20150214+git3a710f9", "0.6.7", 1), ("15.8b", "15.8.0.1", -1), ("1.2rc1", "1.2.0", -1), ]: ver_a = Version(a) ver_b = Version(b) self.assertEqual(ver_a.__cmp__(ver_b), result) self.assertEqual(ver_b.__cmp__(ver_a), -result) @unittest.skipIf(is_tarball(), 'Skipping because this is a tarball release') class DataTests(unittest.TestCase): def test_snippets(self): hashcounter = re.compile('^ *(#)+') snippet_dir = Path('docs/markdown/snippets') self.assertTrue(snippet_dir.is_dir()) for f in snippet_dir.glob('*'): self.assertTrue(f.is_file()) if f.parts[-1].endswith('~'): continue if f.suffix == '.md': in_code_block = False with f.open() as snippet: for line in snippet: if line.startswith(' '): continue if line.startswith('```'): in_code_block = not in_code_block if in_code_block: continue m = re.match(hashcounter, line) if m: self.assertEqual(len(m.group(0)), 2, 'All headings in snippets must have two hash symbols: ' + f.name) self.assertFalse(in_code_block, 'Unclosed code block.') else: if f.name != 'add_release_note_snippets_here': self.assertTrue(False, 'A file without .md suffix in snippets dir: ' + f.name) def test_compiler_options_documented(self): ''' Test that C and C++ compiler options and base options are documented in Builtin-Options.md. Only tests the default compiler for the current platform on the CI. ''' md = None with open('docs/markdown/Builtin-options.md') as f: md = f.read() self.assertIsNotNone(md) env = get_fake_env('', '', '') # FIXME: Support other compilers cc = env.detect_c_compiler(False) cpp = env.detect_cpp_compiler(False) for comp in (cc, cpp): for opt in comp.get_options().keys(): self.assertIn(opt, md) for opt in comp.base_options: self.assertIn(opt, md) self.assertNotIn('b_unknown', md) def test_cpu_families_documented(self): with open("docs/markdown/Reference-tables.md") as f: md = f.read() self.assertIsNotNone(md) sections = list(re.finditer(r"^## (.+)$", md, re.MULTILINE)) for s1, s2 in zip(sections[::2], sections[1::2]): if s1.group(1) == "CPU families": # Extract the content for this section content = md[s1.end():s2.start()] # Find the list entries arches = [m.group(1) for m in re.finditer(r"^\| (\w+) +\|", content, re.MULTILINE)] # Drop the header arches = set(arches[1:]) self.assertEqual(arches, set(mesonbuild.environment.known_cpu_families)) def test_markdown_files_in_sitemap(self): ''' Test that each markdown files in docs/markdown is referenced in sitemap.txt ''' with open("docs/sitemap.txt") as f: md = f.read() self.assertIsNotNone(md) toc = list(m.group(1) for m in re.finditer(r"^\s*(\w.*)$", md, re.MULTILINE)) markdownfiles = [f.name for f in Path("docs/markdown").iterdir() if f.is_file() and f.suffix == '.md'] exceptions = ['_Sidebar.md'] for f in markdownfiles: if f not in exceptions: self.assertIn(f, toc) def test_syntax_highlighting_files(self): ''' Ensure that syntax highlighting files were updated for new functions in the global namespace in build files. ''' env = get_fake_env('', '', '') interp = Interpreter(FakeBuild(env), mock=True) with open('data/syntax-highlighting/vim/syntax/meson.vim') as f: res = re.search(r'syn keyword mesonBuiltin(\s+\\\s\w+)+', f.read(), re.MULTILINE) defined = set([a.strip() for a in res.group().split('\\')][1:]) self.assertEqual(defined, set(chain(interp.funcs.keys(), interp.builtin.keys()))) class BasePlatformTests(unittest.TestCase): def setUp(self): super().setUp() src_root = os.path.dirname(__file__) src_root = os.path.join(os.getcwd(), src_root) self.src_root = src_root self.prefix = '/usr' self.libdir = 'lib' # Get the backend # FIXME: Extract this from argv? self.backend = getattr(Backend, os.environ.get('MESON_UNIT_TEST_BACKEND', 'ninja')) self.meson_args = ['--backend=' + self.backend.name] self.meson_cross_file = None self.meson_command = python_command + [get_meson_script()] self.setup_command = self.meson_command + self.meson_args self.mconf_command = self.meson_command + ['configure'] self.mintro_command = self.meson_command + ['introspect'] self.wrap_command = self.meson_command + ['wrap'] self.rewrite_command = self.meson_command + ['rewrite'] # Backend-specific build commands self.build_command, self.clean_command, self.test_command, self.install_command, \ self.uninstall_command = get_backend_commands(self.backend) # Test directories self.common_test_dir = os.path.join(src_root, 'test cases/common') self.vala_test_dir = os.path.join(src_root, 'test cases/vala') self.framework_test_dir = os.path.join(src_root, 'test cases/frameworks') self.unit_test_dir = os.path.join(src_root, 'test cases/unit') self.rewrite_test_dir = os.path.join(src_root, 'test cases/rewrite') # Misc stuff self.orig_env = os.environ.copy() if self.backend is Backend.ninja: self.no_rebuild_stdout = ['ninja: no work to do.', 'samu: nothing to do'] else: # VS doesn't have a stable output when no changes are done # XCode backend is untested with unit tests, help welcome! self.no_rebuild_stdout = ['UNKNOWN BACKEND {!r}'.format(self.backend.name)] self.builddirs = [] self.new_builddir() def change_builddir(self, newdir): self.builddir = newdir self.privatedir = os.path.join(self.builddir, 'meson-private') self.logdir = os.path.join(self.builddir, 'meson-logs') self.installdir = os.path.join(self.builddir, 'install') self.distdir = os.path.join(self.builddir, 'meson-dist') self.mtest_command = self.meson_command + ['test', '-C', self.builddir] self.builddirs.append(self.builddir) def new_builddir(self): # In case the directory is inside a symlinked directory, find the real # path otherwise we might not find the srcdir from inside the builddir. newdir = os.path.realpath(tempfile.mkdtemp()) self.change_builddir(newdir) def _print_meson_log(self): log = os.path.join(self.logdir, 'meson-log.txt') if not os.path.isfile(log): print("{!r} doesn't exist".format(log)) return with open(log, 'r', encoding='utf-8') as f: print(f.read()) def tearDown(self): for path in self.builddirs: try: windows_proof_rmtree(path) except FileNotFoundError: pass os.environ.clear() os.environ.update(self.orig_env) super().tearDown() def _run(self, command, workdir=None): ''' Run a command while printing the stdout and stderr to stdout, and also return a copy of it ''' # If this call hangs CI will just abort. It is very hard to distinguish # between CI issue and test bug in that case. Set timeout and fail loud # instead. p = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=os.environ.copy(), universal_newlines=True, cwd=workdir, timeout=60 * 5) print(p.stdout) if p.returncode != 0: if 'MESON_SKIP_TEST' in p.stdout: raise unittest.SkipTest('Project requested skipping.') raise subprocess.CalledProcessError(p.returncode, command, output=p.stdout) return p.stdout def init(self, srcdir, extra_args=None, default_args=True, inprocess=False): self.assertPathExists(srcdir) if extra_args is None: extra_args = [] if not isinstance(extra_args, list): extra_args = [extra_args] args = [srcdir, self.builddir] if default_args: args += ['--prefix', self.prefix, '--libdir', self.libdir] if self.meson_cross_file: args += ['--cross-file', self.meson_cross_file] self.privatedir = os.path.join(self.builddir, 'meson-private') if inprocess: try: (returncode, out, err) = run_configure_inprocess(self.meson_args + args + extra_args) if 'MESON_SKIP_TEST' in out: raise unittest.SkipTest('Project requested skipping.') if returncode != 0: self._print_meson_log() print('Stdout:\n') print(out) print('Stderr:\n') print(err) raise RuntimeError('Configure failed') except: self._print_meson_log() raise finally: # Close log file to satisfy Windows file locking mesonbuild.mlog.shutdown() mesonbuild.mlog.log_dir = None mesonbuild.mlog.log_file = None else: try: out = self._run(self.setup_command + args + extra_args) except unittest.SkipTest: raise unittest.SkipTest('Project requested skipping: ' + srcdir) except: self._print_meson_log() raise return out def build(self, target=None, extra_args=None): if extra_args is None: extra_args = [] # Add arguments for building the target (if specified), # and using the build dir (if required, with VS) args = get_builddir_target_args(self.backend, self.builddir, target) return self._run(self.build_command + args + extra_args, workdir=self.builddir) def clean(self): dir_args = get_builddir_target_args(self.backend, self.builddir, None) self._run(self.clean_command + dir_args, workdir=self.builddir) def run_tests(self, inprocess=False): if not inprocess: self._run(self.test_command, workdir=self.builddir) else: run_mtest_inprocess(['-C', self.builddir]) def install(self, *, use_destdir=True): if self.backend is not Backend.ninja: raise unittest.SkipTest('{!r} backend can\'t install files'.format(self.backend.name)) if use_destdir: os.environ['DESTDIR'] = self.installdir self._run(self.install_command, workdir=self.builddir) def uninstall(self): self._run(self.uninstall_command, workdir=self.builddir) def run_target(self, target): ''' Run a Ninja target while printing the stdout and stderr to stdout, and also return a copy of it ''' return self.build(target=target) def setconf(self, arg, will_build=True): if not isinstance(arg, list): arg = [arg] if will_build: ensure_backend_detects_changes(self.backend) self._run(self.mconf_command + arg + [self.builddir]) def wipe(self): windows_proof_rmtree(self.builddir) def utime(self, f): ensure_backend_detects_changes(self.backend) os.utime(f) def get_compdb(self): if self.backend is not Backend.ninja: raise unittest.SkipTest('Compiler db not available with {} backend'.format(self.backend.name)) try: with open(os.path.join(self.builddir, 'compile_commands.json')) as ifile: contents = json.load(ifile) except FileNotFoundError: raise unittest.SkipTest('Compiler db not found') # If Ninja is using .rsp files, generate them, read their contents, and # replace it as the command for all compile commands in the parsed json. if len(contents) > 0 and contents[0]['command'].endswith('.rsp'): # Pretend to build so that the rsp files are generated self.build(extra_args=['-d', 'keeprsp', '-n']) for each in contents: # Extract the actual command from the rsp file compiler, rsp = each['command'].split(' @') rsp = os.path.join(self.builddir, rsp) # Replace the command with its contents with open(rsp, 'r', encoding='utf-8') as f: each['command'] = compiler + ' ' + f.read() return contents def get_meson_log(self): with open(os.path.join(self.builddir, 'meson-logs', 'meson-log.txt')) as f: return f.readlines() def get_meson_log_compiler_checks(self): ''' Fetch a list command-lines run by meson for compiler checks. Each command-line is returned as a list of arguments. ''' log = self.get_meson_log() prefix = 'Command line:' cmds = [l[len(prefix):].split() for l in log if l.startswith(prefix)] return cmds def introspect(self, args): if isinstance(args, str): args = [args] out = subprocess.check_output(self.mintro_command + args + [self.builddir], universal_newlines=True) return json.loads(out) def introspect_directory(self, directory, args): if isinstance(args, str): args = [args] out = subprocess.check_output(self.mintro_command + args + [directory], universal_newlines=True) try: obj = json.loads(out) except Exception as e: print(out) raise e return obj def assertPathEqual(self, path1, path2): ''' Handles a lot of platform-specific quirks related to paths such as separator, case-sensitivity, etc. ''' self.assertEqual(PurePath(path1), PurePath(path2)) def assertPathListEqual(self, pathlist1, pathlist2): self.assertEqual(len(pathlist1), len(pathlist2)) worklist = list(zip(pathlist1, pathlist2)) for i in worklist: if i[0] is None: self.assertEqual(i[0], i[1]) else: self.assertPathEqual(i[0], i[1]) def assertPathBasenameEqual(self, path, basename): msg = '{!r} does not end with {!r}'.format(path, basename) # We cannot use os.path.basename because it returns '' when the path # ends with '/' for some silly reason. This is not how the UNIX utility # `basename` works. path_basename = PurePath(path).parts[-1] self.assertEqual(PurePath(path_basename), PurePath(basename), msg) def assertBuildIsNoop(self): ret = self.build() if self.backend is Backend.ninja: self.assertIn(ret.split('\n')[-2], self.no_rebuild_stdout) elif self.backend is Backend.vs: # Ensure that some target said that no rebuild was done self.assertIn('CustomBuild:\n All outputs are up-to-date.', ret) self.assertIn('ClCompile:\n All outputs are up-to-date.', ret) self.assertIn('Link:\n All outputs are up-to-date.', ret) # Ensure that no targets were built clre = re.compile('ClCompile:\n [^\n]*cl', flags=re.IGNORECASE) linkre = re.compile('Link:\n [^\n]*link', flags=re.IGNORECASE) self.assertNotRegex(ret, clre) self.assertNotRegex(ret, linkre) elif self.backend is Backend.xcode: raise unittest.SkipTest('Please help us fix this test on the xcode backend') else: raise RuntimeError('Invalid backend: {!r}'.format(self.backend.name)) def assertRebuiltTarget(self, target): ret = self.build() if self.backend is Backend.ninja: self.assertIn('Linking target {}'.format(target), ret) elif self.backend is Backend.vs: # Ensure that this target was rebuilt linkre = re.compile('Link:\n [^\n]*link[^\n]*' + target, flags=re.IGNORECASE) self.assertRegex(ret, linkre) elif self.backend is Backend.xcode: raise unittest.SkipTest('Please help us fix this test on the xcode backend') else: raise RuntimeError('Invalid backend: {!r}'.format(self.backend.name)) def assertPathExists(self, path): m = 'Path {!r} should exist'.format(path) self.assertTrue(os.path.exists(path), msg=m) def assertPathDoesNotExist(self, path): m = 'Path {!r} should not exist'.format(path) self.assertFalse(os.path.exists(path), msg=m) class AllPlatformTests(BasePlatformTests): ''' Tests that should run on all platforms ''' def test_default_options_prefix(self): ''' Tests that setting a prefix in default_options in project() works. Can't be an ordinary test because we pass --prefix to meson there. https://github.com/mesonbuild/meson/issues/1349 ''' testdir = os.path.join(self.common_test_dir, '91 default options') self.init(testdir, default_args=False) opts = self.introspect('--buildoptions') for opt in opts: if opt['name'] == 'prefix': prefix = opt['value'] self.assertEqual(prefix, '/absoluteprefix') def test_absolute_prefix_libdir(self): ''' Tests that setting absolute paths for --prefix and --libdir work. Can't be an ordinary test because these are set via the command-line. https://github.com/mesonbuild/meson/issues/1341 https://github.com/mesonbuild/meson/issues/1345 ''' testdir = os.path.join(self.common_test_dir, '91 default options') prefix = '/someabs' libdir = 'libdir' extra_args = ['--prefix=' + prefix, # This can just be a relative path, but we want to test # that passing this as an absolute path also works '--libdir=' + prefix + '/' + libdir] self.init(testdir, extra_args, default_args=False) opts = self.introspect('--buildoptions') for opt in opts: if opt['name'] == 'prefix': self.assertEqual(prefix, opt['value']) elif opt['name'] == 'libdir': self.assertEqual(libdir, opt['value']) def test_libdir_must_be_inside_prefix(self): ''' Tests that libdir is forced to be inside prefix no matter how it is set. Must be a unit test for obvious reasons. ''' testdir = os.path.join(self.common_test_dir, '1 trivial') # libdir being inside prefix is ok args = ['--prefix', '/opt', '--libdir', '/opt/lib32'] self.init(testdir, args) self.wipe() # libdir not being inside prefix is not ok args = ['--prefix', '/usr', '--libdir', '/opt/lib32'] self.assertRaises(subprocess.CalledProcessError, self.init, testdir, args) self.wipe() # libdir must be inside prefix even when set via mesonconf self.init(testdir) self.assertRaises(subprocess.CalledProcessError, self.setconf, '-Dlibdir=/opt', False) def test_prefix_dependent_defaults(self): ''' Tests that configured directory paths are set to prefix dependent defaults. ''' testdir = os.path.join(self.common_test_dir, '1 trivial') expected = { '/opt': {'prefix': '/opt', 'bindir': 'bin', 'datadir': 'share', 'includedir': 'include', 'infodir': 'share/info', 'libexecdir': 'libexec', 'localedir': 'share/locale', 'localstatedir': 'var', 'mandir': 'share/man', 'sbindir': 'sbin', 'sharedstatedir': 'com', 'sysconfdir': 'etc'}, '/usr': {'prefix': '/usr', 'bindir': 'bin', 'datadir': 'share', 'includedir': 'include', 'infodir': 'share/info', 'libexecdir': 'libexec', 'localedir': 'share/locale', 'localstatedir': '/var', 'mandir': 'share/man', 'sbindir': 'sbin', 'sharedstatedir': '/var/lib', 'sysconfdir': '/etc'}, '/usr/local': {'prefix': '/usr/local', 'bindir': 'bin', 'datadir': 'share', 'includedir': 'include', 'infodir': 'share/info', 'libexecdir': 'libexec', 'localedir': 'share/locale', 'localstatedir': '/var/local', 'mandir': 'share/man', 'sbindir': 'sbin', 'sharedstatedir': '/var/local/lib', 'sysconfdir': 'etc'}, # N.B. We don't check 'libdir' as it's platform dependent, see # default_libdir(): } for prefix in expected: args = ['--prefix', prefix] self.init(testdir, args, default_args=False) opts = self.introspect('--buildoptions') for opt in opts: name = opt['name'] value = opt['value'] if name in expected[prefix]: self.assertEqual(value, expected[prefix][name]) self.wipe() def test_default_options_prefix_dependent_defaults(self): ''' Tests that setting a prefix in default_options in project() sets prefix dependent defaults for other options, and that those defaults can be overridden in default_options or by the command line. ''' testdir = os.path.join(self.common_test_dir, '169 default options prefix dependent defaults') expected = { '': {'prefix': '/usr', 'sysconfdir': '/etc', 'localstatedir': '/var', 'sharedstatedir': '/sharedstate'}, '--prefix=/usr': {'prefix': '/usr', 'sysconfdir': '/etc', 'localstatedir': '/var', 'sharedstatedir': '/sharedstate'}, '--sharedstatedir=/var/state': {'prefix': '/usr', 'sysconfdir': '/etc', 'localstatedir': '/var', 'sharedstatedir': '/var/state'}, '--sharedstatedir=/var/state --prefix=/usr --sysconfdir=sysconf': {'prefix': '/usr', 'sysconfdir': 'sysconf', 'localstatedir': '/var', 'sharedstatedir': '/var/state'}, } for args in expected: self.init(testdir, args.split(), default_args=False) opts = self.introspect('--buildoptions') for opt in opts: name = opt['name'] value = opt['value'] if name in expected[args]: self.assertEqual(value, expected[args][name]) self.wipe() def test_static_library_overwrite(self): ''' Tests that static libraries are never appended to, always overwritten. Has to be a unit test because this involves building a project, reconfiguring, and building it again so that `ar` is run twice on the same static library. https://github.com/mesonbuild/meson/issues/1355 ''' testdir = os.path.join(self.common_test_dir, '3 static') env = get_fake_env(testdir, self.builddir, self.prefix) cc = env.detect_c_compiler(False) static_linker = env.detect_static_linker(cc) if is_windows(): raise unittest.SkipTest('https://github.com/mesonbuild/meson/issues/1526') if not isinstance(static_linker, mesonbuild.linkers.ArLinker): raise unittest.SkipTest('static linker is not `ar`') # Configure self.init(testdir) # Get name of static library targets = self.introspect('--targets') self.assertEqual(len(targets), 1) libname = targets[0]['filename'][0] # Build and get contents of static library self.build() before = self._run(['ar', 't', os.path.join(self.builddir, libname)]).split() # Filter out non-object-file contents before = [f for f in before if f.endswith(('.o', '.obj'))] # Static library should contain only one object self.assertEqual(len(before), 1, msg=before) # Change the source to be built into the static library self.setconf('-Dsource=libfile2.c') self.build() after = self._run(['ar', 't', os.path.join(self.builddir, libname)]).split() # Filter out non-object-file contents after = [f for f in after if f.endswith(('.o', '.obj'))] # Static library should contain only one object self.assertEqual(len(after), 1, msg=after) # and the object must have changed self.assertNotEqual(before, after) def test_static_compile_order(self): ''' Test that the order of files in a compiler command-line while compiling and linking statically is deterministic. This can't be an ordinary test case because we need to inspect the compiler database. https://github.com/mesonbuild/meson/pull/951 ''' testdir = os.path.join(self.common_test_dir, '5 linkstatic') self.init(testdir) compdb = self.get_compdb() # Rules will get written out in this order self.assertTrue(compdb[0]['file'].endswith("libfile.c")) self.assertTrue(compdb[1]['file'].endswith("libfile2.c")) self.assertTrue(compdb[2]['file'].endswith("libfile3.c")) self.assertTrue(compdb[3]['file'].endswith("libfile4.c")) # FIXME: We don't have access to the linker command def test_run_target_files_path(self): ''' Test that run_targets are run from the correct directory https://github.com/mesonbuild/meson/issues/957 ''' testdir = os.path.join(self.common_test_dir, '55 run target') self.init(testdir) self.run_target('check_exists') def test_install_introspection(self): ''' Tests that the Meson introspection API exposes install filenames correctly https://github.com/mesonbuild/meson/issues/829 ''' if self.backend is not Backend.ninja: raise unittest.SkipTest('{!r} backend can\'t install files'.format(self.backend.name)) testdir = os.path.join(self.common_test_dir, '8 install') self.init(testdir) intro = self.introspect('--targets') if intro[0]['type'] == 'executable': intro = intro[::-1] self.assertPathListEqual(intro[0]['install_filename'], ['/usr/lib/libstat.a']) self.assertPathListEqual(intro[1]['install_filename'], ['/usr/bin/prog' + exe_suffix]) def test_install_introspection_multiple_outputs(self): ''' Tests that the Meson introspection API exposes multiple install filenames correctly without crashing https://github.com/mesonbuild/meson/pull/4555 Reverted to the first file only because of https://github.com/mesonbuild/meson/pull/4547#discussion_r244173438 TODO Change the format to a list officialy in a followup PR ''' if self.backend is not Backend.ninja: raise unittest.SkipTest('{!r} backend can\'t install files'.format(self.backend.name)) testdir = os.path.join(self.common_test_dir, '145 custom target multiple outputs') self.init(testdir) intro = self.introspect('--targets') if intro[0]['type'] == 'executable': intro = intro[::-1] self.assertPathListEqual(intro[0]['install_filename'], ['/usr/include/diff.h', '/usr/bin/diff.sh']) self.assertPathListEqual(intro[1]['install_filename'], ['/opt/same.h', '/opt/same.sh']) self.assertPathListEqual(intro[2]['install_filename'], ['/usr/include/first.h', None]) self.assertPathListEqual(intro[3]['install_filename'], [None, '/usr/bin/second.sh']) def test_uninstall(self): exename = os.path.join(self.installdir, 'usr/bin/prog' + exe_suffix) testdir = os.path.join(self.common_test_dir, '8 install') self.init(testdir) self.assertPathDoesNotExist(exename) self.install() self.assertPathExists(exename) self.uninstall() self.assertPathDoesNotExist(exename) def test_forcefallback(self): testdir = os.path.join(self.unit_test_dir, '31 forcefallback') self.init(testdir, ['--wrap-mode=forcefallback']) self.build() self.run_tests() def test_testsetups(self): if not shutil.which('valgrind'): raise unittest.SkipTest('Valgrind not installed.') testdir = os.path.join(self.unit_test_dir, '2 testsetups') self.init(testdir) self.build() # Run tests without setup self.run_tests() with open(os.path.join(self.logdir, 'testlog.txt')) as f: basic_log = f.read() # Run buggy test with setup that has env that will make it fail self.assertRaises(subprocess.CalledProcessError, self._run, self.mtest_command + ['--setup=valgrind']) with open(os.path.join(self.logdir, 'testlog-valgrind.txt')) as f: vg_log = f.read() self.assertFalse('TEST_ENV is set' in basic_log) self.assertFalse('Memcheck' in basic_log) self.assertTrue('TEST_ENV is set' in vg_log) self.assertTrue('Memcheck' in vg_log) # Run buggy test with setup without env that will pass self._run(self.mtest_command + ['--setup=wrapper']) # Setup with no properties works self._run(self.mtest_command + ['--setup=empty']) # Setup with only env works self._run(self.mtest_command + ['--setup=onlyenv']) self._run(self.mtest_command + ['--setup=onlyenv2']) self._run(self.mtest_command + ['--setup=onlyenv3']) # Setup with only a timeout works self._run(self.mtest_command + ['--setup=timeout']) def test_testsetup_selection(self): testdir = os.path.join(self.unit_test_dir, '14 testsetup selection') self.init(testdir) self.build() # Run tests without setup self.run_tests() self.assertRaises(subprocess.CalledProcessError, self._run, self.mtest_command + ['--setup=missingfromfoo']) self._run(self.mtest_command + ['--setup=missingfromfoo', '--no-suite=foo:']) self._run(self.mtest_command + ['--setup=worksforall']) self._run(self.mtest_command + ['--setup=main:worksforall']) self.assertRaises(subprocess.CalledProcessError, self._run, self.mtest_command + ['--setup=onlyinbar']) self.assertRaises(subprocess.CalledProcessError, self._run, self.mtest_command + ['--setup=onlyinbar', '--no-suite=main:']) self._run(self.mtest_command + ['--setup=onlyinbar', '--no-suite=main:', '--no-suite=foo:']) self._run(self.mtest_command + ['--setup=bar:onlyinbar']) self.assertRaises(subprocess.CalledProcessError, self._run, self.mtest_command + ['--setup=foo:onlyinbar']) self.assertRaises(subprocess.CalledProcessError, self._run, self.mtest_command + ['--setup=main:onlyinbar']) def test_testsetup_default(self): testdir = os.path.join(self.unit_test_dir, '47 testsetup default') self.init(testdir) self.build() # Run tests without --setup will cause the default setup to be used self.run_tests() with open(os.path.join(self.logdir, 'testlog.txt')) as f: default_log = f.read() # Run tests with explicitly using the same setup that is set as default self._run(self.mtest_command + ['--setup=mydefault']) with open(os.path.join(self.logdir, 'testlog-mydefault.txt')) as f: mydefault_log = f.read() # Run tests with another setup self._run(self.mtest_command + ['--setup=other']) with open(os.path.join(self.logdir, 'testlog-other.txt')) as f: other_log = f.read() self.assertTrue('ENV_A is 1' in default_log) self.assertTrue('ENV_B is 2' in default_log) self.assertTrue('ENV_C is 2' in default_log) self.assertTrue('ENV_A is 1' in mydefault_log) self.assertTrue('ENV_B is 2' in mydefault_log) self.assertTrue('ENV_C is 2' in mydefault_log) self.assertTrue('ENV_A is 1' in other_log) self.assertTrue('ENV_B is 3' in other_log) self.assertTrue('ENV_C is 2' in other_log) def assertFailedTestCount(self, failure_count, command): try: self._run(command) self.assertEqual(0, failure_count, 'Expected %d tests to fail.' % failure_count) except subprocess.CalledProcessError as e: self.assertEqual(e.returncode, failure_count) def test_suite_selection(self): testdir = os.path.join(self.unit_test_dir, '4 suite selection') self.init(testdir) self.build() self.assertFailedTestCount(3, self.mtest_command) self.assertFailedTestCount(0, self.mtest_command + ['--suite', ':success']) self.assertFailedTestCount(3, self.mtest_command + ['--suite', ':fail']) self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', ':success']) self.assertFailedTestCount(0, self.mtest_command + ['--no-suite', ':fail']) self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'mainprj']) self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjsucc']) self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjfail']) self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjmix']) self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'mainprj']) self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjsucc']) self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjfail']) self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjmix']) self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'mainprj:fail']) self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'mainprj:success']) self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'mainprj:fail']) self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'mainprj:success']) self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjfail:fail']) self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjfail:success']) self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjfail:fail']) self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjfail:success']) self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjsucc:fail']) self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjsucc:success']) self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjsucc:fail']) self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjsucc:success']) self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjmix:fail']) self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjmix:success']) self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjmix:fail']) self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjmix:success']) self.assertFailedTestCount(2, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix:fail']) self.assertFailedTestCount(3, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix', '--suite', 'mainprj']) self.assertFailedTestCount(2, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix', '--suite', 'mainprj', '--no-suite', 'subprjmix:fail']) self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix', '--suite', 'mainprj', '--no-suite', 'subprjmix:fail', 'mainprj-failing_test']) self.assertFailedTestCount(1, self.mtest_command + ['--no-suite', 'subprjfail:fail', '--no-suite', 'subprjmix:fail']) def test_build_by_default(self): testdir = os.path.join(self.common_test_dir, '134 build by default') self.init(testdir) self.build() genfile1 = os.path.join(self.builddir, 'generated1.dat') genfile2 = os.path.join(self.builddir, 'generated2.dat') exe1 = os.path.join(self.builddir, 'fooprog' + exe_suffix) exe2 = os.path.join(self.builddir, 'barprog' + exe_suffix) self.assertPathExists(genfile1) self.assertPathExists(genfile2) self.assertPathDoesNotExist(exe1) self.assertPathDoesNotExist(exe2) self.build(target=('fooprog' + exe_suffix)) self.assertPathExists(exe1) self.build(target=('barprog' + exe_suffix)) self.assertPathExists(exe2) def test_internal_include_order(self): testdir = os.path.join(self.common_test_dir, '135 include order') self.init(testdir) execmd = fxecmd = None for cmd in self.get_compdb(): if 'someexe' in cmd['command']: execmd = cmd['command'] continue if 'somefxe' in cmd['command']: fxecmd = cmd['command'] continue if not execmd or not fxecmd: raise Exception('Could not find someexe and somfxe commands') # Check include order for 'someexe' incs = [a for a in shlex.split(execmd) if a.startswith("-I")] self.assertEqual(len(incs), 9) # target private dir someexe_id = Target.construct_id_from_path("sub4", "someexe", "@exe") self.assertPathEqual(incs[0], "-I" + os.path.join("sub4", someexe_id)) # target build subdir self.assertPathEqual(incs[1], "-Isub4") # target source subdir self.assertPathBasenameEqual(incs[2], 'sub4') # include paths added via per-target c_args: ['-I'...] self.assertPathBasenameEqual(incs[3], 'sub3') # target include_directories: build dir self.assertPathEqual(incs[4], "-Isub2") # target include_directories: source dir self.assertPathBasenameEqual(incs[5], 'sub2') # target internal dependency include_directories: build dir self.assertPathEqual(incs[6], "-Isub1") # target internal dependency include_directories: source dir self.assertPathBasenameEqual(incs[7], 'sub1') # custom target include dir self.assertPathEqual(incs[8], '-Ictsub') # Check include order for 'somefxe' incs = [a for a in shlex.split(fxecmd) if a.startswith('-I')] self.assertEqual(len(incs), 9) # target private dir self.assertPathEqual(incs[0], '-Isomefxe@exe') # target build dir self.assertPathEqual(incs[1], '-I.') # target source dir self.assertPathBasenameEqual(incs[2], os.path.basename(testdir)) # target internal dependency correct include_directories: build dir self.assertPathEqual(incs[3], "-Isub4") # target internal dependency correct include_directories: source dir self.assertPathBasenameEqual(incs[4], 'sub4') # target internal dependency dep include_directories: build dir self.assertPathEqual(incs[5], "-Isub1") # target internal dependency dep include_directories: source dir self.assertPathBasenameEqual(incs[6], 'sub1') # target internal dependency wrong include_directories: build dir self.assertPathEqual(incs[7], "-Isub2") # target internal dependency wrong include_directories: source dir self.assertPathBasenameEqual(incs[8], 'sub2') def test_compiler_detection(self): ''' Test that automatic compiler detection and setting from the environment both work just fine. This is needed because while running project tests and other unit tests, we always read CC/CXX/etc from the environment. ''' gnu = mesonbuild.compilers.GnuCompiler clang = mesonbuild.compilers.ClangCompiler intel = mesonbuild.compilers.IntelCompiler msvc = mesonbuild.compilers.VisualStudioCCompiler clangcl = mesonbuild.compilers.ClangClCCompiler ar = mesonbuild.linkers.ArLinker lib = mesonbuild.linkers.VisualStudioLinker langs = [('c', 'CC'), ('cpp', 'CXX')] if not is_windows(): langs += [('objc', 'OBJC'), ('objcpp', 'OBJCXX')] testdir = os.path.join(self.unit_test_dir, '5 compiler detection') env = get_fake_env(testdir, self.builddir, self.prefix) for lang, evar in langs: # Detect with evar and do sanity checks on that if evar in os.environ: ecc = getattr(env, 'detect_{}_compiler'.format(lang))(False) self.assertTrue(ecc.version) elinker = env.detect_static_linker(ecc) # Pop it so we don't use it for the next detection evalue = os.environ.pop(evar) # Very rough/strict heuristics. Would never work for actual # compiler detection, but should be ok for the tests. ebase = os.path.basename(evalue) if ebase.startswith('g') or ebase.endswith(('-gcc', '-g++')): self.assertIsInstance(ecc, gnu) self.assertIsInstance(elinker, ar) elif 'clang-cl' in ebase: self.assertIsInstance(ecc, clangcl) self.assertIsInstance(elinker, lib) elif 'clang' in ebase: self.assertIsInstance(ecc, clang) self.assertIsInstance(elinker, ar) elif ebase.startswith('ic'): self.assertIsInstance(ecc, intel) self.assertIsInstance(elinker, ar) elif ebase.startswith('cl'): self.assertIsInstance(ecc, msvc) self.assertIsInstance(elinker, lib) else: raise AssertionError('Unknown compiler {!r}'.format(evalue)) # Check that we actually used the evalue correctly as the compiler self.assertEqual(ecc.get_exelist(), shlex.split(evalue)) # Do auto-detection of compiler based on platform, PATH, etc. cc = getattr(env, 'detect_{}_compiler'.format(lang))(False) self.assertTrue(cc.version) linker = env.detect_static_linker(cc) # Check compiler type if isinstance(cc, gnu): self.assertIsInstance(linker, ar) if is_osx(): self.assertEqual(cc.compiler_type, mesonbuild.compilers.CompilerType.GCC_OSX) elif is_windows(): self.assertEqual(cc.compiler_type, mesonbuild.compilers.CompilerType.GCC_MINGW) elif is_cygwin(): self.assertEqual(cc.compiler_type, mesonbuild.compilers.CompilerType.GCC_CYGWIN) else: self.assertEqual(cc.compiler_type, mesonbuild.compilers.CompilerType.GCC_STANDARD) if isinstance(cc, clang): self.assertIsInstance(linker, ar) if is_osx(): self.assertEqual(cc.compiler_type, mesonbuild.compilers.CompilerType.CLANG_OSX) elif is_windows(): # Not implemented yet self.assertEqual(cc.compiler_type, mesonbuild.compilers.CompilerType.CLANG_MINGW) else: self.assertEqual(cc.compiler_type, mesonbuild.compilers.CompilerType.CLANG_STANDARD) if isinstance(cc, intel): self.assertIsInstance(linker, ar) if is_osx(): self.assertEqual(cc.compiler_type, mesonbuild.compilers.CompilerType.ICC_OSX) elif is_windows(): self.assertEqual(cc.compiler_type, mesonbuild.compilers.CompilerType.ICC_WIN) else: self.assertEqual(cc.compiler_type, mesonbuild.compilers.CompilerType.ICC_STANDARD) if isinstance(cc, msvc): self.assertTrue(is_windows()) self.assertIsInstance(linker, lib) self.assertEqual(cc.id, 'msvc') self.assertTrue(hasattr(cc, 'is_64')) # If we're on Windows CI, we know what the compiler will be if 'arch' in os.environ: if os.environ['arch'] == 'x64': self.assertTrue(cc.is_64) else: self.assertFalse(cc.is_64) # Set evar ourselves to a wrapper script that just calls the same # exelist + some argument. This is meant to test that setting # something like `ccache gcc -pipe` or `distcc ccache gcc` works. wrapper = os.path.join(testdir, 'compiler wrapper.py') wrappercc = python_command + [wrapper] + cc.get_exelist() + ['-DSOME_ARG'] wrappercc_s = '' for w in wrappercc: wrappercc_s += shlex.quote(w) + ' ' os.environ[evar] = wrappercc_s wcc = getattr(env, 'detect_{}_compiler'.format(lang))(False) # Check static linker too wrapperlinker = python_command + [wrapper] + linker.get_exelist() + linker.get_always_args() wrapperlinker_s = '' for w in wrapperlinker: wrapperlinker_s += shlex.quote(w) + ' ' os.environ['AR'] = wrapperlinker_s wlinker = env.detect_static_linker(wcc) # Pop it so we don't use it for the next detection evalue = os.environ.pop('AR') # Must be the same type since it's a wrapper around the same exelist self.assertIs(type(cc), type(wcc)) self.assertIs(type(linker), type(wlinker)) # Ensure that the exelist is correct self.assertEqual(wcc.get_exelist(), wrappercc) self.assertEqual(wlinker.get_exelist(), wrapperlinker) # Ensure that the version detection worked correctly self.assertEqual(cc.version, wcc.version) if hasattr(cc, 'is_64'): self.assertEqual(cc.is_64, wcc.is_64) def test_always_prefer_c_compiler_for_asm(self): testdir = os.path.join(self.common_test_dir, '138 c cpp and asm') # Skip if building with MSVC env = get_fake_env(testdir, self.builddir, self.prefix) if env.detect_c_compiler(False).get_id() == 'msvc': raise unittest.SkipTest('MSVC can\'t compile assembly') self.init(testdir) commands = {'c-asm': {}, 'cpp-asm': {}, 'cpp-c-asm': {}, 'c-cpp-asm': {}} for cmd in self.get_compdb(): # Get compiler split = shlex.split(cmd['command']) if split[0] == 'ccache': compiler = split[1] else: compiler = split[0] # Classify commands if 'Ic-asm' in cmd['command']: if cmd['file'].endswith('.S'): commands['c-asm']['asm'] = compiler elif cmd['file'].endswith('.c'): commands['c-asm']['c'] = compiler else: raise AssertionError('{!r} found in cpp-asm?'.format(cmd['command'])) elif 'Icpp-asm' in cmd['command']: if cmd['file'].endswith('.S'): commands['cpp-asm']['asm'] = compiler elif cmd['file'].endswith('.cpp'): commands['cpp-asm']['cpp'] = compiler else: raise AssertionError('{!r} found in cpp-asm?'.format(cmd['command'])) elif 'Ic-cpp-asm' in cmd['command']: if cmd['file'].endswith('.S'): commands['c-cpp-asm']['asm'] = compiler elif cmd['file'].endswith('.c'): commands['c-cpp-asm']['c'] = compiler elif cmd['file'].endswith('.cpp'): commands['c-cpp-asm']['cpp'] = compiler else: raise AssertionError('{!r} found in c-cpp-asm?'.format(cmd['command'])) elif 'Icpp-c-asm' in cmd['command']: if cmd['file'].endswith('.S'): commands['cpp-c-asm']['asm'] = compiler elif cmd['file'].endswith('.c'): commands['cpp-c-asm']['c'] = compiler elif cmd['file'].endswith('.cpp'): commands['cpp-c-asm']['cpp'] = compiler else: raise AssertionError('{!r} found in cpp-c-asm?'.format(cmd['command'])) else: raise AssertionError('Unknown command {!r} found'.format(cmd['command'])) # Check that .S files are always built with the C compiler self.assertEqual(commands['c-asm']['asm'], commands['c-asm']['c']) self.assertEqual(commands['c-asm']['asm'], commands['cpp-asm']['asm']) self.assertEqual(commands['cpp-asm']['asm'], commands['c-cpp-asm']['c']) self.assertEqual(commands['c-cpp-asm']['asm'], commands['c-cpp-asm']['c']) self.assertEqual(commands['cpp-c-asm']['asm'], commands['cpp-c-asm']['c']) self.assertNotEqual(commands['cpp-asm']['asm'], commands['cpp-asm']['cpp']) self.assertNotEqual(commands['c-cpp-asm']['c'], commands['c-cpp-asm']['cpp']) self.assertNotEqual(commands['cpp-c-asm']['c'], commands['cpp-c-asm']['cpp']) # Check that the c-asm target is always linked with the C linker build_ninja = os.path.join(self.builddir, 'build.ninja') with open(build_ninja, 'r', encoding='utf-8') as f: contents = f.read() m = re.search('build c-asm.*: c_LINKER', contents) self.assertIsNotNone(m, msg=contents) def test_preprocessor_checks_CPPFLAGS(self): ''' Test that preprocessor compiler checks read CPPFLAGS but not CFLAGS ''' testdir = os.path.join(self.common_test_dir, '137 get define') define = 'MESON_TEST_DEFINE_VALUE' # NOTE: this list can't have \n, ' or " # \n is never substituted by the GNU pre-processor via a -D define # ' and " confuse shlex.split() even when they are escaped # % and # confuse the MSVC preprocessor # !, ^, *, and < confuse lcc preprocessor value = 'spaces and fun@$&()-=_+{}[]:;>?,./~`' os.environ['CPPFLAGS'] = '-D{}="{}"'.format(define, value) os.environ['CFLAGS'] = '-DMESON_FAIL_VALUE=cflags-read'.format(define) self.init(testdir, ['-D{}={}'.format(define, value)]) def test_custom_target_exe_data_deterministic(self): testdir = os.path.join(self.common_test_dir, '114 custom target capture') self.init(testdir) meson_exe_dat1 = glob(os.path.join(self.privatedir, 'meson_exe*.dat')) self.wipe() self.init(testdir) meson_exe_dat2 = glob(os.path.join(self.privatedir, 'meson_exe*.dat')) self.assertListEqual(meson_exe_dat1, meson_exe_dat2) def test_source_changes_cause_rebuild(self): ''' Test that changes to sources and headers cause rebuilds, but not changes to unused files (as determined by the dependency file) in the input files list. ''' testdir = os.path.join(self.common_test_dir, '20 header in file list') self.init(testdir) self.build() # Immediately rebuilding should not do anything self.assertBuildIsNoop() # Changing mtime of header.h should rebuild everything self.utime(os.path.join(testdir, 'header.h')) self.assertRebuiltTarget('prog') def test_custom_target_changes_cause_rebuild(self): ''' Test that in a custom target, changes to the input files, the ExternalProgram, and any File objects on the command-line cause a rebuild. ''' testdir = os.path.join(self.common_test_dir, '61 custom header generator') self.init(testdir) self.build() # Immediately rebuilding should not do anything self.assertBuildIsNoop() # Changing mtime of these should rebuild everything for f in ('input.def', 'makeheader.py', 'somefile.txt'): self.utime(os.path.join(testdir, f)) self.assertRebuiltTarget('prog') def test_static_library_lto(self): ''' Test that static libraries can be built with LTO and linked to executables. On Linux, this requires the use of gcc-ar. https://github.com/mesonbuild/meson/issues/1646 ''' testdir = os.path.join(self.common_test_dir, '5 linkstatic') env = get_fake_env(testdir, self.builddir, self.prefix) if env.detect_c_compiler(False).get_id() == 'clang' and is_windows(): raise unittest.SkipTest('LTO not (yet) supported by windows clang') self.init(testdir, extra_args='-Db_lto=true') self.build() self.run_tests() def test_dist_git(self): if not shutil.which('git'): raise unittest.SkipTest('Git not found') try: self.dist_impl(_git_init) except PermissionError: # When run under Windows CI, something (virus scanner?) # holds on to the git files so cleaning up the dir # fails sometimes. pass def test_dist_hg(self): if not shutil.which('hg'): raise unittest.SkipTest('Mercurial not found') if self.backend is not Backend.ninja: raise unittest.SkipTest('Dist is only supported with Ninja') def hg_init(project_dir): subprocess.check_call(['hg', 'init'], cwd=project_dir) with open(os.path.join(project_dir, '.hg', 'hgrc'), 'w') as f: print('[ui]', file=f) print('username=Author Person <teh_coderz@example.com>', file=f) subprocess.check_call(['hg', 'add', 'meson.build', 'distexe.c'], cwd=project_dir) subprocess.check_call(['hg', 'commit', '-m', 'I am a project'], cwd=project_dir) try: self.dist_impl(hg_init) except PermissionError: # When run under Windows CI, something (virus scanner?) # holds on to the hg files so cleaning up the dir # fails sometimes. pass def test_dist_git_script(self): if not shutil.which('git'): raise unittest.SkipTest('Git not found') try: with tempfile.TemporaryDirectory() as tmpdir: project_dir = os.path.join(tmpdir, 'a') shutil.copytree(os.path.join(self.unit_test_dir, '35 dist script'), project_dir) _git_init(project_dir) self.init(project_dir) self.build('dist') except PermissionError: # When run under Windows CI, something (virus scanner?) # holds on to the git files so cleaning up the dir # fails sometimes. pass def dist_impl(self, vcs_init): # Create this on the fly because having rogue .git directories inside # the source tree leads to all kinds of trouble. with tempfile.TemporaryDirectory() as project_dir: with open(os.path.join(project_dir, 'meson.build'), 'w') as ofile: ofile.write('''project('disttest', 'c', version : '1.4.3') e = executable('distexe', 'distexe.c') test('dist test', e) ''') with open(os.path.join(project_dir, 'distexe.c'), 'w') as ofile: ofile.write('''#include<stdio.h> int main(int argc, char **argv) { printf("I am a distribution test.\\n"); return 0; } ''') vcs_init(project_dir) self.init(project_dir) self.build('dist') distfile = os.path.join(self.distdir, 'disttest-1.4.3.tar.xz') checksumfile = distfile + '.sha256sum' self.assertPathExists(distfile) self.assertPathExists(checksumfile) def test_rpath_uses_ORIGIN(self): ''' Test that built targets use $ORIGIN in rpath, which ensures that they are relocatable and ensures that builds are reproducible since the build directory won't get embedded into the built binaries. ''' if is_windows() or is_cygwin(): raise unittest.SkipTest('Windows PE/COFF binaries do not use RPATH') testdir = os.path.join(self.common_test_dir, '43 library chain') self.init(testdir) self.build() for each in ('prog', 'subdir/liblib1.so', ): rpath = get_rpath(os.path.join(self.builddir, each)) self.assertTrue(rpath, 'Rpath could not be determined for {}.'.format(each)) if is_dragonflybsd(): # DragonflyBSD will prepend /usr/lib/gccVERSION to the rpath, # so ignore that. self.assertTrue(rpath.startswith('/usr/lib/gcc')) rpaths = rpath.split(':')[1:] else: rpaths = rpath.split(':') for path in rpaths: self.assertTrue(path.startswith('$ORIGIN'), msg=(each, path)) # These two don't link to anything else, so they do not need an rpath entry. for each in ('subdir/subdir2/liblib2.so', 'subdir/subdir3/liblib3.so'): rpath = get_rpath(os.path.join(self.builddir, each)) if is_dragonflybsd(): # The rpath should be equal to /usr/lib/gccVERSION self.assertTrue(rpath.startswith('/usr/lib/gcc')) self.assertEqual(len(rpath.split(':')), 1) else: self.assertTrue(rpath is None) def test_dash_d_dedup(self): testdir = os.path.join(self.unit_test_dir, '9 d dedup') self.init(testdir) cmd = self.get_compdb()[0]['command'] self.assertTrue('-D FOO -D BAR' in cmd or '"-D" "FOO" "-D" "BAR"' in cmd or '/D FOO /D BAR' in cmd or '"/D" "FOO" "/D" "BAR"' in cmd) def test_all_forbidden_targets_tested(self): ''' Test that all forbidden targets are tested in the '155 reserved targets' test. Needs to be a unit test because it accesses Meson internals. ''' testdir = os.path.join(self.common_test_dir, '155 reserved targets') targets = mesonbuild.coredata.forbidden_target_names # We don't actually define a target with this name targets.pop('build.ninja') # Remove this to avoid multiple entries with the same name # but different case. targets.pop('PHONY') for i in targets: self.assertPathExists(os.path.join(testdir, i)) def detect_prebuild_env(self): env = get_fake_env('', self.builddir, self.prefix) cc = env.detect_c_compiler(False) stlinker = env.detect_static_linker(cc) if mesonbuild.mesonlib.is_windows(): object_suffix = 'obj' shared_suffix = 'dll' elif mesonbuild.mesonlib.is_cygwin(): object_suffix = 'o' shared_suffix = 'dll' elif mesonbuild.mesonlib.is_osx(): object_suffix = 'o' shared_suffix = 'dylib' else: object_suffix = 'o' shared_suffix = 'so' return (cc, stlinker, object_suffix, shared_suffix) def pbcompile(self, compiler, source, objectfile, extra_args=[]): cmd = compiler.get_exelist() if compiler.get_argument_syntax() == 'msvc': cmd += ['/nologo', '/Fo' + objectfile, '/c', source] + extra_args else: cmd += ['-c', source, '-o', objectfile] + extra_args subprocess.check_call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) def test_prebuilt_object(self): (compiler, _, object_suffix, _) = self.detect_prebuild_env() tdir = os.path.join(self.unit_test_dir, '15 prebuilt object') source = os.path.join(tdir, 'source.c') objectfile = os.path.join(tdir, 'prebuilt.' + object_suffix) self.pbcompile(compiler, source, objectfile) try: self.init(tdir) self.build() self.run_tests() finally: os.unlink(objectfile) def build_static_lib(self, compiler, linker, source, objectfile, outfile, extra_args=None): if extra_args is None: extra_args = [] if compiler.get_argument_syntax() == 'msvc': link_cmd = ['lib', '/NOLOGO', '/OUT:' + outfile, objectfile] else: link_cmd = ['ar', 'csr', outfile, objectfile] link_cmd = linker.get_exelist() link_cmd += linker.get_always_args() link_cmd += linker.get_std_link_args() link_cmd += linker.get_output_args(outfile) link_cmd += [objectfile] self.pbcompile(compiler, source, objectfile, extra_args=extra_args) try: subprocess.check_call(link_cmd) finally: os.unlink(objectfile) def test_prebuilt_static_lib(self): (cc, stlinker, object_suffix, _) = self.detect_prebuild_env() tdir = os.path.join(self.unit_test_dir, '16 prebuilt static') source = os.path.join(tdir, 'libdir/best.c') objectfile = os.path.join(tdir, 'libdir/best.' + object_suffix) stlibfile = os.path.join(tdir, 'libdir/libbest.a') self.build_static_lib(cc, stlinker, source, objectfile, stlibfile) # Run the test try: self.init(tdir) self.build() self.run_tests() finally: os.unlink(stlibfile) def build_shared_lib(self, compiler, source, objectfile, outfile, impfile, extra_args=None): if extra_args is None: extra_args = [] if compiler.get_argument_syntax() == 'msvc': link_cmd = compiler.get_linker_exelist() + [ '/NOLOGO', '/DLL', '/DEBUG', '/IMPLIB:' + impfile, '/OUT:' + outfile, objectfile] else: if not (compiler.compiler_type.is_windows_compiler or compiler.compiler_type.is_osx_compiler): extra_args += ['-fPIC'] link_cmd = compiler.get_exelist() + ['-shared', '-o', outfile, objectfile] if not mesonbuild.mesonlib.is_osx(): link_cmd += ['-Wl,-soname=' + os.path.basename(outfile)] self.pbcompile(compiler, source, objectfile, extra_args=extra_args) try: subprocess.check_call(link_cmd) finally: os.unlink(objectfile) def test_prebuilt_shared_lib(self): (cc, _, object_suffix, shared_suffix) = self.detect_prebuild_env() tdir = os.path.join(self.unit_test_dir, '17 prebuilt shared') source = os.path.join(tdir, 'alexandria.c') objectfile = os.path.join(tdir, 'alexandria.' + object_suffix) impfile = os.path.join(tdir, 'alexandria.lib') if cc.get_argument_syntax() == 'msvc': shlibfile = os.path.join(tdir, 'alexandria.' + shared_suffix) elif is_cygwin(): shlibfile = os.path.join(tdir, 'cygalexandria.' + shared_suffix) else: shlibfile = os.path.join(tdir, 'libalexandria.' + shared_suffix) self.build_shared_lib(cc, source, objectfile, shlibfile, impfile) # Run the test try: self.init(tdir) self.build() self.run_tests() finally: os.unlink(shlibfile) if mesonbuild.mesonlib.is_windows(): # Clean up all the garbage MSVC writes in the # source tree. for fname in glob(os.path.join(tdir, 'alexandria.*')): if os.path.splitext(fname)[1] not in ['.c', '.h']: os.unlink(fname) @skipIfNoPkgconfig def test_pkgconfig_static(self): ''' Test that the we prefer static libraries when `static: true` is passed to dependency() with pkg-config. Can't be an ordinary test because we need to build libs and try to find them from meson.build Also test that it's not a hard error to have unsatisfiable library deps since system libraries -lm will never be found statically. https://github.com/mesonbuild/meson/issues/2785 ''' (cc, stlinker, objext, shext) = self.detect_prebuild_env() testdir = os.path.join(self.unit_test_dir, '18 pkgconfig static') source = os.path.join(testdir, 'foo.c') objectfile = os.path.join(testdir, 'foo.' + objext) stlibfile = os.path.join(testdir, 'libfoo.a') impfile = os.path.join(testdir, 'foo.lib') if cc.get_argument_syntax() == 'msvc': shlibfile = os.path.join(testdir, 'foo.' + shext) elif is_cygwin(): shlibfile = os.path.join(testdir, 'cygfoo.' + shext) else: shlibfile = os.path.join(testdir, 'libfoo.' + shext) # Build libs self.build_static_lib(cc, stlinker, source, objectfile, stlibfile, extra_args=['-DFOO_STATIC']) self.build_shared_lib(cc, source, objectfile, shlibfile, impfile) # Run test os.environ['PKG_CONFIG_LIBDIR'] = self.builddir try: self.init(testdir) self.build() self.run_tests() finally: os.unlink(stlibfile) os.unlink(shlibfile) if mesonbuild.mesonlib.is_windows(): # Clean up all the garbage MSVC writes in the # source tree. for fname in glob(os.path.join(testdir, 'foo.*')): if os.path.splitext(fname)[1] not in ['.c', '.h', '.in']: os.unlink(fname) @skipIfNoPkgconfig def test_pkgconfig_gen_escaping(self): testdir = os.path.join(self.common_test_dir, '48 pkgconfig-gen') prefix = '/usr/with spaces' libdir = 'lib' self.init(testdir, extra_args=['--prefix=' + prefix, '--libdir=' + libdir]) # Find foo dependency os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir env = get_fake_env(testdir, self.builddir, self.prefix) kwargs = {'required': True, 'silent': True} foo_dep = PkgConfigDependency('libfoo', env, kwargs) # Ensure link_args are properly quoted libdir = PurePath(prefix) / PurePath(libdir) link_args = ['-L' + libdir.as_posix(), '-lfoo'] self.assertEqual(foo_dep.get_link_args(), link_args) # Ensure include args are properly quoted incdir = PurePath(prefix) / PurePath('include') cargs = ['-I' + incdir.as_posix()] self.assertEqual(foo_dep.get_compile_args(), cargs) def test_array_option_change(self): def get_opt(): opts = self.introspect('--buildoptions') for x in opts: if x.get('name') == 'list': return x raise Exception(opts) expected = { 'name': 'list', 'description': 'list', 'section': 'user', 'type': 'array', 'value': ['foo', 'bar'], } tdir = os.path.join(self.unit_test_dir, '19 array option') self.init(tdir) original = get_opt() self.assertDictEqual(original, expected) expected['value'] = ['oink', 'boink'] self.setconf('-Dlist=oink,boink') changed = get_opt() self.assertEqual(changed, expected) def test_array_option_bad_change(self): def get_opt(): opts = self.introspect('--buildoptions') for x in opts: if x.get('name') == 'list': return x raise Exception(opts) expected = { 'name': 'list', 'description': 'list', 'section': 'user', 'type': 'array', 'value': ['foo', 'bar'], } tdir = os.path.join(self.unit_test_dir, '19 array option') self.init(tdir) original = get_opt() self.assertDictEqual(original, expected) with self.assertRaises(subprocess.CalledProcessError): self.setconf('-Dlist=bad') changed = get_opt() self.assertDictEqual(changed, expected) def test_array_option_empty_equivalents(self): """Array options treat -Dopt=[] and -Dopt= as equivalent.""" def get_opt(): opts = self.introspect('--buildoptions') for x in opts: if x.get('name') == 'list': return x raise Exception(opts) expected = { 'name': 'list', 'description': 'list', 'section': 'user', 'type': 'array', 'value': [], } tdir = os.path.join(self.unit_test_dir, '19 array option') self.init(tdir, extra_args='-Dlist=') original = get_opt() self.assertDictEqual(original, expected) def opt_has(self, name, value): res = self.introspect('--buildoptions') found = False for i in res: if i['name'] == name: self.assertEqual(i['value'], value) found = True break self.assertTrue(found, "Array option not found in introspect data.") def test_free_stringarray_setting(self): testdir = os.path.join(self.common_test_dir, '44 options') self.init(testdir) self.opt_has('free_array_opt', []) self.setconf('-Dfree_array_opt=foo,bar', will_build=False) self.opt_has('free_array_opt', ['foo', 'bar']) self.setconf("-Dfree_array_opt=['a,b', 'c,d']", will_build=False) self.opt_has('free_array_opt', ['a,b', 'c,d']) def test_subproject_promotion(self): testdir = os.path.join(self.unit_test_dir, '12 promote') workdir = os.path.join(self.builddir, 'work') shutil.copytree(testdir, workdir) spdir = os.path.join(workdir, 'subprojects') s3dir = os.path.join(spdir, 's3') scommondir = os.path.join(spdir, 'scommon') self.assertFalse(os.path.isdir(s3dir)) subprocess.check_call(self.wrap_command + ['promote', 's3'], cwd=workdir) self.assertTrue(os.path.isdir(s3dir)) self.assertFalse(os.path.isdir(scommondir)) self.assertNotEqual(subprocess.call(self.wrap_command + ['promote', 'scommon'], cwd=workdir, stdout=subprocess.DEVNULL), 0) self.assertNotEqual(subprocess.call(self.wrap_command + ['promote', 'invalid/path/to/scommon'], cwd=workdir, stderr=subprocess.DEVNULL), 0) self.assertFalse(os.path.isdir(scommondir)) subprocess.check_call(self.wrap_command + ['promote', 'subprojects/s2/subprojects/scommon'], cwd=workdir) self.assertTrue(os.path.isdir(scommondir)) promoted_wrap = os.path.join(spdir, 'athing.wrap') self.assertFalse(os.path.isfile(promoted_wrap)) subprocess.check_call(self.wrap_command + ['promote', 'athing'], cwd=workdir) self.assertTrue(os.path.isfile(promoted_wrap)) self.init(workdir) self.build() def test_subproject_promotion_wrap(self): testdir = os.path.join(self.unit_test_dir, '44 promote wrap') workdir = os.path.join(self.builddir, 'work') shutil.copytree(testdir, workdir) spdir = os.path.join(workdir, 'subprojects') ambiguous_wrap = os.path.join(spdir, 'ambiguous.wrap') self.assertNotEqual(subprocess.call(self.wrap_command + ['promote', 'ambiguous'], cwd=workdir, stdout=subprocess.DEVNULL), 0) self.assertFalse(os.path.isfile(ambiguous_wrap)) subprocess.check_call(self.wrap_command + ['promote', 'subprojects/s2/subprojects/ambiguous.wrap'], cwd=workdir) self.assertTrue(os.path.isfile(ambiguous_wrap)) def test_warning_location(self): tdir = os.path.join(self.unit_test_dir, '22 warning location') out = self.init(tdir) for expected in [ r'meson.build:4: WARNING: Keyword argument "link_with" defined multiple times.', r'sub' + os.path.sep + r'meson.build:3: WARNING: Keyword argument "link_with" defined multiple times.', r'meson.build:6: WARNING: a warning of some sort', r'sub' + os.path.sep + r'meson.build:4: WARNING: subdir warning', r'meson.build:7: WARNING: Module unstable-simd has no backwards or forwards compatibility and might not exist in future releases.', r"meson.build:11: WARNING: The variable(s) 'MISSING' in the input file 'conf.in' are not present in the given configuration data.", r'meson.build:1: WARNING: Passed invalid keyword argument "invalid".', ]: self.assertRegex(out, re.escape(expected)) def test_permitted_method_kwargs(self): tdir = os.path.join(self.unit_test_dir, '25 non-permitted kwargs') out = self.init(tdir) for expected in [ r'WARNING: Passed invalid keyword argument "prefixxx".', r'WARNING: Passed invalid keyword argument "argsxx".', r'WARNING: Passed invalid keyword argument "invalidxx".', ]: self.assertRegex(out, re.escape(expected)) def test_templates(self): ninja = detect_ninja() if ninja is None: raise unittest.SkipTest('This test currently requires ninja. Fix this once "meson build" works.') for lang in ('c', 'cpp'): for type in ('executable', 'library'): with tempfile.TemporaryDirectory() as tmpdir: self._run(self.meson_command + ['init', '--language', lang, '--type', type], workdir=tmpdir) self._run(self.setup_command + ['--backend=ninja', 'builddir'], workdir=tmpdir) self._run(ninja, workdir=os.path.join(tmpdir, 'builddir')) with tempfile.TemporaryDirectory() as tmpdir: with open(os.path.join(tmpdir, 'foo.' + lang), 'w') as f: f.write('int main() {}') self._run(self.meson_command + ['init', '-b'], workdir=tmpdir) # The test uses mocking and thus requires that # the current process is the one to run the Meson steps. # If we are using an external test executable (most commonly # in Debian autopkgtests) then the mocking won't work. @unittest.skipIf('MESON_EXE' in os.environ, 'MESON_EXE is defined, can not use mocking.') def test_cross_file_system_paths(self): if is_windows(): raise unittest.SkipTest('system crossfile paths not defined for Windows (yet)') testdir = os.path.join(self.common_test_dir, '1 trivial') cross_content = textwrap.dedent("""\ [binaries] c = '/usr/bin/cc' ar = '/usr/bin/ar' strip = '/usr/bin/ar' [properties] [host_machine] system = 'linux' cpu_family = 'x86' cpu = 'i686' endian = 'little' """) with tempfile.TemporaryDirectory() as d: dir_ = os.path.join(d, 'meson', 'cross') os.makedirs(dir_) with tempfile.NamedTemporaryFile('w', dir=dir_, delete=False) as f: f.write(cross_content) name = os.path.basename(f.name) with mock.patch.dict(os.environ, {'XDG_DATA_HOME': d}): self.init(testdir, ['--cross-file=' + name], inprocess=True) self.wipe() with mock.patch.dict(os.environ, {'XDG_DATA_DIRS': d}): os.environ.pop('XDG_DATA_HOME', None) self.init(testdir, ['--cross-file=' + name], inprocess=True) self.wipe() with tempfile.TemporaryDirectory() as d: dir_ = os.path.join(d, '.local', 'share', 'meson', 'cross') os.makedirs(dir_) with tempfile.NamedTemporaryFile('w', dir=dir_, delete=False) as f: f.write(cross_content) name = os.path.basename(f.name) with mock.patch('mesonbuild.coredata.os.path.expanduser', lambda x: x.replace('~', d)): self.init(testdir, ['--cross-file=' + name], inprocess=True) self.wipe() def test_introspect_target_files(self): ''' Tests that mesonintrospect --target-files returns expected output. ''' testdir = os.path.join(self.common_test_dir, '8 install') self.init(testdir) expected = { 'stat@sta': ['stat.c'], 'prog@exe': ['prog.c'], } t_intro = self.introspect('--targets') self.assertCountEqual([t['id'] for t in t_intro], expected) for t in t_intro: id = t['id'] tf_intro = self.introspect(['--target-files', id]) self.assertEqual(tf_intro, expected[id]) self.wipe() testdir = os.path.join(self.common_test_dir, '53 custom target') self.init(testdir) expected = { 'bindat@cus': ['data_source.txt'], 'depfile@cus': [], } t_intro = self.introspect('--targets') self.assertCountEqual([t['id'] for t in t_intro], expected) for t in t_intro: id = t['id'] tf_intro = self.introspect(['--target-files', id]) self.assertEqual(tf_intro, expected[id]) self.wipe() def test_compiler_run_command(self): ''' The test checks that the compiler object can be passed to run_command(). ''' testdir = os.path.join(self.unit_test_dir, '24 compiler run_command') self.init(testdir) def test_identical_target_name_in_subproject_flat_layout(self): ''' Test that identical targets in different subprojects do not collide if layout is flat. ''' testdir = os.path.join(self.common_test_dir, '178 identical target name in subproject flat layout') self.init(testdir, extra_args=['--layout=flat']) self.build() def test_identical_target_name_in_subdir_flat_layout(self): ''' Test that identical targets in different subdirs do not collide if layout is flat. ''' testdir = os.path.join(self.common_test_dir, '187 same target name flat layout') self.init(testdir, extra_args=['--layout=flat']) self.build() def test_flock(self): exception_raised = False with tempfile.TemporaryDirectory() as tdir: os.mkdir(os.path.join(tdir, 'meson-private')) with BuildDirLock(tdir): try: with BuildDirLock(tdir): pass except MesonException: exception_raised = True self.assertTrue(exception_raised, 'Double locking did not raise exception.') @unittest.skipIf(is_osx(), 'Test not applicable to OSX') def test_check_module_linking(self): """ Test that link_with: a shared module issues a warning https://github.com/mesonbuild/meson/issues/2865 (That an error is raised on OSX is exercised by test failing/78) """ tdir = os.path.join(self.unit_test_dir, '30 shared_mod linking') out = self.init(tdir) msg = ('''WARNING: target links against shared modules. This is not recommended as it is not supported on some platforms''') self.assertIn(msg, out) def test_ndebug_if_release_disabled(self): testdir = os.path.join(self.unit_test_dir, '28 ndebug if-release') self.init(testdir, extra_args=['--buildtype=release', '-Db_ndebug=if-release']) self.build() exe = os.path.join(self.builddir, 'main') self.assertEqual(b'NDEBUG=1', subprocess.check_output(exe).strip()) def test_ndebug_if_release_enabled(self): testdir = os.path.join(self.unit_test_dir, '28 ndebug if-release') self.init(testdir, extra_args=['--buildtype=debugoptimized', '-Db_ndebug=if-release']) self.build() exe = os.path.join(self.builddir, 'main') self.assertEqual(b'NDEBUG=0', subprocess.check_output(exe).strip()) def test_guessed_linker_dependencies(self): ''' Test that meson adds dependencies for libraries based on the final linker command line. ''' # build library testdirbase = os.path.join(self.unit_test_dir, '29 guessed linker dependencies') testdirlib = os.path.join(testdirbase, 'lib') extra_args = None env = get_fake_env(testdirlib, self.builddir, self.prefix) if env.detect_c_compiler(False).get_id() not in ['msvc', 'clang-cl']: # static libraries are not linkable with -l with msvc because meson installs them # as .a files which unix_args_to_native will not know as it expects libraries to use # .lib as extension. For a DLL the import library is installed as .lib. Thus for msvc # this tests needs to use shared libraries to test the path resolving logic in the # dependency generation code path. extra_args = ['--default-library', 'static'] self.init(testdirlib, extra_args=extra_args) self.build() self.install() libbuilddir = self.builddir installdir = self.installdir libdir = os.path.join(self.installdir, self.prefix.lstrip('/').lstrip('\\'), 'lib') # build user of library self.new_builddir() # replace is needed because meson mangles platform pathes passed via LDFLAGS os.environ["LDFLAGS"] = '-L{}'.format(libdir.replace('\\', '/')) self.init(os.path.join(testdirbase, 'exe')) del os.environ["LDFLAGS"] self.build() self.assertBuildIsNoop() # rebuild library exebuilddir = self.builddir self.installdir = installdir self.builddir = libbuilddir # Microsoft's compiler is quite smart about touching import libs on changes, # so ensure that there is actually a change in symbols. self.setconf('-Dmore_exports=true') self.build() self.install() # no ensure_backend_detects_changes needed because self.setconf did that already # assert user of library will be rebuild self.builddir = exebuilddir self.assertRebuiltTarget('app') def test_conflicting_d_dash_option(self): testdir = os.path.join(self.unit_test_dir, '37 mixed command line args') with self.assertRaises(subprocess.CalledProcessError) as e: self.init(testdir, extra_args=['-Dbindir=foo', '--bindir=bar']) # Just to ensure that we caught the correct error self.assertIn('passed as both', e.stderr) def _test_same_option_twice(self, arg, args): testdir = os.path.join(self.unit_test_dir, '37 mixed command line args') self.init(testdir, extra_args=args) opts = self.introspect('--buildoptions') for item in opts: if item['name'] == arg: self.assertEqual(item['value'], 'bar') return raise Exception('Missing {} value?'.format(arg)) def test_same_dash_option_twice(self): self._test_same_option_twice('bindir', ['--bindir=foo', '--bindir=bar']) def test_same_d_option_twice(self): self._test_same_option_twice('bindir', ['-Dbindir=foo', '-Dbindir=bar']) def test_same_project_d_option_twice(self): self._test_same_option_twice('one', ['-Done=foo', '-Done=bar']) def _test_same_option_twice_configure(self, arg, args): testdir = os.path.join(self.unit_test_dir, '37 mixed command line args') self.init(testdir) self.setconf(args) opts = self.introspect('--buildoptions') for item in opts: if item['name'] == arg: self.assertEqual(item['value'], 'bar') return raise Exception('Missing {} value?'.format(arg)) def test_same_dash_option_twice_configure(self): self._test_same_option_twice_configure( 'bindir', ['--bindir=foo', '--bindir=bar']) def test_same_d_option_twice_configure(self): self._test_same_option_twice_configure( 'bindir', ['-Dbindir=foo', '-Dbindir=bar']) def test_same_project_d_option_twice_configure(self): self._test_same_option_twice_configure( 'one', ['-Done=foo', '-Done=bar']) def test_command_line(self): testdir = os.path.join(self.unit_test_dir, '34 command line') # Verify default values when passing no args self.init(testdir) obj = mesonbuild.coredata.load(self.builddir) self.assertEqual(obj.builtins['default_library'].value, 'static') self.assertEqual(obj.builtins['warning_level'].value, '1') self.assertEqual(obj.user_options['set_sub_opt'].value, True) self.assertEqual(obj.user_options['subp:subp_opt'].value, 'default3') self.wipe() # warning_level is special, it's --warnlevel instead of --warning-level # for historical reasons self.init(testdir, extra_args=['--warnlevel=2']) obj = mesonbuild.coredata.load(self.builddir) self.assertEqual(obj.builtins['warning_level'].value, '2') self.setconf('--warnlevel=3') obj = mesonbuild.coredata.load(self.builddir) self.assertEqual(obj.builtins['warning_level'].value, '3') self.wipe() # But when using -D syntax, it should be 'warning_level' self.init(testdir, extra_args=['-Dwarning_level=2']) obj = mesonbuild.coredata.load(self.builddir) self.assertEqual(obj.builtins['warning_level'].value, '2') self.setconf('-Dwarning_level=3') obj = mesonbuild.coredata.load(self.builddir) self.assertEqual(obj.builtins['warning_level'].value, '3') self.wipe() # Mixing --option and -Doption is forbidden with self.assertRaises(subprocess.CalledProcessError) as cm: self.init(testdir, extra_args=['--warnlevel=1', '-Dwarning_level=3']) self.assertNotEqual(0, cm.exception.returncode) self.assertIn('as both', cm.exception.output) self.init(testdir) with self.assertRaises(subprocess.CalledProcessError) as cm: self.setconf(['--warnlevel=1', '-Dwarning_level=3']) self.assertNotEqual(0, cm.exception.returncode) self.assertIn('as both', cm.exception.output) self.wipe() # --default-library should override default value from project() self.init(testdir, extra_args=['--default-library=both']) obj = mesonbuild.coredata.load(self.builddir) self.assertEqual(obj.builtins['default_library'].value, 'both') self.setconf('--default-library=shared') obj = mesonbuild.coredata.load(self.builddir) self.assertEqual(obj.builtins['default_library'].value, 'shared') if self.backend is Backend.ninja: # reconfigure target works only with ninja backend self.build('reconfigure') obj = mesonbuild.coredata.load(self.builddir) self.assertEqual(obj.builtins['default_library'].value, 'shared') self.wipe() # Should warn on unknown options out = self.init(testdir, extra_args=['-Dbad=1', '-Dfoo=2', '-Dwrong_link_args=foo']) self.assertIn('Unknown options: "bad, foo, wrong_link_args"', out) self.wipe() # Should fail on malformed option with self.assertRaises(subprocess.CalledProcessError) as cm: self.init(testdir, extra_args=['-Dfoo']) self.assertNotEqual(0, cm.exception.returncode) self.assertIn('Option \'foo\' must have a value separated by equals sign.', cm.exception.output) self.init(testdir) with self.assertRaises(subprocess.CalledProcessError) as cm: self.setconf('-Dfoo') self.assertNotEqual(0, cm.exception.returncode) self.assertIn('Option \'foo\' must have a value separated by equals sign.', cm.exception.output) self.wipe() # It is not an error to set wrong option for unknown subprojects or # language because we don't have control on which one will be selected. self.init(testdir, extra_args=['-Dc_wrong=1', '-Dwrong:bad=1', '-Db_wrong=1']) self.wipe() # Test we can set subproject option self.init(testdir, extra_args=['-Dsubp:subp_opt=foo']) obj = mesonbuild.coredata.load(self.builddir) self.assertEqual(obj.user_options['subp:subp_opt'].value, 'foo') self.wipe() # c_args value should be parsed with shlex self.init(testdir, extra_args=['-Dc_args=foo bar "one two"']) obj = mesonbuild.coredata.load(self.builddir) self.assertEqual(obj.compiler_options['c_args'].value, ['foo', 'bar', 'one two']) self.setconf('-Dc_args="foo bar" one two') obj = mesonbuild.coredata.load(self.builddir) self.assertEqual(obj.compiler_options['c_args'].value, ['foo bar', 'one', 'two']) self.wipe() # Setting a 2nd time the same option should override the first value try: self.init(testdir, extra_args=['--bindir=foo', '--bindir=bar', '-Dbuildtype=plain', '-Dbuildtype=release', '-Db_sanitize=address', '-Db_sanitize=thread', '-Dc_args=foo', '-Dc_args=bar']) obj = mesonbuild.coredata.load(self.builddir) self.assertEqual(obj.builtins['bindir'].value, 'bar') self.assertEqual(obj.builtins['buildtype'].value, 'release') self.assertEqual(obj.base_options['b_sanitize'].value, 'thread') self.assertEqual(obj.compiler_options['c_args'].value, ['bar']) self.setconf(['--bindir=bar', '--bindir=foo', '-Dbuildtype=release', '-Dbuildtype=plain', '-Db_sanitize=thread', '-Db_sanitize=address', '-Dc_args=bar', '-Dc_args=foo']) obj = mesonbuild.coredata.load(self.builddir) self.assertEqual(obj.builtins['bindir'].value, 'foo') self.assertEqual(obj.builtins['buildtype'].value, 'plain') self.assertEqual(obj.base_options['b_sanitize'].value, 'address') self.assertEqual(obj.compiler_options['c_args'].value, ['foo']) self.wipe() except KeyError: # Ignore KeyError, it happens on CI for compilers that does not # support b_sanitize. We have to test with a base option because # they used to fail this test with Meson 0.46 an earlier versions. pass def test_feature_check_usage_subprojects(self): testdir = os.path.join(self.unit_test_dir, '41 featurenew subprojects') out = self.init(testdir) # Parent project warns correctly self.assertRegex(out, "WARNING: Project targetting '>=0.45'.*'0.47.0': dict") # Subprojects warn correctly self.assertRegex(out, r"\|WARNING: Project targetting '>=0.40'.*'0.44.0': disabler") self.assertRegex(out, r"\|WARNING: Project targetting '!=0.40'.*'0.44.0': disabler") # Subproject has a new-enough meson_version, no warning self.assertNotRegex(out, "WARNING: Project targetting.*Python") # Ensure a summary is printed in the subproject and the outer project self.assertRegex(out, r"\|WARNING: Project specifies a minimum meson_version '>=0.40'") self.assertRegex(out, r"\| \* 0.44.0: {'disabler'}") self.assertRegex(out, "WARNING: Project specifies a minimum meson_version '>=0.45'") self.assertRegex(out, " * 0.47.0: {'dict'}") def test_configure_file_warnings(self): testdir = os.path.join(self.common_test_dir, "14 configure file") out = self.init(testdir) self.assertRegex(out, "WARNING:.*'empty'.*config.h.in.*not present.*") self.assertRegex(out, "WARNING:.*'FOO_BAR'.*nosubst-nocopy2.txt.in.*not present.*") self.assertRegex(out, "WARNING:.*'empty'.*config.h.in.*not present.*") self.assertRegex(out, "WARNING:.*empty configuration_data.*test.py.in") # Warnings for configuration files that are overwritten. self.assertRegex(out, "WARNING:.*\"double_output.txt\".*overwrites") self.assertRegex(out, "WARNING:.*\"subdir.double_output2.txt\".*overwrites") self.assertNotRegex(out, "WARNING:.*no_write_conflict.txt.*overwrites") self.assertNotRegex(out, "WARNING:.*@BASENAME@.*overwrites") self.assertRegex(out, "WARNING:.*\"sameafterbasename\".*overwrites") # No warnings about empty configuration data objects passed to files with substitutions self.assertNotRegex(out, "WARNING:.*empty configuration_data.*nosubst-nocopy1.txt.in") self.assertNotRegex(out, "WARNING:.*empty configuration_data.*nosubst-nocopy2.txt.in") with open(os.path.join(self.builddir, 'nosubst-nocopy1.txt'), 'rb') as f: self.assertEqual(f.read().strip(), b'/* #undef FOO_BAR */') with open(os.path.join(self.builddir, 'nosubst-nocopy2.txt'), 'rb') as f: self.assertEqual(f.read().strip(), b'') self.assertRegex(out, r"DEPRECATION:.*\['array'\] is invalid.*dict") def test_dirs(self): with tempfile.TemporaryDirectory() as containing: with tempfile.TemporaryDirectory(dir=containing) as srcdir: mfile = os.path.join(srcdir, 'meson.build') of = open(mfile, 'w') of.write("project('foobar', 'c')\n") of.close() pc = subprocess.run(self.setup_command, cwd=srcdir, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) self.assertIn(b'Must specify at least one directory name', pc.stdout) with tempfile.TemporaryDirectory(dir=srcdir) as builddir: subprocess.run(self.setup_command, check=True, cwd=builddir, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) def get_opts_as_dict(self): result = {} for i in self.introspect('--buildoptions'): result[i['name']] = i['value'] return result def test_buildtype_setting(self): testdir = os.path.join(self.common_test_dir, '1 trivial') self.init(testdir) opts = self.get_opts_as_dict() self.assertEqual(opts['buildtype'], 'debug') self.assertEqual(opts['debug'], True) self.setconf('-Ddebug=false') opts = self.get_opts_as_dict() self.assertEqual(opts['debug'], False) self.assertEqual(opts['buildtype'], 'plain') self.assertEqual(opts['optimization'], '0') # Setting optimizations to 3 should cause buildtype # to go to release mode. self.setconf('-Doptimization=3') opts = self.get_opts_as_dict() self.assertEqual(opts['buildtype'], 'release') self.assertEqual(opts['debug'], False) self.assertEqual(opts['optimization'], '3') # Going to debug build type should reset debugging # and optimization self.setconf('-Dbuildtype=debug') opts = self.get_opts_as_dict() self.assertEqual(opts['buildtype'], 'debug') self.assertEqual(opts['debug'], True) self.assertEqual(opts['optimization'], '0') @skipIfNoPkgconfig