ninjabackend.py 124 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561
  1. # Copyright 2012-2017 The Meson development team
  2. # Licensed under the Apache License, Version 2.0 (the "License");
  3. # you may not use this file except in compliance with the License.
  4. # You may obtain a copy of the License at
  5. # http://www.apache.org/licenses/LICENSE-2.0
  6. # Unless required by applicable law or agreed to in writing, software
  7. # distributed under the License is distributed on an "AS IS" BASIS,
  8. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. # See the License for the specific language governing permissions and
  10. # limitations under the License.
  11. import os, pickle, re, shlex, shutil, subprocess, sys
  12. from collections import OrderedDict
  13. from . import backends
  14. from .. import modules
  15. from .. import environment, mesonlib
  16. from .. import build
  17. from .. import mlog
  18. from .. import dependencies
  19. from .. import compilers
  20. from ..compilers import CompilerArgs
  21. from ..linkers import ArLinker
  22. from ..mesonlib import File, MesonException, OrderedSet
  23. from ..mesonlib import get_meson_script, get_compiler_for_source
  24. from .backends import CleanTrees, InstallData
  25. from ..build import InvalidArguments
  26. if mesonlib.is_windows():
  27. quote_func = lambda s: '"{}"'.format(s)
  28. execute_wrapper = 'cmd /c'
  29. rmfile_prefix = 'del /f /s /q {} &&'
  30. else:
  31. quote_func = shlex.quote
  32. execute_wrapper = ''
  33. rmfile_prefix = 'rm -f {} &&'
  34. def ninja_quote(text):
  35. for char in ('$', ' ', ':'):
  36. text = text.replace(char, '$' + char)
  37. if '\n' in text:
  38. raise MesonException('Ninja does not support newlines in rules. '
  39. 'Please report this error with a test case to the Meson bug tracker.')
  40. return text
  41. class NinjaBuildElement:
  42. def __init__(self, all_outputs, outfilenames, rule, infilenames):
  43. if isinstance(outfilenames, str):
  44. self.outfilenames = [outfilenames]
  45. else:
  46. self.outfilenames = outfilenames
  47. assert(isinstance(rule, str))
  48. self.rule = rule
  49. if isinstance(infilenames, str):
  50. self.infilenames = [infilenames]
  51. else:
  52. self.infilenames = infilenames
  53. self.deps = set()
  54. self.orderdeps = set()
  55. self.elems = []
  56. self.all_outputs = all_outputs
  57. def add_dep(self, dep):
  58. if isinstance(dep, list):
  59. self.deps.update(dep)
  60. else:
  61. self.deps.add(dep)
  62. def add_orderdep(self, dep):
  63. if isinstance(dep, list):
  64. self.orderdeps.update(dep)
  65. else:
  66. self.orderdeps.add(dep)
  67. def add_item(self, name, elems):
  68. if isinstance(elems, str):
  69. elems = [elems]
  70. self.elems.append((name, elems))
  71. def write(self, outfile):
  72. self.check_outputs()
  73. line = 'build %s: %s %s' % (
  74. ' '.join([ninja_quote(i) for i in self.outfilenames]),
  75. self.rule,
  76. ' '.join([ninja_quote(i) for i in self.infilenames]))
  77. if len(self.deps) > 0:
  78. line += ' | ' + ' '.join([ninja_quote(x) for x in self.deps])
  79. if len(self.orderdeps) > 0:
  80. line += ' || ' + ' '.join([ninja_quote(x) for x in self.orderdeps])
  81. line += '\n'
  82. # This is the only way I could find to make this work on all
  83. # platforms including Windows command shell. Slash is a dir separator
  84. # on Windows, too, so all characters are unambiguous and, more importantly,
  85. # do not require quoting.
  86. line = line.replace('\\', '/')
  87. outfile.write(line)
  88. # All the entries that should remain unquoted
  89. raw_names = {'DEPFILE', 'DESC', 'pool', 'description'}
  90. for e in self.elems:
  91. (name, elems) = e
  92. should_quote = name not in raw_names
  93. line = ' %s = ' % name
  94. noq_templ = "%s"
  95. newelems = []
  96. for i in elems:
  97. if not should_quote or i == '&&': # Hackety hack hack
  98. quoter = ninja_quote
  99. else:
  100. quoter = lambda x: ninja_quote(quote_func(x))
  101. i = i.replace('\\', '\\\\')
  102. if quote_func('') == '""':
  103. i = i.replace('"', '\\"')
  104. newelems.append(quoter(i))
  105. line += ' '.join(newelems)
  106. line += '\n'
  107. outfile.write(line)
  108. outfile.write('\n')
  109. def check_outputs(self):
  110. for n in self.outfilenames:
  111. if n in self.all_outputs:
  112. raise MesonException('Multiple producers for Ninja target "%s". Please rename your targets.' % n)
  113. self.all_outputs[n] = True
  114. class NinjaBackend(backends.Backend):
  115. def __init__(self, build):
  116. super().__init__(build)
  117. self.name = 'ninja'
  118. self.ninja_filename = 'build.ninja'
  119. self.target_arg_cache = {}
  120. self.fortran_deps = {}
  121. self.all_outputs = {}
  122. def detect_vs_dep_prefix(self, tempfilename):
  123. '''VS writes its dependency in a locale dependent format.
  124. Detect the search prefix to use.'''
  125. # Of course there is another program called 'cl' on
  126. # some platforms. Let's just require that on Windows
  127. # cl points to msvc.
  128. if not mesonlib.is_windows() or shutil.which('cl') is None:
  129. return open(tempfilename, 'a')
  130. filename = os.path.join(self.environment.get_scratch_dir(),
  131. 'incdetect.c')
  132. with open(filename, 'w') as f:
  133. f.write('''#include<stdio.h>
  134. int dummy;
  135. ''')
  136. # The output of cl dependency information is language
  137. # and locale dependent. Any attempt at converting it to
  138. # Python strings leads to failure. We _must_ do this detection
  139. # in raw byte mode and write the result in raw bytes.
  140. pc = subprocess.Popen(['cl', '/showIncludes', '/c', 'incdetect.c'],
  141. cwd=self.environment.get_scratch_dir(),
  142. stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  143. (stdo, _) = pc.communicate()
  144. # We want to match 'Note: including file: ' in the line
  145. # 'Note: including file: d:\MyDir\include\stdio.h', however
  146. # different locales have different messages with a different
  147. # number of colons. Match up to the the drive name 'd:\'.
  148. matchre = re.compile(rb"^(.*\s)[a-zA-Z]:\\.*stdio.h$")
  149. for line in stdo.split(b'\r\n'):
  150. match = matchre.match(line)
  151. if match:
  152. with open(tempfilename, 'ab') as binfile:
  153. binfile.write(b'msvc_deps_prefix = ' + match.group(1) + b'\n')
  154. return open(tempfilename, 'a')
  155. raise MesonException('Could not determine vs dep dependency prefix string.')
  156. def generate(self, interp):
  157. self.interpreter = interp
  158. outfilename = os.path.join(self.environment.get_build_dir(), self.ninja_filename)
  159. tempfilename = outfilename + '~'
  160. with open(tempfilename, 'w') as outfile:
  161. outfile.write('# This is the build file for project "%s"\n' %
  162. self.build.get_project())
  163. outfile.write('# It is autogenerated by the Meson build system.\n')
  164. outfile.write('# Do not edit by hand.\n\n')
  165. outfile.write('ninja_required_version = 1.5.1\n\n')
  166. with self.detect_vs_dep_prefix(tempfilename) as outfile:
  167. self.generate_rules(outfile)
  168. self.generate_phony(outfile)
  169. outfile.write('# Build rules for targets\n\n')
  170. for t in self.build.get_targets().values():
  171. self.generate_target(t, outfile)
  172. outfile.write('# Test rules\n\n')
  173. self.generate_tests(outfile)
  174. outfile.write('# Install rules\n\n')
  175. self.generate_install(outfile)
  176. self.generate_dist(outfile)
  177. if 'b_coverage' in self.environment.coredata.base_options and \
  178. self.environment.coredata.base_options['b_coverage'].value:
  179. outfile.write('# Coverage rules\n\n')
  180. self.generate_coverage_rules(outfile)
  181. outfile.write('# Suffix\n\n')
  182. self.generate_utils(outfile)
  183. self.generate_ending(outfile)
  184. # Only ovewrite the old build file after the new one has been
  185. # fully created.
  186. os.replace(tempfilename, outfilename)
  187. self.generate_compdb()
  188. # http://clang.llvm.org/docs/JSONCompilationDatabase.html
  189. def generate_compdb(self):
  190. ninja_exe = environment.detect_ninja()
  191. pch_compilers = ['%s_PCH' % i for i in self.build.compilers]
  192. native_compilers = ['%s_COMPILER' % i for i in self.build.compilers]
  193. cross_compilers = ['%s_CROSS_COMPILER' % i for i in self.build.cross_compilers]
  194. ninja_compdb = [ninja_exe, '-t', 'compdb'] + pch_compilers + native_compilers + cross_compilers
  195. builddir = self.environment.get_build_dir()
  196. try:
  197. jsondb = subprocess.check_output(ninja_compdb, cwd=builddir)
  198. with open(os.path.join(builddir, 'compile_commands.json'), 'wb') as f:
  199. f.write(jsondb)
  200. except Exception:
  201. mlog.warning('Could not create compilation database.')
  202. # Get all generated headers. Any source file might need them so
  203. # we need to add an order dependency to them.
  204. def get_generated_headers(self, target):
  205. header_deps = []
  206. # XXX: Why don't we add deps to CustomTarget headers here?
  207. for genlist in target.get_generated_sources():
  208. if isinstance(genlist, build.CustomTarget):
  209. continue
  210. for src in genlist.get_outputs():
  211. if self.environment.is_header(src):
  212. header_deps.append(self.get_target_generated_dir(target, genlist, src))
  213. if 'vala' in target.compilers and not isinstance(target, build.Executable):
  214. vala_header = File.from_built_file(self.get_target_dir(target), target.vala_header)
  215. header_deps.append(vala_header)
  216. # Recurse and find generated headers
  217. for dep in target.link_targets:
  218. if isinstance(dep, (build.StaticLibrary, build.SharedLibrary)):
  219. header_deps += self.get_generated_headers(dep)
  220. return header_deps
  221. def get_target_generated_sources(self, target):
  222. """
  223. Returns a dictionary with the keys being the path to the file
  224. (relative to the build directory) of that type and the value
  225. being the GeneratorList or CustomTarget that generated it.
  226. """
  227. srcs = OrderedDict()
  228. for gensrc in target.get_generated_sources():
  229. for s in gensrc.get_outputs():
  230. f = self.get_target_generated_dir(target, gensrc, s)
  231. srcs[f] = s
  232. return srcs
  233. def get_target_sources(self, target):
  234. srcs = OrderedDict()
  235. for s in target.get_sources():
  236. # BuildTarget sources are always mesonlib.File files which are
  237. # either in the source root, or generated with configure_file and
  238. # in the build root
  239. if not isinstance(s, File):
  240. raise InvalidArguments('All sources in target {!r} must be of type mesonlib.File'.format(s))
  241. f = s.rel_to_builddir(self.build_to_src)
  242. srcs[f] = s
  243. return srcs
  244. # Languages that can mix with C or C++ but don't support unity builds yet
  245. # because the syntax we use for unity builds is specific to C/++/ObjC/++.
  246. # Assembly files cannot be unitified and neither can LLVM IR files
  247. langs_cant_unity = ('d', 'fortran')
  248. def get_target_source_can_unity(self, target, source):
  249. if isinstance(source, File):
  250. source = source.fname
  251. if self.environment.is_llvm_ir(source) or \
  252. self.environment.is_assembly(source):
  253. return False
  254. suffix = os.path.splitext(source)[1][1:]
  255. for lang in self.langs_cant_unity:
  256. if lang not in target.compilers:
  257. continue
  258. if suffix in target.compilers[lang].file_suffixes:
  259. return False
  260. return True
  261. def generate_target(self, target, outfile):
  262. if isinstance(target, build.CustomTarget):
  263. self.generate_custom_target(target, outfile)
  264. if isinstance(target, build.RunTarget):
  265. self.generate_run_target(target, outfile)
  266. name = target.get_id()
  267. if name in self.processed_targets:
  268. return
  269. self.processed_targets[name] = True
  270. # Generate rules for all dependency targets
  271. self.process_target_dependencies(target, outfile)
  272. # If target uses a language that cannot link to C objects,
  273. # just generate for that language and return.
  274. if isinstance(target, build.Jar):
  275. self.generate_jar_target(target, outfile)
  276. return
  277. if 'rust' in target.compilers:
  278. self.generate_rust_target(target, outfile)
  279. return
  280. if 'cs' in target.compilers:
  281. self.generate_cs_target(target, outfile)
  282. return
  283. if 'swift' in target.compilers:
  284. self.generate_swift_target(target, outfile)
  285. return
  286. # Now we handle the following languages:
  287. # ObjC++, ObjC, C++, C, D, Fortran, Vala
  288. # target_sources:
  289. # Pre-existing target C/C++ sources to be built; dict of full path to
  290. # source relative to build root and the original File object.
  291. # generated_sources:
  292. # GeneratedList and CustomTarget sources to be built; dict of the full
  293. # path to source relative to build root and the generating target/list
  294. # vala_generated_sources:
  295. # Array of sources generated by valac that have to be compiled
  296. if 'vala' in target.compilers:
  297. # Sources consumed by valac are filtered out. These only contain
  298. # C/C++ sources, objects, generated libs, and unknown sources now.
  299. target_sources, generated_sources, \
  300. vala_generated_sources = self.generate_vala_compile(target, outfile)
  301. else:
  302. target_sources = self.get_target_sources(target)
  303. generated_sources = self.get_target_generated_sources(target)
  304. vala_generated_sources = []
  305. self.scan_fortran_module_outputs(target)
  306. # Generate rules for GeneratedLists
  307. self.generate_generator_list_rules(target, outfile)
  308. # Generate rules for building the remaining source files in this target
  309. outname = self.get_target_filename(target)
  310. obj_list = []
  311. use_pch = self.environment.coredata.base_options.get('b_pch', False)
  312. is_unity = self.is_unity(target)
  313. if use_pch and target.has_pch():
  314. pch_objects = self.generate_pch(target, outfile)
  315. else:
  316. pch_objects = []
  317. header_deps = []
  318. unity_src = []
  319. unity_deps = [] # Generated sources that must be built before compiling a Unity target.
  320. header_deps += self.get_generated_headers(target)
  321. if is_unity:
  322. # Warn about incompatible sources if a unity build is enabled
  323. langs = set(target.compilers.keys())
  324. langs_cant = langs.intersection(self.langs_cant_unity)
  325. if langs_cant:
  326. langs_are = langs = ', '.join(langs_cant).upper()
  327. langs_are += ' are' if len(langs_cant) > 1 else ' is'
  328. msg = '{} not supported in Unity builds yet, so {} ' \
  329. 'sources in the {!r} target will be compiled normally' \
  330. ''.format(langs_are, langs, target.name)
  331. mlog.log(mlog.red('FIXME'), msg)
  332. # Get a list of all generated headers that will be needed while building
  333. # this target's sources (generated sources and pre-existing sources).
  334. # This will be set as dependencies of all the target's sources. At the
  335. # same time, also deal with generated sources that need to be compiled.
  336. generated_source_files = []
  337. for rel_src, gensrc in generated_sources.items():
  338. dirpart, fnamepart = os.path.split(rel_src)
  339. raw_src = File(True, dirpart, fnamepart)
  340. if self.environment.is_source(rel_src) and not self.environment.is_header(rel_src):
  341. if is_unity and self.get_target_source_can_unity(target, rel_src):
  342. unity_deps.append(raw_src)
  343. abs_src = os.path.join(self.environment.get_build_dir(), rel_src)
  344. unity_src.append(abs_src)
  345. else:
  346. generated_source_files.append(raw_src)
  347. elif self.environment.is_object(rel_src):
  348. obj_list.append(rel_src)
  349. elif self.environment.is_library(rel_src):
  350. pass
  351. else:
  352. # Assume anything not specifically a source file is a header. This is because
  353. # people generate files with weird suffixes (.inc, .fh) that they then include
  354. # in their source files.
  355. header_deps.append(raw_src)
  356. # These are the generated source files that need to be built for use by
  357. # this target. We create the Ninja build file elements for this here
  358. # because we need `header_deps` to be fully generated in the above loop.
  359. for src in generated_source_files:
  360. if self.environment.is_llvm_ir(src):
  361. o = self.generate_llvm_ir_compile(target, outfile, src)
  362. else:
  363. o = self.generate_single_compile(target, outfile, src, True,
  364. header_deps=header_deps)
  365. obj_list.append(o)
  366. # Generate compilation targets for C sources generated from Vala
  367. # sources. This can be extended to other $LANG->C compilers later if
  368. # necessary. This needs to be separate for at least Vala
  369. vala_generated_source_files = []
  370. for src in vala_generated_sources:
  371. dirpart, fnamepart = os.path.split(src)
  372. raw_src = File(True, dirpart, fnamepart)
  373. if is_unity:
  374. unity_src.append(os.path.join(self.environment.get_build_dir(), src))
  375. header_deps.append(raw_src)
  376. else:
  377. # Generated targets are ordered deps because the must exist
  378. # before the sources compiling them are used. After the first
  379. # compile we get precise dependency info from dep files.
  380. # This should work in all cases. If it does not, then just
  381. # move them from orderdeps to proper deps.
  382. if self.environment.is_header(src):
  383. header_deps.append(raw_src)
  384. else:
  385. # We gather all these and generate compile rules below
  386. # after `header_deps` (above) is fully generated
  387. vala_generated_source_files.append(raw_src)
  388. for src in vala_generated_source_files:
  389. # Passing 'vala' here signifies that we want the compile
  390. # arguments to be specialized for C code generated by
  391. # valac. For instance, no warnings should be emitted.
  392. obj_list.append(self.generate_single_compile(target, outfile, src, 'vala', [], header_deps))
  393. # Generate compile targets for all the pre-existing sources for this target
  394. for f, src in target_sources.items():
  395. if not self.environment.is_header(src):
  396. if self.environment.is_llvm_ir(src):
  397. obj_list.append(self.generate_llvm_ir_compile(target, outfile, src))
  398. elif is_unity and self.get_target_source_can_unity(target, src):
  399. abs_src = os.path.join(self.environment.get_build_dir(),
  400. src.rel_to_builddir(self.build_to_src))
  401. unity_src.append(abs_src)
  402. else:
  403. obj_list.append(self.generate_single_compile(target, outfile, src, False, [], header_deps))
  404. obj_list += self.flatten_object_list(target)
  405. if is_unity:
  406. for src in self.generate_unity_files(target, unity_src):
  407. obj_list.append(self.generate_single_compile(target, outfile, src, True, unity_deps + header_deps))
  408. linker = self.determine_linker(target)
  409. elem = self.generate_link(target, outfile, outname, obj_list, linker, pch_objects)
  410. self.generate_shlib_aliases(target, self.get_target_dir(target))
  411. elem.write(outfile)
  412. def process_target_dependencies(self, target, outfile):
  413. for t in target.get_dependencies():
  414. tname = t.get_basename() + t.type_suffix()
  415. if tname not in self.processed_targets:
  416. self.generate_target(t, outfile)
  417. def custom_target_generator_inputs(self, target, outfile):
  418. for s in target.sources:
  419. if hasattr(s, 'held_object'):
  420. s = s.held_object
  421. if isinstance(s, build.GeneratedList):
  422. self.generate_genlist_for_target(s, target, outfile)
  423. def unwrap_dep_list(self, target):
  424. deps = []
  425. for i in target.get_dependencies():
  426. # FIXME, should not grab element at zero but rather expand all.
  427. if isinstance(i, list):
  428. i = i[0]
  429. # Add a dependency on all the outputs of this target
  430. for output in i.get_outputs():
  431. deps.append(os.path.join(self.get_target_dir(i), output))
  432. return deps
  433. def generate_custom_target(self, target, outfile):
  434. self.custom_target_generator_inputs(target, outfile)
  435. (srcs, ofilenames, cmd) = self.eval_custom_target_command(target)
  436. deps = self.unwrap_dep_list(target)
  437. deps += self.get_custom_target_depend_files(target)
  438. desc = 'Generating {0} with a {1} command.'
  439. if target.build_always:
  440. deps.append('PHONY')
  441. if target.depfile is None:
  442. rulename = 'CUSTOM_COMMAND'
  443. else:
  444. rulename = 'CUSTOM_COMMAND_DEP'
  445. elem = NinjaBuildElement(self.all_outputs, ofilenames, rulename, srcs)
  446. elem.add_dep(deps)
  447. for d in target.extra_depends:
  448. # Add a dependency on all the outputs of this target
  449. for output in d.get_outputs():
  450. elem.add_dep(os.path.join(self.get_target_dir(d), output))
  451. # If the target requires capturing stdout, then use the serialized
  452. # executable wrapper to capture that output and save it to a file.
  453. #
  454. # If the command line requires a newline, also use the wrapper, as
  455. # ninja does not support them in its build rule syntax.
  456. #
  457. # Windows doesn't have -rpath, so for EXEs that need DLLs built within
  458. # the project, we need to set PATH so the DLLs are found. We use
  459. # a serialized executable wrapper for that and check if the
  460. # CustomTarget command needs extra paths first.
  461. if (target.capture or any('\n' in c for c in cmd) or
  462. ((mesonlib.is_windows() or mesonlib.is_cygwin()) and
  463. self.determine_windows_extra_paths(target.command[0]))):
  464. exe_data = self.serialize_executable(target.command[0], cmd[1:],
  465. # All targets are built from the build dir
  466. self.environment.get_build_dir(),
  467. capture=ofilenames[0] if target.capture else None)
  468. cmd = [sys.executable, self.environment.get_build_command(),
  469. '--internal', 'exe', exe_data]
  470. cmd_type = 'meson_exe.py custom'
  471. else:
  472. cmd_type = 'custom'
  473. if target.depfile is not None:
  474. rel_dfile = os.path.join(self.get_target_dir(target), target.depfile)
  475. abs_pdir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target))
  476. os.makedirs(abs_pdir, exist_ok=True)
  477. elem.add_item('DEPFILE', rel_dfile)
  478. cmd = self.replace_paths(target, cmd)
  479. elem.add_item('COMMAND', cmd)
  480. elem.add_item('description', desc.format(target.name, cmd_type))
  481. elem.write(outfile)
  482. self.processed_targets[target.name + target.type_suffix()] = True
  483. def generate_run_target(self, target, outfile):
  484. cmd = [sys.executable, self.environment.get_build_command(), '--internal', 'commandrunner']
  485. deps = self.unwrap_dep_list(target)
  486. arg_strings = []
  487. for i in target.args:
  488. if isinstance(i, str):
  489. arg_strings.append(i)
  490. elif isinstance(i, (build.BuildTarget, build.CustomTarget)):
  491. relfname = self.get_target_filename(i)
  492. arg_strings.append(os.path.join(self.environment.get_build_dir(), relfname))
  493. deps.append(relfname)
  494. elif isinstance(i, mesonlib.File):
  495. relfname = i.rel_to_builddir(self.build_to_src)
  496. arg_strings.append(os.path.join(self.environment.get_build_dir(), relfname))
  497. else:
  498. raise AssertionError('Unreachable code in generate_run_target: ' + str(i))
  499. elem = NinjaBuildElement(self.all_outputs, target.name, 'CUSTOM_COMMAND', [])
  500. cmd += [self.environment.get_source_dir(),
  501. self.environment.get_build_dir(),
  502. target.subdir,
  503. get_meson_script(self.environment, 'mesonintrospect')]
  504. texe = target.command
  505. try:
  506. texe = texe.held_object
  507. except AttributeError:
  508. pass
  509. if isinstance(texe, build.Executable):
  510. abs_exe = os.path.join(self.environment.get_build_dir(), self.get_target_filename(texe))
  511. deps.append(self.get_target_filename(texe))
  512. if self.environment.is_cross_build() and \
  513. self.environment.cross_info.need_exe_wrapper():
  514. exe_wrap = self.environment.cross_info.config['binaries'].get('exe_wrapper', None)
  515. if exe_wrap is not None:
  516. cmd += [exe_wrap]
  517. cmd.append(abs_exe)
  518. elif isinstance(texe, dependencies.ExternalProgram):
  519. cmd += texe.get_command()
  520. elif isinstance(texe, build.CustomTarget):
  521. deps.append(self.get_target_filename(texe))
  522. cmd += [os.path.join(self.environment.get_build_dir(), self.get_target_filename(texe))]
  523. elif isinstance(texe, mesonlib.File):
  524. cmd.append(texe.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir()))
  525. else:
  526. cmd.append(target.command)
  527. cmd += arg_strings
  528. elem.add_dep(deps)
  529. cmd = self.replace_paths(target, cmd)
  530. elem.add_item('COMMAND', cmd)
  531. elem.add_item('description', 'Running external command %s.' % target.name)
  532. elem.add_item('pool', 'console')
  533. elem.write(outfile)
  534. self.processed_targets[target.name + target.type_suffix()] = True
  535. def generate_coverage_rules(self, outfile):
  536. e = NinjaBuildElement(self.all_outputs, 'coverage', 'CUSTOM_COMMAND', 'PHONY')
  537. e.add_item('COMMAND', [sys.executable,
  538. self.environment.get_build_command(),
  539. '--internal', 'coverage',
  540. self.environment.get_source_dir(),
  541. self.environment.get_build_dir(),
  542. self.environment.get_log_dir()])
  543. e.add_item('description', 'Generates coverage reports.')
  544. e.write(outfile)
  545. self.generate_coverage_legacy_rules(outfile)
  546. def generate_coverage_legacy_rules(self, outfile):
  547. (gcovr_exe, lcov_exe, genhtml_exe) = environment.find_coverage_tools()
  548. added_rule = False
  549. if gcovr_exe:
  550. added_rule = True
  551. elem = NinjaBuildElement(self.all_outputs, 'coverage-xml', 'CUSTOM_COMMAND', '')
  552. elem.add_item('COMMAND', [gcovr_exe, '-x', '-r', self.environment.get_source_dir(),
  553. '-o', os.path.join(self.environment.get_log_dir(), 'coverage.xml')])
  554. elem.add_item('DESC', 'Generating XML coverage report.')
  555. elem.write(outfile)
  556. elem = NinjaBuildElement(self.all_outputs, 'coverage-text', 'CUSTOM_COMMAND', '')
  557. elem.add_item('COMMAND', [gcovr_exe, '-r', self.environment.get_source_dir(),
  558. '-o', os.path.join(self.environment.get_log_dir(), 'coverage.txt')])
  559. elem.add_item('DESC', 'Generating text coverage report.')
  560. elem.write(outfile)
  561. if lcov_exe and genhtml_exe:
  562. added_rule = True
  563. htmloutdir = os.path.join(self.environment.get_log_dir(), 'coveragereport')
  564. covinfo = os.path.join(self.environment.get_log_dir(), 'coverage.info')
  565. phony_elem = NinjaBuildElement(self.all_outputs, 'coverage-html', 'phony', os.path.join(htmloutdir, 'index.html'))
  566. phony_elem.write(outfile)
  567. elem = NinjaBuildElement(self.all_outputs, os.path.join(htmloutdir, 'index.html'), 'CUSTOM_COMMAND', '')
  568. command = [lcov_exe, '--directory', self.environment.get_build_dir(),
  569. '--capture', '--output-file', covinfo, '--no-checksum',
  570. '&&', genhtml_exe, '--prefix', self.environment.get_build_dir(),
  571. '--output-directory', htmloutdir, '--title', 'Code coverage',
  572. '--legend', '--show-details', covinfo]
  573. elem.add_item('COMMAND', command)
  574. elem.add_item('DESC', 'Generating HTML coverage report.')
  575. elem.write(outfile)
  576. if not added_rule:
  577. mlog.warning('coverage requested but neither gcovr nor lcov/genhtml found.')
  578. def generate_install(self, outfile):
  579. install_data_file = os.path.join(self.environment.get_scratch_dir(), 'install.dat')
  580. if self.environment.is_cross_build():
  581. bins = self.environment.cross_info.config['binaries']
  582. if 'strip' not in bins:
  583. mlog.warning('Cross file does not specify strip binary, result will not be stripped.')
  584. strip_bin = None
  585. else:
  586. strip_bin = mesonlib.stringlistify(bins['strip'])
  587. else:
  588. strip_bin = self.environment.native_strip_bin
  589. d = InstallData(self.environment.get_source_dir(),
  590. self.environment.get_build_dir(),
  591. self.environment.get_prefix(),
  592. strip_bin,
  593. get_meson_script(self.environment, 'mesonintrospect'))
  594. elem = NinjaBuildElement(self.all_outputs, 'install', 'CUSTOM_COMMAND', 'PHONY')
  595. elem.add_dep('all')
  596. elem.add_item('DESC', 'Installing files.')
  597. elem.add_item('COMMAND', [sys.executable, self.environment.get_build_command(), '--internal', 'install', install_data_file])
  598. elem.add_item('pool', 'console')
  599. self.generate_depmf_install(d)
  600. self.generate_target_install(d)
  601. self.generate_header_install(d)
  602. self.generate_man_install(d)
  603. self.generate_data_install(d)
  604. self.generate_custom_install_script(d)
  605. self.generate_subdir_install(d)
  606. elem.write(outfile)
  607. with open(install_data_file, 'wb') as ofile:
  608. pickle.dump(d, ofile)
  609. def generate_target_install(self, d):
  610. for t in self.build.get_targets().values():
  611. if not t.should_install():
  612. continue
  613. # Find the installation directory.
  614. outdirs = t.get_custom_install_dir()
  615. custom_install_dir = False
  616. if outdirs[0] is not None and outdirs[0] is not True:
  617. # Either the value is set, or is set to False which means
  618. # we want this specific output out of many outputs to not
  619. # be installed.
  620. custom_install_dir = True
  621. elif isinstance(t, build.SharedModule):
  622. outdirs[0] = self.environment.get_shared_module_dir()
  623. elif isinstance(t, build.SharedLibrary):
  624. outdirs[0] = self.environment.get_shared_lib_dir()
  625. elif isinstance(t, build.StaticLibrary):
  626. outdirs[0] = self.environment.get_static_lib_dir()
  627. elif isinstance(t, build.Executable):
  628. outdirs[0] = self.environment.get_bindir()
  629. else:
  630. assert(isinstance(t, build.BuildTarget))
  631. # XXX: Add BuildTarget-specific install dir cases here
  632. outdirs[0] = self.environment.get_libdir()
  633. # Sanity-check the outputs and install_dirs
  634. num_outdirs, num_out = len(outdirs), len(t.get_outputs())
  635. if num_outdirs != 1 and num_outdirs != num_out:
  636. m = 'Target {!r} has {} outputs: {!r}, but only {} "install_dir"s were found.\n' \
  637. "Pass 'false' for outputs that should not be installed and 'true' for\n" \
  638. 'using the default installation directory for an output.'
  639. raise MesonException(m.format(t.name, num_out, t.get_outputs(), num_outdirs))
  640. # Install the target output(s)
  641. if isinstance(t, build.BuildTarget):
  642. should_strip = self.get_option_for_target('strip', t)
  643. # Install primary build output (library/executable/jar, etc)
  644. # Done separately because of strip/aliases/rpath
  645. if outdirs[0] is not False:
  646. i = [self.get_target_filename(t), outdirs[0],
  647. t.get_aliases(), should_strip, t.install_rpath]
  648. d.targets.append(i)
  649. # On toolchains/platforms that use an import library for
  650. # linking (separate from the shared library with all the
  651. # code), we need to install that too (dll.a/.lib).
  652. if (isinstance(t, build.SharedLibrary) or
  653. isinstance(t, build.Executable)) and t.get_import_filename():
  654. if custom_install_dir:
  655. # If the DLL is installed into a custom directory,
  656. # install the import library into the same place so
  657. # it doesn't go into a surprising place
  658. implib_install_dir = outdirs[0]
  659. else:
  660. implib_install_dir = self.environment.get_import_lib_dir()
  661. # Install the import library.
  662. i = [self.get_target_filename_for_linking(t),
  663. implib_install_dir,
  664. # It has no aliases, should not be stripped, and
  665. # doesn't have an install_rpath
  666. {}, False, '']
  667. d.targets.append(i)
  668. # Install secondary outputs. Only used for Vala right now.
  669. if num_outdirs > 1:
  670. for output, outdir in zip(t.get_outputs()[1:], outdirs[1:]):
  671. # User requested that we not install this output
  672. if outdir is False:
  673. continue
  674. f = os.path.join(self.get_target_dir(t), output)
  675. d.targets.append([f, outdir, {}, False, None])
  676. elif isinstance(t, build.CustomTarget):
  677. # If only one install_dir is specified, assume that all
  678. # outputs will be installed into it. This is for
  679. # backwards-compatibility and because it makes sense to
  680. # avoid repetition since this is a common use-case.
  681. #
  682. # To selectively install only some outputs, pass `false` as
  683. # the install_dir for the corresponding output by index
  684. if num_outdirs == 1 and num_out > 1:
  685. for output in t.get_outputs():
  686. f = os.path.join(self.get_target_dir(t), output)
  687. d.targets.append([f, outdirs[0], {}, False, None])
  688. else:
  689. for output, outdir in zip(t.get_outputs(), outdirs):
  690. # User requested that we not install this output
  691. if outdir is False:
  692. continue
  693. f = os.path.join(self.get_target_dir(t), output)
  694. d.targets.append([f, outdir, {}, False, None])
  695. def generate_custom_install_script(self, d):
  696. result = []
  697. srcdir = self.environment.get_source_dir()
  698. builddir = self.environment.get_build_dir()
  699. for i in self.build.install_scripts:
  700. exe = i['exe']
  701. args = i['args']
  702. fixed_args = []
  703. for a in args:
  704. a = a.replace('@SOURCE_ROOT@', srcdir)
  705. a = a.replace('@BUILD_ROOT@', builddir)
  706. fixed_args.append(a)
  707. result.append(build.RunScript(exe, fixed_args))
  708. d.install_scripts = result
  709. def generate_header_install(self, d):
  710. incroot = self.environment.get_includedir()
  711. headers = self.build.get_headers()
  712. srcdir = self.environment.get_source_dir()
  713. builddir = self.environment.get_build_dir()
  714. for h in headers:
  715. outdir = h.get_custom_install_dir()
  716. if outdir is None:
  717. outdir = os.path.join(incroot, h.get_install_subdir())
  718. for f in h.get_sources():
  719. if not isinstance(f, File):
  720. msg = 'Invalid header type {!r} can\'t be installed'
  721. raise MesonException(msg.format(f))
  722. abspath = f.absolute_path(srcdir, builddir)
  723. i = [abspath, outdir]
  724. d.headers.append(i)
  725. def generate_man_install(self, d):
  726. manroot = self.environment.get_mandir()
  727. man = self.build.get_man()
  728. for m in man:
  729. for f in m.get_sources():
  730. num = f.split('.')[-1]
  731. subdir = m.get_custom_install_dir()
  732. if subdir is None:
  733. subdir = os.path.join(manroot, 'man' + num)
  734. srcabs = os.path.join(self.environment.get_source_dir(), m.get_source_subdir(), f)
  735. dstabs = os.path.join(subdir, os.path.split(f)[1] + '.gz')
  736. i = [srcabs, dstabs]
  737. d.man.append(i)
  738. def generate_data_install(self, d):
  739. data = self.build.get_data()
  740. srcdir = self.environment.get_source_dir()
  741. builddir = self.environment.get_build_dir()
  742. for de in data:
  743. assert(isinstance(de, build.Data))
  744. subdir = de.install_dir
  745. for f in de.sources:
  746. assert(isinstance(f, mesonlib.File))
  747. plain_f = os.path.split(f.fname)[1]
  748. dstabs = os.path.join(subdir, plain_f)
  749. i = [f.absolute_path(srcdir, builddir), dstabs, de.install_mode]
  750. d.data.append(i)
  751. def generate_subdir_install(self, d):
  752. for sd in self.build.get_install_subdirs():
  753. inst_subdir = sd.installable_subdir.rstrip('/')
  754. idir_parts = inst_subdir.split('/')
  755. if len(idir_parts) > 1:
  756. subdir = os.path.join(sd.source_subdir, '/'.join(idir_parts[:-1]))
  757. inst_dir = idir_parts[-1]
  758. else:
  759. subdir = sd.source_subdir
  760. inst_dir = sd.installable_subdir
  761. src_dir = os.path.join(self.environment.get_source_dir(), subdir)
  762. dst_dir = os.path.join(self.environment.get_prefix(), sd.install_dir)
  763. d.install_subdirs.append([src_dir, inst_dir, dst_dir, sd.install_mode])
  764. def generate_tests(self, outfile):
  765. self.serialize_tests()
  766. test_exe = get_meson_script(self.environment, 'mesontest')
  767. cmd = [sys.executable, '-u', test_exe, '--no-rebuild']
  768. if not self.environment.coredata.get_builtin_option('stdsplit'):
  769. cmd += ['--no-stdsplit']
  770. if self.environment.coredata.get_builtin_option('errorlogs'):
  771. cmd += ['--print-errorlogs']
  772. elem = NinjaBuildElement(self.all_outputs, 'test', 'CUSTOM_COMMAND', ['all', 'PHONY'])
  773. elem.add_item('COMMAND', cmd)
  774. elem.add_item('DESC', 'Running all tests.')
  775. elem.add_item('pool', 'console')
  776. elem.write(outfile)
  777. # And then benchmarks.
  778. cmd = [sys.executable, '-u', test_exe, '--benchmark', '--logbase',
  779. 'benchmarklog', '--num-processes=1', '--no-rebuild']
  780. elem = NinjaBuildElement(self.all_outputs, 'benchmark', 'CUSTOM_COMMAND', ['all', 'PHONY'])
  781. elem.add_item('COMMAND', cmd)
  782. elem.add_item('DESC', 'Running benchmark suite.')
  783. elem.add_item('pool', 'console')
  784. elem.write(outfile)
  785. def generate_rules(self, outfile):
  786. outfile.write('# Rules for compiling.\n\n')
  787. self.generate_compile_rules(outfile)
  788. outfile.write('# Rules for linking.\n\n')
  789. if self.environment.is_cross_build():
  790. self.generate_static_link_rules(True, outfile)
  791. self.generate_static_link_rules(False, outfile)
  792. self.generate_dynamic_link_rules(outfile)
  793. outfile.write('# Other rules\n\n')
  794. outfile.write('rule CUSTOM_COMMAND\n')
  795. outfile.write(' command = $COMMAND\n')
  796. outfile.write(' description = $DESC\n')
  797. outfile.write(' restat = 1\n\n')
  798. # Ninja errors out if you have deps = gcc but no depfile, so we must
  799. # have two rules for custom commands.
  800. outfile.write('rule CUSTOM_COMMAND_DEP\n')
  801. outfile.write(' command = $COMMAND\n')
  802. outfile.write(' description = $DESC\n')
  803. outfile.write(' deps = gcc\n')
  804. outfile.write(' depfile = $DEPFILE\n')
  805. outfile.write(' restat = 1\n\n')
  806. outfile.write('rule REGENERATE_BUILD\n')
  807. c = (ninja_quote(quote_func(sys.executable)),
  808. ninja_quote(quote_func(self.environment.get_build_command())),
  809. '--internal',
  810. 'regenerate',
  811. ninja_quote(quote_func(self.environment.get_source_dir())),
  812. ninja_quote(quote_func(self.environment.get_build_dir())))
  813. outfile.write(" command = %s %s %s %s %s %s --backend ninja\n" % c)
  814. outfile.write(' description = Regenerating build files.\n')
  815. outfile.write(' generator = 1\n\n')
  816. outfile.write('\n')
  817. def generate_phony(self, outfile):
  818. outfile.write('# Phony build target, always out of date\n')
  819. outfile.write('build PHONY: phony\n')
  820. outfile.write('\n')
  821. def generate_jar_target(self, target, outfile):
  822. fname = target.get_filename()
  823. outname_rel = os.path.join(self.get_target_dir(target), fname)
  824. src_list = target.get_sources()
  825. class_list = []
  826. compiler = target.compilers['java']
  827. c = 'c'
  828. m = ''
  829. e = ''
  830. f = 'f'
  831. main_class = target.get_main_class()
  832. if main_class != '':
  833. e = 'e'
  834. for src in src_list:
  835. plain_class_path = self.generate_single_java_compile(src, target, compiler, outfile)
  836. class_list.append(plain_class_path)
  837. class_dep_list = [os.path.join(self.get_target_private_dir(target), i) for i in class_list]
  838. jar_rule = 'java_LINKER'
  839. commands = [c + m + e + f]
  840. if e != '':
  841. commands.append(main_class)
  842. commands.append(self.get_target_filename(target))
  843. # Java compilation can produce an arbitrary number of output
  844. # class files for a single source file. Thus tell jar to just
  845. # grab everything in the final package.
  846. commands += ['-C', self.get_target_private_dir(target), '.']
  847. elem = NinjaBuildElement(self.all_outputs, outname_rel, jar_rule, [])
  848. elem.add_dep(class_dep_list)
  849. elem.add_item('ARGS', commands)
  850. elem.write(outfile)
  851. def generate_cs_resource_tasks(self, target, outfile):
  852. args = []
  853. deps = []
  854. for r in target.resources:
  855. rel_sourcefile = os.path.join(self.build_to_src, target.subdir, r)
  856. if r.endswith('.resources'):
  857. a = '-resource:' + rel_sourcefile
  858. elif r.endswith('.txt') or r.endswith('.resx'):
  859. ofilebase = os.path.splitext(os.path.basename(r))[0] + '.resources'
  860. ofilename = os.path.join(self.get_target_private_dir(target), ofilebase)
  861. elem = NinjaBuildElement(self.all_outputs, ofilename, "CUSTOM_COMMAND", rel_sourcefile)
  862. elem.add_item('COMMAND', ['resgen', rel_sourcefile, ofilename])
  863. elem.add_item('DESC', 'Compiling resource %s.' % rel_sourcefile)
  864. elem.write(outfile)
  865. deps.append(ofilename)
  866. a = '-resource:' + ofilename
  867. else:
  868. raise InvalidArguments('Unknown resource file %s.' % r)
  869. args.append(a)
  870. return args, deps
  871. def generate_cs_target(self, target, outfile):
  872. buildtype = self.get_option_for_target('buildtype', target)
  873. fname = target.get_filename()
  874. outname_rel = os.path.join(self.get_target_dir(target), fname)
  875. src_list = target.get_sources()
  876. compiler = target.compilers['cs']
  877. rel_srcs = [s.rel_to_builddir(self.build_to_src) for s in src_list]
  878. deps = []
  879. commands = target.extra_args.get('cs', [])
  880. commands += compiler.get_buildtype_args(buildtype)
  881. if isinstance(target, build.Executable):
  882. commands.append('-target:exe')
  883. elif isinstance(target, build.SharedLibrary):
  884. commands.append('-target:library')
  885. else:
  886. raise MesonException('Unknown C# target type.')
  887. (resource_args, resource_deps) = self.generate_cs_resource_tasks(target, outfile)
  888. commands += resource_args
  889. deps += resource_deps
  890. commands += compiler.get_output_args(outname_rel)
  891. for l in target.link_targets:
  892. lname = os.path.join(self.get_target_dir(l), l.get_filename())
  893. commands += compiler.get_link_args(lname)
  894. deps.append(lname)
  895. if '-g' in commands:
  896. outputs = [outname_rel, outname_rel + '.mdb']
  897. else:
  898. outputs = [outname_rel]
  899. elem = NinjaBuildElement(self.all_outputs, outputs, 'cs_COMPILER', rel_srcs)
  900. elem.add_dep(deps)
  901. elem.add_item('ARGS', commands)
  902. elem.write(outfile)
  903. def generate_single_java_compile(self, src, target, compiler, outfile):
  904. args = []
  905. args += compiler.get_buildtype_args(self.get_option_for_target('buildtype', target))
  906. args += self.build.get_global_args(compiler)
  907. args += self.build.get_project_args(compiler, target.subproject)
  908. args += target.get_java_args()
  909. args += compiler.get_output_args(self.get_target_private_dir(target))
  910. for i in target.include_dirs:
  911. for idir in i.get_incdirs():
  912. args += ['-sourcepath', os.path.join(self.build_to_src, i.curdir, idir)]
  913. rel_src = src.rel_to_builddir(self.build_to_src)
  914. plain_class_path = src.fname[:-4] + 'class'
  915. rel_obj = os.path.join(self.get_target_private_dir(target), plain_class_path)
  916. element = NinjaBuildElement(self.all_outputs, rel_obj, compiler.get_language() + '_COMPILER', rel_src)
  917. element.add_item('ARGS', args)
  918. element.write(outfile)
  919. return plain_class_path
  920. def generate_java_link(self, outfile):
  921. rule = 'rule java_LINKER\n'
  922. command = ' command = jar $ARGS\n'
  923. description = ' description = Creating JAR $out.\n'
  924. outfile.write(rule)
  925. outfile.write(command)
  926. outfile.write(description)
  927. outfile.write('\n')
  928. def determine_dep_vapis(self, target):
  929. """
  930. Peek into the sources of BuildTargets we're linking with, and if any of
  931. them was built with Vala, assume that it also generated a .vapi file of
  932. the same name as the BuildTarget and return the path to it relative to
  933. the build directory.
  934. """
  935. result = OrderedSet()
  936. for dep in target.link_targets + target.link_whole_targets:
  937. for i in dep.sources:
  938. if hasattr(i, 'fname'):
  939. i = i.fname
  940. if i.endswith('vala'):
  941. vapiname = dep.name + '.vapi'
  942. fullname = os.path.join(self.get_target_dir(dep), vapiname)
  943. result.add(fullname)
  944. break
  945. return list(result)
  946. def split_vala_sources(self, t):
  947. """
  948. Splits the target's sources into .vala, .gs, .vapi, and other sources.
  949. Handles both pre-existing and generated sources.
  950. Returns a tuple (vala, vapi, others) each of which is a dictionary with
  951. the keys being the path to the file (relative to the build directory)
  952. and the value being the object that generated or represents the file.
  953. """
  954. vala = OrderedDict()
  955. vapi = OrderedDict()
  956. others = OrderedDict()
  957. othersgen = OrderedDict()
  958. # Split pre-existing sources
  959. for s in t.get_sources():
  960. # BuildTarget sources are always mesonlib.File files which are
  961. # either in the source root, or generated with configure_file and
  962. # in the build root
  963. if not isinstance(s, File):
  964. msg = 'All sources in target {!r} must be of type ' \
  965. 'mesonlib.File, not {!r}'.format(t, s)
  966. raise InvalidArguments(msg)
  967. f = s.rel_to_builddir(self.build_to_src)
  968. if s.endswith(('.vala', '.gs')):
  969. srctype = vala
  970. elif s.endswith('.vapi'):
  971. srctype = vapi
  972. else:
  973. srctype = others
  974. srctype[f] = s
  975. # Split generated sources
  976. for gensrc in t.get_generated_sources():
  977. for s in gensrc.get_outputs():
  978. f = self.get_target_generated_dir(t, gensrc, s)
  979. if s.endswith(('.vala', '.gs')):
  980. srctype = vala
  981. elif s.endswith('.vapi'):
  982. srctype = vapi
  983. # Generated non-Vala (C/C++) sources. Won't be used for
  984. # generating the Vala compile rule below.
  985. else:
  986. srctype = othersgen
  987. # Duplicate outputs are disastrous
  988. if f in srctype and srctype[f] is not gensrc:
  989. msg = 'Duplicate output {0!r} from {1!r} {2!r}; ' \
  990. 'conflicts with {0!r} from {4!r} {3!r}' \
  991. ''.format(f, type(gensrc).__name__, gensrc.name,
  992. srctype[f].name, type(srctype[f]).__name__)
  993. raise InvalidArguments(msg)
  994. # Store 'somefile.vala': GeneratedList (or CustomTarget)
  995. srctype[f] = gensrc
  996. return vala, vapi, (others, othersgen)
  997. def generate_vala_compile(self, target, outfile):
  998. """Vala is compiled into C. Set up all necessary build steps here."""
  999. (vala_src, vapi_src, other_src) = self.split_vala_sources(target)
  1000. extra_dep_files = []
  1001. if not vala_src:
  1002. msg = 'Vala library {!r} has no Vala or Genie source files.'
  1003. raise InvalidArguments(msg.format(target.name))
  1004. valac = target.compilers['vala']
  1005. c_out_dir = self.get_target_private_dir(target)
  1006. # C files generated by valac
  1007. vala_c_src = []
  1008. # Files generated by valac
  1009. valac_outputs = []
  1010. # All sources that are passed to valac on the commandline
  1011. all_files = list(vapi_src.keys())
  1012. for (vala_file, gensrc) in vala_src.items():
  1013. all_files.append(vala_file)
  1014. # Figure out where the Vala compiler will write the compiled C file
  1015. # If the Vala file is in a subdir of the build dir (in our case
  1016. # because it was generated/built by something else), the subdir path
  1017. # components will be preserved in the output path. But if the Vala
  1018. # file is outside the build directory, the path components will be
  1019. # stripped and just the basename will be used.
  1020. if isinstance(gensrc, (build.CustomTarget, build.GeneratedList)) or gensrc.is_built:
  1021. vala_c_file = os.path.splitext(vala_file)[0] + '.c'
  1022. else:
  1023. vala_c_file = os.path.splitext(os.path.basename(vala_file))[0] + '.c'
  1024. # All this will be placed inside the c_out_dir
  1025. vala_c_file = os.path.join(c_out_dir, vala_c_file)
  1026. vala_c_src.append(vala_c_file)
  1027. valac_outputs.append(vala_c_file)
  1028. args = self.generate_basic_compiler_args(target, valac)
  1029. # Tell Valac to output everything in our private directory. Sadly this
  1030. # means it will also preserve the directory components of Vala sources
  1031. # found inside the build tree (generated sources).
  1032. args += ['-d', c_out_dir]
  1033. if not isinstance(target, build.Executable):
  1034. # Library name
  1035. args += ['--library=' + target.name]
  1036. # Outputted header
  1037. hname = os.path.join(self.get_target_dir(target), target.vala_header)
  1038. args += ['-H', hname]
  1039. if self.is_unity(target):
  1040. # Without this the declarations will get duplicated in the .c
  1041. # files and cause a build failure when all of them are
  1042. # #include-d in one .c file.
  1043. # https://github.com/mesonbuild/meson/issues/1969
  1044. args += ['--use-header']
  1045. valac_outputs.append(hname)
  1046. # Outputted vapi file
  1047. vapiname = os.path.join(self.get_target_dir(target), target.vala_vapi)
  1048. # Force valac to write the vapi and gir files in the target build dir.
  1049. # Without this, it will write it inside c_out_dir
  1050. args += ['--vapi', os.path.join('..', target.vala_vapi)]
  1051. valac_outputs.append(vapiname)
  1052. target.outputs += [target.vala_header, target.vala_vapi]
  1053. # Install header and vapi to default locations if user requests this
  1054. if len(target.install_dir) > 1 and target.install_dir[1] is True:
  1055. target.install_dir[1] = self.environment.get_includedir()
  1056. if len(target.install_dir) > 2 and target.install_dir[2] is True:
  1057. target.install_dir[2] = os.path.join(self.environment.get_datadir(), 'vala', 'vapi')
  1058. # Generate GIR if requested
  1059. if isinstance(target.vala_gir, str):
  1060. girname = os.path.join(self.get_target_dir(target), target.vala_gir)
  1061. args += ['--gir', os.path.join('..', target.vala_gir)]
  1062. valac_outputs.append(girname)
  1063. target.outputs.append(target.vala_gir)
  1064. # Install GIR to default location if requested by user
  1065. if len(target.install_dir) > 3 and target.install_dir[3] is True:
  1066. target.install_dir[3] = os.path.join(self.environment.get_datadir(), 'gir-1.0')
  1067. # Detect gresources and add --gresources arguments for each
  1068. for (gres, gensrc) in other_src[1].items():
  1069. if isinstance(gensrc, modules.GResourceTarget):
  1070. gres_xml, = self.get_custom_target_sources(gensrc)
  1071. args += ['--gresources=' + gres_xml]
  1072. extra_args = []
  1073. for a in target.extra_args.get('vala', []):
  1074. if isinstance(a, File):
  1075. relname = a.rel_to_builddir(self.build_to_src)
  1076. extra_dep_files.append(relname)
  1077. extra_args.append(relname)
  1078. else:
  1079. extra_args.append(a)
  1080. dependency_vapis = self.determine_dep_vapis(target)
  1081. extra_dep_files += dependency_vapis
  1082. args += extra_args
  1083. element = NinjaBuildElement(self.all_outputs, valac_outputs,
  1084. valac.get_language() + '_COMPILER',
  1085. all_files + dependency_vapis)
  1086. element.add_item('ARGS', args)
  1087. element.add_dep(extra_dep_files)
  1088. element.write(outfile)
  1089. return other_src[0], other_src[1], vala_c_src
  1090. def generate_rust_target(self, target, outfile):
  1091. rustc = target.compilers['rust']
  1092. relsrc = []
  1093. for i in target.get_sources():
  1094. if not rustc.can_compile(i):
  1095. raise InvalidArguments('Rust target %s contains a non-rust source file.' % target.get_basename())
  1096. relsrc.append(i.rel_to_builddir(self.build_to_src))
  1097. target_name = os.path.join(target.subdir, target.get_filename())
  1098. args = ['--crate-type']
  1099. if isinstance(target, build.Executable):
  1100. cratetype = 'bin'
  1101. elif hasattr(target, 'rust_crate_type'):
  1102. cratetype = target.rust_crate_type
  1103. elif isinstance(target, build.SharedLibrary):
  1104. cratetype = 'dylib'
  1105. elif isinstance(target, build.StaticLibrary):
  1106. cratetype = 'rlib'
  1107. else:
  1108. raise InvalidArguments('Unknown target type for rustc.')
  1109. args.append(cratetype)
  1110. args += ['--crate-name', target.name]
  1111. args += rustc.get_buildtype_args(self.get_option_for_target('buildtype', target))
  1112. depfile = os.path.join(target.subdir, target.name + '.d')
  1113. args += ['--emit', 'dep-info={}'.format(depfile), '--emit', 'link']
  1114. args += target.get_extra_args('rust')
  1115. args += ['-o', os.path.join(target.subdir, target.get_filename())]
  1116. orderdeps = [os.path.join(t.subdir, t.get_filename()) for t in target.link_targets]
  1117. linkdirs = OrderedDict()
  1118. for d in target.link_targets:
  1119. linkdirs[d.subdir] = True
  1120. for d in linkdirs.keys():
  1121. if d == '':
  1122. d = '.'
  1123. args += ['-L', d]
  1124. has_shared_deps = False
  1125. for dep in target.get_dependencies():
  1126. if isinstance(dep, build.SharedLibrary):
  1127. has_shared_deps = True
  1128. if isinstance(target, build.SharedLibrary) or has_shared_deps:
  1129. # add prefer-dynamic if any of the Rust libraries we link
  1130. # against are dynamic, otherwise we'll end up with
  1131. # multiple implementations of crates
  1132. args += ['-C', 'prefer-dynamic']
  1133. # build the usual rpath arguments as well...
  1134. # Set runtime-paths so we can run executables without needing to set
  1135. # LD_LIBRARY_PATH, etc in the environment. Doesn't work on Windows.
  1136. if '/' in target.name or '\\' in target.name:
  1137. # Target names really should not have slashes in them, but
  1138. # unfortunately we did not check for that and some downstream projects
  1139. # now have them. Once slashes are forbidden, remove this bit.
  1140. target_slashname_workaround_dir = os.path.join(os.path.split(target.name)[0],
  1141. self.get_target_dir(target))
  1142. else:
  1143. target_slashname_workaround_dir = self.get_target_dir(target)
  1144. rpath_args = rustc.build_rpath_args(self.environment.get_build_dir(),
  1145. target_slashname_workaround_dir,
  1146. self.determine_rpath_dirs(target),
  1147. target.build_rpath,
  1148. target.install_rpath)
  1149. # ... but then add rustc's sysroot to account for rustup
  1150. # installations
  1151. for rpath_arg in rpath_args:
  1152. args += ['-C', 'link-arg=' + rpath_arg + ':' + os.path.join(rustc.get_sysroot(), 'lib')]
  1153. element = NinjaBuildElement(self.all_outputs, target_name, 'rust_COMPILER', relsrc)
  1154. if len(orderdeps) > 0:
  1155. element.add_orderdep(orderdeps)
  1156. element.add_item('ARGS', args)
  1157. element.add_item('targetdep', depfile)
  1158. element.add_item('cratetype', cratetype)
  1159. element.write(outfile)
  1160. if isinstance(target, build.SharedLibrary):
  1161. self.generate_shsym(outfile, target)
  1162. def swift_module_file_name(self, target):
  1163. return os.path.join(self.get_target_private_dir(target),
  1164. self.target_swift_modulename(target) + '.swiftmodule')
  1165. def target_swift_modulename(self, target):
  1166. return target.name
  1167. def is_swift_target(self, target):
  1168. for s in target.sources:
  1169. if s.endswith('swift'):
  1170. return True
  1171. return False
  1172. def determine_swift_dep_modules(self, target):
  1173. result = []
  1174. for l in target.link_targets:
  1175. if self.is_swift_target(l):
  1176. result.append(self.swift_module_file_name(l))
  1177. return result
  1178. def determine_swift_dep_dirs(self, target):
  1179. result = []
  1180. for l in target.link_targets:
  1181. result.append(self.get_target_private_dir_abs(l))
  1182. return result
  1183. def get_swift_link_deps(self, target):
  1184. result = []
  1185. for l in target.link_targets:
  1186. result.append(self.get_target_filename(l))
  1187. return result
  1188. def split_swift_generated_sources(self, target):
  1189. all_srcs = self.get_target_generated_sources(target)
  1190. srcs = []
  1191. others = []
  1192. for i in all_srcs:
  1193. if i.endswith('.swift'):
  1194. srcs.append(i)
  1195. else:
  1196. others.append(i)
  1197. return srcs, others
  1198. def generate_swift_target(self, target, outfile):
  1199. module_name = self.target_swift_modulename(target)
  1200. swiftc = target.compilers['swift']
  1201. abssrc = []
  1202. abs_headers = []
  1203. header_imports = []
  1204. for i in target.get_sources():
  1205. if swiftc.can_compile(i):
  1206. relsrc = i.rel_to_builddir(self.build_to_src)
  1207. abss = os.path.normpath(os.path.join(self.environment.get_build_dir(), relsrc))
  1208. abssrc.append(abss)
  1209. elif self.environment.is_header(i):
  1210. relh = i.rel_to_builddir(self.build_to_src)
  1211. absh = os.path.normpath(os.path.join(self.environment.get_build_dir(), relh))
  1212. abs_headers.append(absh)
  1213. header_imports += swiftc.get_header_import_args(absh)
  1214. else:
  1215. raise InvalidArguments('Swift target %s contains a non-swift source file.' % target.get_basename())
  1216. os.makedirs(self.get_target_private_dir_abs(target), exist_ok=True)
  1217. compile_args = swiftc.get_compile_only_args()
  1218. compile_args += swiftc.get_module_args(module_name)
  1219. compile_args += self.build.get_project_args(swiftc, target.subproject)
  1220. compile_args += self.build.get_global_args(swiftc)
  1221. for i in reversed(target.get_include_dirs()):
  1222. basedir = i.get_curdir()
  1223. for d in i.get_incdirs():
  1224. if d not in ('', '.'):
  1225. expdir = os.path.join(basedir, d)
  1226. else:
  1227. expdir = basedir
  1228. srctreedir = os.path.normpath(os.path.join(self.environment.get_build_dir(), self.build_to_src, expdir))
  1229. sargs = swiftc.get_include_args(srctreedir)
  1230. compile_args += sargs
  1231. link_args = swiftc.get_output_args(os.path.join(self.environment.get_build_dir(), self.get_target_filename(target)))
  1232. link_args += self.build.get_project_link_args(swiftc, target.subproject)
  1233. link_args += self.build.get_global_link_args(swiftc)
  1234. rundir = self.get_target_private_dir(target)
  1235. out_module_name = self.swift_module_file_name(target)
  1236. in_module_files = self.determine_swift_dep_modules(target)
  1237. abs_module_dirs = self.determine_swift_dep_dirs(target)
  1238. module_includes = []
  1239. for x in abs_module_dirs:
  1240. module_includes += swiftc.get_include_args(x)
  1241. link_deps = self.get_swift_link_deps(target)
  1242. abs_link_deps = [os.path.join(self.environment.get_build_dir(), x) for x in link_deps]
  1243. for d in target.link_targets:
  1244. reldir = self.get_target_dir(d)
  1245. if reldir == '':
  1246. reldir = '.'
  1247. link_args += ['-L', os.path.normpath(os.path.join(self.environment.get_build_dir(), reldir))]
  1248. (rel_generated, _) = self.split_swift_generated_sources(target)
  1249. abs_generated = [os.path.join(self.environment.get_build_dir(), x) for x in rel_generated]
  1250. # We need absolute paths because swiftc needs to be invoked in a subdir
  1251. # and this is the easiest way about it.
  1252. objects = [] # Relative to swift invocation dir
  1253. rel_objects = [] # Relative to build.ninja
  1254. for i in abssrc + abs_generated:
  1255. base = os.path.split(i)[1]
  1256. oname = os.path.splitext(base)[0] + '.o'
  1257. objects.append(oname)
  1258. rel_objects.append(os.path.join(self.get_target_private_dir(target), oname))
  1259. # Swiftc does not seem to be able to emit objects and module files in one go.
  1260. elem = NinjaBuildElement(self.all_outputs, rel_objects,
  1261. 'swift_COMPILER',
  1262. abssrc)
  1263. elem.add_dep(in_module_files + rel_generated)
  1264. elem.add_dep(abs_headers)
  1265. elem.add_item('ARGS', compile_args + header_imports + abs_generated + module_includes)
  1266. elem.add_item('RUNDIR', rundir)
  1267. elem.write(outfile)
  1268. elem = NinjaBuildElement(self.all_outputs, out_module_name,
  1269. 'swift_COMPILER',
  1270. abssrc)
  1271. elem.add_dep(in_module_files + rel_generated)
  1272. elem.add_item('ARGS', compile_args + abs_generated + module_includes + swiftc.get_mod_gen_args())
  1273. elem.add_item('RUNDIR', rundir)
  1274. elem.write(outfile)
  1275. if isinstance(target, build.StaticLibrary):
  1276. elem = self.generate_link(target, outfile, self.get_target_filename(target),
  1277. rel_objects, self.build.static_linker)
  1278. elem.write(outfile)
  1279. elif isinstance(target, build.Executable):
  1280. elem = NinjaBuildElement(self.all_outputs, self.get_target_filename(target), 'swift_COMPILER', [])
  1281. elem.add_dep(rel_objects)
  1282. elem.add_dep(link_deps)
  1283. elem.add_item('ARGS', link_args + swiftc.get_std_exe_link_args() + objects + abs_link_deps)
  1284. elem.add_item('RUNDIR', rundir)
  1285. elem.write(outfile)
  1286. else:
  1287. raise MesonException('Swift supports only executable and static library targets.')
  1288. def generate_static_link_rules(self, is_cross, outfile):
  1289. if 'java' in self.build.compilers:
  1290. if not is_cross:
  1291. self.generate_java_link(outfile)
  1292. if is_cross:
  1293. if self.environment.cross_info.need_cross_compiler():
  1294. static_linker = self.build.static_cross_linker
  1295. else:
  1296. static_linker = self.build.static_linker
  1297. crstr = '_CROSS'
  1298. else:
  1299. static_linker = self.build.static_linker
  1300. crstr = ''
  1301. if static_linker is None:
  1302. return
  1303. rule = 'rule STATIC%s_LINKER\n' % crstr
  1304. # We don't use @file.rsp on Windows with ArLinker because llvm-ar and
  1305. # gcc-ar blindly pass the --plugin argument to `ar` and you cannot pass
  1306. # options as arguments while using the @file.rsp syntax.
  1307. # See: https://github.com/mesonbuild/meson/issues/1646
  1308. if mesonlib.is_windows() and not isinstance(static_linker, ArLinker):
  1309. command_template = ''' command = {executable} @$out.rsp
  1310. rspfile = $out.rsp
  1311. rspfile_content = $LINK_ARGS {output_args} $in
  1312. '''
  1313. else:
  1314. command_template = ' command = {executable} $LINK_ARGS {output_args} $in\n'
  1315. cmdlist = []
  1316. # FIXME: Must normalize file names with pathlib.Path before writing
  1317. # them out to fix this properly on Windows. See:
  1318. # https://github.com/mesonbuild/meson/issues/1517
  1319. # https://github.com/mesonbuild/meson/issues/1526
  1320. if isinstance(static_linker, ArLinker) and not mesonlib.is_windows():
  1321. # `ar` has no options to overwrite archives. It always appends,
  1322. # which is never what we want. Delete an existing library first if
  1323. # it exists. https://github.com/mesonbuild/meson/issues/1355
  1324. cmdlist = [execute_wrapper, rmfile_prefix.format('$out')]
  1325. cmdlist += static_linker.get_exelist()
  1326. command = command_template.format(
  1327. executable=' '.join(cmdlist),
  1328. output_args=' '.join(static_linker.get_output_args('$out')))
  1329. description = ' description = Linking static target $out.\n\n'
  1330. outfile.write(rule)
  1331. outfile.write(command)
  1332. outfile.write(description)
  1333. def generate_dynamic_link_rules(self, outfile):
  1334. ctypes = [(self.build.compilers, False)]
  1335. if self.environment.is_cross_build():
  1336. if self.environment.cross_info.need_cross_compiler():
  1337. ctypes.append((self.build.cross_compilers, True))
  1338. else:
  1339. # Native compiler masquerades as the cross compiler.
  1340. ctypes.append((self.build.compilers, True))
  1341. else:
  1342. ctypes.append((self.build.cross_compilers, True))
  1343. for (complist, is_cross) in ctypes:
  1344. for langname, compiler in complist.items():
  1345. if langname == 'java' \
  1346. or langname == 'vala' \
  1347. or langname == 'rust' \
  1348. or langname == 'cs':
  1349. continue
  1350. crstr = ''
  1351. cross_args = []
  1352. if is_cross:
  1353. crstr = '_CROSS'
  1354. try:
  1355. cross_args = self.environment.cross_info.config['properties'][langname + '_link_args']
  1356. except KeyError:
  1357. pass
  1358. rule = 'rule %s%s_LINKER\n' % (langname, crstr)
  1359. if mesonlib.is_windows():
  1360. command_template = ''' command = {executable} @$out.rsp
  1361. rspfile = $out.rsp
  1362. rspfile_content = $ARGS {output_args} $in $LINK_ARGS {cross_args} $aliasing
  1363. '''
  1364. else:
  1365. command_template = ' command = {executable} $ARGS {output_args} $in $LINK_ARGS {cross_args} $aliasing\n'
  1366. command = command_template.format(
  1367. executable=' '.join(compiler.get_linker_exelist()),
  1368. cross_args=' '.join(cross_args),
  1369. output_args=' '.join(compiler.get_linker_output_args('$out'))
  1370. )
  1371. description = ' description = Linking target $out.'
  1372. outfile.write(rule)
  1373. outfile.write(command)
  1374. outfile.write(description)
  1375. outfile.write('\n')
  1376. outfile.write('\n')
  1377. symrule = 'rule SHSYM\n'
  1378. symcmd = ' command = "%s" "%s" %s %s %s %s $CROSS\n' % (ninja_quote(sys.executable),
  1379. self.environment.get_build_command(),
  1380. '--internal',
  1381. 'symbolextractor',
  1382. '$in',
  1383. '$out')
  1384. synstat = ' restat = 1\n'
  1385. syndesc = ' description = Generating symbol file $out.\n'
  1386. outfile.write(symrule)
  1387. outfile.write(symcmd)
  1388. outfile.write(synstat)
  1389. outfile.write(syndesc)
  1390. outfile.write('\n')
  1391. def generate_java_compile_rule(self, compiler, outfile):
  1392. rule = 'rule %s_COMPILER\n' % compiler.get_language()
  1393. invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()])
  1394. command = ' command = %s $ARGS $in\n' % invoc
  1395. description = ' description = Compiling Java object $in.\n'
  1396. outfile.write(rule)
  1397. outfile.write(command)
  1398. outfile.write(description)
  1399. outfile.write('\n')
  1400. def generate_cs_compile_rule(self, compiler, outfile):
  1401. rule = 'rule %s_COMPILER\n' % compiler.get_language()
  1402. invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()])
  1403. command = ' command = %s $ARGS $in\n' % invoc
  1404. description = ' description = Compiling C Sharp target $out.\n'
  1405. outfile.write(rule)
  1406. outfile.write(command)
  1407. outfile.write(description)
  1408. outfile.write('\n')
  1409. def generate_vala_compile_rules(self, compiler, outfile):
  1410. rule = 'rule %s_COMPILER\n' % compiler.get_language()
  1411. invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()])
  1412. command = ' command = %s $ARGS $in\n' % invoc
  1413. description = ' description = Compiling Vala source $in.\n'
  1414. restat = ' restat = 1\n' # ValaC does this always to take advantage of it.
  1415. outfile.write(rule)
  1416. outfile.write(command)
  1417. outfile.write(description)
  1418. outfile.write(restat)
  1419. outfile.write('\n')
  1420. def generate_rust_compile_rules(self, compiler, outfile):
  1421. rule = 'rule %s_COMPILER\n' % compiler.get_language()
  1422. invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()])
  1423. command = ' command = %s $ARGS $in\n' % invoc
  1424. description = ' description = Compiling Rust source $in.\n'
  1425. depfile = ' depfile = $targetdep\n'
  1426. depstyle = ' deps = gcc\n'
  1427. outfile.write(rule)
  1428. outfile.write(command)
  1429. outfile.write(description)
  1430. outfile.write(depfile)
  1431. outfile.write(depstyle)
  1432. outfile.write('\n')
  1433. def generate_swift_compile_rules(self, compiler, outfile):
  1434. rule = 'rule %s_COMPILER\n' % compiler.get_language()
  1435. full_exe = [ninja_quote(sys.executable),
  1436. ninja_quote(self.environment.get_build_command()),
  1437. '--internal',
  1438. 'dirchanger',
  1439. '$RUNDIR']
  1440. invoc = (' '.join(full_exe) + ' ' +
  1441. ' '.join(ninja_quote(i) for i in compiler.get_exelist()))
  1442. command = ' command = %s $ARGS $in\n' % invoc
  1443. description = ' description = Compiling Swift source $in.\n'
  1444. outfile.write(rule)
  1445. outfile.write(command)
  1446. outfile.write(description)
  1447. outfile.write('\n')
  1448. def generate_fortran_dep_hack(self, outfile):
  1449. if mesonlib.is_windows():
  1450. cmd = 'cmd /C ""'
  1451. else:
  1452. cmd = 'true'
  1453. template = '''# Workaround for these issues:
  1454. # https://groups.google.com/forum/#!topic/ninja-build/j-2RfBIOd_8
  1455. # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485
  1456. rule FORTRAN_DEP_HACK
  1457. command = %s
  1458. description = Dep hack
  1459. restat = 1
  1460. '''
  1461. outfile.write(template % cmd)
  1462. def generate_llvm_ir_compile_rule(self, compiler, is_cross, outfile):
  1463. if getattr(self, 'created_llvm_ir_rule', False):
  1464. return
  1465. rule = 'rule llvm_ir{}_COMPILER\n'.format('_CROSS' if is_cross else '')
  1466. if mesonlib.is_windows():
  1467. command_template = ' command = {executable} @$out.rsp\n' \
  1468. ' rspfile = $out.rsp\n' \
  1469. ' rspfile_content = {cross_args} $ARGS {output_args} {compile_only_args} $in\n'
  1470. else:
  1471. command_template = ' command = {executable} {cross_args} $ARGS {output_args} {compile_only_args} $in\n'
  1472. command = command_template.format(
  1473. executable=' '.join([ninja_quote(i) for i in compiler.get_exelist()]),
  1474. cross_args=' '.join(self.get_cross_info_lang_args(compiler.language, is_cross)),
  1475. output_args=' '.join(compiler.get_output_args('$out')),
  1476. compile_only_args=' '.join(compiler.get_compile_only_args())
  1477. )
  1478. description = ' description = Compiling LLVM IR object $in.\n'
  1479. outfile.write(rule)
  1480. outfile.write(command)
  1481. outfile.write(description)
  1482. outfile.write('\n')
  1483. self.created_llvm_ir_rule = True
  1484. def get_cross_info_lang_args(self, lang, is_cross):
  1485. if is_cross:
  1486. try:
  1487. return self.environment.cross_info.config['properties'][lang + '_args']
  1488. except KeyError:
  1489. pass
  1490. return []
  1491. def generate_compile_rule_for(self, langname, compiler, is_cross, outfile):
  1492. if langname == 'java':
  1493. if not is_cross:
  1494. self.generate_java_compile_rule(compiler, outfile)
  1495. return
  1496. if langname == 'cs':
  1497. if not is_cross:
  1498. self.generate_cs_compile_rule(compiler, outfile)
  1499. return
  1500. if langname == 'vala':
  1501. if not is_cross:
  1502. self.generate_vala_compile_rules(compiler, outfile)
  1503. return
  1504. if langname == 'rust':
  1505. if not is_cross:
  1506. self.generate_rust_compile_rules(compiler, outfile)
  1507. return
  1508. if langname == 'swift':
  1509. if not is_cross:
  1510. self.generate_swift_compile_rules(compiler, outfile)
  1511. return
  1512. if langname == 'fortran':
  1513. self.generate_fortran_dep_hack(outfile)
  1514. if is_cross:
  1515. crstr = '_CROSS'
  1516. else:
  1517. crstr = ''
  1518. rule = 'rule %s%s_COMPILER\n' % (langname, crstr)
  1519. depargs = compiler.get_dependency_gen_args('$out', '$DEPFILE')
  1520. quoted_depargs = []
  1521. for d in depargs:
  1522. if d != '$out' and d != '$in':
  1523. d = quote_func(d)
  1524. quoted_depargs.append(d)
  1525. cross_args = self.get_cross_info_lang_args(langname, is_cross)
  1526. if mesonlib.is_windows():
  1527. command_template = ''' command = {executable} @$out.rsp
  1528. rspfile = $out.rsp
  1529. rspfile_content = {cross_args} $ARGS {dep_args} {output_args} {compile_only_args} $in
  1530. '''
  1531. else:
  1532. command_template = ' command = {executable} {cross_args} $ARGS {dep_args} {output_args} {compile_only_args} $in\n'
  1533. command = command_template.format(
  1534. executable=' '.join([ninja_quote(i) for i in compiler.get_exelist()]),
  1535. cross_args=' '.join(cross_args),
  1536. dep_args=' '.join(quoted_depargs),
  1537. output_args=' '.join(compiler.get_output_args('$out')),
  1538. compile_only_args=' '.join(compiler.get_compile_only_args())
  1539. )
  1540. description = ' description = Compiling %s object $out.\n' % compiler.get_display_language()
  1541. if compiler.get_id() == 'msvc':
  1542. deps = ' deps = msvc\n'
  1543. else:
  1544. deps = ' deps = gcc\n'
  1545. deps += ' depfile = $DEPFILE\n'
  1546. outfile.write(rule)
  1547. outfile.write(command)
  1548. outfile.write(deps)
  1549. outfile.write(description)
  1550. outfile.write('\n')
  1551. def generate_pch_rule_for(self, langname, compiler, is_cross, outfile):
  1552. if langname != 'c' and langname != 'cpp':
  1553. return
  1554. if is_cross:
  1555. crstr = '_CROSS'
  1556. else:
  1557. crstr = ''
  1558. rule = 'rule %s%s_PCH\n' % (langname, crstr)
  1559. depargs = compiler.get_dependency_gen_args('$out', '$DEPFILE')
  1560. cross_args = []
  1561. if is_cross:
  1562. try:
  1563. cross_args = self.environment.cross_info.config['properties'][langname + '_args']
  1564. except KeyError:
  1565. pass
  1566. quoted_depargs = []
  1567. for d in depargs:
  1568. if d != '$out' and d != '$in':
  1569. d = quote_func(d)
  1570. quoted_depargs.append(d)
  1571. if compiler.get_id() == 'msvc':
  1572. output = ''
  1573. else:
  1574. output = ' '.join(compiler.get_output_args('$out'))
  1575. command = " command = {executable} {cross_args} $ARGS {dep_args} {output_args} {compile_only_args} $in\n".format(
  1576. executable=' '.join(compiler.get_exelist()),
  1577. cross_args=' '.join(cross_args),
  1578. dep_args=' '.join(quoted_depargs),
  1579. output_args=output,
  1580. compile_only_args=' '.join(compiler.get_compile_only_args())
  1581. )
  1582. description = ' description = Precompiling header %s.\n' % '$in'
  1583. if compiler.get_id() == 'msvc':
  1584. deps = ' deps = msvc\n'
  1585. else:
  1586. deps = ' deps = gcc\n'
  1587. deps += ' depfile = $DEPFILE\n'
  1588. outfile.write(rule)
  1589. outfile.write(command)
  1590. outfile.write(deps)
  1591. outfile.write(description)
  1592. outfile.write('\n')
  1593. def generate_compile_rules(self, outfile):
  1594. for langname, compiler in self.build.compilers.items():
  1595. if compiler.get_id() == 'clang':
  1596. self.generate_llvm_ir_compile_rule(compiler, False, outfile)
  1597. self.generate_compile_rule_for(langname, compiler, False, outfile)
  1598. self.generate_pch_rule_for(langname, compiler, False, outfile)
  1599. if self.environment.is_cross_build():
  1600. # In case we are going a target-only build, make the native compilers
  1601. # masquerade as cross compilers.
  1602. if self.environment.cross_info.need_cross_compiler():
  1603. cclist = self.build.cross_compilers
  1604. else:
  1605. cclist = self.build.compilers
  1606. for langname, compiler in cclist.items():
  1607. if compiler.get_id() == 'clang':
  1608. self.generate_llvm_ir_compile_rule(compiler, True, outfile)
  1609. self.generate_compile_rule_for(langname, compiler, True, outfile)
  1610. self.generate_pch_rule_for(langname, compiler, True, outfile)
  1611. outfile.write('\n')
  1612. def generate_generator_list_rules(self, target, outfile):
  1613. # CustomTargets have already written their rules,
  1614. # so write rules for GeneratedLists here
  1615. for genlist in target.get_generated_sources():
  1616. if isinstance(genlist, build.CustomTarget):
  1617. continue
  1618. self.generate_genlist_for_target(genlist, target, outfile)
  1619. def replace_paths(self, target, args):
  1620. source_target_dir = self.get_target_source_dir(target)
  1621. relout = self.get_target_private_dir(target)
  1622. args = [x.replace("@SOURCE_DIR@", self.build_to_src).replace("@BUILD_DIR@", relout)
  1623. for x in args]
  1624. args = [x.replace("@CURRENT_SOURCE_DIR@", source_target_dir) for x in args]
  1625. args = [x.replace("@SOURCE_ROOT@", self.build_to_src).replace("@BUILD_ROOT@", '.')
  1626. for x in args]
  1627. return args
  1628. def generate_genlist_for_target(self, genlist, target, outfile):
  1629. generator = genlist.get_generator()
  1630. exe = generator.get_exe()
  1631. exe_arr = self.exe_object_to_cmd_array(exe)
  1632. infilelist = genlist.get_inputs()
  1633. outfilelist = genlist.get_outputs()
  1634. base_args = generator.get_arglist()
  1635. extra_dependencies = [os.path.join(self.build_to_src, i) for i in genlist.extra_depends]
  1636. source_target_dir = self.get_target_source_dir(target)
  1637. for i in range(len(infilelist)):
  1638. if len(generator.outputs) == 1:
  1639. sole_output = os.path.join(self.get_target_private_dir(target), outfilelist[i])
  1640. else:
  1641. sole_output = ''
  1642. curfile = infilelist[i]
  1643. infilename = curfile.rel_to_builddir(self.build_to_src)
  1644. outfiles = genlist.get_outputs_for(curfile)
  1645. outfiles = [os.path.join(self.get_target_private_dir(target), of) for of in outfiles]
  1646. if generator.depfile is None:
  1647. rulename = 'CUSTOM_COMMAND'
  1648. args = base_args
  1649. else:
  1650. rulename = 'CUSTOM_COMMAND_DEP'
  1651. depfilename = generator.get_dep_outname(infilename)
  1652. depfile = os.path.join(self.get_target_private_dir(target), depfilename)
  1653. args = [x.replace('@DEPFILE@', depfile) for x in base_args]
  1654. args = [x.replace("@INPUT@", infilename).replace('@OUTPUT@', sole_output)
  1655. for x in args]
  1656. args = self.replace_outputs(args, self.get_target_private_dir(target), outfilelist)
  1657. # We have consumed output files, so drop them from the list of remaining outputs.
  1658. if sole_output == '':
  1659. outfilelist = outfilelist[len(generator.outputs):]
  1660. relout = self.get_target_private_dir(target)
  1661. args = self.replace_paths(target, args)
  1662. cmdlist = exe_arr + self.replace_extra_args(args, genlist)
  1663. elem = NinjaBuildElement(self.all_outputs, outfiles, rulename, infilename)
  1664. if generator.depfile is not None:
  1665. elem.add_item('DEPFILE', depfile)
  1666. if len(extra_dependencies) > 0:
  1667. elem.add_dep(extra_dependencies)
  1668. elem.add_item('DESC', 'Generating $out')
  1669. if isinstance(exe, build.BuildTarget):
  1670. elem.add_dep(self.get_target_filename(exe))
  1671. elem.add_item('COMMAND', cmdlist)
  1672. elem.write(outfile)
  1673. def scan_fortran_module_outputs(self, target):
  1674. compiler = None
  1675. for lang, c in self.build.compilers.items():
  1676. if lang == 'fortran':
  1677. compiler = c
  1678. break
  1679. if compiler is None:
  1680. self.fortran_deps[target.get_basename()] = {}
  1681. return
  1682. modre = re.compile(r"\s*module\s+(\w+)", re.IGNORECASE)
  1683. module_files = {}
  1684. for s in target.get_sources():
  1685. # FIXME, does not work for Fortran sources generated by
  1686. # custom_target() and generator() as those are run after
  1687. # the configuration (configure_file() is OK)
  1688. if not compiler.can_compile(s):
  1689. continue
  1690. filename = s.absolute_path(self.environment.get_source_dir(),
  1691. self.environment.get_build_dir())
  1692. with open(filename) as f:
  1693. for line in f:
  1694. modmatch = modre.match(line)
  1695. if modmatch is not None:
  1696. modname = modmatch.group(1).lower()
  1697. if modname == 'procedure':
  1698. # MODULE PROCEDURE construct
  1699. continue
  1700. if modname in module_files:
  1701. raise InvalidArguments(
  1702. 'Namespace collision: module %s defined in '
  1703. 'two files %s and %s.' %
  1704. (modname, module_files[modname], s))
  1705. module_files[modname] = s
  1706. self.fortran_deps[target.get_basename()] = module_files
  1707. def get_fortran_deps(self, compiler, src, target):
  1708. mod_files = []
  1709. usere = re.compile(r"\s*use\s+(\w+)", re.IGNORECASE)
  1710. dirname = self.get_target_private_dir(target)
  1711. tdeps = self.fortran_deps[target.get_basename()]
  1712. with open(src) as f:
  1713. for line in f:
  1714. usematch = usere.match(line)
  1715. if usematch is not None:
  1716. usename = usematch.group(1).lower()
  1717. if usename not in tdeps:
  1718. # The module is not provided by any source file. This
  1719. # is due to:
  1720. # a) missing file/typo/etc
  1721. # b) using a module provided by the compiler, such as
  1722. # OpenMP
  1723. # There's no easy way to tell which is which (that I
  1724. # know of) so just ignore this and go on. Ideally we
  1725. # would print a warning message to the user but this is
  1726. # a common occurrence, which would lead to lots of
  1727. # distracting noise.
  1728. continue
  1729. mod_source_file = tdeps[usename]
  1730. # Check if a source uses a module it exports itself.
  1731. # Potential bug if multiple targets have a file with
  1732. # the same name.
  1733. if mod_source_file.fname == os.path.split(src)[1]:
  1734. continue
  1735. mod_name = compiler.module_name_to_filename(
  1736. usematch.group(1))
  1737. mod_files.append(os.path.join(dirname, mod_name))
  1738. return mod_files
  1739. def get_cross_stdlib_args(self, target, compiler):
  1740. if not target.is_cross:
  1741. return []
  1742. if not self.environment.cross_info.has_stdlib(compiler.language):
  1743. return []
  1744. return compiler.get_no_stdinc_args()
  1745. def get_compile_debugfile_args(self, compiler, target, objfile):
  1746. if compiler.id != 'msvc':
  1747. return []
  1748. # The way MSVC uses PDB files is documented exactly nowhere so
  1749. # the following is what we have been able to decipher via
  1750. # reverse engineering.
  1751. #
  1752. # Each object file gets the path of its PDB file written
  1753. # inside it. This can be either the final PDB (for, say,
  1754. # foo.exe) or an object pdb (for foo.obj). If the former, then
  1755. # each compilation step locks the pdb file for writing, which
  1756. # is a bottleneck and object files from one target can not be
  1757. # used in a different target. The latter seems to be the
  1758. # sensible one (and what Unix does) but there is a catch. If
  1759. # you try to use precompiled headers MSVC will error out
  1760. # because both source and pch pdbs go in the same file and
  1761. # they must be the same.
  1762. #
  1763. # This means:
  1764. #
  1765. # - pch files must be compiled anew for every object file (negating
  1766. # the entire point of having them in the first place)
  1767. # - when using pch, output must go to the target pdb
  1768. #
  1769. # Since both of these are broken in some way, use the one that
  1770. # works for each target. This unfortunately means that you
  1771. # can't combine pch and object extraction in a single target.
  1772. #
  1773. # PDB files also lead to filename collisions. A target foo.exe
  1774. # has a corresponding foo.pdb. A shared library foo.dll _also_
  1775. # has pdb file called foo.pdb. So will a static library
  1776. # foo.lib, which clobbers both foo.pdb _and_ the dll file's
  1777. # export library called foo.lib (by default, currently we name
  1778. # them libfoo.a to avoidt this issue). You can give the files
  1779. # unique names such as foo_exe.pdb but VC also generates a
  1780. # bunch of other files which take their names from the target
  1781. # basename (i.e. "foo") and stomp on each other.
  1782. #
  1783. # CMake solves this problem by doing two things. First of all
  1784. # static libraries do not generate pdb files at
  1785. # all. Presumably you don't need them and VC is smart enough
  1786. # to look up the original data when linking (speculation, not
  1787. # tested). The second solution is that you can only have
  1788. # target named "foo" as an exe, shared lib _or_ static
  1789. # lib. This makes filename collisions not happen. The downside
  1790. # is that you can't have an executable foo that uses a shared
  1791. # library libfoo.so, which is a common idiom on Unix.
  1792. #
  1793. # If you feel that the above is completely wrong and all of
  1794. # this is actually doable, please send patches.
  1795. if target.has_pch():
  1796. tfilename = self.get_target_filename_abs(target)
  1797. return compiler.get_compile_debugfile_args(tfilename, pch=True)
  1798. else:
  1799. return compiler.get_compile_debugfile_args(objfile, pch=False)
  1800. def get_link_debugfile_args(self, linker, target, outname):
  1801. return linker.get_link_debugfile_args(outname)
  1802. def generate_llvm_ir_compile(self, target, outfile, src):
  1803. compiler = get_compiler_for_source(target.compilers.values(), src)
  1804. commands = CompilerArgs(compiler)
  1805. # Compiler args for compiling this target
  1806. commands += compilers.get_base_compile_args(self.environment.coredata.base_options,
  1807. compiler)
  1808. if isinstance(src, File):
  1809. if src.is_built:
  1810. src_filename = os.path.join(src.subdir, src.fname)
  1811. else:
  1812. src_filename = src.fname
  1813. elif os.path.isabs(src):
  1814. src_filename = os.path.basename(src)
  1815. else:
  1816. src_filename = src
  1817. obj_basename = src_filename.replace('/', '_').replace('\\', '_')
  1818. rel_obj = os.path.join(self.get_target_private_dir(target), obj_basename)
  1819. rel_obj += '.' + self.environment.get_object_suffix()
  1820. commands += self.get_compile_debugfile_args(compiler, target, rel_obj)
  1821. if isinstance(src, File) and src.is_built:
  1822. rel_src = src.fname
  1823. elif isinstance(src, File):
  1824. rel_src = src.rel_to_builddir(self.build_to_src)
  1825. else:
  1826. raise InvalidArguments('Invalid source type: {!r}'.format(src))
  1827. # Write the Ninja build command
  1828. compiler_name = 'llvm_ir{}_COMPILER'.format('_CROSS' if target.is_cross else '')
  1829. element = NinjaBuildElement(self.all_outputs, rel_obj, compiler_name, rel_src)
  1830. # Convert from GCC-style link argument naming to the naming used by the
  1831. # current compiler.
  1832. commands = commands.to_native()
  1833. element.add_item('ARGS', commands)
  1834. element.write(outfile)
  1835. return rel_obj
  1836. def get_source_dir_include_args(self, target, compiler):
  1837. curdir = target.get_subdir()
  1838. tmppath = os.path.normpath(os.path.join(self.build_to_src, curdir))
  1839. return compiler.get_include_args(tmppath, False)
  1840. def get_build_dir_include_args(self, target, compiler):
  1841. curdir = target.get_subdir()
  1842. if curdir == '':
  1843. curdir = '.'
  1844. return compiler.get_include_args(curdir, False)
  1845. def get_custom_target_dir_include_args(self, target, compiler):
  1846. custom_target_include_dirs = []
  1847. for i in target.get_generated_sources():
  1848. # Generator output goes into the target private dir which is
  1849. # already in the include paths list. Only custom targets have their
  1850. # own target build dir.
  1851. if not isinstance(i, build.CustomTarget):
  1852. continue
  1853. idir = self.get_target_dir(i)
  1854. if idir not in custom_target_include_dirs:
  1855. custom_target_include_dirs.append(idir)
  1856. incs = []
  1857. for i in custom_target_include_dirs:
  1858. incs += compiler.get_include_args(i, False)
  1859. return incs
  1860. def _generate_single_compile(self, target, compiler, is_generated=False):
  1861. base_proxy = backends.OptionOverrideProxy(target.option_overrides,
  1862. self.environment.coredata.base_options)
  1863. # Create an empty commands list, and start adding arguments from
  1864. # various sources in the order in which they must override each other
  1865. commands = CompilerArgs(compiler)
  1866. # Add compiler args for compiling this target derived from 'base' build
  1867. # options passed on the command-line, in default_options, etc.
  1868. # These have the lowest priority.
  1869. commands += compilers.get_base_compile_args(base_proxy,
  1870. compiler)
  1871. # The code generated by valac is usually crap and has tons of unused
  1872. # variables and such, so disable warnings for Vala C sources.
  1873. no_warn_args = (is_generated == 'vala')
  1874. # Add compiler args and include paths from several sources; defaults,
  1875. # build options, external dependencies, etc.
  1876. commands += self.generate_basic_compiler_args(target, compiler, no_warn_args)
  1877. # Add include dirs from the `include_directories:` kwarg on the target
  1878. # and from `include_directories:` of internal deps of the target.
  1879. #
  1880. # Target include dirs should override internal deps include dirs.
  1881. # This is handled in BuildTarget.process_kwargs()
  1882. #
  1883. # Include dirs from internal deps should override include dirs from
  1884. # external deps and must maintain the order in which they are specified.
  1885. # Hence, we must reverse the list so that the order is preserved.
  1886. for i in reversed(target.get_include_dirs()):
  1887. basedir = i.get_curdir()
  1888. for d in i.get_incdirs():
  1889. # Avoid superfluous '/.' at the end of paths when d is '.'
  1890. if d not in ('', '.'):
  1891. expdir = os.path.join(basedir, d)
  1892. else:
  1893. expdir = basedir
  1894. srctreedir = os.path.join(self.build_to_src, expdir)
  1895. # Add source subdir first so that the build subdir overrides it
  1896. sargs = compiler.get_include_args(srctreedir, i.is_system)
  1897. commands += sargs
  1898. # There may be include dirs where a build directory has not been
  1899. # created for some source dir. For example if someone does this:
  1900. #
  1901. # inc = include_directories('foo/bar/baz')
  1902. #
  1903. # But never subdir()s into the actual dir.
  1904. if os.path.isdir(os.path.join(self.environment.get_build_dir(), expdir)):
  1905. bargs = compiler.get_include_args(expdir, i.is_system)
  1906. else:
  1907. bargs = []
  1908. commands += bargs
  1909. for d in i.get_extra_build_dirs():
  1910. commands += compiler.get_include_args(d, i.is_system)
  1911. # Add per-target compile args, f.ex, `c_args : ['-DFOO']`. We set these
  1912. # near the end since these are supposed to override everything else.
  1913. commands += self.escape_extra_args(compiler,
  1914. target.get_extra_args(compiler.get_language()))
  1915. # Add source dir and build dir. Project-specific and target-specific
  1916. # include paths must override per-target compile args, include paths
  1917. # from external dependencies, internal dependencies, and from
  1918. # per-target `include_directories:`
  1919. #
  1920. # We prefer headers in the build dir and the custom target dir over the
  1921. # source dir since, for instance, the user might have an
  1922. # srcdir == builddir Autotools build in their source tree. Many
  1923. # projects that are moving to Meson have both Meson and Autotools in
  1924. # parallel as part of the transition.
  1925. commands += self.get_source_dir_include_args(target, compiler)
  1926. commands += self.get_custom_target_dir_include_args(target, compiler)
  1927. commands += self.get_build_dir_include_args(target, compiler)
  1928. # Finally add the private dir for the target to the include path. This
  1929. # must override everything else and must be the final path added.
  1930. commands += compiler.get_include_args(self.get_target_private_dir(target), False)
  1931. return commands
  1932. def generate_single_compile(self, target, outfile, src, is_generated=False, header_deps=[], order_deps=[]):
  1933. """
  1934. Compiles C/C++, ObjC/ObjC++, Fortran, and D sources
  1935. """
  1936. if isinstance(src, str) and src.endswith('.h'):
  1937. raise AssertionError('BUG: sources should not contain headers {!r}'.format(src))
  1938. compiler = get_compiler_for_source(target.compilers.values(), src)
  1939. key = (target, compiler, is_generated)
  1940. if key in self.target_arg_cache:
  1941. commands = self.target_arg_cache[key]
  1942. else:
  1943. commands = self._generate_single_compile(target, compiler, is_generated)
  1944. self.target_arg_cache[key] = commands
  1945. commands = CompilerArgs(commands.compiler, commands)
  1946. if isinstance(src, mesonlib.File) and src.is_built:
  1947. rel_src = os.path.join(src.subdir, src.fname)
  1948. if os.path.isabs(rel_src):
  1949. assert(rel_src.startswith(self.environment.get_build_dir()))
  1950. rel_src = rel_src[len(self.environment.get_build_dir()) + 1:]
  1951. abs_src = os.path.join(self.environment.get_build_dir(), rel_src)
  1952. elif isinstance(src, mesonlib.File):
  1953. rel_src = src.rel_to_builddir(self.build_to_src)
  1954. abs_src = src.absolute_path(self.environment.get_source_dir(),
  1955. self.environment.get_build_dir())
  1956. elif is_generated:
  1957. raise AssertionError('BUG: broken generated source file handling for {!r}'.format(src))
  1958. else:
  1959. if isinstance(src, File):
  1960. rel_src = src.rel_to_builddir(self.build_to_src)
  1961. else:
  1962. raise InvalidArguments('Invalid source type: {!r}'.format(src))
  1963. abs_src = os.path.join(self.environment.get_build_dir(), rel_src)
  1964. if isinstance(src, File):
  1965. if src.is_built:
  1966. src_filename = os.path.join(src.subdir, src.fname)
  1967. if os.path.isabs(src_filename):
  1968. assert(src_filename.startswith(self.environment.get_build_dir()))
  1969. src_filename = src_filename[len(self.environment.get_build_dir()) + 1:]
  1970. else:
  1971. src_filename = src.fname
  1972. elif os.path.isabs(src):
  1973. src_filename = os.path.basename(src)
  1974. else:
  1975. src_filename = src
  1976. obj_basename = src_filename.replace('/', '_').replace('\\', '_')
  1977. rel_obj = os.path.join(self.get_target_private_dir(target), obj_basename)
  1978. rel_obj += '.' + self.environment.get_object_suffix()
  1979. dep_file = compiler.depfile_for_object(rel_obj)
  1980. # Add MSVC debug file generation compile flags: /Fd /FS
  1981. commands += self.get_compile_debugfile_args(compiler, target, rel_obj)
  1982. # PCH handling
  1983. if self.environment.coredata.base_options.get('b_pch', False):
  1984. commands += self.get_pch_include_args(compiler, target)
  1985. pchlist = target.get_pch(compiler.language)
  1986. else:
  1987. pchlist = []
  1988. if not pchlist:
  1989. pch_dep = []
  1990. elif compiler.id == 'intel':
  1991. pch_dep = []
  1992. else:
  1993. arr = []
  1994. i = os.path.join(self.get_target_private_dir(target), compiler.get_pch_name(pchlist[0]))
  1995. arr.append(i)
  1996. pch_dep = arr
  1997. crstr = ''
  1998. if target.is_cross:
  1999. crstr = '_CROSS'
  2000. compiler_name = '%s%s_COMPILER' % (compiler.get_language(), crstr)
  2001. extra_deps = []
  2002. if compiler.get_language() == 'fortran':
  2003. # Can't read source file to scan for deps if it's generated later
  2004. # at build-time. Skip scanning for deps, and just set the module
  2005. # outdir argument instead.
  2006. # https://github.com/mesonbuild/meson/issues/1348
  2007. if not is_generated:
  2008. extra_deps += self.get_fortran_deps(compiler, abs_src, target)
  2009. # Dependency hack. Remove once multiple outputs in Ninja is fixed:
  2010. # https://groups.google.com/forum/#!topic/ninja-build/j-2RfBIOd_8
  2011. for modname, srcfile in self.fortran_deps[target.get_basename()].items():
  2012. modfile = os.path.join(self.get_target_private_dir(target),
  2013. compiler.module_name_to_filename(modname))
  2014. if srcfile == src:
  2015. depelem = NinjaBuildElement(self.all_outputs, modfile, 'FORTRAN_DEP_HACK', rel_obj)
  2016. depelem.write(outfile)
  2017. commands += compiler.get_module_outdir_args(self.get_target_private_dir(target))
  2018. element = NinjaBuildElement(self.all_outputs, rel_obj, compiler_name, rel_src)
  2019. for d in header_deps:
  2020. if isinstance(d, File):
  2021. d = d.rel_to_builddir(self.build_to_src)
  2022. elif not self.has_dir_part(d):
  2023. d = os.path.join(self.get_target_private_dir(target), d)
  2024. element.add_dep(d)
  2025. for d in extra_deps:
  2026. element.add_dep(d)
  2027. for d in order_deps:
  2028. if isinstance(d, File):
  2029. d = d.rel_to_builddir(self.build_to_src)
  2030. elif not self.has_dir_part(d):
  2031. d = os.path.join(self.get_target_private_dir(target), d)
  2032. element.add_orderdep(d)
  2033. element.add_orderdep(pch_dep)
  2034. # Convert from GCC-style link argument naming to the naming used by the
  2035. # current compiler.
  2036. commands = commands.to_native()
  2037. for i in self.get_fortran_orderdeps(target, compiler):
  2038. element.add_orderdep(i)
  2039. element.add_item('DEPFILE', dep_file)
  2040. element.add_item('ARGS', commands)
  2041. element.write(outfile)
  2042. return rel_obj
  2043. def has_dir_part(self, fname):
  2044. # FIXME FIXME: The usage of this is a terrible and unreliable hack
  2045. if isinstance(fname, File):
  2046. return fname.subdir != ''
  2047. return '/' in fname or '\\' in fname
  2048. # Fortran is a bit weird (again). When you link against a library, just compiling a source file
  2049. # requires the mod files that are output when single files are built. To do this right we would need to
  2050. # scan all inputs and write out explicit deps for each file. That is stoo slow and too much effort so
  2051. # instead just have an ordered dependendy on the library. This ensures all required mod files are created.
  2052. # The real deps are then detected via dep file generation from the compiler. This breaks on compilers that
  2053. # produce incorrect dep files but such is life.
  2054. def get_fortran_orderdeps(self, target, compiler):
  2055. if compiler.language != 'fortran':
  2056. return []
  2057. return [os.path.join(self.get_target_dir(lt), lt.get_filename()) for lt in target.link_targets]
  2058. def generate_msvc_pch_command(self, target, compiler, pch):
  2059. if len(pch) != 2:
  2060. raise RuntimeError('MSVC requires one header and one source to produce precompiled headers.')
  2061. header = pch[0]
  2062. source = pch[1]
  2063. pchname = compiler.get_pch_name(header)
  2064. dst = os.path.join(self.get_target_private_dir(target), pchname)
  2065. commands = []
  2066. commands += self.generate_basic_compiler_args(target, compiler)
  2067. just_name = os.path.split(header)[1]
  2068. (objname, pch_args) = compiler.gen_pch_args(just_name, source, dst)
  2069. commands += pch_args
  2070. commands += self.get_compile_debugfile_args(compiler, target, objname)
  2071. dep = dst + '.' + compiler.get_depfile_suffix()
  2072. return commands, dep, dst, [objname]
  2073. def generate_gcc_pch_command(self, target, compiler, pch):
  2074. commands = self._generate_single_compile(target, compiler)
  2075. dst = os.path.join(self.get_target_private_dir(target),
  2076. os.path.split(pch)[-1] + '.' + compiler.get_pch_suffix())
  2077. dep = dst + '.' + compiler.get_depfile_suffix()
  2078. return commands, dep, dst, [] # Gcc does not create an object file during pch generation.
  2079. def generate_pch(self, target, outfile):
  2080. cstr = ''
  2081. pch_objects = []
  2082. if target.is_cross:
  2083. cstr = '_CROSS'
  2084. for lang in ['c', 'cpp']:
  2085. pch = target.get_pch(lang)
  2086. if not pch:
  2087. continue
  2088. if '/' not in pch[0] or '/' not in pch[-1]:
  2089. msg = 'Precompiled header of {!r} must not be in the same ' \
  2090. 'directory as source, please put it in a subdirectory.' \
  2091. ''.format(target.get_basename())
  2092. raise InvalidArguments(msg)
  2093. compiler = target.compilers[lang]
  2094. if compiler.id == 'msvc':
  2095. src = os.path.join(self.build_to_src, target.get_source_subdir(), pch[-1])
  2096. (commands, dep, dst, objs) = self.generate_msvc_pch_command(target, compiler, pch)
  2097. extradep = os.path.join(self.build_to_src, target.get_source_subdir(), pch[0])
  2098. elif compiler.id == 'intel':
  2099. # Intel generates on target generation
  2100. continue
  2101. else:
  2102. src = os.path.join(self.build_to_src, target.get_source_subdir(), pch[0])
  2103. (commands, dep, dst, objs) = self.generate_gcc_pch_command(target, compiler, pch[0])
  2104. extradep = None
  2105. pch_objects += objs
  2106. rulename = compiler.get_language() + cstr + '_PCH'
  2107. elem = NinjaBuildElement(self.all_outputs, dst, rulename, src)
  2108. if extradep is not None:
  2109. elem.add_dep(extradep)
  2110. elem.add_item('ARGS', commands)
  2111. elem.add_item('DEPFILE', dep)
  2112. elem.write(outfile)
  2113. return pch_objects
  2114. def generate_shsym(self, outfile, target):
  2115. target_name = self.get_target_filename(target)
  2116. targetdir = self.get_target_private_dir(target)
  2117. symname = os.path.join(targetdir, target_name + '.symbols')
  2118. elem = NinjaBuildElement(self.all_outputs, symname, 'SHSYM', target_name)
  2119. if self.environment.is_cross_build() and self.environment.cross_info.need_cross_compiler():
  2120. elem.add_item('CROSS', '--cross-host=' + self.environment.cross_info.config['host_machine']['system'])
  2121. elem.write(outfile)
  2122. def get_cross_stdlib_link_args(self, target, linker):
  2123. if isinstance(target, build.StaticLibrary) or not target.is_cross:
  2124. return []
  2125. if not self.environment.cross_info.has_stdlib(linker.language):
  2126. return []
  2127. return linker.get_no_stdlib_link_args()
  2128. def get_target_type_link_args(self, target, linker):
  2129. abspath = os.path.join(self.environment.get_build_dir(), target.subdir)
  2130. commands = []
  2131. if isinstance(target, build.Executable):
  2132. # Currently only used with the Swift compiler to add '-emit-executable'
  2133. commands += linker.get_std_exe_link_args()
  2134. # If gui_app, and that's significant on this platform
  2135. if target.gui_app and hasattr(linker, 'get_gui_app_args'):
  2136. commands += linker.get_gui_app_args()
  2137. # If implib, and that's significant on this platform (i.e. Windows using either GCC or Visual Studio)
  2138. if target.import_filename:
  2139. commands += linker.gen_import_library_args(os.path.join(target.subdir, target.import_filename))
  2140. elif isinstance(target, build.SharedLibrary):
  2141. if isinstance(target, build.SharedModule):
  2142. commands += linker.get_std_shared_module_link_args()
  2143. else:
  2144. commands += linker.get_std_shared_lib_link_args()
  2145. # All shared libraries are PIC
  2146. commands += linker.get_pic_args()
  2147. # Add -Wl,-soname arguments on Linux, -install_name on OS X
  2148. commands += linker.get_soname_args(target.prefix, target.name, target.suffix,
  2149. abspath, target.soversion,
  2150. isinstance(target, build.SharedModule))
  2151. # This is only visited when building for Windows using either GCC or Visual Studio
  2152. if target.vs_module_defs and hasattr(linker, 'gen_vs_module_defs_args'):
  2153. commands += linker.gen_vs_module_defs_args(target.vs_module_defs.rel_to_builddir(self.build_to_src))
  2154. # This is only visited when building for Windows using either GCC or Visual Studio
  2155. if target.import_filename:
  2156. commands += linker.gen_import_library_args(os.path.join(target.subdir, target.import_filename))
  2157. elif isinstance(target, build.StaticLibrary):
  2158. commands += linker.get_std_link_args()
  2159. else:
  2160. raise RuntimeError('Unknown build target type.')
  2161. return commands
  2162. def get_link_whole_args(self, linker, target):
  2163. target_args = self.build_target_link_arguments(linker, target.link_whole_targets)
  2164. return linker.get_link_whole_for(target_args) if len(target_args) else []
  2165. def generate_link(self, target, outfile, outname, obj_list, linker, extra_args=[]):
  2166. if isinstance(target, build.StaticLibrary):
  2167. linker_base = 'STATIC'
  2168. else:
  2169. linker_base = linker.get_language() # Fixme.
  2170. if isinstance(target, build.SharedLibrary):
  2171. self.generate_shsym(outfile, target)
  2172. crstr = ''
  2173. if target.is_cross:
  2174. crstr = '_CROSS'
  2175. linker_rule = linker_base + crstr + '_LINKER'
  2176. # Create an empty commands list, and start adding link arguments from
  2177. # various sources in the order in which they must override each other
  2178. # starting from hard-coded defaults followed by build options and so on.
  2179. #
  2180. # Once all the linker options have been passed, we will start passing
  2181. # libraries and library paths from internal and external sources.
  2182. commands = CompilerArgs(linker)
  2183. # First, the trivial ones that are impossible to override.
  2184. #
  2185. # Add linker args for linking this target derived from 'base' build
  2186. # options passed on the command-line, in default_options, etc.
  2187. # These have the lowest priority.
  2188. if not isinstance(target, build.StaticLibrary):
  2189. commands += compilers.get_base_link_args(self.environment.coredata.base_options,
  2190. linker,
  2191. isinstance(target, build.SharedModule))
  2192. # Add -nostdlib if needed; can't be overriden
  2193. commands += self.get_cross_stdlib_link_args(target, linker)
  2194. # Add things like /NOLOGO; usually can't be overriden
  2195. commands += linker.get_linker_always_args()
  2196. # Add buildtype linker args: optimization level, etc.
  2197. commands += linker.get_buildtype_linker_args(self.get_option_for_target('buildtype', target))
  2198. # Add /DEBUG and the pdb filename when using MSVC
  2199. commands += self.get_link_debugfile_args(linker, target, outname)
  2200. # Add link args specific to this BuildTarget type, such as soname args,
  2201. # PIC, import library generation, etc.
  2202. commands += self.get_target_type_link_args(target, linker)
  2203. # Archives that are copied wholesale in the result. Must be before any
  2204. # other link targets so missing symbols from whole archives are found in those.
  2205. if not isinstance(target, build.StaticLibrary):
  2206. commands += self.get_link_whole_args(linker, target)
  2207. if not isinstance(target, build.StaticLibrary):
  2208. # Add link args added using add_project_link_arguments()
  2209. commands += self.build.get_project_link_args(linker, target.subproject)
  2210. # Add link args added using add_global_link_arguments()
  2211. # These override per-project link arguments
  2212. commands += self.build.get_global_link_args(linker)
  2213. if not target.is_cross:
  2214. # Link args added from the env: LDFLAGS. We want these to
  2215. # override all the defaults but not the per-target link args.
  2216. commands += self.environment.coredata.external_link_args[linker.get_language()]
  2217. # Now we will add libraries and library paths from various sources
  2218. # Add link args to link to all internal libraries (link_with:) and
  2219. # internal dependencies needed by this target.
  2220. if linker_base == 'STATIC':
  2221. # Link arguments of static libraries are not put in the command
  2222. # line of the library. They are instead appended to the command
  2223. # line where the static library is used.
  2224. dependencies = []
  2225. else:
  2226. dependencies = target.get_dependencies()
  2227. commands += self.build_target_link_arguments(linker, dependencies)
  2228. # For 'automagic' deps: Boost and GTest. Also dependency('threads').
  2229. # pkg-config puts the thread flags itself via `Cflags:`
  2230. for d in target.external_deps:
  2231. if d.need_threads():
  2232. commands += linker.thread_link_flags()
  2233. # Only non-static built targets need link args and link dependencies
  2234. if not isinstance(target, build.StaticLibrary):
  2235. commands += target.link_args
  2236. # External deps must be last because target link libraries may depend on them.
  2237. for dep in target.get_external_deps():
  2238. # Extend without reordering or de-dup to preserve `-L -l` sets
  2239. # https://github.com/mesonbuild/meson/issues/1718
  2240. commands.extend_direct(dep.get_link_args())
  2241. for d in target.get_dependencies():
  2242. if isinstance(d, build.StaticLibrary):
  2243. for dep in d.get_external_deps():
  2244. commands.extend_direct(dep.get_link_args())
  2245. # Add link args for c_* or cpp_* build options. Currently this only
  2246. # adds c_winlibs and cpp_winlibs when building for Windows. This needs
  2247. # to be after all internal and external libraries so that unresolved
  2248. # symbols from those can be found here. This is needed when the
  2249. # *_winlibs that we want to link to are static mingw64 libraries.
  2250. commands += linker.get_option_link_args(self.environment.coredata.compiler_options)
  2251. # Set runtime-paths so we can run executables without needing to set
  2252. # LD_LIBRARY_PATH, etc in the environment. Doesn't work on Windows.
  2253. if '/' in target.name or '\\' in target.name:
  2254. # Target names really should not have slashes in them, but
  2255. # unfortunately we did not check for that and some downstream projects
  2256. # now have them. Once slashes are forbidden, remove this bit.
  2257. target_slashname_workaround_dir = os.path.join(
  2258. os.path.split(target.name)[0],
  2259. self.get_target_dir(target))
  2260. else:
  2261. target_slashname_workaround_dir = self.get_target_dir(target)
  2262. commands += linker.build_rpath_args(self.environment.get_build_dir(),
  2263. target_slashname_workaround_dir,
  2264. self.determine_rpath_dirs(target),
  2265. target.build_rpath,
  2266. target.install_rpath)
  2267. # Add libraries generated by custom targets
  2268. custom_target_libraries = self.get_custom_target_provided_libraries(target)
  2269. commands += extra_args
  2270. commands += custom_target_libraries
  2271. # Convert from GCC-style link argument naming to the naming used by the
  2272. # current compiler.
  2273. commands = commands.to_native()
  2274. dep_targets = [self.get_dependency_filename(t) for t in dependencies]
  2275. dep_targets.extend([self.get_dependency_filename(t)
  2276. for t in target.link_depends])
  2277. elem = NinjaBuildElement(self.all_outputs, outname, linker_rule, obj_list)
  2278. elem.add_dep(dep_targets + custom_target_libraries)
  2279. elem.add_item('LINK_ARGS', commands)
  2280. return elem
  2281. def get_dependency_filename(self, t):
  2282. if isinstance(t, build.SharedLibrary):
  2283. return os.path.join(self.get_target_private_dir(t), self.get_target_filename(t) + '.symbols')
  2284. elif isinstance(t, mesonlib.File):
  2285. if t.is_built:
  2286. return t.relative_name()
  2287. else:
  2288. return t.absolute_path(self.environment.get_source_dir(),
  2289. self.environment.get_build_dir())
  2290. return self.get_target_filename(t)
  2291. def generate_shlib_aliases(self, target, outdir):
  2292. aliases = target.get_aliases()
  2293. for alias, to in aliases.items():
  2294. aliasfile = os.path.join(self.environment.get_build_dir(), outdir, alias)
  2295. try:
  2296. os.remove(aliasfile)
  2297. except Exception:
  2298. pass
  2299. try:
  2300. os.symlink(to, aliasfile)
  2301. except NotImplementedError:
  2302. mlog.debug("Library versioning disabled because symlinks are not supported.")
  2303. except OSError:
  2304. mlog.debug("Library versioning disabled because we do not have symlink creation privileges.")
  2305. def generate_custom_target_clean(self, outfile, trees):
  2306. e = NinjaBuildElement(self.all_outputs, 'clean-ctlist', 'CUSTOM_COMMAND', 'PHONY')
  2307. d = CleanTrees(self.environment.get_build_dir(), trees)
  2308. d_file = os.path.join(self.environment.get_scratch_dir(), 'cleantrees.dat')
  2309. e.add_item('COMMAND', [sys.executable,
  2310. self.environment.get_build_command(),
  2311. '--internal', 'cleantrees', d_file])
  2312. e.add_item('description', 'Cleaning custom target directories.')
  2313. e.write(outfile)
  2314. # Write out the data file passed to the script
  2315. with open(d_file, 'wb') as ofile:
  2316. pickle.dump(d, ofile)
  2317. return 'clean-ctlist'
  2318. def generate_gcov_clean(self, outfile):
  2319. gcno_elem = NinjaBuildElement(self.all_outputs, 'clean-gcno', 'CUSTOM_COMMAND', 'PHONY')
  2320. script_root = self.environment.get_script_dir()
  2321. clean_script = os.path.join(script_root, 'delwithsuffix.py')
  2322. gcno_elem.add_item('COMMAND', [sys.executable, clean_script, '.', 'gcno'])
  2323. gcno_elem.add_item('description', 'Deleting gcno files.')
  2324. gcno_elem.write(outfile)
  2325. gcda_elem = NinjaBuildElement(self.all_outputs, 'clean-gcda', 'CUSTOM_COMMAND', 'PHONY')
  2326. script_root = self.environment.get_script_dir()
  2327. clean_script = os.path.join(script_root, 'delwithsuffix.py')
  2328. gcda_elem.add_item('COMMAND', [sys.executable, clean_script, '.', 'gcda'])
  2329. gcda_elem.add_item('description', 'Deleting gcda files.')
  2330. gcda_elem.write(outfile)
  2331. def get_user_option_args(self):
  2332. cmds = []
  2333. for (k, v) in self.environment.coredata.user_options.items():
  2334. cmds.append('-D' + k + '=' + (v.value if isinstance(v.value, str) else str(v.value).lower()))
  2335. # The order of these arguments must be the same between runs of Meson
  2336. # to ensure reproducible output. The order we pass them shouldn't
  2337. # affect behavior in any other way.
  2338. return sorted(cmds)
  2339. def generate_dist(self, outfile):
  2340. elem = NinjaBuildElement(self.all_outputs, 'dist', 'CUSTOM_COMMAND', 'PHONY')
  2341. elem.add_item('DESC', 'Creating source packages')
  2342. elem.add_item('COMMAND', [sys.executable,
  2343. self.environment.get_build_command(),
  2344. '--internal', 'dist',
  2345. self.environment.source_dir,
  2346. self.environment.build_dir,
  2347. sys.executable,
  2348. self.environment.get_build_command()])
  2349. elem.add_item('pool', 'console')
  2350. elem.write(outfile)
  2351. # For things like scan-build and other helper tools we might have.
  2352. def generate_utils(self, outfile):
  2353. cmd = [sys.executable, self.environment.get_build_command(),
  2354. '--internal', 'scanbuild', self.environment.source_dir, self.environment.build_dir,
  2355. sys.executable, self.environment.get_build_command()] + self.get_user_option_args()
  2356. elem = NinjaBuildElement(self.all_outputs, 'scan-build', 'CUSTOM_COMMAND', 'PHONY')
  2357. elem.add_item('COMMAND', cmd)
  2358. elem.add_item('pool', 'console')
  2359. elem.write(outfile)
  2360. cmd = [sys.executable, self.environment.get_build_command(),
  2361. '--internal', 'uninstall']
  2362. elem = NinjaBuildElement(self.all_outputs, 'uninstall', 'CUSTOM_COMMAND', 'PHONY')
  2363. elem.add_item('COMMAND', cmd)
  2364. elem.add_item('pool', 'console')
  2365. elem.write(outfile)
  2366. def generate_ending(self, outfile):
  2367. targetlist = []
  2368. for t in self.get_build_by_default_targets().values():
  2369. # Add the first output of each target to the 'all' target so that
  2370. # they are all built
  2371. targetlist.append(os.path.join(self.get_target_dir(t), t.get_outputs()[0]))
  2372. elem = NinjaBuildElement(self.all_outputs, 'all', 'phony', targetlist)
  2373. elem.write(outfile)
  2374. default = 'default all\n\n'
  2375. outfile.write(default)
  2376. ninja_command = environment.detect_ninja()
  2377. if ninja_command is None:
  2378. raise MesonException('Could not detect Ninja v1.6 or newer')
  2379. elem = NinjaBuildElement(self.all_outputs, 'clean', 'CUSTOM_COMMAND', 'PHONY')
  2380. elem.add_item('COMMAND', [ninja_command, '-t', 'clean'])
  2381. elem.add_item('description', 'Cleaning.')
  2382. # If we have custom targets in this project, add all their outputs to
  2383. # the list that is passed to the `cleantrees.py` script. The script
  2384. # will manually delete all custom_target outputs that are directories
  2385. # instead of files. This is needed because on platforms other than
  2386. # Windows, Ninja only deletes directories while cleaning if they are
  2387. # empty. https://github.com/mesonbuild/meson/issues/1220
  2388. ctlist = []
  2389. for t in self.build.get_targets().values():
  2390. if isinstance(t, build.CustomTarget):
  2391. # Create a list of all custom target outputs
  2392. for o in t.get_outputs():
  2393. ctlist.append(os.path.join(self.get_target_dir(t), o))
  2394. if ctlist:
  2395. elem.add_dep(self.generate_custom_target_clean(outfile, ctlist))
  2396. if 'b_coverage' in self.environment.coredata.base_options and \
  2397. self.environment.coredata.base_options['b_coverage'].value:
  2398. self.generate_gcov_clean(outfile)
  2399. elem.add_dep('clean-gcda')
  2400. elem.add_dep('clean-gcno')
  2401. elem.write(outfile)
  2402. deps = self.get_regen_filelist()
  2403. elem = NinjaBuildElement(self.all_outputs, 'build.ninja', 'REGENERATE_BUILD', deps)
  2404. elem.add_item('pool', 'console')
  2405. elem.write(outfile)
  2406. elem = NinjaBuildElement(self.all_outputs, 'reconfigure', 'REGENERATE_BUILD', 'PHONY')
  2407. elem.add_item('pool', 'console')
  2408. elem.write(outfile)
  2409. elem = NinjaBuildElement(self.all_outputs, deps, 'phony', '')
  2410. elem.write(outfile)