run_unittests.py 106 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331
  1. #!/usr/bin/env python3
  2. # Copyright 2016-2017 The Meson development team
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. # http://www.apache.org/licenses/LICENSE-2.0
  7. # Unless required by applicable law or agreed to in writing, software
  8. # distributed under the License is distributed on an "AS IS" BASIS,
  9. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. # See the License for the specific language governing permissions and
  11. # limitations under the License.
  12. import stat
  13. import shlex
  14. import subprocess
  15. import re, json
  16. import tempfile
  17. import os
  18. import shutil
  19. import sys
  20. import unittest
  21. from configparser import ConfigParser
  22. from glob import glob
  23. from pathlib import PurePath
  24. import mesonbuild.mlog
  25. import mesonbuild.compilers
  26. import mesonbuild.environment
  27. import mesonbuild.mesonlib
  28. import mesonbuild.coredata
  29. from mesonbuild.interpreter import ObjectHolder
  30. from mesonbuild.mesonlib import is_linux, is_windows, is_osx, is_cygwin, windows_proof_rmtree
  31. from mesonbuild.mesonlib import python_command, meson_command
  32. from mesonbuild.environment import Environment
  33. from mesonbuild.dependencies import DependencyException
  34. from mesonbuild.dependencies import PkgConfigDependency, ExternalProgram
  35. from run_tests import exe_suffix, get_fake_options, FakeEnvironment
  36. from run_tests import get_builddir_target_args, get_backend_commands, Backend
  37. from run_tests import ensure_backend_detects_changes, run_configure, meson_exe
  38. from run_tests import should_run_linux_cross_tests
  39. def get_dynamic_section_entry(fname, entry):
  40. try:
  41. raw_out = subprocess.check_output(['readelf', '-d', fname],
  42. universal_newlines=True)
  43. except FileNotFoundError:
  44. # FIXME: Try using depfixer.py:Elf() as a fallback
  45. raise unittest.SkipTest('readelf not found')
  46. pattern = re.compile(entry + r': \[(.*?)\]')
  47. for line in raw_out.split('\n'):
  48. m = pattern.search(line)
  49. if m is not None:
  50. return m.group(1)
  51. raise RuntimeError('Could not determine {}:\n\n'.format(entry) + raw_out)
  52. def get_soname(fname):
  53. return get_dynamic_section_entry(fname, 'soname')
  54. def get_rpath(fname):
  55. return get_dynamic_section_entry(fname, r'(?:rpath|runpath)')
  56. class InternalTests(unittest.TestCase):
  57. def test_version_number(self):
  58. searchfunc = mesonbuild.environment.search_version
  59. self.assertEqual(searchfunc('foobar 1.2.3'), '1.2.3')
  60. self.assertEqual(searchfunc('1.2.3'), '1.2.3')
  61. self.assertEqual(searchfunc('foobar 2016.10.28 1.2.3'), '1.2.3')
  62. self.assertEqual(searchfunc('2016.10.28 1.2.3'), '1.2.3')
  63. self.assertEqual(searchfunc('foobar 2016.10.128'), 'unknown version')
  64. self.assertEqual(searchfunc('2016.10.128'), 'unknown version')
  65. def test_mode_symbolic_to_bits(self):
  66. modefunc = mesonbuild.mesonlib.FileMode.perms_s_to_bits
  67. self.assertEqual(modefunc('---------'), 0)
  68. self.assertEqual(modefunc('r--------'), stat.S_IRUSR)
  69. self.assertEqual(modefunc('---r-----'), stat.S_IRGRP)
  70. self.assertEqual(modefunc('------r--'), stat.S_IROTH)
  71. self.assertEqual(modefunc('-w-------'), stat.S_IWUSR)
  72. self.assertEqual(modefunc('----w----'), stat.S_IWGRP)
  73. self.assertEqual(modefunc('-------w-'), stat.S_IWOTH)
  74. self.assertEqual(modefunc('--x------'), stat.S_IXUSR)
  75. self.assertEqual(modefunc('-----x---'), stat.S_IXGRP)
  76. self.assertEqual(modefunc('--------x'), stat.S_IXOTH)
  77. self.assertEqual(modefunc('--S------'), stat.S_ISUID)
  78. self.assertEqual(modefunc('-----S---'), stat.S_ISGID)
  79. self.assertEqual(modefunc('--------T'), stat.S_ISVTX)
  80. self.assertEqual(modefunc('--s------'), stat.S_ISUID | stat.S_IXUSR)
  81. self.assertEqual(modefunc('-----s---'), stat.S_ISGID | stat.S_IXGRP)
  82. self.assertEqual(modefunc('--------t'), stat.S_ISVTX | stat.S_IXOTH)
  83. self.assertEqual(modefunc('rwx------'), stat.S_IRWXU)
  84. self.assertEqual(modefunc('---rwx---'), stat.S_IRWXG)
  85. self.assertEqual(modefunc('------rwx'), stat.S_IRWXO)
  86. # We could keep listing combinations exhaustively but that seems
  87. # tedious and pointless. Just test a few more.
  88. self.assertEqual(modefunc('rwxr-xr-x'),
  89. stat.S_IRWXU |
  90. stat.S_IRGRP | stat.S_IXGRP |
  91. stat.S_IROTH | stat.S_IXOTH)
  92. self.assertEqual(modefunc('rw-r--r--'),
  93. stat.S_IRUSR | stat.S_IWUSR |
  94. stat.S_IRGRP |
  95. stat.S_IROTH)
  96. self.assertEqual(modefunc('rwsr-x---'),
  97. stat.S_IRWXU | stat.S_ISUID |
  98. stat.S_IRGRP | stat.S_IXGRP)
  99. def test_compiler_args_class(self):
  100. cargsfunc = mesonbuild.compilers.CompilerArgs
  101. c = mesonbuild.compilers.CCompiler([], 'fake', False)
  102. # Test that bad initialization fails
  103. self.assertRaises(TypeError, cargsfunc, [])
  104. self.assertRaises(TypeError, cargsfunc, [], [])
  105. self.assertRaises(TypeError, cargsfunc, c, [], [])
  106. # Test that empty initialization works
  107. a = cargsfunc(c)
  108. self.assertEqual(a, [])
  109. # Test that list initialization works
  110. a = cargsfunc(['-I.', '-I..'], c)
  111. self.assertEqual(a, ['-I.', '-I..'])
  112. # Test that there is no de-dup on initialization
  113. self.assertEqual(cargsfunc(['-I.', '-I.'], c), ['-I.', '-I.'])
  114. ## Test that appending works
  115. a.append('-I..')
  116. self.assertEqual(a, ['-I..', '-I.'])
  117. a.append('-O3')
  118. self.assertEqual(a, ['-I..', '-I.', '-O3'])
  119. ## Test that in-place addition works
  120. a += ['-O2', '-O2']
  121. self.assertEqual(a, ['-I..', '-I.', '-O3', '-O2', '-O2'])
  122. # Test that removal works
  123. a.remove('-O2')
  124. self.assertEqual(a, ['-I..', '-I.', '-O3', '-O2'])
  125. # Test that de-dup happens on addition
  126. a += ['-Ifoo', '-Ifoo']
  127. self.assertEqual(a, ['-Ifoo', '-I..', '-I.', '-O3', '-O2'])
  128. # .extend() is just +=, so we don't test it
  129. ## Test that addition works
  130. # Test that adding a list with just one old arg works and yields the same array
  131. a = a + ['-Ifoo']
  132. self.assertEqual(a, ['-Ifoo', '-I..', '-I.', '-O3', '-O2'])
  133. # Test that adding a list with one arg new and one old works
  134. a = a + ['-Ifoo', '-Ibaz']
  135. self.assertEqual(a, ['-Ifoo', '-Ibaz', '-I..', '-I.', '-O3', '-O2'])
  136. # Test that adding args that must be prepended and appended works
  137. a = a + ['-Ibar', '-Wall']
  138. self.assertEqual(a, ['-Ibar', '-Ifoo', '-Ibaz', '-I..', '-I.', '-O3', '-O2', '-Wall'])
  139. ## Test that reflected addition works
  140. # Test that adding to a list with just one old arg works and yields the same array
  141. a = ['-Ifoo'] + a
  142. self.assertEqual(a, ['-Ibar', '-Ifoo', '-Ibaz', '-I..', '-I.', '-O3', '-O2', '-Wall'])
  143. # Test that adding to a list with just one new arg that is not pre-pended works
  144. a = ['-Werror'] + a
  145. self.assertEqual(a, ['-Ibar', '-Ifoo', '-Ibaz', '-I..', '-I.', '-Werror', '-O3', '-O2', '-Wall'])
  146. # Test that adding to a list with two new args preserves the order
  147. a = ['-Ldir', '-Lbah'] + a
  148. self.assertEqual(a, ['-Ibar', '-Ifoo', '-Ibaz', '-I..', '-I.', '-Ldir', '-Lbah', '-Werror', '-O3', '-O2', '-Wall'])
  149. # Test that adding to a list with old args does nothing
  150. a = ['-Ibar', '-Ibaz', '-Ifoo'] + a
  151. self.assertEqual(a, ['-Ibar', '-Ifoo', '-Ibaz', '-I..', '-I.', '-Ldir', '-Lbah', '-Werror', '-O3', '-O2', '-Wall'])
  152. ## Test that adding libraries works
  153. l = cargsfunc(c, ['-Lfoodir', '-lfoo'])
  154. self.assertEqual(l, ['-Lfoodir', '-lfoo'])
  155. # Adding a library and a libpath appends both correctly
  156. l += ['-Lbardir', '-lbar']
  157. self.assertEqual(l, ['-Lbardir', '-Lfoodir', '-lfoo', '-lbar'])
  158. # Adding the same library again does nothing
  159. l += ['-lbar']
  160. self.assertEqual(l, ['-Lbardir', '-Lfoodir', '-lfoo', '-lbar'])
  161. ## Test that 'direct' append and extend works
  162. l = cargsfunc(c, ['-Lfoodir', '-lfoo'])
  163. self.assertEqual(l, ['-Lfoodir', '-lfoo'])
  164. # Direct-adding a library and a libpath appends both correctly
  165. l.extend_direct(['-Lbardir', '-lbar'])
  166. self.assertEqual(l, ['-Lfoodir', '-lfoo', '-Lbardir', '-lbar'])
  167. # Direct-adding the same library again still adds it
  168. l.append_direct('-lbar')
  169. self.assertEqual(l, ['-Lfoodir', '-lfoo', '-Lbardir', '-lbar', '-lbar'])
  170. def test_commonpath(self):
  171. from os.path import sep
  172. commonpath = mesonbuild.mesonlib.commonpath
  173. self.assertRaises(ValueError, commonpath, [])
  174. self.assertEqual(commonpath(['/usr', '/usr']), sep + 'usr')
  175. self.assertEqual(commonpath(['/usr', '/usr/']), sep + 'usr')
  176. self.assertEqual(commonpath(['/usr', '/usr/bin']), sep + 'usr')
  177. self.assertEqual(commonpath(['/usr/', '/usr/bin']), sep + 'usr')
  178. self.assertEqual(commonpath(['/usr/./', '/usr/bin']), sep + 'usr')
  179. self.assertEqual(commonpath(['/usr/bin', '/usr/bin']), sep + 'usr' + sep + 'bin')
  180. self.assertEqual(commonpath(['/usr//bin', '/usr/bin']), sep + 'usr' + sep + 'bin')
  181. self.assertEqual(commonpath(['/usr/./bin', '/usr/bin']), sep + 'usr' + sep + 'bin')
  182. self.assertEqual(commonpath(['/usr/local', '/usr/lib']), sep + 'usr')
  183. self.assertEqual(commonpath(['/usr', '/bin']), sep)
  184. self.assertEqual(commonpath(['/usr', 'bin']), '')
  185. self.assertEqual(commonpath(['blam', 'bin']), '')
  186. prefix = '/some/path/to/prefix'
  187. libdir = '/some/path/to/prefix/libdir'
  188. self.assertEqual(commonpath([prefix, libdir]), str(PurePath(prefix)))
  189. def test_string_templates_substitution(self):
  190. dictfunc = mesonbuild.mesonlib.get_filenames_templates_dict
  191. substfunc = mesonbuild.mesonlib.substitute_values
  192. ME = mesonbuild.mesonlib.MesonException
  193. # Identity
  194. self.assertEqual(dictfunc([], []), {})
  195. # One input, no outputs
  196. inputs = ['bar/foo.c.in']
  197. outputs = []
  198. ret = dictfunc(inputs, outputs)
  199. d = {'@INPUT@': inputs, '@INPUT0@': inputs[0],
  200. '@PLAINNAME@': 'foo.c.in', '@BASENAME@': 'foo.c'}
  201. # Check dictionary
  202. self.assertEqual(ret, d)
  203. # Check substitutions
  204. cmd = ['some', 'ordinary', 'strings']
  205. self.assertEqual(substfunc(cmd, d), cmd)
  206. cmd = ['@INPUT@.out', 'ordinary', 'strings']
  207. self.assertEqual(substfunc(cmd, d), [inputs[0] + '.out'] + cmd[1:])
  208. cmd = ['@INPUT0@.out', '@PLAINNAME@.ok', 'strings']
  209. self.assertEqual(substfunc(cmd, d),
  210. [inputs[0] + '.out'] + [d['@PLAINNAME@'] + '.ok'] + cmd[2:])
  211. cmd = ['@INPUT@', '@BASENAME@.hah', 'strings']
  212. self.assertEqual(substfunc(cmd, d),
  213. inputs + [d['@BASENAME@'] + '.hah'] + cmd[2:])
  214. cmd = ['@OUTPUT@']
  215. self.assertRaises(ME, substfunc, cmd, d)
  216. # One input, one output
  217. inputs = ['bar/foo.c.in']
  218. outputs = ['out.c']
  219. ret = dictfunc(inputs, outputs)
  220. d = {'@INPUT@': inputs, '@INPUT0@': inputs[0],
  221. '@PLAINNAME@': 'foo.c.in', '@BASENAME@': 'foo.c',
  222. '@OUTPUT@': outputs, '@OUTPUT0@': outputs[0], '@OUTDIR@': '.'}
  223. # Check dictionary
  224. self.assertEqual(ret, d)
  225. # Check substitutions
  226. cmd = ['some', 'ordinary', 'strings']
  227. self.assertEqual(substfunc(cmd, d), cmd)
  228. cmd = ['@INPUT@.out', '@OUTPUT@', 'strings']
  229. self.assertEqual(substfunc(cmd, d),
  230. [inputs[0] + '.out'] + outputs + cmd[2:])
  231. cmd = ['@INPUT0@.out', '@PLAINNAME@.ok', '@OUTPUT0@']
  232. self.assertEqual(substfunc(cmd, d),
  233. [inputs[0] + '.out', d['@PLAINNAME@'] + '.ok'] + outputs)
  234. cmd = ['@INPUT@', '@BASENAME@.hah', 'strings']
  235. self.assertEqual(substfunc(cmd, d),
  236. inputs + [d['@BASENAME@'] + '.hah'] + cmd[2:])
  237. # One input, one output with a subdir
  238. outputs = ['dir/out.c']
  239. ret = dictfunc(inputs, outputs)
  240. d = {'@INPUT@': inputs, '@INPUT0@': inputs[0],
  241. '@PLAINNAME@': 'foo.c.in', '@BASENAME@': 'foo.c',
  242. '@OUTPUT@': outputs, '@OUTPUT0@': outputs[0], '@OUTDIR@': 'dir'}
  243. # Check dictionary
  244. self.assertEqual(ret, d)
  245. # Two inputs, no outputs
  246. inputs = ['bar/foo.c.in', 'baz/foo.c.in']
  247. outputs = []
  248. ret = dictfunc(inputs, outputs)
  249. d = {'@INPUT@': inputs, '@INPUT0@': inputs[0], '@INPUT1@': inputs[1]}
  250. # Check dictionary
  251. self.assertEqual(ret, d)
  252. # Check substitutions
  253. cmd = ['some', 'ordinary', 'strings']
  254. self.assertEqual(substfunc(cmd, d), cmd)
  255. cmd = ['@INPUT@', 'ordinary', 'strings']
  256. self.assertEqual(substfunc(cmd, d), inputs + cmd[1:])
  257. cmd = ['@INPUT0@.out', 'ordinary', 'strings']
  258. self.assertEqual(substfunc(cmd, d), [inputs[0] + '.out'] + cmd[1:])
  259. cmd = ['@INPUT0@.out', '@INPUT1@.ok', 'strings']
  260. self.assertEqual(substfunc(cmd, d), [inputs[0] + '.out', inputs[1] + '.ok'] + cmd[2:])
  261. cmd = ['@INPUT0@', '@INPUT1@', 'strings']
  262. self.assertEqual(substfunc(cmd, d), inputs + cmd[2:])
  263. # Many inputs, can't use @INPUT@ like this
  264. cmd = ['@INPUT@.out', 'ordinary', 'strings']
  265. self.assertRaises(ME, substfunc, cmd, d)
  266. # Not enough inputs
  267. cmd = ['@INPUT2@.out', 'ordinary', 'strings']
  268. self.assertRaises(ME, substfunc, cmd, d)
  269. # Too many inputs
  270. cmd = ['@PLAINNAME@']
  271. self.assertRaises(ME, substfunc, cmd, d)
  272. cmd = ['@BASENAME@']
  273. self.assertRaises(ME, substfunc, cmd, d)
  274. # No outputs
  275. cmd = ['@OUTPUT@']
  276. self.assertRaises(ME, substfunc, cmd, d)
  277. cmd = ['@OUTPUT0@']
  278. self.assertRaises(ME, substfunc, cmd, d)
  279. cmd = ['@OUTDIR@']
  280. self.assertRaises(ME, substfunc, cmd, d)
  281. # Two inputs, one output
  282. outputs = ['dir/out.c']
  283. ret = dictfunc(inputs, outputs)
  284. d = {'@INPUT@': inputs, '@INPUT0@': inputs[0], '@INPUT1@': inputs[1],
  285. '@OUTPUT@': outputs, '@OUTPUT0@': outputs[0], '@OUTDIR@': 'dir'}
  286. # Check dictionary
  287. self.assertEqual(ret, d)
  288. # Check substitutions
  289. cmd = ['some', 'ordinary', 'strings']
  290. self.assertEqual(substfunc(cmd, d), cmd)
  291. cmd = ['@OUTPUT@', 'ordinary', 'strings']
  292. self.assertEqual(substfunc(cmd, d), outputs + cmd[1:])
  293. cmd = ['@OUTPUT@.out', 'ordinary', 'strings']
  294. self.assertEqual(substfunc(cmd, d), [outputs[0] + '.out'] + cmd[1:])
  295. cmd = ['@OUTPUT0@.out', '@INPUT1@.ok', 'strings']
  296. self.assertEqual(substfunc(cmd, d), [outputs[0] + '.out', inputs[1] + '.ok'] + cmd[2:])
  297. # Many inputs, can't use @INPUT@ like this
  298. cmd = ['@INPUT@.out', 'ordinary', 'strings']
  299. self.assertRaises(ME, substfunc, cmd, d)
  300. # Not enough inputs
  301. cmd = ['@INPUT2@.out', 'ordinary', 'strings']
  302. self.assertRaises(ME, substfunc, cmd, d)
  303. # Not enough outputs
  304. cmd = ['@OUTPUT2@.out', 'ordinary', 'strings']
  305. self.assertRaises(ME, substfunc, cmd, d)
  306. # Two inputs, two outputs
  307. outputs = ['dir/out.c', 'dir/out2.c']
  308. ret = dictfunc(inputs, outputs)
  309. d = {'@INPUT@': inputs, '@INPUT0@': inputs[0], '@INPUT1@': inputs[1],
  310. '@OUTPUT@': outputs, '@OUTPUT0@': outputs[0], '@OUTPUT1@': outputs[1],
  311. '@OUTDIR@': 'dir'}
  312. # Check dictionary
  313. self.assertEqual(ret, d)
  314. # Check substitutions
  315. cmd = ['some', 'ordinary', 'strings']
  316. self.assertEqual(substfunc(cmd, d), cmd)
  317. cmd = ['@OUTPUT@', 'ordinary', 'strings']
  318. self.assertEqual(substfunc(cmd, d), outputs + cmd[1:])
  319. cmd = ['@OUTPUT0@', '@OUTPUT1@', 'strings']
  320. self.assertEqual(substfunc(cmd, d), outputs + cmd[2:])
  321. cmd = ['@OUTPUT0@.out', '@INPUT1@.ok', '@OUTDIR@']
  322. self.assertEqual(substfunc(cmd, d), [outputs[0] + '.out', inputs[1] + '.ok', 'dir'])
  323. # Many inputs, can't use @INPUT@ like this
  324. cmd = ['@INPUT@.out', 'ordinary', 'strings']
  325. self.assertRaises(ME, substfunc, cmd, d)
  326. # Not enough inputs
  327. cmd = ['@INPUT2@.out', 'ordinary', 'strings']
  328. self.assertRaises(ME, substfunc, cmd, d)
  329. # Not enough outputs
  330. cmd = ['@OUTPUT2@.out', 'ordinary', 'strings']
  331. self.assertRaises(ME, substfunc, cmd, d)
  332. # Many outputs, can't use @OUTPUT@ like this
  333. cmd = ['@OUTPUT@.out', 'ordinary', 'strings']
  334. self.assertRaises(ME, substfunc, cmd, d)
  335. def test_needs_exe_wrapper_override(self):
  336. config = ConfigParser()
  337. config['binaries'] = {
  338. 'c': '\'/usr/bin/gcc\'',
  339. }
  340. config['host_machine'] = {
  341. 'system': '\'linux\'',
  342. 'cpu_family': '\'arm\'',
  343. 'cpu': '\'armv7\'',
  344. 'endian': '\'little\'',
  345. }
  346. # Can not be used as context manager because we need to
  347. # open it a second time and this is not possible on
  348. # Windows.
  349. configfile = tempfile.NamedTemporaryFile(mode='w+', delete=False)
  350. configfilename = configfile.name
  351. config.write(configfile)
  352. configfile.flush()
  353. configfile.close()
  354. detected_value = mesonbuild.environment.CrossBuildInfo(configfile.name).need_exe_wrapper()
  355. os.unlink(configfilename)
  356. desired_value = not detected_value
  357. config['properties'] = {
  358. 'needs_exe_wrapper': 'true' if desired_value else 'false'
  359. }
  360. configfile = tempfile.NamedTemporaryFile(mode='w+', delete=False)
  361. configfilename = configfile.name
  362. config.write(configfile)
  363. configfile.close()
  364. forced_value = mesonbuild.environment.CrossBuildInfo(configfile.name).need_exe_wrapper()
  365. os.unlink(configfilename)
  366. self.assertEqual(forced_value, desired_value)
  367. def test_listify(self):
  368. listify = mesonbuild.mesonlib.listify
  369. # Test sanity
  370. self.assertEqual([1], listify(1))
  371. self.assertEqual([], listify([]))
  372. self.assertEqual([1], listify([1]))
  373. # Test flattening
  374. self.assertEqual([1, 2, 3], listify([1, [2, 3]]))
  375. self.assertEqual([1, 2, 3], listify([1, [2, [3]]]))
  376. self.assertEqual([1, [2, [3]]], listify([1, [2, [3]]], flatten=False))
  377. # Test flattening and unholdering
  378. holder1 = ObjectHolder(1)
  379. holder3 = ObjectHolder(3)
  380. self.assertEqual([holder1], listify(holder1))
  381. self.assertEqual([holder1], listify([holder1]))
  382. self.assertEqual([holder1, 2], listify([holder1, 2]))
  383. self.assertEqual([holder1, 2, 3], listify([holder1, 2, [3]]))
  384. self.assertEqual([1], listify(holder1, unholder=True))
  385. self.assertEqual([1], listify([holder1], unholder=True))
  386. self.assertEqual([1, 2], listify([holder1, 2], unholder=True))
  387. self.assertEqual([1, 2, 3], listify([holder1, 2, [holder3]], unholder=True))
  388. # Unholding doesn't work recursively when not flattening
  389. self.assertEqual([1, [2], [holder3]], listify([holder1, [2], [holder3]], unholder=True, flatten=False))
  390. def test_extract_as_list(self):
  391. extract = mesonbuild.mesonlib.extract_as_list
  392. # Test sanity
  393. kwargs = {'sources': [1, 2, 3]}
  394. self.assertEqual([1, 2, 3], extract(kwargs, 'sources'))
  395. self.assertEqual(kwargs, {'sources': [1, 2, 3]})
  396. self.assertEqual([1, 2, 3], extract(kwargs, 'sources', pop=True))
  397. self.assertEqual(kwargs, {})
  398. # Test unholding
  399. holder3 = ObjectHolder(3)
  400. kwargs = {'sources': [1, 2, holder3]}
  401. self.assertEqual([1, 2, 3], extract(kwargs, 'sources', unholder=True))
  402. self.assertEqual(kwargs, {'sources': [1, 2, holder3]})
  403. self.assertEqual([1, 2, 3], extract(kwargs, 'sources', unholder=True, pop=True))
  404. self.assertEqual(kwargs, {})
  405. # Test listification
  406. kwargs = {'sources': [1, 2, 3], 'pch_sources': [4, 5, 6]}
  407. self.assertEqual([[1, 2, 3], [4, 5, 6]], extract(kwargs, 'sources', 'pch_sources'))
  408. class BasePlatformTests(unittest.TestCase):
  409. def setUp(self):
  410. super().setUp()
  411. src_root = os.path.dirname(__file__)
  412. src_root = os.path.join(os.getcwd(), src_root)
  413. self.src_root = src_root
  414. # In case the directory is inside a symlinked directory, find the real
  415. # path otherwise we might not find the srcdir from inside the builddir.
  416. self.builddir = os.path.realpath(tempfile.mkdtemp())
  417. self.logdir = os.path.join(self.builddir, 'meson-logs')
  418. self.prefix = '/usr'
  419. self.libdir = os.path.join(self.prefix, 'lib')
  420. self.installdir = os.path.join(self.builddir, 'install')
  421. self.distdir = os.path.join(self.builddir, 'meson-dist')
  422. # Get the backend
  423. # FIXME: Extract this from argv?
  424. self.backend = getattr(Backend, os.environ.get('MESON_UNIT_TEST_BACKEND', 'ninja'))
  425. self.meson_mainfile = os.path.join(src_root, 'meson.py')
  426. self.meson_args = ['--backend=' + self.backend.name]
  427. self.meson_command = meson_command + self.meson_args
  428. self.mconf_command = meson_command + ['configure']
  429. self.mintro_command = meson_command + ['introspect']
  430. self.mtest_command = meson_command + ['test', '-C', self.builddir]
  431. # Backend-specific build commands
  432. self.build_command, self.clean_command, self.test_command, self.install_command, \
  433. self.uninstall_command = get_backend_commands(self.backend)
  434. # Test directories
  435. self.common_test_dir = os.path.join(src_root, 'test cases/common')
  436. self.vala_test_dir = os.path.join(src_root, 'test cases/vala')
  437. self.framework_test_dir = os.path.join(src_root, 'test cases/frameworks')
  438. self.unit_test_dir = os.path.join(src_root, 'test cases/unit')
  439. # Misc stuff
  440. self.orig_env = os.environ.copy()
  441. if self.backend is Backend.ninja:
  442. self.no_rebuild_stdout = 'ninja: no work to do.'
  443. else:
  444. # VS doesn't have a stable output when no changes are done
  445. # XCode backend is untested with unit tests, help welcome!
  446. self.no_rebuild_stdout = 'UNKNOWN BACKEND {!r}'.format(self.backend.name)
  447. def _print_meson_log(self):
  448. log = os.path.join(self.logdir, 'meson-log.txt')
  449. if not os.path.isfile(log):
  450. print("{!r} doesn't exist".format(log))
  451. return
  452. with open(log, 'r', encoding='utf-8') as f:
  453. print(f.read())
  454. def tearDown(self):
  455. try:
  456. windows_proof_rmtree(self.builddir)
  457. except FileNotFoundError:
  458. pass
  459. os.environ = self.orig_env
  460. super().tearDown()
  461. def _run(self, command, workdir=None):
  462. '''
  463. Run a command while printing the stdout and stderr to stdout,
  464. and also return a copy of it
  465. '''
  466. p = subprocess.Popen(command, stdout=subprocess.PIPE,
  467. stderr=subprocess.STDOUT, env=os.environ.copy(),
  468. universal_newlines=True, cwd=workdir)
  469. output = p.communicate()[0]
  470. print(output)
  471. if p.returncode != 0:
  472. if 'MESON_SKIP_TEST' in output:
  473. raise unittest.SkipTest('Project requested skipping.')
  474. raise subprocess.CalledProcessError(p.returncode, command)
  475. return output
  476. def init(self, srcdir, extra_args=None, default_args=True, inprocess=False):
  477. self.assertPathExists(srcdir)
  478. if extra_args is None:
  479. extra_args = []
  480. if not isinstance(extra_args, list):
  481. extra_args = [extra_args]
  482. args = [srcdir, self.builddir]
  483. if default_args:
  484. args += ['--prefix', self.prefix,
  485. '--libdir', self.libdir]
  486. self.privatedir = os.path.join(self.builddir, 'meson-private')
  487. if inprocess:
  488. try:
  489. out = run_configure(self.meson_mainfile, self.meson_args + args + extra_args)[1]
  490. except:
  491. self._print_meson_log()
  492. raise
  493. finally:
  494. # Close log file to satisfy Windows file locking
  495. mesonbuild.mlog.shutdown()
  496. mesonbuild.mlog.log_dir = None
  497. mesonbuild.mlog.log_file = None
  498. else:
  499. try:
  500. out = self._run(self.meson_command + args + extra_args)
  501. except unittest.SkipTest:
  502. raise unittest.SkipTest('Project requested skipping: ' + srcdir)
  503. except:
  504. self._print_meson_log()
  505. raise
  506. return out
  507. def build(self, target=None, extra_args=None):
  508. if extra_args is None:
  509. extra_args = []
  510. # Add arguments for building the target (if specified),
  511. # and using the build dir (if required, with VS)
  512. args = get_builddir_target_args(self.backend, self.builddir, target)
  513. return self._run(self.build_command + args + extra_args, workdir=self.builddir)
  514. def clean(self):
  515. dir_args = get_builddir_target_args(self.backend, self.builddir, None)
  516. self._run(self.clean_command + dir_args, workdir=self.builddir)
  517. def run_tests(self):
  518. self._run(self.test_command, workdir=self.builddir)
  519. def install(self):
  520. if self.backend is not Backend.ninja:
  521. raise unittest.SkipTest('{!r} backend can\'t install files'.format(self.backend.name))
  522. os.environ['DESTDIR'] = self.installdir
  523. self._run(self.install_command, workdir=self.builddir)
  524. def uninstall(self):
  525. self._run(self.uninstall_command, workdir=self.builddir)
  526. def run_target(self, target):
  527. '''
  528. Run a Ninja target while printing the stdout and stderr to stdout,
  529. and also return a copy of it
  530. '''
  531. return self.build(target=target)
  532. def setconf(self, arg, will_build=True):
  533. if will_build:
  534. ensure_backend_detects_changes(self.backend)
  535. self._run(self.mconf_command + [arg, self.builddir])
  536. def wipe(self):
  537. windows_proof_rmtree(self.builddir)
  538. def utime(self, f):
  539. ensure_backend_detects_changes(self.backend)
  540. os.utime(f)
  541. def get_compdb(self):
  542. if self.backend is not Backend.ninja:
  543. raise unittest.SkipTest('Compiler db not available with {} backend'.format(self.backend.name))
  544. with open(os.path.join(self.builddir, 'compile_commands.json')) as ifile:
  545. contents = json.load(ifile)
  546. # If Ninja is using .rsp files, generate them, read their contents, and
  547. # replace it as the command for all compile commands in the parsed json.
  548. if len(contents) > 0 and contents[0]['command'].endswith('.rsp'):
  549. # Pretend to build so that the rsp files are generated
  550. self.build(extra_args=['-d', 'keeprsp', '-n'])
  551. for each in contents:
  552. # Extract the actual command from the rsp file
  553. compiler, rsp = each['command'].split(' @')
  554. rsp = os.path.join(self.builddir, rsp)
  555. # Replace the command with its contents
  556. with open(rsp, 'r', encoding='utf-8') as f:
  557. each['command'] = compiler + ' ' + f.read()
  558. return contents
  559. def get_meson_log(self):
  560. with open(os.path.join(self.builddir, 'meson-logs', 'meson-log.txt')) as f:
  561. return f.readlines()
  562. def get_meson_log_compiler_checks(self):
  563. '''
  564. Fetch a list command-lines run by meson for compiler checks.
  565. Each command-line is returned as a list of arguments.
  566. '''
  567. log = self.get_meson_log()
  568. prefix = 'Command line:'
  569. cmds = [l[len(prefix):].split() for l in log if l.startswith(prefix)]
  570. return cmds
  571. def introspect(self, arg):
  572. out = subprocess.check_output(self.mintro_command + [arg, self.builddir],
  573. universal_newlines=True)
  574. return json.loads(out)
  575. def assertPathEqual(self, path1, path2):
  576. '''
  577. Handles a lot of platform-specific quirks related to paths such as
  578. separator, case-sensitivity, etc.
  579. '''
  580. self.assertEqual(PurePath(path1), PurePath(path2))
  581. def assertPathBasenameEqual(self, path, basename):
  582. msg = '{!r} does not end with {!r}'.format(path, basename)
  583. # We cannot use os.path.basename because it returns '' when the path
  584. # ends with '/' for some silly reason. This is not how the UNIX utility
  585. # `basename` works.
  586. path_basename = PurePath(path).parts[-1]
  587. self.assertEqual(PurePath(path_basename), PurePath(basename), msg)
  588. def assertBuildIsNoop(self):
  589. ret = self.build()
  590. if self.backend is Backend.ninja:
  591. self.assertEqual(ret.split('\n')[-2], self.no_rebuild_stdout)
  592. elif self.backend is Backend.vs:
  593. # Ensure that some target said that no rebuild was done
  594. self.assertIn('CustomBuild:\n All outputs are up-to-date.', ret)
  595. self.assertIn('ClCompile:\n All outputs are up-to-date.', ret)
  596. self.assertIn('Link:\n All outputs are up-to-date.', ret)
  597. # Ensure that no targets were built
  598. clre = re.compile('ClCompile:\n [^\n]*cl', flags=re.IGNORECASE)
  599. linkre = re.compile('Link:\n [^\n]*link', flags=re.IGNORECASE)
  600. self.assertNotRegex(ret, clre)
  601. self.assertNotRegex(ret, linkre)
  602. elif self.backend is Backend.xcode:
  603. raise unittest.SkipTest('Please help us fix this test on the xcode backend')
  604. else:
  605. raise RuntimeError('Invalid backend: {!r}'.format(self.backend.name))
  606. def assertRebuiltTarget(self, target):
  607. ret = self.build()
  608. if self.backend is Backend.ninja:
  609. self.assertIn('Linking target {}'.format(target), ret)
  610. elif self.backend is Backend.vs:
  611. # Ensure that this target was rebuilt
  612. clre = re.compile('ClCompile:\n [^\n]*cl[^\n]*' + target, flags=re.IGNORECASE)
  613. linkre = re.compile('Link:\n [^\n]*link[^\n]*' + target, flags=re.IGNORECASE)
  614. self.assertRegex(ret, clre)
  615. self.assertRegex(ret, linkre)
  616. elif self.backend is Backend.xcode:
  617. raise unittest.SkipTest('Please help us fix this test on the xcode backend')
  618. else:
  619. raise RuntimeError('Invalid backend: {!r}'.format(self.backend.name))
  620. def assertPathExists(self, path):
  621. m = 'Path {!r} should exist'.format(path)
  622. self.assertTrue(os.path.exists(path), msg=m)
  623. def assertPathDoesNotExist(self, path):
  624. m = 'Path {!r} should not exist'.format(path)
  625. self.assertFalse(os.path.exists(path), msg=m)
  626. class AllPlatformTests(BasePlatformTests):
  627. '''
  628. Tests that should run on all platforms
  629. '''
  630. def test_default_options_prefix(self):
  631. '''
  632. Tests that setting a prefix in default_options in project() works.
  633. Can't be an ordinary test because we pass --prefix to meson there.
  634. https://github.com/mesonbuild/meson/issues/1349
  635. '''
  636. testdir = os.path.join(self.common_test_dir, '94 default options')
  637. self.init(testdir, default_args=False)
  638. opts = self.introspect('--buildoptions')
  639. for opt in opts:
  640. if opt['name'] == 'prefix':
  641. prefix = opt['value']
  642. self.assertEqual(prefix, '/absoluteprefix')
  643. def test_absolute_prefix_libdir(self):
  644. '''
  645. Tests that setting absolute paths for --prefix and --libdir work. Can't
  646. be an ordinary test because these are set via the command-line.
  647. https://github.com/mesonbuild/meson/issues/1341
  648. https://github.com/mesonbuild/meson/issues/1345
  649. '''
  650. testdir = os.path.join(self.common_test_dir, '94 default options')
  651. prefix = '/someabs'
  652. libdir = 'libdir'
  653. extra_args = ['--prefix=' + prefix,
  654. # This can just be a relative path, but we want to test
  655. # that passing this as an absolute path also works
  656. '--libdir=' + prefix + '/' + libdir]
  657. self.init(testdir, extra_args, default_args=False)
  658. opts = self.introspect('--buildoptions')
  659. for opt in opts:
  660. if opt['name'] == 'prefix':
  661. self.assertEqual(prefix, opt['value'])
  662. elif opt['name'] == 'libdir':
  663. self.assertEqual(libdir, opt['value'])
  664. def test_libdir_must_be_inside_prefix(self):
  665. '''
  666. Tests that libdir is forced to be inside prefix no matter how it is set.
  667. Must be a unit test for obvious reasons.
  668. '''
  669. testdir = os.path.join(self.common_test_dir, '1 trivial')
  670. # libdir being inside prefix is ok
  671. args = ['--prefix', '/opt', '--libdir', '/opt/lib32']
  672. self.init(testdir, args)
  673. self.wipe()
  674. # libdir not being inside prefix is not ok
  675. args = ['--prefix', '/usr', '--libdir', '/opt/lib32']
  676. self.assertRaises(subprocess.CalledProcessError, self.init, testdir, args)
  677. self.wipe()
  678. # libdir must be inside prefix even when set via mesonconf
  679. self.init(testdir)
  680. self.assertRaises(subprocess.CalledProcessError, self.setconf, '-Dlibdir=/opt', False)
  681. def test_prefix_dependent_defaults(self):
  682. '''
  683. Tests that configured directory paths are set to prefix dependent
  684. defaults.
  685. '''
  686. testdir = os.path.join(self.common_test_dir, '1 trivial')
  687. expected = {
  688. '/opt': {'prefix': '/opt',
  689. 'bindir': 'bin', 'datadir': 'share', 'includedir': 'include',
  690. 'infodir': 'share/info',
  691. 'libexecdir': 'libexec', 'localedir': 'share/locale',
  692. 'localstatedir': 'var', 'mandir': 'share/man',
  693. 'sbindir': 'sbin', 'sharedstatedir': 'com',
  694. 'sysconfdir': 'etc'},
  695. '/usr': {'prefix': '/usr',
  696. 'bindir': 'bin', 'datadir': 'share', 'includedir': 'include',
  697. 'infodir': 'share/info',
  698. 'libexecdir': 'libexec', 'localedir': 'share/locale',
  699. 'localstatedir': '/var', 'mandir': 'share/man',
  700. 'sbindir': 'sbin', 'sharedstatedir': '/var/lib',
  701. 'sysconfdir': '/etc'},
  702. '/usr/local': {'prefix': '/usr/local',
  703. 'bindir': 'bin', 'datadir': 'share',
  704. 'includedir': 'include', 'infodir': 'share/info',
  705. 'libexecdir': 'libexec',
  706. 'localedir': 'share/locale',
  707. 'localstatedir': '/var/local', 'mandir': 'share/man',
  708. 'sbindir': 'sbin', 'sharedstatedir': '/var/local/lib',
  709. 'sysconfdir': 'etc'},
  710. # N.B. We don't check 'libdir' as it's platform dependent, see
  711. # default_libdir():
  712. }
  713. for prefix in expected:
  714. args = ['--prefix', prefix]
  715. self.init(testdir, args, default_args=False)
  716. opts = self.introspect('--buildoptions')
  717. for opt in opts:
  718. name = opt['name']
  719. value = opt['value']
  720. if name in expected[prefix]:
  721. self.assertEqual(value, expected[prefix][name])
  722. self.wipe()
  723. def test_static_library_overwrite(self):
  724. '''
  725. Tests that static libraries are never appended to, always overwritten.
  726. Has to be a unit test because this involves building a project,
  727. reconfiguring, and building it again so that `ar` is run twice on the
  728. same static library.
  729. https://github.com/mesonbuild/meson/issues/1355
  730. '''
  731. testdir = os.path.join(self.common_test_dir, '3 static')
  732. env = Environment(testdir, self.builddir, self.meson_command,
  733. get_fake_options(self.prefix), [])
  734. cc = env.detect_c_compiler(False)
  735. static_linker = env.detect_static_linker(cc)
  736. if is_windows():
  737. raise unittest.SkipTest('https://github.com/mesonbuild/meson/issues/1526')
  738. if not isinstance(static_linker, mesonbuild.linkers.ArLinker):
  739. raise unittest.SkipTest('static linker is not `ar`')
  740. # Configure
  741. self.init(testdir)
  742. # Get name of static library
  743. targets = self.introspect('--targets')
  744. self.assertEqual(len(targets), 1)
  745. libname = targets[0]['filename']
  746. # Build and get contents of static library
  747. self.build()
  748. before = self._run(['ar', 't', os.path.join(self.builddir, libname)]).split()
  749. # Filter out non-object-file contents
  750. before = [f for f in before if f.endswith(('.o', '.obj'))]
  751. # Static library should contain only one object
  752. self.assertEqual(len(before), 1, msg=before)
  753. # Change the source to be built into the static library
  754. self.setconf('-Dsource=libfile2.c')
  755. self.build()
  756. after = self._run(['ar', 't', os.path.join(self.builddir, libname)]).split()
  757. # Filter out non-object-file contents
  758. after = [f for f in after if f.endswith(('.o', '.obj'))]
  759. # Static library should contain only one object
  760. self.assertEqual(len(after), 1, msg=after)
  761. # and the object must have changed
  762. self.assertNotEqual(before, after)
  763. def test_static_compile_order(self):
  764. '''
  765. Test that the order of files in a compiler command-line while compiling
  766. and linking statically is deterministic. This can't be an ordinary test
  767. case because we need to inspect the compiler database.
  768. https://github.com/mesonbuild/meson/pull/951
  769. '''
  770. testdir = os.path.join(self.common_test_dir, '5 linkstatic')
  771. self.init(testdir)
  772. compdb = self.get_compdb()
  773. # Rules will get written out in this order
  774. self.assertTrue(compdb[0]['file'].endswith("libfile.c"))
  775. self.assertTrue(compdb[1]['file'].endswith("libfile2.c"))
  776. self.assertTrue(compdb[2]['file'].endswith("libfile3.c"))
  777. self.assertTrue(compdb[3]['file'].endswith("libfile4.c"))
  778. # FIXME: We don't have access to the linker command
  779. def test_run_target_files_path(self):
  780. '''
  781. Test that run_targets are run from the correct directory
  782. https://github.com/mesonbuild/meson/issues/957
  783. '''
  784. testdir = os.path.join(self.common_test_dir, '58 run target')
  785. self.init(testdir)
  786. self.run_target('check_exists')
  787. def test_install_introspection(self):
  788. '''
  789. Tests that the Meson introspection API exposes install filenames correctly
  790. https://github.com/mesonbuild/meson/issues/829
  791. '''
  792. if self.backend is not Backend.ninja:
  793. raise unittest.SkipTest('{!r} backend can\'t install files'.format(self.backend.name))
  794. testdir = os.path.join(self.common_test_dir, '8 install')
  795. self.init(testdir)
  796. intro = self.introspect('--targets')
  797. if intro[0]['type'] == 'executable':
  798. intro = intro[::-1]
  799. self.assertPathEqual(intro[0]['install_filename'], '/usr/lib/libstat.a')
  800. self.assertPathEqual(intro[1]['install_filename'], '/usr/bin/prog' + exe_suffix)
  801. def test_uninstall(self):
  802. exename = os.path.join(self.installdir, 'usr/bin/prog' + exe_suffix)
  803. testdir = os.path.join(self.common_test_dir, '8 install')
  804. self.init(testdir)
  805. self.assertPathDoesNotExist(exename)
  806. self.install()
  807. self.assertPathExists(exename)
  808. self.uninstall()
  809. self.assertPathDoesNotExist(exename)
  810. def test_testsetups(self):
  811. if not shutil.which('valgrind'):
  812. raise unittest.SkipTest('Valgrind not installed.')
  813. testdir = os.path.join(self.unit_test_dir, '2 testsetups')
  814. self.init(testdir)
  815. self.build()
  816. # Run tests without setup
  817. self.run_tests()
  818. with open(os.path.join(self.logdir, 'testlog.txt')) as f:
  819. basic_log = f.read()
  820. # Run buggy test with setup that has env that will make it fail
  821. self.assertRaises(subprocess.CalledProcessError,
  822. self._run, self.mtest_command + ['--setup=valgrind'])
  823. with open(os.path.join(self.logdir, 'testlog-valgrind.txt')) as f:
  824. vg_log = f.read()
  825. self.assertFalse('TEST_ENV is set' in basic_log)
  826. self.assertFalse('Memcheck' in basic_log)
  827. self.assertTrue('TEST_ENV is set' in vg_log)
  828. self.assertTrue('Memcheck' in vg_log)
  829. # Run buggy test with setup without env that will pass
  830. self._run(self.mtest_command + ['--setup=wrapper'])
  831. # Setup with no properties works
  832. self._run(self.mtest_command + ['--setup=empty'])
  833. # Setup with only env works
  834. self._run(self.mtest_command + ['--setup=onlyenv'])
  835. self._run(self.mtest_command + ['--setup=onlyenv2'])
  836. self._run(self.mtest_command + ['--setup=onlyenv3'])
  837. # Setup with only a timeout works
  838. self._run(self.mtest_command + ['--setup=timeout'])
  839. def assertFailedTestCount(self, failure_count, command):
  840. try:
  841. self._run(command)
  842. self.assertEqual(0, failure_count, 'Expected %d tests to fail.' % failure_count)
  843. except subprocess.CalledProcessError as e:
  844. self.assertEqual(e.returncode, failure_count)
  845. def test_suite_selection(self):
  846. testdir = os.path.join(self.unit_test_dir, '4 suite selection')
  847. self.init(testdir)
  848. self.build()
  849. self.assertFailedTestCount(3, self.mtest_command)
  850. self.assertFailedTestCount(0, self.mtest_command + ['--suite', ':success'])
  851. self.assertFailedTestCount(3, self.mtest_command + ['--suite', ':fail'])
  852. self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', ':success'])
  853. self.assertFailedTestCount(0, self.mtest_command + ['--no-suite', ':fail'])
  854. self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'mainprj'])
  855. self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjsucc'])
  856. self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjfail'])
  857. self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjmix'])
  858. self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'mainprj'])
  859. self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjsucc'])
  860. self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjfail'])
  861. self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjmix'])
  862. self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'mainprj:fail'])
  863. self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'mainprj:success'])
  864. self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'mainprj:fail'])
  865. self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'mainprj:success'])
  866. self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjfail:fail'])
  867. self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjfail:success'])
  868. self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjfail:fail'])
  869. self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjfail:success'])
  870. self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjsucc:fail'])
  871. self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjsucc:success'])
  872. self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjsucc:fail'])
  873. self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjsucc:success'])
  874. self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjmix:fail'])
  875. self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjmix:success'])
  876. self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjmix:fail'])
  877. self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjmix:success'])
  878. self.assertFailedTestCount(2, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix:fail'])
  879. self.assertFailedTestCount(3, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix', '--suite', 'mainprj'])
  880. self.assertFailedTestCount(2, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix', '--suite', 'mainprj', '--no-suite', 'subprjmix:fail'])
  881. self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix', '--suite', 'mainprj', '--no-suite', 'subprjmix:fail', 'mainprj-failing_test'])
  882. self.assertFailedTestCount(1, self.mtest_command + ['--no-suite', 'subprjfail:fail', '--no-suite', 'subprjmix:fail'])
  883. def test_build_by_default(self):
  884. testdir = os.path.join(self.common_test_dir, '137 build by default')
  885. self.init(testdir)
  886. self.build()
  887. genfile = os.path.join(self.builddir, 'generated.dat')
  888. exe = os.path.join(self.builddir, 'fooprog' + exe_suffix)
  889. self.assertPathExists(genfile)
  890. self.assertPathDoesNotExist(exe)
  891. self.build(target=('fooprog' + exe_suffix))
  892. self.assertPathExists(exe)
  893. def test_internal_include_order(self):
  894. testdir = os.path.join(self.common_test_dir, '138 include order')
  895. self.init(testdir)
  896. execmd = fxecmd = None
  897. for cmd in self.get_compdb():
  898. if 'someexe' in cmd['command']:
  899. execmd = cmd['command']
  900. continue
  901. if 'somefxe' in cmd['command']:
  902. fxecmd = cmd['command']
  903. continue
  904. if not execmd or not fxecmd:
  905. raise Exception('Could not find someexe and somfxe commands')
  906. # Check include order for 'someexe'
  907. incs = [a for a in shlex.split(execmd) if a.startswith("-I")]
  908. self.assertEqual(len(incs), 9)
  909. # target private dir
  910. self.assertPathEqual(incs[0], "-Isub4/someexe@exe")
  911. # target build subdir
  912. self.assertPathEqual(incs[1], "-Isub4")
  913. # target source subdir
  914. self.assertPathBasenameEqual(incs[2], 'sub4')
  915. # include paths added via per-target c_args: ['-I'...]
  916. self.assertPathBasenameEqual(incs[3], 'sub3')
  917. # target include_directories: build dir
  918. self.assertPathEqual(incs[4], "-Isub2")
  919. # target include_directories: source dir
  920. self.assertPathBasenameEqual(incs[5], 'sub2')
  921. # target internal dependency include_directories: build dir
  922. self.assertPathEqual(incs[6], "-Isub1")
  923. # target internal dependency include_directories: source dir
  924. self.assertPathBasenameEqual(incs[7], 'sub1')
  925. # custom target include dir
  926. self.assertPathEqual(incs[8], '-Ictsub')
  927. # Check include order for 'somefxe'
  928. incs = [a for a in shlex.split(fxecmd) if a.startswith('-I')]
  929. self.assertEqual(len(incs), 9)
  930. # target private dir
  931. self.assertPathEqual(incs[0], '-Isomefxe@exe')
  932. # target build dir
  933. self.assertPathEqual(incs[1], '-I.')
  934. # target source dir
  935. self.assertPathBasenameEqual(incs[2], os.path.basename(testdir))
  936. # target internal dependency correct include_directories: build dir
  937. self.assertPathEqual(incs[3], "-Isub4")
  938. # target internal dependency correct include_directories: source dir
  939. self.assertPathBasenameEqual(incs[4], 'sub4')
  940. # target internal dependency dep include_directories: build dir
  941. self.assertPathEqual(incs[5], "-Isub1")
  942. # target internal dependency dep include_directories: source dir
  943. self.assertPathBasenameEqual(incs[6], 'sub1')
  944. # target internal dependency wrong include_directories: build dir
  945. self.assertPathEqual(incs[7], "-Isub2")
  946. # target internal dependency wrong include_directories: source dir
  947. self.assertPathBasenameEqual(incs[8], 'sub2')
  948. def test_compiler_detection(self):
  949. '''
  950. Test that automatic compiler detection and setting from the environment
  951. both work just fine. This is needed because while running project tests
  952. and other unit tests, we always read CC/CXX/etc from the environment.
  953. '''
  954. gnu = mesonbuild.compilers.GnuCompiler
  955. clang = mesonbuild.compilers.ClangCompiler
  956. intel = mesonbuild.compilers.IntelCompiler
  957. msvc = mesonbuild.compilers.VisualStudioCCompiler
  958. ar = mesonbuild.linkers.ArLinker
  959. lib = mesonbuild.linkers.VisualStudioLinker
  960. langs = [('c', 'CC'), ('cpp', 'CXX')]
  961. if not is_windows():
  962. langs += [('objc', 'OBJC'), ('objcpp', 'OBJCXX')]
  963. testdir = os.path.join(self.unit_test_dir, '5 compiler detection')
  964. env = Environment(testdir, self.builddir, self.meson_command,
  965. get_fake_options(self.prefix), [])
  966. for lang, evar in langs:
  967. # Detect with evar and do sanity checks on that
  968. if evar in os.environ:
  969. ecc = getattr(env, 'detect_{}_compiler'.format(lang))(False)
  970. self.assertTrue(ecc.version)
  971. elinker = env.detect_static_linker(ecc)
  972. # Pop it so we don't use it for the next detection
  973. evalue = os.environ.pop(evar)
  974. # Very rough/strict heuristics. Would never work for actual
  975. # compiler detection, but should be ok for the tests.
  976. if os.path.basename(evalue).startswith('g'):
  977. self.assertIsInstance(ecc, gnu)
  978. self.assertIsInstance(elinker, ar)
  979. elif 'clang' in os.path.basename(evalue):
  980. self.assertIsInstance(ecc, clang)
  981. self.assertIsInstance(elinker, ar)
  982. elif os.path.basename(evalue).startswith('ic'):
  983. self.assertIsInstance(ecc, intel)
  984. self.assertIsInstance(elinker, ar)
  985. elif os.path.basename(evalue).startswith('cl'):
  986. self.assertIsInstance(ecc, msvc)
  987. self.assertIsInstance(elinker, lib)
  988. else:
  989. raise AssertionError('Unknown compiler {!r}'.format(evalue))
  990. # Check that we actually used the evalue correctly as the compiler
  991. self.assertEqual(ecc.get_exelist(), shlex.split(evalue))
  992. # Do auto-detection of compiler based on platform, PATH, etc.
  993. cc = getattr(env, 'detect_{}_compiler'.format(lang))(False)
  994. self.assertTrue(cc.version)
  995. linker = env.detect_static_linker(cc)
  996. # Check compiler type
  997. if isinstance(cc, gnu):
  998. self.assertIsInstance(linker, ar)
  999. if is_osx():
  1000. self.assertEqual(cc.gcc_type, mesonbuild.compilers.GCC_OSX)
  1001. elif is_windows():
  1002. self.assertEqual(cc.gcc_type, mesonbuild.compilers.GCC_MINGW)
  1003. elif is_cygwin():
  1004. self.assertEqual(cc.gcc_type, mesonbuild.compilers.GCC_CYGWIN)
  1005. else:
  1006. self.assertEqual(cc.gcc_type, mesonbuild.compilers.GCC_STANDARD)
  1007. if isinstance(cc, clang):
  1008. self.assertIsInstance(linker, ar)
  1009. if is_osx():
  1010. self.assertEqual(cc.clang_type, mesonbuild.compilers.CLANG_OSX)
  1011. elif is_windows():
  1012. # Not implemented yet
  1013. self.assertEqual(cc.clang_type, mesonbuild.compilers.CLANG_WIN)
  1014. else:
  1015. self.assertEqual(cc.clang_type, mesonbuild.compilers.CLANG_STANDARD)
  1016. if isinstance(cc, intel):
  1017. self.assertIsInstance(linker, ar)
  1018. if is_osx():
  1019. self.assertEqual(cc.icc_type, mesonbuild.compilers.ICC_OSX)
  1020. elif is_windows():
  1021. self.assertEqual(cc.icc_type, mesonbuild.compilers.ICC_WIN)
  1022. else:
  1023. self.assertEqual(cc.icc_type, mesonbuild.compilers.ICC_STANDARD)
  1024. if isinstance(cc, msvc):
  1025. self.assertTrue(is_windows())
  1026. self.assertIsInstance(linker, lib)
  1027. self.assertEqual(cc.id, 'msvc')
  1028. self.assertTrue(hasattr(cc, 'is_64'))
  1029. # If we're in the appveyor CI, we know what the compiler will be
  1030. if 'arch' in os.environ:
  1031. if os.environ['arch'] == 'x64':
  1032. self.assertTrue(cc.is_64)
  1033. else:
  1034. self.assertFalse(cc.is_64)
  1035. # Set evar ourselves to a wrapper script that just calls the same
  1036. # exelist + some argument. This is meant to test that setting
  1037. # something like `ccache gcc -pipe` or `distcc ccache gcc` works.
  1038. wrapper = os.path.join(testdir, 'compiler wrapper.py')
  1039. wrappercc = python_command + [wrapper] + cc.get_exelist() + ['-DSOME_ARG']
  1040. wrappercc_s = ''
  1041. for w in wrappercc:
  1042. wrappercc_s += shlex.quote(w) + ' '
  1043. os.environ[evar] = wrappercc_s
  1044. wcc = getattr(env, 'detect_{}_compiler'.format(lang))(False)
  1045. # Check static linker too
  1046. wrapperlinker = python_command + [wrapper] + linker.get_exelist() + linker.get_always_args()
  1047. wrapperlinker_s = ''
  1048. for w in wrapperlinker:
  1049. wrapperlinker_s += shlex.quote(w) + ' '
  1050. os.environ['AR'] = wrapperlinker_s
  1051. wlinker = env.detect_static_linker(wcc)
  1052. # Must be the same type since it's a wrapper around the same exelist
  1053. self.assertIs(type(cc), type(wcc))
  1054. self.assertIs(type(linker), type(wlinker))
  1055. # Ensure that the exelist is correct
  1056. self.assertEqual(wcc.get_exelist(), wrappercc)
  1057. self.assertEqual(wlinker.get_exelist(), wrapperlinker)
  1058. # Ensure that the version detection worked correctly
  1059. self.assertEqual(cc.version, wcc.version)
  1060. if hasattr(cc, 'is_64'):
  1061. self.assertEqual(cc.is_64, wcc.is_64)
  1062. def test_always_prefer_c_compiler_for_asm(self):
  1063. testdir = os.path.join(self.common_test_dir, '141 c cpp and asm')
  1064. # Skip if building with MSVC
  1065. env = Environment(testdir, self.builddir, self.meson_command,
  1066. get_fake_options(self.prefix), [])
  1067. if env.detect_c_compiler(False).get_id() == 'msvc':
  1068. raise unittest.SkipTest('MSVC can\'t compile assembly')
  1069. self.init(testdir)
  1070. commands = {'c-asm': {}, 'cpp-asm': {}, 'cpp-c-asm': {}, 'c-cpp-asm': {}}
  1071. for cmd in self.get_compdb():
  1072. # Get compiler
  1073. split = shlex.split(cmd['command'])
  1074. if split[0] == 'ccache':
  1075. compiler = split[1]
  1076. else:
  1077. compiler = split[0]
  1078. # Classify commands
  1079. if 'Ic-asm' in cmd['command']:
  1080. if cmd['file'].endswith('.S'):
  1081. commands['c-asm']['asm'] = compiler
  1082. elif cmd['file'].endswith('.c'):
  1083. commands['c-asm']['c'] = compiler
  1084. else:
  1085. raise AssertionError('{!r} found in cpp-asm?'.format(cmd['command']))
  1086. elif 'Icpp-asm' in cmd['command']:
  1087. if cmd['file'].endswith('.S'):
  1088. commands['cpp-asm']['asm'] = compiler
  1089. elif cmd['file'].endswith('.cpp'):
  1090. commands['cpp-asm']['cpp'] = compiler
  1091. else:
  1092. raise AssertionError('{!r} found in cpp-asm?'.format(cmd['command']))
  1093. elif 'Ic-cpp-asm' in cmd['command']:
  1094. if cmd['file'].endswith('.S'):
  1095. commands['c-cpp-asm']['asm'] = compiler
  1096. elif cmd['file'].endswith('.c'):
  1097. commands['c-cpp-asm']['c'] = compiler
  1098. elif cmd['file'].endswith('.cpp'):
  1099. commands['c-cpp-asm']['cpp'] = compiler
  1100. else:
  1101. raise AssertionError('{!r} found in c-cpp-asm?'.format(cmd['command']))
  1102. elif 'Icpp-c-asm' in cmd['command']:
  1103. if cmd['file'].endswith('.S'):
  1104. commands['cpp-c-asm']['asm'] = compiler
  1105. elif cmd['file'].endswith('.c'):
  1106. commands['cpp-c-asm']['c'] = compiler
  1107. elif cmd['file'].endswith('.cpp'):
  1108. commands['cpp-c-asm']['cpp'] = compiler
  1109. else:
  1110. raise AssertionError('{!r} found in cpp-c-asm?'.format(cmd['command']))
  1111. else:
  1112. raise AssertionError('Unknown command {!r} found'.format(cmd['command']))
  1113. # Check that .S files are always built with the C compiler
  1114. self.assertEqual(commands['c-asm']['asm'], commands['c-asm']['c'])
  1115. self.assertEqual(commands['c-asm']['asm'], commands['cpp-asm']['asm'])
  1116. self.assertEqual(commands['cpp-asm']['asm'], commands['c-cpp-asm']['c'])
  1117. self.assertEqual(commands['c-cpp-asm']['asm'], commands['c-cpp-asm']['c'])
  1118. self.assertEqual(commands['cpp-c-asm']['asm'], commands['cpp-c-asm']['c'])
  1119. self.assertNotEqual(commands['cpp-asm']['asm'], commands['cpp-asm']['cpp'])
  1120. self.assertNotEqual(commands['c-cpp-asm']['c'], commands['c-cpp-asm']['cpp'])
  1121. self.assertNotEqual(commands['cpp-c-asm']['c'], commands['cpp-c-asm']['cpp'])
  1122. # Check that the c-asm target is always linked with the C linker
  1123. build_ninja = os.path.join(self.builddir, 'build.ninja')
  1124. with open(build_ninja, 'r', encoding='utf-8') as f:
  1125. contents = f.read()
  1126. m = re.search('build c-asm.*: c_LINKER', contents)
  1127. self.assertIsNotNone(m, msg=contents)
  1128. def test_preprocessor_checks_CPPFLAGS(self):
  1129. '''
  1130. Test that preprocessor compiler checks read CPPFLAGS but not CFLAGS
  1131. '''
  1132. testdir = os.path.join(self.common_test_dir, '140 get define')
  1133. define = 'MESON_TEST_DEFINE_VALUE'
  1134. # NOTE: this list can't have \n, ' or "
  1135. # \n is never substituted by the GNU pre-processor via a -D define
  1136. # ' and " confuse shlex.split() even when they are escaped
  1137. # % and # confuse the MSVC preprocessor
  1138. value = 'spaces and fun!@$^&*()-=_+{}[]:;<>?,./~`'
  1139. os.environ['CPPFLAGS'] = '-D{}="{}"'.format(define, value)
  1140. os.environ['CFLAGS'] = '-DMESON_FAIL_VALUE=cflags-read'.format(define)
  1141. self.init(testdir, ['-D{}={}'.format(define, value)])
  1142. def test_custom_target_exe_data_deterministic(self):
  1143. testdir = os.path.join(self.common_test_dir, '117 custom target capture')
  1144. self.init(testdir)
  1145. meson_exe_dat1 = glob(os.path.join(self.privatedir, 'meson_exe*.dat'))
  1146. self.wipe()
  1147. self.init(testdir)
  1148. meson_exe_dat2 = glob(os.path.join(self.privatedir, 'meson_exe*.dat'))
  1149. self.assertListEqual(meson_exe_dat1, meson_exe_dat2)
  1150. def test_source_changes_cause_rebuild(self):
  1151. '''
  1152. Test that changes to sources and headers cause rebuilds, but not
  1153. changes to unused files (as determined by the dependency file) in the
  1154. input files list.
  1155. '''
  1156. testdir = os.path.join(self.common_test_dir, '22 header in file list')
  1157. self.init(testdir)
  1158. self.build()
  1159. # Immediately rebuilding should not do anything
  1160. self.assertBuildIsNoop()
  1161. # Changing mtime of header.h should rebuild everything
  1162. self.utime(os.path.join(testdir, 'header.h'))
  1163. self.assertRebuiltTarget('prog')
  1164. def test_custom_target_changes_cause_rebuild(self):
  1165. '''
  1166. Test that in a custom target, changes to the input files, the
  1167. ExternalProgram, and any File objects on the command-line cause
  1168. a rebuild.
  1169. '''
  1170. testdir = os.path.join(self.common_test_dir, '64 custom header generator')
  1171. self.init(testdir)
  1172. self.build()
  1173. # Immediately rebuilding should not do anything
  1174. self.assertBuildIsNoop()
  1175. # Changing mtime of these should rebuild everything
  1176. for f in ('input.def', 'makeheader.py', 'somefile.txt'):
  1177. self.utime(os.path.join(testdir, f))
  1178. self.assertRebuiltTarget('prog')
  1179. def test_static_library_lto(self):
  1180. '''
  1181. Test that static libraries can be built with LTO and linked to
  1182. executables. On Linux, this requires the use of gcc-ar.
  1183. https://github.com/mesonbuild/meson/issues/1646
  1184. '''
  1185. testdir = os.path.join(self.common_test_dir, '5 linkstatic')
  1186. self.init(testdir, extra_args='-Db_lto=true')
  1187. self.build()
  1188. self.run_tests()
  1189. def test_dist_git(self):
  1190. if not shutil.which('git'):
  1191. raise unittest.SkipTest('Git not found')
  1192. def git_init(project_dir):
  1193. subprocess.check_call(['git', 'init'], cwd=project_dir)
  1194. subprocess.check_call(['git', 'config',
  1195. 'user.name', 'Author Person'], cwd=project_dir)
  1196. subprocess.check_call(['git', 'config',
  1197. 'user.email', 'teh_coderz@example.com'], cwd=project_dir)
  1198. subprocess.check_call(['git', 'add', 'meson.build', 'distexe.c'], cwd=project_dir)
  1199. subprocess.check_call(['git', 'commit', '-a', '-m', 'I am a project'], cwd=project_dir)
  1200. try:
  1201. self.dist_impl(git_init)
  1202. except PermissionError:
  1203. # When run under Windows CI, something (virus scanner?)
  1204. # holds on to the git files so cleaning up the dir
  1205. # fails sometimes.
  1206. pass
  1207. def test_dist_hg(self):
  1208. if not shutil.which('hg'):
  1209. raise unittest.SkipTest('Mercurial not found')
  1210. if self.backend is not Backend.ninja:
  1211. raise unittest.SkipTest('Dist is only supported with Ninja')
  1212. def hg_init(project_dir):
  1213. subprocess.check_call(['hg', 'init'], cwd=project_dir)
  1214. with open(os.path.join(project_dir, '.hg', 'hgrc'), 'w') as f:
  1215. print('[ui]', file=f)
  1216. print('username=Author Person <teh_coderz@example.com>', file=f)
  1217. subprocess.check_call(['hg', 'add', 'meson.build', 'distexe.c'], cwd=project_dir)
  1218. subprocess.check_call(['hg', 'commit', '-m', 'I am a project'], cwd=project_dir)
  1219. try:
  1220. self.dist_impl(hg_init)
  1221. except PermissionError:
  1222. # When run under Windows CI, something (virus scanner?)
  1223. # holds on to the hg files so cleaning up the dir
  1224. # fails sometimes.
  1225. pass
  1226. def dist_impl(self, vcs_init):
  1227. # Create this on the fly because having rogue .git directories inside
  1228. # the source tree leads to all kinds of trouble.
  1229. with tempfile.TemporaryDirectory() as project_dir:
  1230. with open(os.path.join(project_dir, 'meson.build'), 'w') as ofile:
  1231. ofile.write('''project('disttest', 'c', version : '1.4.3')
  1232. e = executable('distexe', 'distexe.c')
  1233. test('dist test', e)
  1234. ''')
  1235. with open(os.path.join(project_dir, 'distexe.c'), 'w') as ofile:
  1236. ofile.write('''#include<stdio.h>
  1237. int main(int argc, char **argv) {
  1238. printf("I am a distribution test.\\n");
  1239. return 0;
  1240. }
  1241. ''')
  1242. vcs_init(project_dir)
  1243. self.init(project_dir)
  1244. self.build('dist')
  1245. distfile = os.path.join(self.distdir, 'disttest-1.4.3.tar.xz')
  1246. checksumfile = distfile + '.sha256sum'
  1247. self.assertPathExists(distfile)
  1248. self.assertPathExists(checksumfile)
  1249. def test_rpath_uses_ORIGIN(self):
  1250. '''
  1251. Test that built targets use $ORIGIN in rpath, which ensures that they
  1252. are relocatable and ensures that builds are reproducible since the
  1253. build directory won't get embedded into the built binaries.
  1254. '''
  1255. if is_windows() or is_cygwin():
  1256. raise unittest.SkipTest('Windows PE/COFF binaries do not use RPATH')
  1257. testdir = os.path.join(self.common_test_dir, '46 library chain')
  1258. self.init(testdir)
  1259. self.build()
  1260. for each in ('prog', 'subdir/liblib1.so', 'subdir/subdir2/liblib2.so',
  1261. 'subdir/subdir3/liblib3.so'):
  1262. rpath = get_rpath(os.path.join(self.builddir, each))
  1263. self.assertTrue(rpath)
  1264. for path in rpath.split(':'):
  1265. self.assertTrue(path.startswith('$ORIGIN'), msg=(each, path))
  1266. def test_dash_d_dedup(self):
  1267. testdir = os.path.join(self.unit_test_dir, '10 d dedup')
  1268. self.init(testdir)
  1269. cmd = self.get_compdb()[0]['command']
  1270. self.assertTrue('-D FOO -D BAR' in cmd or
  1271. '"-D" "FOO" "-D" "BAR"' in cmd or
  1272. '/D FOO /D BAR' in cmd or
  1273. '"/D" "FOO" "/D" "BAR"' in cmd)
  1274. def test_all_forbidden_targets_tested(self):
  1275. '''
  1276. Test that all forbidden targets are tested in the '159 reserved targets'
  1277. test. Needs to be a unit test because it accesses Meson internals.
  1278. '''
  1279. testdir = os.path.join(self.common_test_dir, '159 reserved targets')
  1280. targets = mesonbuild.coredata.forbidden_target_names
  1281. # We don't actually define a target with this name
  1282. targets.pop('build.ninja')
  1283. # Remove this to avoid multiple entries with the same name
  1284. # but different case.
  1285. targets.pop('PHONY')
  1286. for i in targets:
  1287. self.assertPathExists(os.path.join(testdir, i))
  1288. def detect_prebuild_env(self):
  1289. env = Environment('', self.builddir, self.meson_command,
  1290. get_fake_options(self.prefix), [])
  1291. cc = env.detect_c_compiler(False)
  1292. if mesonbuild.mesonlib.is_windows():
  1293. object_suffix = 'obj'
  1294. shared_suffix = 'dll'
  1295. elif mesonbuild.mesonlib.is_cygwin():
  1296. object_suffix = 'o'
  1297. shared_suffix = 'dll'
  1298. elif mesonbuild.mesonlib.is_osx():
  1299. object_suffix = 'o'
  1300. shared_suffix = 'dylib'
  1301. else:
  1302. object_suffix = 'o'
  1303. shared_suffix = 'so'
  1304. return (cc, object_suffix, shared_suffix)
  1305. def pbcompile(self, compiler, source, objectfile, extra_args=[]):
  1306. cmd = compiler.get_exelist()
  1307. if compiler.id == 'msvc':
  1308. cmd += ['/nologo', '/Fo' + objectfile, '/c', source] + extra_args
  1309. else:
  1310. cmd += ['-c', source, '-o', objectfile] + extra_args
  1311. subprocess.check_call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
  1312. def test_prebuilt_object(self):
  1313. (compiler, object_suffix, _) = self.detect_prebuild_env()
  1314. tdir = os.path.join(self.unit_test_dir, '14 prebuilt object')
  1315. source = os.path.join(tdir, 'source.c')
  1316. objectfile = os.path.join(tdir, 'prebuilt.' + object_suffix)
  1317. self.pbcompile(compiler, source, objectfile)
  1318. try:
  1319. self.init(tdir)
  1320. self.build()
  1321. self.run_tests()
  1322. finally:
  1323. os.unlink(objectfile)
  1324. def build_static_lib(self, compiler, source, objectfile, outfile, extra_args=None):
  1325. if extra_args is None:
  1326. extra_args = []
  1327. if compiler.id == 'msvc':
  1328. link_cmd = ['lib', '/NOLOGO', '/OUT:' + outfile, objectfile]
  1329. else:
  1330. link_cmd = ['ar', 'csr', outfile, objectfile]
  1331. self.pbcompile(compiler, source, objectfile, extra_args=extra_args)
  1332. try:
  1333. subprocess.check_call(link_cmd)
  1334. finally:
  1335. os.unlink(objectfile)
  1336. def test_prebuilt_static_lib(self):
  1337. (cc, object_suffix, _) = self.detect_prebuild_env()
  1338. tdir = os.path.join(self.unit_test_dir, '15 prebuilt static')
  1339. source = os.path.join(tdir, 'libdir/best.c')
  1340. objectfile = os.path.join(tdir, 'libdir/best.' + object_suffix)
  1341. stlibfile = os.path.join(tdir, 'libdir/libbest.a')
  1342. self.build_static_lib(cc, source, objectfile, stlibfile)
  1343. # Run the test
  1344. try:
  1345. self.init(tdir)
  1346. self.build()
  1347. self.run_tests()
  1348. finally:
  1349. os.unlink(stlibfile)
  1350. def build_shared_lib(self, compiler, source, objectfile, outfile, impfile, extra_args=None):
  1351. if extra_args is None:
  1352. extra_args = []
  1353. if compiler.id == 'msvc':
  1354. link_cmd = ['link', '/NOLOGO', '/DLL', '/DEBUG',
  1355. '/IMPLIB:' + impfile, '/OUT:' + outfile, objectfile]
  1356. else:
  1357. extra_args += ['-fPIC']
  1358. link_cmd = compiler.get_exelist() + ['-shared', '-o', outfile, objectfile]
  1359. if not mesonbuild.mesonlib.is_osx():
  1360. link_cmd += ['-Wl,-soname=' + os.path.basename(outfile)]
  1361. self.pbcompile(compiler, source, objectfile, extra_args=extra_args)
  1362. try:
  1363. subprocess.check_call(link_cmd)
  1364. finally:
  1365. os.unlink(objectfile)
  1366. def test_prebuilt_shared_lib(self):
  1367. (cc, object_suffix, shared_suffix) = self.detect_prebuild_env()
  1368. tdir = os.path.join(self.unit_test_dir, '16 prebuilt shared')
  1369. source = os.path.join(tdir, 'alexandria.c')
  1370. objectfile = os.path.join(tdir, 'alexandria.' + object_suffix)
  1371. impfile = os.path.join(tdir, 'alexandria.lib')
  1372. if cc.id == 'msvc':
  1373. shlibfile = os.path.join(tdir, 'alexandria.' + shared_suffix)
  1374. elif is_cygwin():
  1375. shlibfile = os.path.join(tdir, 'cygalexandria.' + shared_suffix)
  1376. else:
  1377. shlibfile = os.path.join(tdir, 'libalexandria.' + shared_suffix)
  1378. self.build_shared_lib(cc, source, objectfile, shlibfile, impfile)
  1379. # Run the test
  1380. try:
  1381. self.init(tdir)
  1382. self.build()
  1383. self.run_tests()
  1384. finally:
  1385. os.unlink(shlibfile)
  1386. if mesonbuild.mesonlib.is_windows():
  1387. # Clean up all the garbage MSVC writes in the
  1388. # source tree.
  1389. for fname in glob(os.path.join(tdir, 'alexandria.*')):
  1390. if os.path.splitext(fname)[1] not in ['.c', '.h']:
  1391. os.unlink(fname)
  1392. def test_pkgconfig_static(self):
  1393. '''
  1394. Test that the we only use static libraries when `static: true` is
  1395. passed to dependency() with pkg-config. Can't be an ordinary test
  1396. because we need to build libs and try to find them from meson.build
  1397. '''
  1398. if not shutil.which('pkg-config'):
  1399. raise unittest.SkipTest('pkg-config not found')
  1400. (cc, objext, shext) = self.detect_prebuild_env()
  1401. testdir = os.path.join(self.unit_test_dir, '17 pkgconfig static')
  1402. source = os.path.join(testdir, 'foo.c')
  1403. objectfile = os.path.join(testdir, 'foo.' + objext)
  1404. stlibfile = os.path.join(testdir, 'libfoo.a')
  1405. impfile = os.path.join(testdir, 'foo.lib')
  1406. if cc.id == 'msvc':
  1407. shlibfile = os.path.join(testdir, 'foo.' + shext)
  1408. elif is_cygwin():
  1409. shlibfile = os.path.join(testdir, 'cygfoo.' + shext)
  1410. else:
  1411. shlibfile = os.path.join(testdir, 'libfoo.' + shext)
  1412. # Build libs
  1413. self.build_static_lib(cc, source, objectfile, stlibfile, extra_args=['-DFOO_STATIC'])
  1414. self.build_shared_lib(cc, source, objectfile, shlibfile, impfile)
  1415. # Run test
  1416. os.environ['PKG_CONFIG_LIBDIR'] = self.builddir
  1417. try:
  1418. self.init(testdir)
  1419. self.build()
  1420. self.run_tests()
  1421. finally:
  1422. os.unlink(stlibfile)
  1423. os.unlink(shlibfile)
  1424. if mesonbuild.mesonlib.is_windows():
  1425. # Clean up all the garbage MSVC writes in the
  1426. # source tree.
  1427. for fname in glob(os.path.join(testdir, 'foo.*')):
  1428. if os.path.splitext(fname)[1] not in ['.c', '.h', '.in']:
  1429. os.unlink(fname)
  1430. def test_pkgconfig_gen_escaping(self):
  1431. if not shutil.which('pkg-config'):
  1432. raise unittest.SkipTest('pkg-config not found')
  1433. testdir = os.path.join(self.common_test_dir, '51 pkgconfig-gen')
  1434. prefix = '/usr/with spaces'
  1435. libdir = 'lib'
  1436. self.init(testdir, extra_args=['--prefix=' + prefix,
  1437. '--libdir=' + libdir])
  1438. # Find foo dependency
  1439. os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir
  1440. env = FakeEnvironment()
  1441. kwargs = {'required': True, 'silent': True}
  1442. foo_dep = PkgConfigDependency('libfoo', env, kwargs)
  1443. # Ensure link_args are properly quoted
  1444. libdir = PurePath(prefix) / PurePath(libdir)
  1445. link_args = ['-L' + libdir.as_posix(), '-lfoo']
  1446. self.assertEqual(foo_dep.get_link_args(), link_args)
  1447. # Ensure include args are properly quoted
  1448. incdir = PurePath(prefix) / PurePath('include')
  1449. cargs = ['-I' + incdir.as_posix()]
  1450. self.assertEqual(foo_dep.get_compile_args(), cargs)
  1451. class FailureTests(BasePlatformTests):
  1452. '''
  1453. Tests that test failure conditions. Build files here should be dynamically
  1454. generated and static tests should go into `test cases/failing*`.
  1455. This is useful because there can be many ways in which a particular
  1456. function can fail, and creating failing tests for all of them is tedious
  1457. and slows down testing.
  1458. '''
  1459. dnf = "[Dd]ependency.*not found"
  1460. def setUp(self):
  1461. super().setUp()
  1462. self.srcdir = os.path.realpath(tempfile.mkdtemp())
  1463. self.mbuild = os.path.join(self.srcdir, 'meson.build')
  1464. def tearDown(self):
  1465. super().tearDown()
  1466. windows_proof_rmtree(self.srcdir)
  1467. def assertMesonRaises(self, contents, match, extra_args=None, langs=None):
  1468. '''
  1469. Assert that running meson configure on the specified @contents raises
  1470. a error message matching regex @match.
  1471. '''
  1472. if meson_exe is not None:
  1473. # Because the exception happens in a different process.
  1474. raise unittest.SkipTest('Can not test assert raise tests with an external Meson command.')
  1475. if langs is None:
  1476. langs = []
  1477. with open(self.mbuild, 'w') as f:
  1478. f.write("project('failure test', 'c', 'cpp')\n")
  1479. for lang in langs:
  1480. f.write("add_languages('{}', required : false)\n".format(lang))
  1481. f.write(contents)
  1482. # Force tracebacks so we can detect them properly
  1483. os.environ['MESON_FORCE_BACKTRACE'] = '1'
  1484. with self.assertRaisesRegex(DependencyException, match, msg=contents):
  1485. # Must run in-process or we'll get a generic CalledProcessError
  1486. self.init(self.srcdir, extra_args=extra_args, inprocess=True)
  1487. def assertMesonOutputs(self, contents, match, extra_args=None, langs=None):
  1488. '''
  1489. Assert that running meson configure on the specified @contents outputs
  1490. something that matches regex @match.
  1491. '''
  1492. if langs is None:
  1493. langs = []
  1494. with open(self.mbuild, 'w') as f:
  1495. f.write("project('output test', 'c', 'cpp')\n")
  1496. for lang in langs:
  1497. f.write("add_languages('{}', required : false)\n".format(lang))
  1498. f.write(contents)
  1499. # Run in-process for speed and consistency with assertMesonRaises
  1500. out = self.init(self.srcdir, extra_args=extra_args, inprocess=True)
  1501. self.assertRegex(out, match)
  1502. def test_dependency(self):
  1503. if not shutil.which('pkg-config'):
  1504. raise unittest.SkipTest('pkg-config not found')
  1505. if subprocess.call(['pkg-config', '--exists', 'zlib']) != 0:
  1506. raise unittest.SkipTest('zlib not found with pkg-config')
  1507. a = (("dependency('zlib', method : 'fail')", "'fail' is invalid"),
  1508. ("dependency('zlib', static : '1')", "[Ss]tatic.*boolean"),
  1509. ("dependency('zlib', version : 1)", "[Vv]ersion.*string or list"),
  1510. ("dependency('zlib', required : 1)", "[Rr]equired.*boolean"),
  1511. ("dependency('zlib', method : 1)", "[Mm]ethod.*string"),
  1512. ("dependency('zlibfail')", self.dnf),)
  1513. for contents, match in a:
  1514. self.assertMesonRaises(contents, match)
  1515. def test_apple_frameworks_dependency(self):
  1516. if not is_osx():
  1517. raise unittest.SkipTest('only run on macOS')
  1518. self.assertMesonRaises("dependency('appleframeworks')",
  1519. "requires at least one module")
  1520. def test_sdl2_notfound_dependency(self):
  1521. # Want to test failure, so skip if available
  1522. if shutil.which('sdl2-config'):
  1523. raise unittest.SkipTest('sdl2-config found')
  1524. self.assertMesonRaises("dependency('sdl2', method : 'sdlconfig')", self.dnf)
  1525. self.assertMesonRaises("dependency('sdl2', method : 'pkg-config')", self.dnf)
  1526. def test_gnustep_notfound_dependency(self):
  1527. # Want to test failure, so skip if available
  1528. if shutil.which('gnustep-config'):
  1529. raise unittest.SkipTest('gnustep-config found')
  1530. self.assertMesonRaises("dependency('gnustep')",
  1531. "(requires a Objc compiler|{})".format(self.dnf),
  1532. langs = ['objc'])
  1533. def test_wx_notfound_dependency(self):
  1534. # Want to test failure, so skip if available
  1535. if shutil.which('wx-config-3.0') or shutil.which('wx-config'):
  1536. raise unittest.SkipTest('wx-config or wx-config-3.0 found')
  1537. self.assertMesonRaises("dependency('wxwidgets')", self.dnf)
  1538. self.assertMesonOutputs("dependency('wxwidgets', required : false)",
  1539. "nor wx-config found")
  1540. def test_wx_dependency(self):
  1541. if not shutil.which('wx-config-3.0') and not shutil.which('wx-config'):
  1542. raise unittest.SkipTest('Neither wx-config nor wx-config-3.0 found')
  1543. self.assertMesonRaises("dependency('wxwidgets', modules : 1)",
  1544. "module argument is not a string")
  1545. def test_llvm_dependency(self):
  1546. self.assertMesonRaises("dependency('llvm', modules : 'fail')",
  1547. "(required.*fail|{})".format(self.dnf))
  1548. def test_boost_notfound_dependency(self):
  1549. # Can be run even if Boost is found or not
  1550. self.assertMesonRaises("dependency('boost', modules : 1)",
  1551. "module.*not a string")
  1552. self.assertMesonRaises("dependency('boost', modules : 'fail')",
  1553. "(fail.*not found|{})".format(self.dnf))
  1554. def test_boost_BOOST_ROOT_dependency(self):
  1555. # Test BOOST_ROOT; can be run even if Boost is found or not
  1556. os.environ['BOOST_ROOT'] = 'relative/path'
  1557. self.assertMesonRaises("dependency('boost')",
  1558. "(BOOST_ROOT.*absolute|{})".format(self.dnf))
  1559. class WindowsTests(BasePlatformTests):
  1560. '''
  1561. Tests that should run on Cygwin, MinGW, and MSVC
  1562. '''
  1563. def setUp(self):
  1564. super().setUp()
  1565. self.platform_test_dir = os.path.join(self.src_root, 'test cases/windows')
  1566. def test_find_program(self):
  1567. '''
  1568. Test that Windows-specific edge-cases in find_program are functioning
  1569. correctly. Cannot be an ordinary test because it involves manipulating
  1570. PATH to point to a directory with Python scripts.
  1571. '''
  1572. testdir = os.path.join(self.platform_test_dir, '9 find program')
  1573. # Find `cmd` and `cmd.exe`
  1574. prog1 = ExternalProgram('cmd')
  1575. self.assertTrue(prog1.found(), msg='cmd not found')
  1576. prog2 = ExternalProgram('cmd.exe')
  1577. self.assertTrue(prog2.found(), msg='cmd.exe not found')
  1578. self.assertPathEqual(prog1.get_path(), prog2.get_path())
  1579. # Find cmd with an absolute path that's missing the extension
  1580. cmd_path = prog2.get_path()[:-4]
  1581. prog = ExternalProgram(cmd_path)
  1582. self.assertTrue(prog.found(), msg='{!r} not found'.format(cmd_path))
  1583. # Finding a script with no extension inside a directory works
  1584. prog = ExternalProgram(os.path.join(testdir, 'test-script'))
  1585. self.assertTrue(prog.found(), msg='test-script not found')
  1586. # Finding a script with an extension inside a directory works
  1587. prog = ExternalProgram(os.path.join(testdir, 'test-script-ext.py'))
  1588. self.assertTrue(prog.found(), msg='test-script-ext.py not found')
  1589. # Finding a script in PATH w/o extension works and adds the interpreter
  1590. os.environ['PATH'] += os.pathsep + testdir
  1591. prog = ExternalProgram('test-script-ext')
  1592. self.assertTrue(prog.found(), msg='test-script-ext not found in PATH')
  1593. self.assertPathEqual(prog.get_command()[0], python_command[0])
  1594. self.assertPathBasenameEqual(prog.get_path(), 'test-script-ext.py')
  1595. # Finding a script in PATH with extension works and adds the interpreter
  1596. prog = ExternalProgram('test-script-ext.py')
  1597. self.assertTrue(prog.found(), msg='test-script-ext.py not found in PATH')
  1598. self.assertPathEqual(prog.get_command()[0], python_command[0])
  1599. self.assertPathBasenameEqual(prog.get_path(), 'test-script-ext.py')
  1600. def test_ignore_libs(self):
  1601. '''
  1602. Test that find_library on libs that are to be ignored returns an empty
  1603. array of arguments. Must be a unit test because we cannot inspect
  1604. ExternalLibraryHolder from build files.
  1605. '''
  1606. testdir = os.path.join(self.platform_test_dir, '1 basic')
  1607. env = Environment(testdir, self.builddir, self.meson_command,
  1608. get_fake_options(self.prefix), [])
  1609. cc = env.detect_c_compiler(False)
  1610. if cc.id != 'msvc':
  1611. raise unittest.SkipTest('Not using MSVC')
  1612. # To force people to update this test, and also test
  1613. self.assertEqual(set(cc.ignore_libs), {'c', 'm', 'pthread'})
  1614. for l in cc.ignore_libs:
  1615. self.assertEqual(cc.find_library(l, env, []), [])
  1616. class LinuxlikeTests(BasePlatformTests):
  1617. '''
  1618. Tests that should run on Linux and *BSD
  1619. '''
  1620. def test_basic_soname(self):
  1621. '''
  1622. Test that the soname is set correctly for shared libraries. This can't
  1623. be an ordinary test case because we need to run `readelf` and actually
  1624. check the soname.
  1625. https://github.com/mesonbuild/meson/issues/785
  1626. '''
  1627. testdir = os.path.join(self.common_test_dir, '4 shared')
  1628. self.init(testdir)
  1629. self.build()
  1630. lib1 = os.path.join(self.builddir, 'libmylib.so')
  1631. soname = get_soname(lib1)
  1632. self.assertEqual(soname, 'libmylib.so')
  1633. def test_custom_soname(self):
  1634. '''
  1635. Test that the soname is set correctly for shared libraries when
  1636. a custom prefix and/or suffix is used. This can't be an ordinary test
  1637. case because we need to run `readelf` and actually check the soname.
  1638. https://github.com/mesonbuild/meson/issues/785
  1639. '''
  1640. testdir = os.path.join(self.common_test_dir, '27 library versions')
  1641. self.init(testdir)
  1642. self.build()
  1643. lib1 = os.path.join(self.builddir, 'prefixsomelib.suffix')
  1644. soname = get_soname(lib1)
  1645. self.assertEqual(soname, 'prefixsomelib.suffix')
  1646. def test_pic(self):
  1647. '''
  1648. Test that -fPIC is correctly added to static libraries when b_staticpic
  1649. is true and not when it is false. This can't be an ordinary test case
  1650. because we need to inspect the compiler database.
  1651. '''
  1652. testdir = os.path.join(self.common_test_dir, '3 static')
  1653. self.init(testdir)
  1654. compdb = self.get_compdb()
  1655. self.assertIn('-fPIC', compdb[0]['command'])
  1656. self.setconf('-Db_staticpic=false')
  1657. # Regenerate build
  1658. self.build()
  1659. compdb = self.get_compdb()
  1660. self.assertNotIn('-fPIC', compdb[0]['command'])
  1661. def test_pkgconfig_gen(self):
  1662. '''
  1663. Test that generated pkg-config files can be found and have the correct
  1664. version and link args. This can't be an ordinary test case because we
  1665. need to run pkg-config outside of a Meson build file.
  1666. https://github.com/mesonbuild/meson/issues/889
  1667. '''
  1668. testdir = os.path.join(self.common_test_dir, '51 pkgconfig-gen')
  1669. self.init(testdir)
  1670. env = FakeEnvironment()
  1671. kwargs = {'required': True, 'silent': True}
  1672. os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir
  1673. foo_dep = PkgConfigDependency('libfoo', env, kwargs)
  1674. self.assertTrue(foo_dep.found())
  1675. self.assertEqual(foo_dep.get_version(), '1.0')
  1676. self.assertIn('-lfoo', foo_dep.get_link_args())
  1677. self.assertEqual(foo_dep.get_pkgconfig_variable('foo'), 'bar')
  1678. self.assertPathEqual(foo_dep.get_pkgconfig_variable('datadir'), '/usr/data')
  1679. def test_vala_c_warnings(self):
  1680. '''
  1681. Test that no warnings are emitted for C code generated by Vala. This
  1682. can't be an ordinary test case because we need to inspect the compiler
  1683. database.
  1684. https://github.com/mesonbuild/meson/issues/864
  1685. '''
  1686. testdir = os.path.join(self.vala_test_dir, '5 target glib')
  1687. self.init(testdir)
  1688. compdb = self.get_compdb()
  1689. vala_command = None
  1690. c_command = None
  1691. for each in compdb:
  1692. if each['file'].endswith('GLib.Thread.c'):
  1693. vala_command = each['command']
  1694. elif each['file'].endswith('GLib.Thread.vala'):
  1695. continue
  1696. elif each['file'].endswith('retcode.c'):
  1697. c_command = each['command']
  1698. else:
  1699. m = 'Unknown file {!r} in vala_c_warnings test'.format(each['file'])
  1700. raise AssertionError(m)
  1701. self.assertIsNotNone(vala_command)
  1702. self.assertIsNotNone(c_command)
  1703. # -w suppresses all warnings, should be there in Vala but not in C
  1704. self.assertIn(" -w ", vala_command)
  1705. self.assertNotIn(" -w ", c_command)
  1706. # -Wall enables all warnings, should be there in C but not in Vala
  1707. self.assertNotIn(" -Wall ", vala_command)
  1708. self.assertIn(" -Wall ", c_command)
  1709. # -Werror converts warnings to errors, should always be there since it's
  1710. # injected by an unrelated piece of code and the project has werror=true
  1711. self.assertIn(" -Werror ", vala_command)
  1712. self.assertIn(" -Werror ", c_command)
  1713. def test_qt5dependency_pkgconfig_detection(self):
  1714. '''
  1715. Test that qt4 and qt5 detection with pkgconfig works.
  1716. '''
  1717. # Verify Qt4 or Qt5 can be found with pkg-config
  1718. if not shutil.which('pkg-config'):
  1719. raise unittest.SkipTest('pkg-config not found')
  1720. qt4 = subprocess.call(['pkg-config', '--exists', 'QtCore'])
  1721. qt5 = subprocess.call(['pkg-config', '--exists', 'Qt5Core'])
  1722. if qt4 != 0 or qt5 != 0:
  1723. raise unittest.SkipTest('Qt not found with pkg-config')
  1724. testdir = os.path.join(self.framework_test_dir, '4 qt')
  1725. self.init(testdir, ['-Dmethod=pkg-config'])
  1726. # Confirm that the dependency was found with qmake
  1727. msg = 'Qt4 native `pkg-config` dependency (modules: Core, Gui) found: YES\n'
  1728. msg2 = 'Qt5 native `pkg-config` dependency (modules: Core, Gui) found: YES\n'
  1729. mesonlog = self.get_meson_log()
  1730. self.assertTrue(msg in mesonlog or msg2 in mesonlog)
  1731. def test_qt5dependency_qmake_detection(self):
  1732. '''
  1733. Test that qt5 detection with qmake works. This can't be an ordinary
  1734. test case because it involves setting the environment.
  1735. '''
  1736. # Verify that qmake is for Qt5
  1737. if not shutil.which('qmake-qt5'):
  1738. if not shutil.which('qmake'):
  1739. raise unittest.SkipTest('QMake not found')
  1740. # For some inexplicable reason qmake --version gives different
  1741. # results when run from the command line vs invoked by Python.
  1742. # Check for both cases in case this behavior changes in the future.
  1743. output = subprocess.getoutput(['qmake', '--version'])
  1744. if 'Qt version 5' not in output and 'qt5' not in output:
  1745. raise unittest.SkipTest('Qmake found, but it is not for Qt 5.')
  1746. # Disable pkg-config codepath and force searching with qmake/qmake-qt5
  1747. testdir = os.path.join(self.framework_test_dir, '4 qt')
  1748. self.init(testdir, ['-Dmethod=qmake'])
  1749. # Confirm that the dependency was found with qmake
  1750. msg = 'Qt5 native `qmake-qt5` dependency (modules: Core) found: YES\n'
  1751. msg2 = 'Qt5 native `qmake` dependency (modules: Core) found: YES\n'
  1752. mesonlog = self.get_meson_log()
  1753. self.assertTrue(msg in mesonlog or msg2 in mesonlog)
  1754. def _test_soname_impl(self, libpath, install):
  1755. testdir = os.path.join(self.unit_test_dir, '1 soname')
  1756. self.init(testdir)
  1757. self.build()
  1758. if install:
  1759. self.install()
  1760. # File without aliases set.
  1761. nover = os.path.join(libpath, 'libnover.so')
  1762. self.assertPathExists(nover)
  1763. self.assertFalse(os.path.islink(nover))
  1764. self.assertEqual(get_soname(nover), 'libnover.so')
  1765. self.assertEqual(len(glob(nover[:-3] + '*')), 1)
  1766. # File with version set
  1767. verset = os.path.join(libpath, 'libverset.so')
  1768. self.assertPathExists(verset + '.4.5.6')
  1769. self.assertEqual(os.readlink(verset), 'libverset.so.4')
  1770. self.assertEqual(get_soname(verset), 'libverset.so.4')
  1771. self.assertEqual(len(glob(verset[:-3] + '*')), 3)
  1772. # File with soversion set
  1773. soverset = os.path.join(libpath, 'libsoverset.so')
  1774. self.assertPathExists(soverset + '.1.2.3')
  1775. self.assertEqual(os.readlink(soverset), 'libsoverset.so.1.2.3')
  1776. self.assertEqual(get_soname(soverset), 'libsoverset.so.1.2.3')
  1777. self.assertEqual(len(glob(soverset[:-3] + '*')), 2)
  1778. # File with version and soversion set to same values
  1779. settosame = os.path.join(libpath, 'libsettosame.so')
  1780. self.assertPathExists(settosame + '.7.8.9')
  1781. self.assertEqual(os.readlink(settosame), 'libsettosame.so.7.8.9')
  1782. self.assertEqual(get_soname(settosame), 'libsettosame.so.7.8.9')
  1783. self.assertEqual(len(glob(settosame[:-3] + '*')), 2)
  1784. # File with version and soversion set to different values
  1785. bothset = os.path.join(libpath, 'libbothset.so')
  1786. self.assertPathExists(bothset + '.1.2.3')
  1787. self.assertEqual(os.readlink(bothset), 'libbothset.so.1.2.3')
  1788. self.assertEqual(os.readlink(bothset + '.1.2.3'), 'libbothset.so.4.5.6')
  1789. self.assertEqual(get_soname(bothset), 'libbothset.so.1.2.3')
  1790. self.assertEqual(len(glob(bothset[:-3] + '*')), 3)
  1791. def test_soname(self):
  1792. self._test_soname_impl(self.builddir, False)
  1793. def test_installed_soname(self):
  1794. self._test_soname_impl(self.installdir + self.libdir, True)
  1795. def test_compiler_check_flags_order(self):
  1796. '''
  1797. Test that compiler check flags override all other flags. This can't be
  1798. an ordinary test case because it needs the environment to be set.
  1799. '''
  1800. Oflag = '-O3'
  1801. os.environ['CFLAGS'] = os.environ['CXXFLAGS'] = Oflag
  1802. testdir = os.path.join(self.common_test_dir, '43 has function')
  1803. self.init(testdir)
  1804. cmds = self.get_meson_log_compiler_checks()
  1805. for cmd in cmds:
  1806. if cmd[0] == 'ccache':
  1807. cmd = cmd[1:]
  1808. # Verify that -I flags from the `args` kwarg are first
  1809. # This is set in the '43 has function' test case
  1810. self.assertEqual(cmd[1], '-I/tmp')
  1811. # Verify that -O3 set via the environment is overridden by -O0
  1812. Oargs = [arg for arg in cmd if arg.startswith('-O')]
  1813. self.assertEqual(Oargs, [Oflag, '-O0'])
  1814. def _test_stds_impl(self, testdir, compiler, p):
  1815. lang_std = p + '_std'
  1816. # Check that all the listed -std=xxx options for this compiler work
  1817. # just fine when used
  1818. for v in compiler.get_options()[lang_std].choices:
  1819. std_opt = '{}={}'.format(lang_std, v)
  1820. self.init(testdir, ['-D' + std_opt])
  1821. cmd = self.get_compdb()[0]['command']
  1822. if v != 'none':
  1823. cmd_std = " -std={} ".format(v)
  1824. self.assertIn(cmd_std, cmd)
  1825. try:
  1826. self.build()
  1827. except:
  1828. print('{} was {!r}'.format(lang_std, v))
  1829. raise
  1830. self.wipe()
  1831. # Check that an invalid std option in CFLAGS/CPPFLAGS fails
  1832. # Needed because by default ICC ignores invalid options
  1833. cmd_std = '-std=FAIL'
  1834. env_flags = p.upper() + 'FLAGS'
  1835. os.environ[env_flags] = cmd_std
  1836. self.init(testdir)
  1837. cmd = self.get_compdb()[0]['command']
  1838. qcmd_std = " {} ".format(cmd_std)
  1839. self.assertIn(qcmd_std, cmd)
  1840. with self.assertRaises(subprocess.CalledProcessError,
  1841. msg='{} should have failed'.format(qcmd_std)):
  1842. self.build()
  1843. def test_compiler_c_stds(self):
  1844. '''
  1845. Test that C stds specified for this compiler can all be used. Can't be
  1846. an ordinary test because it requires passing options to meson.
  1847. '''
  1848. testdir = os.path.join(self.common_test_dir, '1 trivial')
  1849. env = Environment(testdir, self.builddir, self.meson_command,
  1850. get_fake_options(self.prefix), [])
  1851. cc = env.detect_c_compiler(False)
  1852. self._test_stds_impl(testdir, cc, 'c')
  1853. def test_compiler_cpp_stds(self):
  1854. '''
  1855. Test that C++ stds specified for this compiler can all be used. Can't
  1856. be an ordinary test because it requires passing options to meson.
  1857. '''
  1858. testdir = os.path.join(self.common_test_dir, '2 cpp')
  1859. env = Environment(testdir, self.builddir, self.meson_command,
  1860. get_fake_options(self.prefix), [])
  1861. cpp = env.detect_cpp_compiler(False)
  1862. self._test_stds_impl(testdir, cpp, 'cpp')
  1863. def test_unity_subproj(self):
  1864. testdir = os.path.join(self.common_test_dir, '49 subproject')
  1865. self.init(testdir, extra_args='--unity=subprojects')
  1866. self.assertPathExists(os.path.join(self.builddir, 'subprojects/sublib/simpletest@exe/simpletest-unity.c'))
  1867. self.assertPathExists(os.path.join(self.builddir, 'subprojects/sublib/sublib@sha/sublib-unity.c'))
  1868. self.assertPathDoesNotExist(os.path.join(self.builddir, 'user@exe/user-unity.c'))
  1869. self.build()
  1870. def test_installed_modes(self):
  1871. '''
  1872. Test that files installed by these tests have the correct permissions.
  1873. Can't be an ordinary test because our installed_files.txt is very basic.
  1874. '''
  1875. # Test file modes
  1876. testdir = os.path.join(self.common_test_dir, '12 data')
  1877. self.init(testdir)
  1878. self.install()
  1879. f = os.path.join(self.installdir, 'etc', 'etcfile.dat')
  1880. found_mode = stat.filemode(os.stat(f).st_mode)
  1881. want_mode = 'rw------T'
  1882. self.assertEqual(want_mode, found_mode[1:])
  1883. f = os.path.join(self.installdir, 'usr', 'bin', 'runscript.sh')
  1884. statf = os.stat(f)
  1885. found_mode = stat.filemode(statf.st_mode)
  1886. want_mode = 'rwxr-sr-x'
  1887. self.assertEqual(want_mode, found_mode[1:])
  1888. if os.getuid() == 0:
  1889. # The chown failed nonfatally if we're not root
  1890. self.assertEqual(0, statf.st_uid)
  1891. self.assertEqual(0, statf.st_gid)
  1892. f = os.path.join(self.installdir, 'usr', 'share', 'progname',
  1893. 'fileobject_datafile.dat')
  1894. orig = os.path.join(testdir, 'fileobject_datafile.dat')
  1895. statf = os.stat(f)
  1896. statorig = os.stat(orig)
  1897. found_mode = stat.filemode(statf.st_mode)
  1898. orig_mode = stat.filemode(statorig.st_mode)
  1899. self.assertEqual(orig_mode[1:], found_mode[1:])
  1900. self.assertEqual(os.getuid(), statf.st_uid)
  1901. if os.getuid() == 0:
  1902. # The chown failed nonfatally if we're not root
  1903. self.assertEqual(0, statf.st_gid)
  1904. self.wipe()
  1905. # Test directory modes
  1906. testdir = os.path.join(self.common_test_dir, '66 install subdir')
  1907. self.init(testdir)
  1908. self.install()
  1909. f = os.path.join(self.installdir, 'usr', 'share', 'sub1')
  1910. statf = os.stat(f)
  1911. found_mode = stat.filemode(statf.st_mode)
  1912. want_mode = 'rwxr-x--t'
  1913. self.assertEqual(want_mode, found_mode[1:])
  1914. if os.getuid() == 0:
  1915. # The chown failed nonfatally if we're not root
  1916. self.assertEqual(0, statf.st_uid)
  1917. def test_cpp_std_override(self):
  1918. testdir = os.path.join(self.unit_test_dir, '6 std override')
  1919. self.init(testdir)
  1920. compdb = self.get_compdb()
  1921. for i in compdb:
  1922. if 'prog03' in i['file']:
  1923. c03_comp = i['command']
  1924. if 'prog11' in i['file']:
  1925. c11_comp = i['command']
  1926. if 'progp' in i['file']:
  1927. plain_comp = i['command']
  1928. self.assertNotEqual(len(plain_comp), 0)
  1929. self.assertIn('-std=c++03', c03_comp)
  1930. self.assertNotIn('-std=c++11', c03_comp)
  1931. self.assertIn('-std=c++11', c11_comp)
  1932. self.assertNotIn('-std=c++03', c11_comp)
  1933. self.assertNotIn('-std=c++03', plain_comp)
  1934. self.assertNotIn('-std=c++11', plain_comp)
  1935. # Now werror
  1936. self.assertIn('-Werror', plain_comp)
  1937. self.assertNotIn('-Werror', c03_comp)
  1938. def test_run_installed(self):
  1939. testdir = os.path.join(self.unit_test_dir, '7 run installed')
  1940. self.init(testdir)
  1941. self.build()
  1942. self.install()
  1943. installed_exe = os.path.join(self.installdir, 'usr/bin/prog')
  1944. installed_libdir = os.path.join(self.installdir, 'usr/foo')
  1945. installed_lib = os.path.join(installed_libdir, 'libfoo.so')
  1946. self.assertTrue(os.path.isfile(installed_exe))
  1947. self.assertTrue(os.path.isdir(installed_libdir))
  1948. self.assertTrue(os.path.isfile(installed_lib))
  1949. # Must fail when run without LD_LIBRARY_PATH to ensure that
  1950. # rpath has been properly stripped rather than pointing to the builddir.
  1951. self.assertNotEqual(subprocess.call(installed_exe, stderr=subprocess.DEVNULL), 0)
  1952. # When LD_LIBRARY_PATH is set it should start working.
  1953. # For some reason setting LD_LIBRARY_PATH in os.environ fails
  1954. # when all tests are run (but works when only this test is run),
  1955. # but doing this explicitly works.
  1956. env = os.environ.copy()
  1957. env['LD_LIBRARY_PATH'] = installed_libdir
  1958. self.assertEqual(subprocess.call(installed_exe, env=env), 0)
  1959. def test_order_of_l_arguments(self):
  1960. testdir = os.path.join(self.unit_test_dir, '9 -L -l order')
  1961. os.environ['PKG_CONFIG_PATH'] = testdir
  1962. self.init(testdir)
  1963. # NOTE: .pc file has -Lfoo -lfoo -Lbar -lbar but pkg-config reorders
  1964. # the flags before returning them to -Lfoo -Lbar -lfoo -lbar
  1965. # but pkgconf seems to not do that. Sigh. Support both.
  1966. expected_order = [('-L/me/first', '-lfoo1'),
  1967. ('-L/me/second', '-lfoo2'),
  1968. ('-L/me/first', '-L/me/second'),
  1969. ('-lfoo1', '-lfoo2'),
  1970. ('-L/me/second', '-L/me/third'),
  1971. ('-L/me/third', '-L/me/fourth',),
  1972. ('-L/me/third', '-lfoo3'),
  1973. ('-L/me/fourth', '-lfoo4'),
  1974. ('-lfoo3', '-lfoo4'),
  1975. ]
  1976. with open(os.path.join(self.builddir, 'build.ninja')) as ifile:
  1977. for line in ifile:
  1978. if expected_order[0][0] in line:
  1979. for first, second in expected_order:
  1980. self.assertLess(line.index(first), line.index(second))
  1981. return
  1982. raise RuntimeError('Linker entries not found in the Ninja file.')
  1983. def test_introspect_dependencies(self):
  1984. '''
  1985. Tests that mesonintrospect --dependencies returns expected output.
  1986. '''
  1987. testdir = os.path.join(self.framework_test_dir, '7 gnome')
  1988. self.init(testdir)
  1989. glib_found = False
  1990. gobject_found = False
  1991. deps = self.introspect('--dependencies')
  1992. self.assertIsInstance(deps, list)
  1993. for dep in deps:
  1994. self.assertIsInstance(dep, dict)
  1995. self.assertIn('name', dep)
  1996. self.assertIn('compile_args', dep)
  1997. self.assertIn('link_args', dep)
  1998. if dep['name'] == 'glib-2.0':
  1999. glib_found = True
  2000. elif dep['name'] == 'gobject-2.0':
  2001. gobject_found = True
  2002. self.assertTrue(glib_found)
  2003. self.assertTrue(gobject_found)
  2004. def test_build_rpath(self):
  2005. testdir = os.path.join(self.unit_test_dir, '11 build_rpath')
  2006. self.init(testdir)
  2007. self.build()
  2008. build_rpath = get_rpath(os.path.join(self.builddir, 'prog'))
  2009. self.assertEqual(build_rpath, '$ORIGIN/sub:/foo/bar')
  2010. self.install()
  2011. install_rpath = get_rpath(os.path.join(self.installdir, 'usr/bin/prog'))
  2012. self.assertEqual(install_rpath, '/baz')
  2013. def test_pch_with_address_sanitizer(self):
  2014. testdir = os.path.join(self.common_test_dir, '13 pch')
  2015. self.init(testdir, ['-Db_sanitize=address'])
  2016. self.build()
  2017. compdb = self.get_compdb()
  2018. for i in compdb:
  2019. self.assertIn("-fsanitize=address", i["command"])
  2020. def test_coverage(self):
  2021. if not shutil.which('gcovr'):
  2022. raise unittest.SkipTest('gcovr not found')
  2023. if not shutil.which('genhtml'):
  2024. raise unittest.SkipTest('genhtml not found')
  2025. if 'clang' in os.environ.get('CC', '') and os.environ.get('TRAVIS_OS_NAME', '') == 'linux':
  2026. raise unittest.SkipTest('Gcovr has a bug and does not work with Clang in the CI environment.')
  2027. testdir = os.path.join(self.common_test_dir, '1 trivial')
  2028. self.init(testdir, ['-Db_coverage=true'])
  2029. self.build()
  2030. self.run_tests()
  2031. self.run_target('coverage-html')
  2032. def test_cross_find_program(self):
  2033. testdir = os.path.join(self.unit_test_dir, '12 cross prog')
  2034. crossfile = tempfile.NamedTemporaryFile(mode='w')
  2035. print(os.path.join(testdir, 'some_cross_tool.py'))
  2036. crossfile.write('''[binaries]
  2037. c = '/usr/bin/cc'
  2038. ar = '/usr/bin/ar'
  2039. strip = '/usr/bin/ar'
  2040. sometool.py = '%s'
  2041. [properties]
  2042. [host_machine]
  2043. system = 'linux'
  2044. cpu_family = 'arm'
  2045. cpu = 'armv7' # Not sure if correct.
  2046. endian = 'little'
  2047. ''' % os.path.join(testdir, 'some_cross_tool.py'))
  2048. crossfile.flush()
  2049. self.init(testdir, ['--cross-file=' + crossfile.name])
  2050. def test_reconfigure(self):
  2051. testdir = os.path.join(self.unit_test_dir, '13 reconfigure')
  2052. self.init(testdir, ['-Db_lto=true'], default_args=False)
  2053. self.build('reconfigure')
  2054. class LinuxArmCrossCompileTests(BasePlatformTests):
  2055. '''
  2056. Tests that verify cross-compilation to Linux/ARM
  2057. '''
  2058. def setUp(self):
  2059. super().setUp()
  2060. src_root = os.path.dirname(__file__)
  2061. self.meson_command += ['--cross=' + os.path.join(src_root, 'cross', 'ubuntu-armhf.txt')]
  2062. def test_cflags_cross_environment_pollution(self):
  2063. '''
  2064. Test that the CFLAGS environment variable does not pollute the cross
  2065. environment. This can't be an ordinary test case because we need to
  2066. inspect the compiler database.
  2067. '''
  2068. testdir = os.path.join(self.common_test_dir, '3 static')
  2069. os.environ['CFLAGS'] = '-DBUILD_ENVIRONMENT_ONLY'
  2070. self.init(testdir)
  2071. compdb = self.get_compdb()
  2072. self.assertNotIn('-DBUILD_ENVIRONMENT_ONLY', compdb[0]['command'])
  2073. class RewriterTests(unittest.TestCase):
  2074. def setUp(self):
  2075. super().setUp()
  2076. src_root = os.path.dirname(__file__)
  2077. self.testroot = os.path.realpath(tempfile.mkdtemp())
  2078. self.rewrite_command = python_command + [os.path.join(src_root, 'mesonrewriter.py')]
  2079. self.tmpdir = os.path.realpath(tempfile.mkdtemp())
  2080. self.workdir = os.path.join(self.tmpdir, 'foo')
  2081. self.test_dir = os.path.join(src_root, 'test cases/rewrite')
  2082. def tearDown(self):
  2083. windows_proof_rmtree(self.tmpdir)
  2084. def read_contents(self, fname):
  2085. with open(os.path.join(self.workdir, fname)) as f:
  2086. return f.read()
  2087. def check_effectively_same(self, mainfile, truth):
  2088. mf = self.read_contents(mainfile)
  2089. t = self.read_contents(truth)
  2090. # Rewriting is not guaranteed to do a perfect job of
  2091. # maintaining whitespace.
  2092. self.assertEqual(mf.replace(' ', ''), t.replace(' ', ''))
  2093. def prime(self, dirname):
  2094. shutil.copytree(os.path.join(self.test_dir, dirname), self.workdir)
  2095. def test_basic(self):
  2096. self.prime('1 basic')
  2097. subprocess.check_call(self.rewrite_command + ['remove',
  2098. '--target=trivialprog',
  2099. '--filename=notthere.c',
  2100. '--sourcedir', self.workdir],
  2101. universal_newlines=True)
  2102. self.check_effectively_same('meson.build', 'removed.txt')
  2103. subprocess.check_call(self.rewrite_command + ['add',
  2104. '--target=trivialprog',
  2105. '--filename=notthere.c',
  2106. '--sourcedir', self.workdir],
  2107. universal_newlines=True)
  2108. self.check_effectively_same('meson.build', 'added.txt')
  2109. subprocess.check_call(self.rewrite_command + ['remove',
  2110. '--target=trivialprog',
  2111. '--filename=notthere.c',
  2112. '--sourcedir', self.workdir],
  2113. universal_newlines=True)
  2114. self.check_effectively_same('meson.build', 'removed.txt')
  2115. def test_subdir(self):
  2116. self.prime('2 subdirs')
  2117. top = self.read_contents('meson.build')
  2118. s2 = self.read_contents('sub2/meson.build')
  2119. subprocess.check_call(self.rewrite_command + ['remove',
  2120. '--target=something',
  2121. '--filename=second.c',
  2122. '--sourcedir', self.workdir],
  2123. universal_newlines=True)
  2124. self.check_effectively_same('sub1/meson.build', 'sub1/after.txt')
  2125. self.assertEqual(top, self.read_contents('meson.build'))
  2126. self.assertEqual(s2, self.read_contents('sub2/meson.build'))
  2127. def unset_envs():
  2128. # For unit tests we must fully control all commend lines
  2129. # so that there are no unexpected changes coming from the
  2130. # environment, for example when doing a package build.
  2131. varnames = ['CPPFLAGS', 'LDFLAGS'] + list(mesonbuild.environment.cflags_mapping.values())
  2132. for v in varnames:
  2133. if v in os.environ:
  2134. del os.environ[v]
  2135. if __name__ == '__main__':
  2136. unset_envs()
  2137. cases = ['InternalTests', 'AllPlatformTests', 'FailureTests']
  2138. if is_linux():
  2139. cases += ['LinuxlikeTests']
  2140. if should_run_linux_cross_tests():
  2141. cases += ['LinuxArmCrossCompileTests']
  2142. elif is_windows():
  2143. cases += ['WindowsTests']
  2144. unittest.main(defaultTest=cases, buffer=True)