ymake_conf.py 129 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257
  1. #!/usr/bin/env python
  2. # coding=utf-8
  3. from __future__ import print_function
  4. import base64
  5. import itertools
  6. import json
  7. import logging
  8. import ntpath
  9. import optparse
  10. import os
  11. import posixpath
  12. import re
  13. import subprocess
  14. import sys
  15. import tempfile
  16. import six
  17. logger = logging.getLogger(__name__ if __name__ != '__main__' else 'ymake_conf.py')
  18. def init_logger(verbose):
  19. logging.basicConfig(level=logging.DEBUG if verbose else logging.INFO)
  20. class DebugString(object):
  21. def __init__(self, get_string_func):
  22. self.get_string_func = get_string_func
  23. def __str__(self):
  24. return self.get_string_func()
  25. class ConfigureError(Exception):
  26. pass
  27. class Platform(object):
  28. def __init__(self, name, os, arch):
  29. """
  30. :type name: str
  31. :type os: str
  32. :type arch: str
  33. """
  34. self.name = name
  35. self.os = self._parse_os(os)
  36. self.arch = arch.lower()
  37. self.is_i386 = self.arch in ('i386', 'x86')
  38. self.is_i686 = self.arch == 'i686'
  39. self.is_x86 = self.is_i386 or self.is_i686
  40. self.is_x86_64 = self.arch in ('x86_64', 'amd64')
  41. self.is_intel = self.is_x86 or self.is_x86_64
  42. self.is_armv7 = self.arch in ('armv7', 'armv7a', 'armv7a_neon', 'arm', 'armv7a_cortex_a9', 'armv7ahf_cortex_a35', 'armv7ahf_cortex_a53')
  43. self.is_armv8 = self.arch in ('armv8', 'armv8a', 'arm64', 'aarch64', 'armv8a_cortex_a35', 'armv8a_cortex_a53')
  44. self.is_armv8m = self.arch in ('armv8m_cortex_m33',)
  45. self.is_arm64 = self.arch in ('arm64',)
  46. self.is_arm = self.is_armv7 or self.is_armv8 or self.is_armv8m
  47. self.is_armv7_neon = self.arch in ('armv7a_neon', 'armv7a_cortex_a9', 'armv7ahf_cortex_a35', 'armv7ahf_cortex_a53')
  48. self.is_armv7hf = self.arch in ('armv7ahf_cortex_a35', 'armv7ahf_cortex_a53')
  49. self.armv7_float_abi = None
  50. if self.is_armv7:
  51. if self.is_armv7hf:
  52. self.armv7_float_abi = 'hard'
  53. else:
  54. self.armv7_float_abi = 'softfp'
  55. self.is_cortex_a9 = self.arch in ('armv7a_cortex_a9',)
  56. self.is_cortex_a35 = self.arch in ('armv7ahf_cortex_a35', 'armv8a_cortex_a35')
  57. self.is_cortex_a53 = self.arch in ('armv7ahf_cortex_a53', 'armv8a_cortex_a53')
  58. self.is_cortex_m33 = self.arch in ('armv8m_cortex_m33',)
  59. self.is_power8le = self.arch == 'ppc64le'
  60. self.is_power9le = self.arch == 'power9le'
  61. self.is_powerpc = self.is_power8le or self.is_power9le
  62. self.is_32_bit = self.is_x86 or self.is_armv7 or self.is_armv8m
  63. self.is_64_bit = self.is_x86_64 or self.is_armv8 or self.is_powerpc
  64. assert self.is_32_bit or self.is_64_bit
  65. assert not (self.is_32_bit and self.is_64_bit)
  66. self.is_linux = self.os == 'linux' or 'yocto' in self.os
  67. self.is_linux_x86_64 = self.is_linux and self.is_x86_64
  68. self.is_linux_armv8 = self.is_linux and self.is_armv8
  69. self.is_linux_armv7 = self.is_linux and self.is_armv7
  70. self.is_linux_power8le = self.is_linux and self.is_power8le
  71. self.is_linux_power9le = self.is_linux and self.is_power9le
  72. self.is_linux_powerpc = self.is_linux_power8le or self.is_linux_power9le
  73. self.is_macos = self.os == 'macos'
  74. self.is_macos_x86_64 = self.is_macos and self.is_x86_64
  75. self.is_macos_arm64 = self.is_macos and self.is_arm64
  76. self.is_iossim = self.os == 'iossim' or (self.os == 'ios' and self.is_intel)
  77. self.is_ios = self.os == 'ios' or self.is_iossim
  78. self.is_apple = self.is_macos or self.is_ios
  79. self.is_windows = self.os == 'windows'
  80. self.is_windows_x86_64 = self.is_windows and self.is_x86_64
  81. self.is_android = self.os == 'android'
  82. if self.is_android:
  83. # This is default Android API level unless `ANDROID_API` is specified
  84. # 18 is the smallest level with OpenGL support
  85. # 21 is the smallest level for 64-bit platforms
  86. default_android_api = 21 if self.is_64_bit else 18
  87. self.android_api = int(preset('ANDROID_API', default_android_api))
  88. self.is_cygwin = self.os == 'cygwin'
  89. self.is_yocto = self.os == 'yocto'
  90. self.is_none = self.os == 'none'
  91. self.is_posix = self.is_linux or self.is_apple or self.is_android or self.is_cygwin or self.is_yocto
  92. @staticmethod
  93. def from_json(data):
  94. name = data.get('visible_name', data['toolchain'])
  95. return Platform(name, os=data['os'], arch=data['arch'])
  96. @property
  97. def os_variables(self):
  98. # 'LINUX' variable, for backward compatibility
  99. yield self.os.upper()
  100. # 'OS_LINUX' variable
  101. yield 'OS_{}'.format(self.os.upper())
  102. # yocto is linux
  103. if 'yocto' in self.os:
  104. yield 'LINUX'
  105. yield 'OS_LINUX'
  106. if self.is_macos:
  107. yield 'DARWIN'
  108. yield 'OS_DARWIN'
  109. if self.is_iossim:
  110. yield 'IOS'
  111. yield 'OS_IOS'
  112. yield 'OS_IOSSIM'
  113. @property
  114. def arch_variables(self):
  115. return select_multiple((
  116. (self.is_i386 or self.is_i686, 'ARCH_I386'),
  117. (self.is_i686, 'ARCH_I686'),
  118. (self.is_x86_64, 'ARCH_X86_64'),
  119. (self.is_armv7, 'ARCH_ARM7'),
  120. (self.is_armv7_neon, 'ARCH_ARM7_NEON'),
  121. (self.is_armv8, 'ARCH_ARM64'),
  122. (self.is_armv8m, 'ARCH_ARM8M'),
  123. (self.is_arm, 'ARCH_ARM'),
  124. (self.is_linux_armv8 or self.is_macos_arm64, 'ARCH_AARCH64'),
  125. (self.is_powerpc, 'ARCH_PPC64LE'),
  126. (self.is_power8le, 'ARCH_POWER8LE'),
  127. (self.is_power9le, 'ARCH_POWER9LE'),
  128. (self.is_32_bit, 'ARCH_TYPE_32'),
  129. (self.is_64_bit, 'ARCH_TYPE_64'),
  130. ))
  131. @property
  132. def library_path_variables(self):
  133. return ['LD_LIBRARY_PATH', 'DYLD_LIBRARY_PATH']
  134. def find_in_dict(self, dict_, default=None):
  135. if dict_ is None:
  136. return default
  137. for key in six.iterkeys(dict_):
  138. if self._parse_os(key) == self.os:
  139. return dict_[key]
  140. return default
  141. @property
  142. def os_compat(self):
  143. if self.is_macos:
  144. return 'DARWIN'
  145. else:
  146. return self.os.upper()
  147. def exe(self, *paths):
  148. if self.is_windows:
  149. return ntpath.join(*itertools.chain(paths[:-1], (paths[-1] + '.exe',)))
  150. else:
  151. return posixpath.join(*paths)
  152. def __str__(self):
  153. return '{name}-{os}-{arch}'.format(name=self.name, os=self.os, arch=self.arch)
  154. def __cmp__(self, other):
  155. return cmp((self.name, self.os, self.arch), (other.name, other.os, other.arch))
  156. def __hash__(self):
  157. return hash((self.name, self.os, self.arch))
  158. @staticmethod
  159. def _parse_os(os):
  160. os = os.lower()
  161. if os == 'darwin':
  162. return 'macos'
  163. if os in ('win', 'win32', 'win64'):
  164. return 'windows'
  165. if os.startswith('cygwin'):
  166. return 'cygwin'
  167. return os
  168. def which(prog):
  169. if os.path.exists(prog) and os.access(prog, os.X_OK):
  170. return prog
  171. # Ищем в $PATH только простые команды, без путей.
  172. if os.path.dirname(prog) != '':
  173. return None
  174. path = os.getenv('PATH', '')
  175. pathext = os.environ.get('PATHEXT')
  176. # На Windows %PATHEXT% указывает на список расширений, которые нужно проверять
  177. # при поиске команды в пути. Точное совпадение без расширения имеет приоритет.
  178. pathext = [''] if pathext is None else [''] + pathext.lower().split(os.pathsep)
  179. for dir_ in path.split(os.path.pathsep):
  180. for ext in pathext:
  181. p = os.path.join(dir_, prog + ext)
  182. if os.path.exists(p) and os.path.isfile(p) and os.access(p, os.X_OK):
  183. return p
  184. return None
  185. def get_stdout(command):
  186. stdout, code = get_stdout_and_code(command)
  187. return stdout if code == 0 else None
  188. def get_stdout_and_code(command):
  189. # noinspection PyBroadException
  190. try:
  191. process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  192. stdout, _ = process.communicate()
  193. return stdout, process.returncode
  194. except Exception:
  195. return None, None
  196. def to_strings(o):
  197. if isinstance(o, (list, tuple)):
  198. for s in o:
  199. for ss in to_strings(s):
  200. yield ss
  201. else:
  202. if o is not None:
  203. if isinstance(o, bool):
  204. yield 'yes' if o else 'no'
  205. elif isinstance(o, (str, int)):
  206. yield str(o)
  207. else:
  208. raise ConfigureError('Unexpected value {} {}'.format(type(o), o))
  209. def emit(key, *value):
  210. print('{0}={1}'.format(key, ' '.join(to_strings(value))))
  211. def emit_with_comment(comment, key, *value):
  212. print('# {}'.format(comment))
  213. emit(key, *value)
  214. def emit_with_ignore_comment(key, *value):
  215. emit_with_comment('IGNORE YMAKE CONF CONTEXT', key, *value)
  216. def append(key, *value):
  217. print('{0}+={1}'.format(key, ' '.join(to_strings(value))))
  218. def emit_big(text):
  219. prefix = None
  220. first = True
  221. for line in text.split('\n'):
  222. if prefix is None:
  223. if not line:
  224. continue
  225. prefix = 0
  226. while prefix < len(line) and line[prefix] == ' ':
  227. prefix += 1
  228. if first: # Be pretty, prepend an empty line before the output
  229. print()
  230. first = False
  231. print(line[prefix:])
  232. class Variables(dict):
  233. def emit(self, with_ignore_comment=[]):
  234. with_ignore_comment_set = set(with_ignore_comment)
  235. for k in sorted(self.keys()):
  236. if k in with_ignore_comment_set:
  237. emit_with_ignore_comment(k, self[k])
  238. else:
  239. emit(k, self[k])
  240. def update_from_presets(self):
  241. for k in six.iterkeys(self):
  242. v = preset(k)
  243. if v is not None:
  244. self[k] = v
  245. def reset_if_any(self, value_check=None, reset_value=None):
  246. if value_check is None:
  247. def value_check(v_):
  248. return v_ is None
  249. if any(map(value_check, six.itervalues(self))):
  250. for k in six.iterkeys(self):
  251. self[k] = reset_value
  252. def format_env(env, list_separator=':'):
  253. def format_value(value):
  254. return value if isinstance(value, str) else ('\\' + list_separator).join(value)
  255. def format(kv):
  256. return '${env:"%s=%s"}' % (kv[0], format_value(kv[1]))
  257. return ' '.join(map(format, sorted(six.iteritems(env))))
  258. # TODO(somov): Проверить, используется ли это. Может быть, выпилить.
  259. def userify_presets(presets, keys):
  260. for key in keys:
  261. user_key = 'USER_{}'.format(key)
  262. values = [presets.pop(key, None), presets.get(user_key)]
  263. presets[user_key] = ' '.join(filter(None, values))
  264. def preset(key, default=None):
  265. return opts().presets.get(key, default)
  266. def is_positive(key):
  267. return is_positive_str(preset(key, ''))
  268. def is_positive_str(s):
  269. return s.lower() in ('yes', 'true', 'on', '1')
  270. def is_negative(key):
  271. return is_negative_str(preset(key, ''))
  272. def is_negative_str(s):
  273. return s.lower() in ('no', 'false', 'off', '0')
  274. def to_bool(s, default=None):
  275. if isinstance(s, six.string_types):
  276. if is_positive_str(s):
  277. return True
  278. if is_negative_str(s):
  279. return False
  280. if default is None:
  281. raise ConfigureError('{} is not a bool value'.format(s))
  282. return default
  283. def select(selectors, default=None, no_default=False):
  284. for enabled, value in selectors:
  285. if enabled:
  286. return value
  287. if no_default:
  288. raise ConfigureError()
  289. return default
  290. def select_multiple(selectors):
  291. for enabled, value in selectors:
  292. if enabled:
  293. yield value
  294. def unique(it):
  295. known = set()
  296. for i in it:
  297. if i not in known:
  298. known.add(i)
  299. yield i
  300. class Options(object):
  301. def __init__(self, argv):
  302. def parse_presets(raw_presets):
  303. presets = {}
  304. for p in raw_presets:
  305. toks = p.split('=', 1)
  306. name = toks[0]
  307. value = toks[1] if len(toks) >= 2 else ''
  308. presets[name] = value
  309. return presets
  310. parser = optparse.OptionParser(add_help_option=False)
  311. opt_group = optparse.OptionGroup(parser, 'Conf script options')
  312. opt_group.add_option('--toolchain-params', dest='toolchain_params', action='store', help='Set toolchain params via file')
  313. opt_group.add_option('-D', '--preset', dest='presets', action='append', default=[], help='set or override presets')
  314. opt_group.add_option('-l', '--local-distbuild', dest='local_distbuild', action='store_true', default=False, help='conf for local distbuild')
  315. parser.add_option_group(opt_group)
  316. self.options, self.arguments = parser.parse_args(argv)
  317. argv = self.arguments
  318. if len(argv) < 4:
  319. print('Usage: ArcRoot, --BuildType--, Verbosity, [Path to local.ymake]', file=sys.stderr)
  320. sys.exit(1)
  321. self.arcadia_root = argv[1]
  322. init_logger(argv[3] == 'verbose')
  323. # Эти переменные не надо использоваться напрямую. Их значения уже разбираются в других местах.
  324. self.build_type = argv[2].lower()
  325. self.local_distbuild = self.options.local_distbuild
  326. self.toolchain_params = self.options.toolchain_params
  327. self.presets = parse_presets(self.options.presets)
  328. userify_presets(self.presets, ('CFLAGS', 'CXXFLAGS', 'CONLYFLAGS', 'LDFLAGS', 'GO_COMPILE_FLAGS', 'GO_LINK_FLAGS', 'USE_LOCAL_SWIG', 'SWIG_TOOL', 'SWIG_LIBRARY'))
  329. Instance = None
  330. def opts():
  331. if Options.Instance is None:
  332. Options.Instance = Options(sys.argv)
  333. return Options.Instance
  334. class Profiler(object):
  335. Generic = 'generic'
  336. GProf = 'gprof'
  337. class Arcadia(object):
  338. def __init__(self, root):
  339. self.root = root
  340. class Build(object):
  341. def __init__(self, arcadia, build_type, toolchain_params, force_ignore_local_files=False):
  342. self.arcadia = arcadia
  343. self.params = self._load_json_from_base64(toolchain_params)
  344. self.build_type = build_type
  345. platform = self.params['platform']
  346. self.host = Platform.from_json(platform['host'])
  347. self.target = Platform.from_json(platform['target'])
  348. self.tc = self._get_toolchain_options()
  349. # TODO(somov): Удалить, когда перестанет использоваться.
  350. self.build_system = 'ymake'
  351. self.ignore_local_files = False
  352. dist_prefix = 'dist-'
  353. if self.build_type.startswith(dist_prefix):
  354. self.build_system = 'distbuild'
  355. self.build_type = self.build_type[len(dist_prefix):]
  356. if force_ignore_local_files:
  357. self.ignore_local_files = True
  358. if self.is_ide_build_type(self.build_type):
  359. self.ignore_local_files = True
  360. self.pic = not is_positive('FORCE_NO_PIC')
  361. @property
  362. def host_target(self):
  363. return self.host, self.target
  364. def print_build(self):
  365. self._print_build_settings()
  366. host_os = System(self.host)
  367. host_os.print_host_settings()
  368. target_os = System(self.target)
  369. target_os.print_target_settings()
  370. if self.pic:
  371. emit('PIC', 'yes')
  372. emit('COMPILER_ID', self.tc.type.upper())
  373. if self.is_valgrind:
  374. emit('WITH_VALGRIND', 'yes')
  375. toolchain_type, compiler_type, linker_type = Compilers[self.tc.type]
  376. toolchain = toolchain_type(self.tc, self)
  377. compiler = compiler_type(self.tc, self)
  378. linker = linker_type(self.tc, self)
  379. toolchain.print_toolchain()
  380. compiler.print_compiler()
  381. linker.print_linker()
  382. self._print_other_settings(compiler)
  383. def _print_build_settings(self):
  384. emit('BUILD_TYPE', self.build_type.upper())
  385. emit('BT_' + self.build_type.upper().replace('-', '_'), 'yes')
  386. if self.build_system == 'distbuild':
  387. emit('DISTBUILD', 'yes')
  388. elif self.build_system != 'ymake':
  389. raise ConfigureError()
  390. python_bin = preset('BUILD_PYTHON_BIN', '$(PYTHON)/python')
  391. emit('YMAKE_PYTHON', python_bin)
  392. emit('YMAKE_UNPICKLER', python_bin, '$ARCADIA_ROOT/build/plugins/_unpickler.py')
  393. @property
  394. def is_release(self):
  395. # TODO(somov): Проверить, бывают ли тут суффиксы на самом деле
  396. return self.build_type in ('release', 'relwithdebinfo', 'minsizerel', 'profile', 'gprof') or self.build_type.endswith('-release')
  397. @property
  398. def is_debug(self):
  399. return self.build_type in ('debug', 'debugnoasserts', 'fastdebug') or self.build_type.endswith('-debug')
  400. @property
  401. def is_fast_debug(self):
  402. return self.build_type == 'fastdebug'
  403. @property
  404. def is_size_optimized(self):
  405. return self.build_type == 'minsizerel'
  406. @property
  407. def is_coverage(self):
  408. return self.build_type == 'coverage'
  409. @property
  410. def is_sanitized(self):
  411. sanitizer = preset('SANITIZER_TYPE')
  412. return bool(sanitizer) and not is_negative_str(sanitizer)
  413. @property
  414. def with_ndebug(self):
  415. return self.build_type in ('release', 'minsizerel', 'valgrind-release', 'profile', 'gprof', 'debugnoasserts')
  416. @property
  417. def is_valgrind(self):
  418. return self.build_type == 'valgrind' or self.build_type == 'valgrind-release'
  419. @property
  420. def is_ide(self):
  421. return self.is_ide_build_type(self.build_type)
  422. @property
  423. def profiler_type(self):
  424. if self.build_type == 'profile':
  425. return Profiler.Generic
  426. elif self.build_type == 'gprof':
  427. return Profiler.GProf
  428. else:
  429. return None
  430. @staticmethod
  431. def is_ide_build_type(build_type):
  432. return build_type == 'nobuild'
  433. def _configure_runtime_versions(self):
  434. res = subprocess.check_output(['xcrun', 'simctl', 'list', '--json', 'runtimes'])
  435. raw_object = json.loads(res)
  436. raw_object = raw_object['runtimes']
  437. for runtime in raw_object:
  438. if runtime['isAvailable']:
  439. if "iOS" in runtime['identifier']:
  440. emit('DEFAULT_IOS_RUNTIME', '{}'.format(runtime['identifier']))
  441. def _get_toolchain_options(self):
  442. type_ = self.params['params']['type']
  443. if self.params['params'].get('local') and type_ == 'xcode':
  444. detector = CompilerDetector()
  445. detector.detect(self.params['params']['c_compiler'], self.params['params']['cxx_compiler'])
  446. emit('LOCAL_XCODE_TOOLS', 'yes')
  447. emit('XCODE', 'yes')
  448. emit('ACTOOL_PATH', self.params['params']['actool'])
  449. emit('IBTOOL_PATH', self.params['params']['ibtool'])
  450. self._configure_runtime_versions()
  451. elif type_ == 'system_cxx':
  452. detector = CompilerDetector()
  453. detector.detect(self.params['params'].get('c_compiler'), self.params['params'].get('cxx_compiler'))
  454. type_ = detector.type
  455. else:
  456. detector = None
  457. if type_ == 'msvc':
  458. return MSVCToolchainOptions(self, detector)
  459. else:
  460. return GnuToolchainOptions(self, detector)
  461. def _print_other_settings(self, compiler):
  462. host = self.host
  463. emit('USE_LOCAL_TOOLS', 'no' if self.ignore_local_files else 'yes')
  464. ragel = Ragel()
  465. ragel.configure_toolchain(self, compiler)
  466. ragel.print_variables()
  467. perl = Perl()
  468. perl.configure_local()
  469. perl.print_variables('LOCAL_')
  470. swiftc = SwiftCompiler(self)
  471. swiftc.configure()
  472. swiftc.print_compiler()
  473. if host.is_linux or host.is_macos or host.is_cygwin:
  474. if is_negative('USE_ARCADIA_PYTHON'):
  475. python = Python(self.tc)
  476. python.configure_posix()
  477. python.print_variables()
  478. cuda = Cuda(self)
  479. cuda.print_()
  480. CuDNN(cuda).print_()
  481. print_swig_config()
  482. if self.ignore_local_files or host.is_windows or is_positive('NO_SVN_DEPENDS'):
  483. emit_with_ignore_comment('SVN_DEPENDS')
  484. emit_with_ignore_comment('SVN_DEPENDS_CACHE__NO_UID__')
  485. else:
  486. def find_svn():
  487. for i in range(0, 3):
  488. for path in (['.svn', 'wc.db'], ['.svn', 'entries'], ['.git', 'logs', 'HEAD']):
  489. path_parts = [os.pardir] * i + path
  490. full_path = os.path.join(self.arcadia.root, *path_parts)
  491. # HACK(somov): No "normpath" here. ymake fails with the "source file name is outside the build tree" error
  492. # when .svn/wc.db found in "trunk" instead of "arcadia". But $ARCADIA_ROOT/../.svn/wc.db is ok.
  493. if os.path.exists(full_path):
  494. out_path = os.path.join('${ARCADIA_ROOT}', *path_parts)
  495. return '${input;hide:"%s"}' % out_path
  496. # Special processing for arc repository since .arc may be a symlink.
  497. dot_arc = os.path.realpath(os.path.join(self.arcadia.root, '.arc'))
  498. full_path = os.path.join(dot_arc, 'TREE')
  499. if os.path.exists(full_path):
  500. out_path = os.path.join('${ARCADIA_ROOT}', os.path.relpath(full_path, self.arcadia.root))
  501. return '${input;hide:"%s"}' % out_path
  502. return ''
  503. emit_with_ignore_comment('SVN_DEPENDS', find_svn())
  504. emit_with_ignore_comment('SVN_DEPENDS_CACHE__NO_UID__', '${hide;kv:"disable_cache"}')
  505. @staticmethod
  506. def _load_json_from_base64(base64str):
  507. """
  508. :rtype: dict[str, Any]
  509. """
  510. def un_unicode(o):
  511. if isinstance(o, six.text_type):
  512. return six.ensure_str(o)
  513. if isinstance(o, list):
  514. return [un_unicode(oo) for oo in o]
  515. if isinstance(o, dict):
  516. return {un_unicode(k): un_unicode(v) for k, v in six.iteritems(o)}
  517. return o
  518. return un_unicode(json.loads(base64.b64decode(base64str)))
  519. class YMake(object):
  520. def __init__(self, arcadia):
  521. self.arcadia = arcadia
  522. def print_presets(self):
  523. presets = opts().presets
  524. if presets and 'YMAKE_JAVA_MODULES' not in presets:
  525. if 'YA_IDE_IDEA' in presets or 'MAVEN_EXPORT' in presets:
  526. presets['YMAKE_JAVA_MODULES'] = 'no'
  527. else:
  528. presets['YMAKE_JAVA_MODULES'] = 'yes'
  529. if presets and 'YMAKE_JAVA_MODULES' in presets and presets['YMAKE_JAVA_MODULES'] == "yes":
  530. print('@import "${CONF_ROOT}/conf/java.ymake.conf"')
  531. else:
  532. print('@import "${CONF_ROOT}/conf/jbuild.ymake.conf"')
  533. if presets:
  534. print('# Variables set from command line by -D options')
  535. for key in sorted(presets):
  536. if key in ('MY_YMAKE_BIN', 'REAL_YMAKE_BIN'):
  537. emit_with_ignore_comment(key, opts().presets[key])
  538. elif key == 'YMAKE_JAVA_MODULES':
  539. continue
  540. else:
  541. emit(key, opts().presets[key])
  542. @staticmethod
  543. def _print_conf_content(path):
  544. with open(path, 'r') as fin:
  545. print(fin.read())
  546. def print_core_conf(self):
  547. emit('YMAKE_YNDEXER_IGNORE_BUILD_ROOT', 'yes')
  548. print('@import "${CONF_ROOT}/ymake.core.conf"')
  549. def print_settings(self):
  550. emit_with_ignore_comment('ARCADIA_ROOT', self.arcadia.root)
  551. @staticmethod
  552. def _find_conf(conf_file):
  553. script_dir = os.path.dirname(__file__)
  554. full_path = os.path.join(script_dir, conf_file)
  555. if os.path.exists(full_path):
  556. return full_path
  557. return None
  558. def _find_core_conf(self):
  559. return self._find_conf('ymake.core.conf')
  560. class System(object):
  561. def __init__(self, platform):
  562. """
  563. :type platform: Platform
  564. """
  565. self.platform = platform
  566. def print_windows_target_const(self):
  567. # TODO(somov): Remove this variables, use generic OS/arch variables in makelists.
  568. emit('WINDOWS', 'yes')
  569. emit('WIN32', 'yes')
  570. if self.platform.is_64_bit == 64:
  571. emit('WIN64', 'yes')
  572. def print_nix_target_const(self):
  573. emit('JAVA_INCLUDE', '-I{0}/include -I{0}/include/{1}'.format('/usr/lib/jvm/default-java', self.platform.os_compat))
  574. emit('UNIX', 'yes')
  575. emit('REALPRJNAME')
  576. emit('SONAME')
  577. @staticmethod
  578. def print_nix_host_const():
  579. emit('WRITE_COMMAND', '/bin/echo', '-e')
  580. print('''
  581. when ($USE_PYTHON) {
  582. C_DEFINES+= -DUSE_PYTHON
  583. }''')
  584. @staticmethod
  585. def print_linux_const():
  586. print('''
  587. when (($USEMPROF == "yes") || ($USE_MPROF == "yes")) {
  588. C_SYSTEM_LIBRARIES_INTERCEPT+=-ldmalloc
  589. }
  590. ''')
  591. def print_target_settings(self):
  592. emit('TARGET_PLATFORM', self.platform.os_compat)
  593. emit('HARDWARE_ARCH', '32' if self.platform.is_32_bit else '64')
  594. emit('HARDWARE_TYPE', self.platform.arch)
  595. for variable in self.platform.arch_variables:
  596. emit(variable, 'yes')
  597. for variable in self.platform.os_variables:
  598. emit(variable, 'yes')
  599. if self.platform.is_armv7:
  600. emit('ARM7_FLOAT_ABI', self.platform.armv7_float_abi)
  601. if self.platform.is_android:
  602. emit('ANDROID_API', str(self.platform.android_api))
  603. if self.platform.is_posix:
  604. self.print_nix_target_const()
  605. if self.platform.is_linux:
  606. self.print_linux_const()
  607. elif self.platform.is_windows:
  608. self.print_windows_target_const()
  609. def print_host_settings(self):
  610. emit('HOST_PLATFORM', self.platform.os_compat)
  611. if not self.platform.is_windows:
  612. self.print_nix_host_const()
  613. for variable in itertools.chain(self.platform.os_variables, self.platform.arch_variables):
  614. emit('HOST_{var}'.format(var=variable), 'yes')
  615. class CompilerDetector(object):
  616. def __init__(self):
  617. self.type = None
  618. self.c_compiler = None
  619. self.cxx_compiler = None
  620. self.version_list = None
  621. @staticmethod
  622. def preprocess_source(compiler, source):
  623. # noinspection PyBroadException
  624. try:
  625. fd, path = tempfile.mkstemp(suffix='.cpp')
  626. try:
  627. with os.fdopen(fd, 'wb') as output:
  628. output.write(source)
  629. stdout, code = get_stdout_and_code([compiler, '-E', path])
  630. finally:
  631. os.remove(path)
  632. return stdout, code
  633. except Exception as e:
  634. logger.debug('Preprocessing failed: %s', e)
  635. return None, None
  636. @staticmethod
  637. def get_compiler_vars(compiler, names):
  638. prefix = '____YA_VAR_'
  639. source = '\n'.join(['{prefix}{name}={name}\n'.format(prefix=prefix, name=n) for n in names])
  640. # Некоторые препроцессоры возвращают ненулевой код возврата. Поэтому его проверять нельзя.
  641. # Мы можем только удостовериться после разбора stdout, что в нём
  642. # присутствовала хотя бы одна подставленная переменная.
  643. # TODO(somov): Исследовать, можно ли проверять ограниченный набор кодов возврата.
  644. stdout, _ = CompilerDetector.preprocess_source(compiler, source)
  645. if stdout is None:
  646. return None
  647. vars_ = {}
  648. for line in stdout.split('\n'):
  649. parts = line.split('=', 1)
  650. if len(parts) == 2 and parts[0].startswith(prefix):
  651. name, value = parts[0][len(prefix):], parts[1]
  652. if value == name:
  653. continue # Preprocessor variable was not substituted
  654. vars_[name] = value
  655. return vars_
  656. def detect(self, c_compiler=None, cxx_compiler=None):
  657. c_compiler = c_compiler or os.environ.get('CC')
  658. cxx_compiler = cxx_compiler or os.environ.get('CXX') or c_compiler
  659. c_compiler = c_compiler or cxx_compiler
  660. logger.debug('e=%s', os.environ)
  661. if c_compiler is None:
  662. raise ConfigureError('Custom compiler was requested but not specified')
  663. c_compiler_path = which(c_compiler)
  664. clang_vars = ['__clang_major__', '__clang_minor__', '__clang_patchlevel__']
  665. gcc_vars = ['__GNUC__', '__GNUC_MINOR__', '__GNUC_PATCHLEVEL__']
  666. msvc_vars = ['_MSC_VER']
  667. apple_var = '__apple_build_version__'
  668. compiler_vars = self.get_compiler_vars(c_compiler_path, clang_vars + [apple_var] + gcc_vars + msvc_vars)
  669. if not compiler_vars:
  670. raise ConfigureError('Could not determine custom compiler version: {}'.format(c_compiler))
  671. def version(version_names):
  672. def iter_version():
  673. for name in version_names:
  674. yield int(compiler_vars[name])
  675. # noinspection PyBroadException
  676. try:
  677. return list(iter_version())
  678. except Exception:
  679. return None
  680. clang_version = version(clang_vars)
  681. apple_build = apple_var in compiler_vars
  682. # TODO(somov): Учитывать номера версий сборки Apple компилятора Clang.
  683. _ = apple_build
  684. gcc_version = version(gcc_vars)
  685. msvc_version = version(msvc_vars)
  686. if clang_version:
  687. logger.debug('Detected Clang version %s', clang_version)
  688. self.type = 'clang'
  689. elif gcc_version:
  690. logger.debug('Detected GCC version %s', gcc_version)
  691. # TODO(somov): Переименовать в gcc.
  692. self.type = 'gnu'
  693. elif msvc_version:
  694. logger.debug('Detected MSVC version %s', msvc_version)
  695. self.type = 'msvc'
  696. else:
  697. raise ConfigureError('Could not determine custom compiler type: {}'.format(c_compiler))
  698. self.version_list = clang_version or gcc_version or msvc_version
  699. self.c_compiler = c_compiler_path
  700. self.cxx_compiler = cxx_compiler and which(cxx_compiler) or c_compiler_path
  701. class ToolchainOptions(object):
  702. def __init__(self, build, detector):
  703. """
  704. :type build: Build
  705. """
  706. self.host = build.host
  707. self.target = build.target
  708. tc_json = build.params
  709. logger.debug('Toolchain host %s', self.host)
  710. logger.debug('Toolchain target %s', self.target)
  711. logger.debug('Toolchain json %s', DebugString(lambda: json.dumps(tc_json, indent=4, sort_keys=True)))
  712. self.params = tc_json['params']
  713. self._name = tc_json.get('name', 'theyknow')
  714. if detector:
  715. self.type = detector.type
  716. self.from_arcadia = False
  717. self.c_compiler = detector.c_compiler
  718. self.cxx_compiler = detector.cxx_compiler
  719. self.compiler_version_list = detector.version_list
  720. self.compiler_version = '.'.join(map(lambda part: six.ensure_str(str(part)), self.compiler_version_list))
  721. else:
  722. self.type = self.params['type']
  723. self.from_arcadia = True
  724. self.c_compiler = self.params['c_compiler']
  725. self.cxx_compiler = self.params['cxx_compiler']
  726. # TODO(somov): Требовать номер версии всегда.
  727. self.compiler_version = self.params.get('gcc_version') or self.params.get('version') or '0'
  728. self.compiler_version_list = list(map(int, self.compiler_version.split('.')))
  729. # TODO(somov): Посмотреть, можно ли спрятать это поле.
  730. self.name_marker = '$(%s)' % self.params.get('match_root', self._name.upper())
  731. self.arch_opt = self.params.get('arch_opt', [])
  732. self.triplet_opt = self.params.get('triplet_opt', {})
  733. self.target_opt = self.params.get('target_opt', [])
  734. # TODO(somov): Убрать чтение настройки из os.environ.
  735. self.werror_mode = preset('WERROR_MODE') or os.environ.get('WERROR_MODE') or self.params.get('werror_mode') or 'compiler_specific'
  736. # default C++ standard is set here, some older toolchains might need to redefine it in ya.conf.json
  737. self.cxx_std = self.params.get('cxx_std', 'c++20')
  738. self._env = tc_json.get('env', {})
  739. self.android_ndk_version = self.params.get('android_ndk_version', None)
  740. logger.debug('c_compiler=%s', self.c_compiler)
  741. logger.debug('cxx_compiler=%s', self.cxx_compiler)
  742. self.compiler_platform_projects = self.target.find_in_dict(self.params.get('platform'), [])
  743. def version_at_least(self, *args):
  744. return args <= tuple(self.compiler_version_list)
  745. def version_exactly(self, *args):
  746. if not args or len(args) > len(self.compiler_version_list):
  747. return False
  748. for l, r in zip(args, list(self.compiler_version_list)[:len(args)]):
  749. if l != r:
  750. return False
  751. return True
  752. @property
  753. def is_gcc(self):
  754. return self.type == 'gnu'
  755. @property
  756. def is_clang(self):
  757. return self.type in ('clang', 'xcode')
  758. @property
  759. def is_xcode(self):
  760. return self.type == 'xcode'
  761. @property
  762. def is_from_arcadia(self):
  763. return self.from_arcadia
  764. def get_env(self, convert_list=None):
  765. convert_list = convert_list or (lambda x: x)
  766. r = {}
  767. for k, v in six.iteritems(self._env):
  768. if isinstance(v, str):
  769. r[k] = v
  770. elif isinstance(v, list):
  771. r[k] = convert_list(v)
  772. else:
  773. logger.debug('Unexpected values in environment: %s', self._env)
  774. raise ConfigureError('Internal error')
  775. return r
  776. class GnuToolchainOptions(ToolchainOptions):
  777. def __init__(self, build, detector):
  778. super(GnuToolchainOptions, self).__init__(build, detector)
  779. self.ar = self.params.get('ar')
  780. self.ar_plugin = self.params.get('ar_plugin')
  781. self.inplace_tools = self.params.get('inplace_tools', False)
  782. self.strip = self.params.get('strip')
  783. self.objcopy = self.params.get('objcopy')
  784. self.isystem = self.params.get('isystem')
  785. self.dwarf_tool = self.target.find_in_dict(self.params.get('dwarf_tool'))
  786. # TODO(somov): Унифицировать формат sys_lib
  787. self.sys_lib = self.params.get('sys_lib', {})
  788. if isinstance(self.sys_lib, dict):
  789. self.sys_lib = self.target.find_in_dict(self.sys_lib, [])
  790. self.os_sdk = preset('OS_SDK') or self._default_os_sdk()
  791. self.os_sdk_local = self.os_sdk == 'local'
  792. def _default_os_sdk(self):
  793. if self.target.is_linux:
  794. if self.target.is_armv8:
  795. return 'ubuntu-16'
  796. if self.target.is_armv7 and self.target.armv7_float_abi == 'hard':
  797. return 'ubuntu-16'
  798. if self.target.is_armv7 and self.target.armv7_float_abi == 'softfp':
  799. return 'ubuntu-18'
  800. if self.target.is_powerpc:
  801. return 'ubuntu-14'
  802. # Default OS SDK for Linux builds
  803. return 'ubuntu-14'
  804. class Toolchain(object):
  805. def __init__(self, tc, build):
  806. """
  807. :type tc: ToolchainOptions
  808. :type build: Build
  809. """
  810. self.tc = tc
  811. self.build = build
  812. self.platform_projects = self.tc.compiler_platform_projects
  813. def print_toolchain(self):
  814. if self.platform_projects:
  815. emit('COMPILER_PLATFORM', list(unique(self.platform_projects)))
  816. class Compiler(object):
  817. def __init__(self, tc, compiler_variable):
  818. self.compiler_variable = compiler_variable
  819. self.tc = tc
  820. def print_compiler(self):
  821. # CLANG and CLANG_VER variables
  822. emit(self.compiler_variable, 'yes')
  823. emit('{}_VER'.format(self.compiler_variable), self.tc.compiler_version)
  824. if self.tc.is_xcode:
  825. emit('XCODE', 'yes')
  826. class GnuToolchain(Toolchain):
  827. def __init__(self, tc, build):
  828. """
  829. :type tc: GnuToolchainOptions
  830. :type build: Build
  831. """
  832. def get_os_sdk(target):
  833. sdk_native_version = 10.11 if not preset('EXPERIMENTAL_MACOS_M1_SUPPORT') else '11.1'
  834. if target.is_macos:
  835. return '$MACOS_SDK_RESOURCE_GLOBAL/MacOSX{}.sdk'.format(sdk_native_version)
  836. elif target.is_yocto:
  837. return '$YOCTO_SDK_RESOURCE_GLOBAL'
  838. return '$OS_SDK_ROOT_RESOURCE_GLOBAL'
  839. super(GnuToolchain, self).__init__(tc, build)
  840. self.tc = tc
  841. host = build.host
  842. target = build.target
  843. self.c_flags_platform = list(tc.target_opt)
  844. self.default_os_sdk_root = get_os_sdk(target)
  845. self.env = self.tc.get_env()
  846. self.env_go = {}
  847. if self.tc.is_clang:
  848. self.env_go = {'PATH': ['{}/bin'.format(self.tc.name_marker)]}
  849. if self.tc.is_gcc:
  850. self.env_go = {'PATH': ['{}/gcc/bin'.format(self.tc.name_marker)]}
  851. if 'PATH' in self.env_go:
  852. if target.is_linux:
  853. self.env_go['PATH'].append('$OS_SDK_ROOT_RESOURCE_GLOBAL/usr/bin')
  854. elif target.is_macos:
  855. self.env_go['PATH'].extend([
  856. '$MACOS_SDK_RESOURCE_GLOBAL/usr/bin',
  857. '$CCTOOLS_ROOT_RESOURCE_GLOBAL/bin',
  858. '$GO_FAKE_XCRUN_RESOURCE_GLOBAL',
  859. ])
  860. self.swift_flags_platform = []
  861. self.swift_lib_path = None
  862. if self.tc.is_from_arcadia:
  863. for lib_path in build.host.library_path_variables:
  864. self.env.setdefault(lib_path, []).append('{}/lib'.format(self.tc.name_marker))
  865. macos_version_min = '10.12'
  866. macos_arm64_version_min = '11.0'
  867. ios_version_min = '11.0'
  868. # min ios simulator version for Metal App is 13.0
  869. # https://developer.apple.com/documentation/metal/supporting_simulator_in_a_metal_app
  870. # Mapkit (MAPSMOBI_BUILD_TARGET) uses Metal Framework
  871. if preset('MAPSMOBI_BUILD_TARGET') and target.is_iossim and target.is_armv8:
  872. ios_version_min = '13.0'
  873. swift_target = select(default=None, selectors=[
  874. (target.is_iossim and target.is_x86_64, 'x86_64-apple-ios{}-simulator'.format(ios_version_min)),
  875. (target.is_iossim and target.is_x86, 'i386-apple-ios{}-simulator'.format(ios_version_min)),
  876. (target.is_iossim and target.is_armv8, 'arm64-apple-ios{}-simulator'.format(ios_version_min)),
  877. (not target.is_iossim and target.is_ios and target.is_armv8, 'arm64-apple-ios9'),
  878. (not target.is_iossim and target.is_ios and target.is_armv7, 'armv7-apple-ios9'),
  879. ])
  880. if swift_target:
  881. self.swift_flags_platform += ['-target', swift_target]
  882. if self.tc.is_from_arcadia:
  883. self.swift_lib_path = select(default=None, selectors=[
  884. (host.is_macos and target.is_iossim, '$SWIFT_XCODE_TOOLCHAIN_ROOT_RESOURCE_GLOBAL/usr/lib/swift/iphonesimulator'),
  885. (host.is_macos and not target.is_iossim and target.is_ios and (target.is_armv8 or target.is_armv7), '$SWIFT_XCODE_TOOLCHAIN_ROOT_RESOURCE_GLOBAL/usr/lib/swift/iphoneos'),
  886. ])
  887. if self.tc.is_clang:
  888. target_triple = self.tc.triplet_opt.get(target.arch, None)
  889. if not target_triple:
  890. target_triple = select(default=None, selectors=[
  891. (target.is_linux and target.is_x86_64, 'x86_64-linux-gnu'),
  892. (target.is_linux and target.is_armv8, 'aarch64-linux-gnu'),
  893. (target.is_linux and target.is_armv7 and target.armv7_float_abi == 'hard', 'arm-linux-gnueabihf'),
  894. (target.is_linux and target.is_armv7 and target.armv7_float_abi == 'softfp', 'arm-linux-gnueabi'),
  895. (target.is_linux and target.is_powerpc, 'powerpc64le-linux-gnu'),
  896. (target.is_iossim and target.is_arm64, 'arm64-apple-ios{}-simulator'.format(ios_version_min)),
  897. (target.is_apple and target.is_x86, 'i386-apple-darwin14'),
  898. (target.is_apple and target.is_x86_64, 'x86_64-apple-darwin14'),
  899. (target.is_apple and target.is_macos_arm64, 'arm64-apple-macos11'),
  900. (target.is_apple and target.is_armv7, 'armv7-apple-darwin14'),
  901. (target.is_apple and target.is_armv8, 'arm64-apple-darwin14'),
  902. (target.is_yocto and target.is_armv7, 'arm-poky-linux-gnueabi'),
  903. (target.is_android and target.is_x86, 'i686-linux-android'),
  904. (target.is_android and target.is_x86_64, 'x86_64-linux-android'),
  905. (target.is_android and target.is_armv7, 'armv7a-linux-androideabi'),
  906. (target.is_android and target.is_armv8, 'aarch64-linux-android'),
  907. ])
  908. if target.is_android:
  909. # Android NDK allows specification of API level in target triple, e.g.:
  910. # armv7a-linux-androideabi16, aarch64-linux-android21
  911. target_triple += str(target.android_api)
  912. if target_triple:
  913. self.c_flags_platform.append('--target={}'.format(target_triple))
  914. if self.tc.isystem:
  915. for root in list(self.tc.isystem):
  916. self.c_flags_platform.extend(['-isystem', root])
  917. if target.is_android:
  918. self.c_flags_platform.extend(['-isystem', '{}/sources/cxx-stl/llvm-libc++abi/include'.format(self.tc.name_marker)])
  919. if target.is_cortex_a9:
  920. self.c_flags_platform.append('-mcpu=cortex-a9')
  921. if target.is_cortex_a35:
  922. self.c_flags_platform.append('-mcpu=cortex-a35')
  923. elif target.is_cortex_a53:
  924. self.c_flags_platform.append('-mcpu=cortex-a53')
  925. elif target.is_cortex_m33:
  926. self.c_flags_platform.append('-mcpu=cortex-m33 -mfpu=fpv5-sp-d16')
  927. elif target.is_armv7_neon:
  928. self.c_flags_platform.append('-mfpu=neon')
  929. if (target.is_armv7 or target.is_armv8m) and build.is_size_optimized:
  930. # Enable ARM Thumb2 variable-length instruction encoding
  931. # to reduce code size
  932. self.c_flags_platform.append('-mthumb')
  933. if target.is_arm or target.is_powerpc:
  934. # On linux, ARM and PPC default to unsigned char
  935. # However, Arcadia requires char to be signed
  936. self.c_flags_platform.append('-fsigned-char')
  937. if self.tc.is_clang or self.tc.is_gcc and self.tc.version_at_least(8, 2):
  938. target_flags = select(default=[], selectors=[
  939. (target.is_linux and target.is_power8le, ['-mcpu=power8', '-mtune=power8', '-maltivec']),
  940. (target.is_linux and target.is_power9le, ['-mcpu=power9', '-mtune=power9', '-maltivec']),
  941. (target.is_linux and target.is_armv8, ['-march=armv8a']),
  942. (target.is_macos_arm64, ['-mmacosx-version-min={}'.format(macos_arm64_version_min)]),
  943. (target.is_macos, ['-mmacosx-version-min={}'.format(macos_version_min)]),
  944. (target.is_ios and not target.is_iossim, ['-mios-version-min={}'.format(ios_version_min)]),
  945. (target.is_iossim, ['-mios-simulator-version-min={}'.format(ios_version_min)]),
  946. (target.is_android and target.is_armv7, ['-march=armv7-a', '-mfloat-abi=softfp']),
  947. (target.is_android and target.is_armv8, ['-march=armv8-a']),
  948. (target.is_yocto and target.is_armv7, ['-march=armv7-a', '-mfpu=neon', '-mfloat-abi=hard', '-mcpu=cortex-a9', '-O1'])
  949. ])
  950. if target_flags:
  951. self.c_flags_platform.extend(target_flags)
  952. if target.is_ios:
  953. self.c_flags_platform.append('-D__IOS__=1')
  954. if self.tc.is_from_arcadia:
  955. if target.is_apple:
  956. if target.is_ios:
  957. self.setup_sdk(project='build/platform/ios_sdk', var='${IOS_SDK_ROOT_RESOURCE_GLOBAL}')
  958. self.platform_projects.append('build/platform/macos_system_stl')
  959. if target.is_macos:
  960. self.setup_sdk(project='build/platform/macos_sdk', var='${MACOS_SDK_RESOURCE_GLOBAL}')
  961. self.platform_projects.append('build/platform/macos_system_stl')
  962. if not self.tc.inplace_tools:
  963. self.setup_tools(project='build/platform/cctools', var='${CCTOOLS_ROOT_RESOURCE_GLOBAL}', bin='bin', ldlibs=None)
  964. if target.is_linux:
  965. if not tc.os_sdk_local:
  966. self.setup_sdk(project='build/platform/linux_sdk', var='$OS_SDK_ROOT_RESOURCE_GLOBAL')
  967. if target.is_x86_64:
  968. if host.is_linux and not self.tc.is_gcc:
  969. self.setup_tools(project='build/platform/linux_sdk', var='$OS_SDK_ROOT_RESOURCE_GLOBAL', bin='usr/bin', ldlibs='usr/lib/x86_64-linux-gnu')
  970. elif host.is_macos:
  971. self.setup_tools(project='build/platform/binutils', var='$BINUTILS_ROOT_RESOURCE_GLOBAL', bin='x86_64-linux-gnu/bin', ldlibs=None)
  972. elif target.is_powerpc:
  973. self.setup_tools(project='build/platform/linux_sdk', var='$OS_SDK_ROOT_RESOURCE_GLOBAL', bin='usr/bin', ldlibs='usr/x86_64-linux-gnu/powerpc64le-linux-gnu/lib')
  974. elif target.is_armv8:
  975. self.setup_tools(project='build/platform/linux_sdk', var='$OS_SDK_ROOT_RESOURCE_GLOBAL', bin='usr/bin', ldlibs='usr/lib/x86_64-linux-gnu')
  976. if target.is_yocto:
  977. self.setup_sdk(project='build/platform/yocto_sdk/yocto_sdk', var='${YOCTO_SDK_ROOT_RESOURCE_GLOBAL}')
  978. elif self.tc.params.get('local'):
  979. if target.is_apple:
  980. if not tc.os_sdk_local:
  981. if target.is_ios:
  982. self.setup_sdk(project='build/platform/ios_sdk', var='${IOS_SDK_ROOT_RESOURCE_GLOBAL}')
  983. self.platform_projects.append('build/platform/macos_system_stl')
  984. if target.is_macos:
  985. self.setup_sdk(project='build/platform/macos_sdk', var='${MACOS_SDK_RESOURCE_GLOBAL}')
  986. self.platform_projects.append('build/platform/macos_system_stl')
  987. else:
  988. if target.is_iossim:
  989. self.env.setdefault('SDKROOT', subprocess.check_output(['xcrun', '-sdk', 'iphonesimulator', '--show-sdk-path']).strip())
  990. elif target.is_ios:
  991. self.env.setdefault('SDKROOT', subprocess.check_output(['xcrun', '-sdk', 'iphoneos', '--show-sdk-path']).strip())
  992. elif target.is_macos:
  993. self.env.setdefault('SDKROOT', subprocess.check_output(['xcrun', '-sdk', 'macosx', '--show-sdk-path']).strip())
  994. def setup_sdk(self, project, var):
  995. self.platform_projects.append(project)
  996. self.c_flags_platform.append('--sysroot={}'.format(var))
  997. self.swift_flags_platform += ['-sdk', var]
  998. # noinspection PyShadowingBuiltins
  999. def setup_tools(self, project, var, bin, ldlibs):
  1000. self.platform_projects.append(project)
  1001. self.c_flags_platform.append('-B{}/{}'.format(var, bin))
  1002. if ldlibs:
  1003. for lib_path in self.build.host.library_path_variables:
  1004. self.env.setdefault(lib_path, []).append('{}/{}'.format(var, ldlibs))
  1005. def print_toolchain(self):
  1006. super(GnuToolchain, self).print_toolchain()
  1007. emit('TOOLCHAIN_ENV', format_env(self.env, list_separator=':'))
  1008. emit('_GO_TOOLCHAIN_ENV_PATH', format_env(self.env_go, list_separator=':'))
  1009. emit('C_FLAGS_PLATFORM', self.c_flags_platform)
  1010. emit('SWIFT_FLAGS_PLATFORM', self.swift_flags_platform)
  1011. emit('SWIFT_LD_FLAGS', '-L{}'.format(self.swift_lib_path) if self.swift_lib_path else '')
  1012. emit('PERL_SDK', preset('OS_SDK') or self.tc.os_sdk)
  1013. if preset('OS_SDK') is None:
  1014. emit('OS_SDK', self.tc.os_sdk)
  1015. emit('OS_SDK_ROOT', None if self.tc.os_sdk_local else self.default_os_sdk_root)
  1016. class GnuCompiler(Compiler):
  1017. gcc_fstack = ['-fstack-protector']
  1018. def __init__(self, tc, build):
  1019. """
  1020. :type tc: GnuToolchainOptions
  1021. :type build: Build
  1022. """
  1023. compiler_variable = 'CLANG' if tc.is_clang else 'GCC'
  1024. super(GnuCompiler, self).__init__(tc, compiler_variable)
  1025. self.build = build
  1026. self.host = self.build.host
  1027. self.target = self.build.target
  1028. self.tc = tc
  1029. self.c_foptions = [
  1030. # Enable C++ exceptions (and allow them to be throw through pure C code)
  1031. '-fexceptions',
  1032. # Enable standard-conforming behavior and generate duplicate symbol error in case of duplicated global constants.
  1033. # See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85678#c0
  1034. '-fno-common',
  1035. ]
  1036. if self.tc.is_clang and self.target.is_linux:
  1037. # Use .init_array instead of .ctors (default for old clang versions)
  1038. # See: https://maskray.me/blog/2021-11-07-init-ctors-init-array
  1039. self.c_foptions.append('-fuse-init-array')
  1040. if self.tc.is_clang:
  1041. self.c_foptions += [
  1042. # Set up output colorization
  1043. '-fcolor-diagnostics',
  1044. # Enable aligned allocation
  1045. '-faligned-allocation',
  1046. ]
  1047. elif self.tc.is_gcc:
  1048. self.c_foptions += [
  1049. # Set up output colorization
  1050. '-fdiagnostics-color=always',
  1051. # It looks like there is no way to enable aligned allocation in gcc
  1052. ]
  1053. self.c_warnings = [
  1054. # Enable default warnings subset
  1055. '-Wall',
  1056. '-Wextra',
  1057. ]
  1058. self.cxx_warnings = [
  1059. # Issue a warning if certain overload is hidden due to inheritance
  1060. '-Woverloaded-virtual',
  1061. ]
  1062. # Disable some warnings which will fail compilation at the time
  1063. self.c_warnings += [
  1064. '-Wno-parentheses'
  1065. ]
  1066. self.c_defines = ['-DFAKEID=$CPP_FAKEID']
  1067. if self.target.is_android:
  1068. self.c_defines.append('-DANDROID_FAKEID=$ANDROID_FAKEID')
  1069. self.c_defines.extend([
  1070. '-DARCADIA_ROOT=${ARCADIA_ROOT}',
  1071. '-DARCADIA_BUILD_ROOT=${ARCADIA_BUILD_ROOT}',
  1072. ])
  1073. self.c_defines.extend([
  1074. '-D_THREAD_SAFE', '-D_PTHREADS', '-D_REENTRANT', '-D_LIBCPP_ENABLE_CXX17_REMOVED_FEATURES',
  1075. '-D_LARGEFILE_SOURCE', '-D__STDC_CONSTANT_MACROS', '-D__STDC_FORMAT_MACROS',
  1076. ])
  1077. if not self.target.is_android:
  1078. # There is no usable _FILE_OFFSET_BITS=64 support in Androids until API 21. And it's incomplete until at least API 24.
  1079. # https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md
  1080. # Arcadia have API 16 for 32-bit Androids.
  1081. self.c_defines.append('-D_FILE_OFFSET_BITS=64')
  1082. if self.target.is_linux or self.target.is_android or self.target.is_cygwin:
  1083. self.c_defines.append('-D_GNU_SOURCE')
  1084. if self.tc.is_clang and self.target.is_linux and self.target.is_x86_64:
  1085. self.c_defines.append('-D_YNDX_LIBUNWIND_ENABLE_EXCEPTION_BACKTRACE')
  1086. if self.target.is_ios:
  1087. self.c_defines.extend(['-D_XOPEN_SOURCE', '-D_DARWIN_C_SOURCE'])
  1088. if preset('MAPSMOBI_BUILD_TARGET') and self.target.is_arm:
  1089. self.c_foptions.append('-fembed-bitcode')
  1090. self.extra_compile_opts = []
  1091. self.c_flags = ['$CL_DEBUG_INFO', '$CL_DEBUG_INFO_DISABLE_CACHE__NO_UID__']
  1092. self.c_flags += self.tc.arch_opt + ['-pipe']
  1093. self.sfdl_flags = ['-E', '-C', '-x', 'c++']
  1094. if self.target.is_x86:
  1095. self.c_flags.append('-m32')
  1096. if self.target.is_x86_64:
  1097. self.c_flags.append('-m64')
  1098. self.debug_info_flags = ['-g']
  1099. if self.target.is_linux:
  1100. self.debug_info_flags.append('-ggnu-pubnames')
  1101. self.cross_suffix = '' if is_positive('FORCE_NO_PIC') else '.pic'
  1102. self.optimize = None
  1103. self.configure_build_type()
  1104. if self.tc.is_clang:
  1105. self.sfdl_flags.append('-Qunused-arguments')
  1106. self.cxx_warnings += [
  1107. '-Wimport-preprocessor-directive-pedantic',
  1108. '-Wno-undefined-var-template',
  1109. '-Wno-return-std-move',
  1110. '-Wno-address-of-packed-member',
  1111. '-Wno-defaulted-function-deleted',
  1112. '-Wno-pessimizing-move',
  1113. '-Wno-range-loop-construct',
  1114. '-Wno-deprecated-anon-enum-enum-conversion',
  1115. '-Wno-deprecated-enum-enum-conversion',
  1116. '-Wno-deprecated-enum-float-conversion',
  1117. '-Wno-ambiguous-reversed-operator',
  1118. '-Wno-deprecated-volatile',
  1119. ]
  1120. self.c_warnings += [
  1121. '-Wno-implicit-const-int-float-conversion',
  1122. # For nvcc to accept the above.
  1123. '-Wno-unknown-warning-option',
  1124. ]
  1125. elif self.tc.is_gcc:
  1126. self.c_foptions.append('-fno-delete-null-pointer-checks')
  1127. self.c_foptions.append('-fabi-version=8')
  1128. # Split all functions and data into separate sections for DCE and ICF linker passes
  1129. # NOTE: iOS build uses -fembed-bitcode which conflicts with -ffunction-sections (only relevant for ELF targets)
  1130. if not self.target.is_ios:
  1131. self.c_foptions.extend(['-ffunction-sections', '-fdata-sections'])
  1132. def configure_build_type(self):
  1133. if self.build.is_valgrind:
  1134. self.c_defines.append('-DWITH_VALGRIND=1')
  1135. if self.build.is_debug:
  1136. self.c_foptions.append('$FSTACK')
  1137. if self.build.is_fast_debug:
  1138. self.c_flags.append('-Og')
  1139. if self.build.is_release:
  1140. self.c_flags.append('$OPTIMIZE')
  1141. if self.build.is_size_optimized:
  1142. # -Oz is clang's more size-aggressive version of -Os
  1143. # For ARM specifically, clang -Oz is on par with gcc -Os:
  1144. # https://github.com/android/ndk/issues/133#issuecomment-365763507
  1145. if self.tc.is_clang:
  1146. self.optimize = '-Oz'
  1147. else:
  1148. self.optimize = '-Os'
  1149. # Generate sections with address significance tables for ICF linker pass
  1150. if self.tc.is_clang:
  1151. self.c_foptions.extend(['-faddrsig'])
  1152. else:
  1153. self.optimize = '-O3'
  1154. if self.build.with_ndebug:
  1155. self.c_defines.append('-DNDEBUG')
  1156. else:
  1157. self.c_defines.append('-UNDEBUG')
  1158. if self.build.profiler_type in (Profiler.Generic, Profiler.GProf):
  1159. self.c_foptions.append('-fno-omit-frame-pointer')
  1160. if self.build.profiler_type == Profiler.GProf:
  1161. self.c_flags.append('-pg')
  1162. def print_compiler(self):
  1163. super(GnuCompiler, self).print_compiler()
  1164. emit('C_COMPILER_UNQUOTED', self.tc.c_compiler)
  1165. emit('C_COMPILER', '${quo:C_COMPILER_UNQUOTED}')
  1166. emit('OPTIMIZE', self.optimize)
  1167. emit('WERROR_MODE', self.tc.werror_mode)
  1168. emit('FSTACK', self.gcc_fstack)
  1169. append('C_DEFINES', self.c_defines)
  1170. emit('DUMP_DEPS')
  1171. emit('GCC_PREPROCESSOR_OPTS', '$DUMP_DEPS', '$C_DEFINES')
  1172. append('C_WARNING_OPTS', self.c_warnings)
  1173. append('CXX_WARNING_OPTS', self.cxx_warnings)
  1174. # PIE is only valid for executables, while PIC implies a shared library
  1175. # `-pie` with a shared library is either ignored or fails to link
  1176. emit_big('''
  1177. when ($PIC == "yes") {
  1178. CFLAGS+=-fPIC
  1179. LDFLAGS+=-fPIC
  1180. }
  1181. elsewhen ($PIE == "yes") {
  1182. CFLAGS+=-fPIE
  1183. LDFLAGS+=-fPIE -pie
  1184. }''')
  1185. append('CFLAGS', self.c_flags, '$DEBUG_INFO_FLAGS', self.c_foptions, '$C_WARNING_OPTS', '$GCC_PREPROCESSOR_OPTS', '$USER_CFLAGS', '$USER_CFLAGS_GLOBAL')
  1186. append('CXXFLAGS', '$CFLAGS', '-std=' + self.tc.cxx_std, '$CXX_WARNING_OPTS', '$USER_CXXFLAGS', '$USER_CXXFLAGS_GLOBAL')
  1187. append('CONLYFLAGS', '$USER_CONLYFLAGS', '$USER_CONLYFLAGS_GLOBAL')
  1188. emit('CXX_COMPILER_UNQUOTED', self.tc.cxx_compiler)
  1189. emit('CXX_COMPILER', '${quo:CXX_COMPILER_UNQUOTED}')
  1190. emit('NOGCCSTACKCHECK', 'yes')
  1191. emit('SFDL_FLAG', self.sfdl_flags, '-o', '$SFDL_TMP_OUT')
  1192. emit('WERROR_FLAG', '-Werror')
  1193. # TODO(somov): Убрать чтение настройки из os.environ
  1194. emit('USE_ARC_PROFILE', 'yes' if preset('USE_ARC_PROFILE') or os.environ.get('USE_ARC_PROFILE') else 'no')
  1195. emit('DEBUG_INFO_FLAGS', self.debug_info_flags)
  1196. emit_big('''
  1197. when ($NO_WSHADOW == "yes") {
  1198. C_WARNING_OPTS += -Wno-shadow
  1199. }''')
  1200. # Though -w is intended to switch off all the warnings,
  1201. # it does not switch at least -Wregister and -Wreserved-user-defined-literal under clang.
  1202. #
  1203. # Use -Wno-everything to force warning suppression.
  1204. emit_big('''
  1205. when ($NO_COMPILER_WARNINGS == "yes") {
  1206. C_WARNING_OPTS = -w
  1207. CXX_WARNING_OPTS = -Wno-everything
  1208. }''')
  1209. emit_big('''
  1210. when ($NO_OPTIMIZE == "yes") {
  1211. OPTIMIZE = -O0
  1212. }
  1213. when ($SAVE_TEMPS == "yes") {
  1214. CXXFLAGS += -save-temps
  1215. }
  1216. when ($NOGCCSTACKCHECK != "yes") {
  1217. FSTACK += -fstack-check
  1218. }''')
  1219. c_builtins = [
  1220. "-Wno-builtin-macro-redefined",
  1221. '-D__DATE__=\\""Sep 31 2019\\""',
  1222. '-D__TIME__=\\"00:00:00\\"',
  1223. ]
  1224. compiler_supports_macro_prefix_map = (
  1225. self.tc.is_clang and self.tc.version_at_least(10) or
  1226. self.tc.is_gcc and self.tc.version_at_least(8)
  1227. )
  1228. if compiler_supports_macro_prefix_map:
  1229. c_builtins += [
  1230. # XXX does not support non-normalized paths
  1231. "-fmacro-prefix-map=${ARCADIA_BUILD_ROOT}/=",
  1232. "-fmacro-prefix-map=${ARCADIA_ROOT}/=",
  1233. "-fmacro-prefix-map=$(TOOL_ROOT)/=",
  1234. ]
  1235. else:
  1236. c_builtins += [
  1237. # XXX this macro substitution breaks __FILE__ in included sources
  1238. '-D__FILE__=\\""${input;qe;rootrel:SRC}\\""',
  1239. ]
  1240. c_debug_map = [
  1241. # XXX does not support non-normalized paths
  1242. "-fdebug-prefix-map=${ARCADIA_BUILD_ROOT}=/-B",
  1243. "-fdebug-prefix-map=${ARCADIA_ROOT}=/-S",
  1244. "-fdebug-prefix-map=$(TOOL_ROOT)=/-T",
  1245. ]
  1246. c_debug_map_cl = c_debug_map + [
  1247. "-Xclang", "-fdebug-compilation-dir", "-Xclang", "/tmp",
  1248. ]
  1249. c_debug_map_light = [
  1250. # XXX does not support non-normalized paths
  1251. "-fdebug-prefix-map=${ARCADIA_BUILD_ROOT}=/-B",
  1252. ]
  1253. c_debug_map_light_cl = c_debug_map_light + [
  1254. "-Xclang", "-fdebug-compilation-dir", "-Xclang", "/tmp",
  1255. ]
  1256. yasm_debug_map = [
  1257. # XXX does not support non-normalized paths
  1258. "--replace=${ARCADIA_BUILD_ROOT}=/-B",
  1259. "--replace=${ARCADIA_ROOT}=/-S",
  1260. "--replace=$(TOOL_ROOT)=/-T"
  1261. ]
  1262. emit_big('''
  1263. when ($FORCE_CONSISTENT_DEBUG == "yes") {{
  1264. when ($CLANG == "yes") {{
  1265. CL_DEBUG_INFO={c_debug_cl}
  1266. }}
  1267. otherwise {{
  1268. CL_DEBUG_INFO={c_debug}
  1269. }}
  1270. YASM_DEBUG_INFO={yasm_debug}
  1271. }}
  1272. elsewhen ($CONSISTENT_DEBUG == "yes") {{
  1273. when ($CLANG == "yes") {{
  1274. CL_DEBUG_INFO_DISABLE_CACHE__NO_UID__={c_debug_cl}
  1275. }}
  1276. otherwise {{
  1277. CL_DEBUG_INFO_DISABLE_CACHE__NO_UID__={c_debug}
  1278. }}
  1279. YASM_DEBUG_INFO_DISABLE_CACHE__NO_UID__={yasm_debug}
  1280. }}
  1281. elsewhen ($CONSISTENT_DEBUG_LIGHT == "yes") {{
  1282. when ($CLANG == "yes") {{
  1283. CL_DEBUG_INFO_DISABLE_CACHE__NO_UID__={c_debug_light_cl}
  1284. }}
  1285. otherwise {{
  1286. CL_DEBUG_INFO_DISABLE_CACHE__NO_UID__={c_debug_light}
  1287. }}
  1288. YASM_DEBUG_INFO_DISABLE_CACHE__NO_UID__={yasm_debug_light}
  1289. }}
  1290. when ($FORCE_CONSISTENT_BUILD == "yes") {{
  1291. CL_MACRO_INFO={macro}
  1292. }}
  1293. elsewhen ($CONSISTENT_BUILD == "yes") {{
  1294. CL_MACRO_INFO_DISABLE_CACHE__NO_UID__={macro}
  1295. }}
  1296. '''.format(c_debug=' '.join(c_debug_map),
  1297. c_debug_cl=' '.join(c_debug_map_cl),
  1298. yasm_debug=' '.join(yasm_debug_map),
  1299. c_debug_light=' '.join(c_debug_map_light), # build_root substitution only
  1300. c_debug_light_cl=' '.join(c_debug_map_light_cl), # build_root substitution only
  1301. yasm_debug_light=yasm_debug_map[0], # build_root substitution only
  1302. macro=' '.join(c_builtins)))
  1303. # TODO(somov): Check whether this specific architecture is needed.
  1304. if self.target.arch == 'i386':
  1305. append('CFLAGS', '-march=pentiumpro')
  1306. append('CFLAGS', '-mtune=pentiumpro')
  1307. append('BC_CFLAGS', '$CFLAGS')
  1308. append('BC_CXXFLAGS', '$CXXFLAGS')
  1309. append('C_DEFINES', '-D__LONG_LONG_SUPPORTED')
  1310. emit('OBJ_CROSS_SUF', '$OBJ_SUF%s' % self.cross_suffix)
  1311. emit('OBJECT_SUF', '$OBJ_SUF%s.o' % self.cross_suffix)
  1312. emit('GCC_COMPILE_FLAGS', '$EXTRA_C_FLAGS -c -o $_COMPILE_OUTPUTS', '${pre=-I:_C__INCLUDE}')
  1313. if is_positive('DUMP_COMPILER_DEPS'):
  1314. emit('DUMP_DEPS', '-MD', '${output;hide;noauto;suf=${OBJ_SUF}.o.d:SRC}')
  1315. elif is_positive('DUMP_COMPILER_DEPS_FAST'):
  1316. emit('DUMP_DEPS', '-E', '-M', '-MF', '${output;noauto;suf=${OBJ_SUF}.o.d:SRC}')
  1317. compiler_time_trace_requested = is_positive('TIME_TRACE') or is_positive('COMPILER_TIME_TRACE')
  1318. compiler_supports_time_trace = self.tc.is_clang and self.tc.version_at_least(9)
  1319. if compiler_time_trace_requested and compiler_supports_time_trace:
  1320. compiler_time_trace_granularity = preset('TIME_TRACE_GRANULARITY', '500')
  1321. emit('COMPILER_TIME_TRACE_FLAGS', '-ftime-trace -ftime-trace-granularity=' + compiler_time_trace_granularity)
  1322. emit('COMPILER_TIME_TRACE_POSTPROCESS', '${YMAKE_PYTHON}', '${input:"build/scripts/find_time_trace.py"}', '$_COMPILE_OUTPUTS', '$_COMPILE_TIME_TRACE_OUTPUTS')
  1323. else:
  1324. emit('COMPILER_TIME_TRACE_FLAGS')
  1325. emit('COMPILER_TIME_TRACE_POSTPROCESS')
  1326. append('EXTRA_OUTPUT')
  1327. style = ['${requirements;hide:CC_REQUIREMENTS} ${hide;kv:"p CC"} ${hide;kv:"pc green"}']
  1328. cxx_args = [
  1329. '$CLANG_TIDY_ARGS',
  1330. '$YNDEXER_ARGS',
  1331. '$CXX_COMPILER',
  1332. '$C_FLAGS_PLATFORM',
  1333. '$GCC_COMPILE_FLAGS',
  1334. '$CXXFLAGS',
  1335. '$CL_MACRO_INFO',
  1336. '$CL_MACRO_INFO_DISABLE_CACHE__NO_UID__',
  1337. '$COMPILER_TIME_TRACE_FLAGS',
  1338. '$EXTRA_OUTPUT',
  1339. '$SRCFLAGS',
  1340. '$_LANG_CFLAGS_VALUE',
  1341. '${input:SRC}',
  1342. '$TOOLCHAIN_ENV',
  1343. '$YNDEXER_OUTPUT',
  1344. '&& $COMPILER_TIME_TRACE_POSTPROCESS',
  1345. ] + style
  1346. c_args = [
  1347. '$CLANG_TIDY_ARGS',
  1348. '$YNDEXER_ARGS',
  1349. '$C_COMPILER',
  1350. '$C_FLAGS_PLATFORM',
  1351. '$GCC_COMPILE_FLAGS',
  1352. '$CFLAGS',
  1353. '$CL_MACRO_INFO',
  1354. '$CL_MACRO_INFO_DISABLE_CACHE__NO_UID__',
  1355. '$CONLYFLAGS',
  1356. '$COMPILER_TIME_TRACE_FLAGS',
  1357. '$EXTRA_OUTPUT',
  1358. '$SRCFLAGS',
  1359. '${input:SRC}',
  1360. '$TOOLCHAIN_ENV',
  1361. '$YNDEXER_OUTPUT',
  1362. '&& $COMPILER_TIME_TRACE_POSTPROCESS',
  1363. ] + style
  1364. ignore_c_args_no_deps = [
  1365. '${input:SRC}',
  1366. '$SRCFLAGS',
  1367. '$CLANG_TIDY_ARGS',
  1368. '$YNDEXER_ARGS',
  1369. '$YNDEXER_OUTPUT',
  1370. '$COMPILER_TIME_TRACE_FLAGS',
  1371. '$EXTRA_OUTPUT',
  1372. '$CL_MACRO_INFO',
  1373. '$CL_MACRO_INFO_DISABLE_CACHE__NO_UID__',
  1374. '&& $COMPILER_TIME_TRACE_POSTPROCESS',
  1375. ]
  1376. c_args_nodeps = [c if c != '$GCC_COMPILE_FLAGS' else '$EXTRA_C_FLAGS -c -o ${OUTFILE} ${SRC} ${pre=-I:INC}' for c in c_args if c not in ignore_c_args_no_deps]
  1377. emit('_SRC_C_NODEPS_CMD', ' '.join(c_args_nodeps))
  1378. emit('_SRC_CPP_CMD', ' '.join(cxx_args))
  1379. emit('_SRC_C_CMD', ' '.join(c_args))
  1380. emit('_SRC_M_CMD', '$SRC_c($SRC $SRCFLAGS)')
  1381. emit('_SRC_MASM_CMD', '$_EMPTY_CMD')
  1382. # fuzzing configuration
  1383. if self.tc.is_clang:
  1384. if self.tc.version_at_least(12):
  1385. emit('LIBFUZZER_PATH', 'contrib/libs/libfuzzer12')
  1386. class SwiftCompiler(object):
  1387. def __init__(self, build):
  1388. self.host = build.host
  1389. self.compiler = None
  1390. def configure(self):
  1391. if self.host.is_macos:
  1392. self.compiler = '$SWIFT_XCODE_TOOLCHAIN_ROOT_RESOURCE_GLOBAL/usr/bin/swiftc'
  1393. def print_compiler(self):
  1394. emit('SWIFT_COMPILER', self.compiler or '')
  1395. class Linker(object):
  1396. BFD = 'bfd'
  1397. LLD = 'lld'
  1398. GOLD = 'gold'
  1399. def __init__(self, tc, build):
  1400. """
  1401. :type tc: ToolchainOptions
  1402. :type build: Build
  1403. """
  1404. self.tc = tc
  1405. self.build = build
  1406. self.type = self._get_default_linker_type()
  1407. def _get_default_linker_type(self):
  1408. if not self.tc.is_from_arcadia or is_positive('EXPORT_CMAKE'):
  1409. # External (e.g. system) toolchain: disable linker selection logic
  1410. return None
  1411. if self.build.target.is_android:
  1412. # Android toolchain is NDK, LLD works on all supported platforms
  1413. return Linker.LLD
  1414. elif self.build.target.is_linux:
  1415. # DEVTOOLS-6782: LLD8 fails to link LTO builds with in-memory ELF objects larger than 4 GiB
  1416. blacklist_lld = is_positive('CLANG7') and is_positive('USE_LTO') and not is_positive('MUSL')
  1417. if self.tc.is_clang and not blacklist_lld:
  1418. return Linker.LLD
  1419. else:
  1420. # GCC et al.
  1421. if self.tc.is_gcc and is_positive('MUSL'):
  1422. # See MUSL_BFD comment below
  1423. return Linker.BFD
  1424. return Linker.GOLD
  1425. # There is no linker choice on Darwin (ld64) or Windows (link.exe)
  1426. return None
  1427. def print_linker(self):
  1428. self._print_linker_selector()
  1429. def _print_linker_selector(self):
  1430. # if self.type is None then _DEFAULT_LINKER is set to empty string value
  1431. emit('_DEFAULT_LINKER_ID', self.type)
  1432. class LD(Linker):
  1433. def __init__(self, tc, build):
  1434. """
  1435. :type tc: GnuToolchainOptions
  1436. :type build: Build
  1437. """
  1438. super(LD, self).__init__(tc, build)
  1439. self.build = build
  1440. self.host = self.build.host
  1441. self.target = self.build.target
  1442. self.tc = tc
  1443. target = self.target
  1444. self.ar = preset('AR') or self.tc.ar
  1445. self.ar_plugin = self.tc.ar_plugin
  1446. self.strip = self.tc.strip
  1447. self.objcopy = self.tc.objcopy
  1448. self.musl = Setting('MUSL', convert=to_bool)
  1449. if self.ar is None:
  1450. if target.is_apple:
  1451. # Use libtool. cctools ar does not understand -M needed for archive merging
  1452. self.ar = '${CCTOOLS_ROOT_RESOURCE_GLOBAL}/bin/libtool'
  1453. elif self.tc.is_from_arcadia:
  1454. if self.tc.is_clang:
  1455. self.ar = '{}/bin/llvm-ar'.format(self.tc.name_marker)
  1456. if self.tc.is_gcc:
  1457. self.ar = '{}/gcc/bin/gcc-ar'.format(self.tc.name_marker)
  1458. else:
  1459. self.ar = 'ar'
  1460. self.ar_type = 'GNU_AR'
  1461. self.llvm_ar_format = 'None'
  1462. if 'libtool' in self.ar:
  1463. self.ar_type = 'LIBTOOL'
  1464. elif 'llvm-ar' in self.ar:
  1465. self.ar_type = 'LLVM_AR'
  1466. if target.is_apple:
  1467. self.llvm_ar_format="darwin"
  1468. else:
  1469. self.llvm_ar_format="gnu"
  1470. self.ld_flags = []
  1471. # Save linker's stdout to an additional .txt output file
  1472. # e.g. LLD writes `--print-gc-sections` or `--print-icf-sections` to stdout
  1473. self.save_linker_output = False
  1474. # Enable section-level DCE (dead code elimination):
  1475. # remove whole unused code and data sections
  1476. # (needs `-ffunction-sections` and `-fdata-sections` to be useful)
  1477. #
  1478. # NOTE: CGO linker doesn't seem to support DCE, but shares common LDFLAGS
  1479. if target.is_macos:
  1480. self.ld_dce_flag = '-Wl,-dead_strip'
  1481. elif target.is_linux or target.is_android:
  1482. self.ld_dce_flag = '-Wl,--gc-sections'
  1483. if preset('LINKER_DCE_PRINT_SECTIONS'):
  1484. self.save_linker_output = True
  1485. self.ld_dce_flag += ' -Wl,--print-gc-sections'
  1486. else:
  1487. self.ld_dce_flag = ''
  1488. if self.type == Linker.LLD:
  1489. # Enable ICF (identical code folding pass) in safe mode
  1490. # https://research.google/pubs/pub36912/
  1491. self.ld_icf_flag = '-Wl,-icf=safe'
  1492. if preset('LINKER_ICF_PRINT_SECTIONS'):
  1493. self.save_linker_output = True
  1494. self.ld_icf_flag += ' -Wl,--print-icf-sections'
  1495. else:
  1496. self.ld_icf_flag = ''
  1497. if self.musl.value:
  1498. self.ld_flags.extend(['-Wl,--no-as-needed'])
  1499. if self.tc.is_gcc:
  1500. # MUSL_BFD: musl build uses --no-dynamic-linker linker flag
  1501. # which gold doesn't know about. And we can only specify linker
  1502. # type, not it's path as we do for Clang through linker selector.
  1503. self.ld_flags.append('-fuse-ld=bfd')
  1504. elif target.is_linux:
  1505. self.ld_flags.extend(['-ldl', '-lrt', '-Wl,--no-as-needed'])
  1506. if self.tc.is_gcc:
  1507. self.ld_flags.extend(('-Wl,-Bstatic', '-latomic', '-Wl,-Bdynamic'))
  1508. elif target.is_android:
  1509. self.ld_flags.extend(['-ldl', '-Wl,--no-as-needed'])
  1510. if self.type == Linker.LLD and target.android_api < 29:
  1511. # https://github.com/android/ndk/issues/1196
  1512. self.ld_flags.append('-Wl,--no-rosegment')
  1513. elif target.is_macos:
  1514. self.ld_flags.append('-Wl,-no_deduplicate')
  1515. if not self.tc.is_clang:
  1516. self.ld_flags.append('-Wl,-no_compact_unwind')
  1517. self.thread_library = select([
  1518. (target.is_linux or target.is_macos, '-lpthread'),
  1519. ])
  1520. self.ld_export_dynamic_flag = None
  1521. self.start_group = None
  1522. self.end_group = None
  1523. self.whole_archive = None
  1524. self.no_whole_archive = None
  1525. self.ld_stripflag = None
  1526. self.use_stdlib = None
  1527. self.soname_option = None
  1528. self.dwarf_command = None
  1529. self.libresolv = '-lresolv' if target.is_linux or target.is_macos or target.is_android else None
  1530. if target.is_linux or target.is_android:
  1531. self.ld_export_dynamic_flag = '-rdynamic'
  1532. self.use_stdlib = '-nodefaultlibs'
  1533. if target.is_linux or target.is_android or target.is_cygwin or target.is_none:
  1534. self.start_group = '-Wl,--start-group'
  1535. self.end_group = '-Wl,--end-group'
  1536. self.whole_archive = '-Wl,--whole-archive'
  1537. self.no_whole_archive = '-Wl,--no-whole-archive'
  1538. self.ld_stripflag = '-s'
  1539. self.soname_option = '-soname'
  1540. if target.is_macos or target.is_ios:
  1541. self.use_stdlib = '-nodefaultlibs'
  1542. self.soname_option = '-install_name'
  1543. if not preset('NO_DEBUGINFO'):
  1544. self.dwarf_command = '$DWARF_TOOL $TARGET -o ${output;pre=$MODULE_PREFIX$REALPRJNAME.dSYM/Contents/Resources/DWARF/$MODULE_PREFIX:REALPRJNAME}'
  1545. if self.target.is_ios and preset('MAPSMOBI_BUILD_TARGET') and self.target.is_arm:
  1546. self.ld_flags.extend(('-fembed-bitcode', '-Wl,-bitcode_verify'))
  1547. if self.build.profiler_type == Profiler.GProf:
  1548. self.ld_flags.append('-pg')
  1549. # TODO(somov): Единое условие на coverage.
  1550. if self.build.is_coverage or is_positive('GCOV_COVERAGE') or is_positive('CLANG_COVERAGE') or self.build.is_sanitized:
  1551. self.use_stdlib = None
  1552. self.ld_sdk = select(default=None, selectors=[
  1553. (target.is_macos_arm64, '-Wl,-sdk_version,11.0'),
  1554. (target.is_macos, '-Wl,-sdk_version,10.15'),
  1555. (not target.is_iossim and target.is_ios, '-Wl,-sdk_version,13.1'),
  1556. (target.is_iossim, '-Wl,-sdk_version,14.5'),
  1557. ])
  1558. if self.ld_sdk:
  1559. self.ld_flags.append(self.ld_sdk)
  1560. self.sys_lib = self.tc.sys_lib
  1561. if target.is_android:
  1562. if target.is_armv7 and self.type != Linker.LLD:
  1563. self.sys_lib.append('-Wl,--fix-cortex-a8')
  1564. # NDK r23 onwards has stopped using libgcc:
  1565. # - https://github.com/android/ndk/wiki/Changelog-r23#changes
  1566. # - https://github.com/android/ndk/issues/1230
  1567. # LLVM's libunwind is now used instead of libgcc for all architectures rather than just 32-bit Arm.
  1568. # - https://github.com/android/ndk/issues/1231
  1569. # LLVM's libclang_rt.builtins is now used instead of libgcc.
  1570. if self.tc.android_ndk_version >= 23:
  1571. # Use toolchain defaults to link with libunwind/clang_rt.builtins
  1572. self.use_stdlib = '-nostdlib++'
  1573. else:
  1574. # Preserve old behaviour: specify runtime libs manually
  1575. self.use_stdlib = '-nodefaultlibs'
  1576. if target.is_armv7:
  1577. self.sys_lib.append('-lunwind')
  1578. self.sys_lib.append('-lgcc')
  1579. if self.tc.is_clang and not self.tc.version_at_least(4, 0) and target.is_linux_x86_64:
  1580. self.sys_lib.append('-L/usr/lib/x86_64-linux-gnu')
  1581. def print_linker(self):
  1582. super(LD, self).print_linker()
  1583. emit('AR_TOOL', self.ar)
  1584. emit('AR_TYPE', self.ar_type)
  1585. emit('STRIP_TOOL_VENDOR', self.strip)
  1586. emit('OBJCOPY_TOOL_VENDOR', self.objcopy)
  1587. append('LDFLAGS', '$USER_LDFLAGS', self.ld_flags)
  1588. append('LDFLAGS_GLOBAL', '')
  1589. emit('LD_STRIP_FLAG', self.ld_stripflag)
  1590. emit('STRIP_FLAG')
  1591. emit('LD_DCE_FLAG', self.ld_dce_flag)
  1592. emit('DCE_FLAG')
  1593. emit('LD_ICF_FLAG', self.ld_icf_flag)
  1594. emit('ICF_FLAG')
  1595. emit('C_LIBRARY_PATH')
  1596. emit('C_SYSTEM_LIBRARIES_INTERCEPT')
  1597. if self.musl.value:
  1598. emit('C_SYSTEM_LIBRARIES', '-nostdlib')
  1599. else:
  1600. emit('C_SYSTEM_LIBRARIES', self.use_stdlib, self.thread_library, self.sys_lib, '-lc')
  1601. emit('START_WHOLE_ARCHIVE_VALUE', self.whole_archive)
  1602. emit('END_WHOLE_ARCHIVE_VALUE', self.no_whole_archive)
  1603. if self.ld_sdk:
  1604. emit('LD_SDK_VERSION', self.ld_sdk)
  1605. dwarf_tool = self.tc.dwarf_tool
  1606. if dwarf_tool is None and self.tc.is_clang and (self.target.is_macos or self.target.is_ios):
  1607. dsymutil = '{}/bin/{}dsymutil'.format(self.tc.name_marker, '' if self.tc.version_at_least(7) else 'llvm-')
  1608. dwarf_tool = '${YMAKE_PYTHON} ${input:"build/scripts/run_llvm_dsymutil.py"} ' + dsymutil
  1609. if self.tc.version_at_least(5, 0):
  1610. dwarf_tool += ' -flat'
  1611. if dwarf_tool is not None:
  1612. emit('DWARF_TOOL', dwarf_tool)
  1613. emit('OBJADDE')
  1614. emit('LD_EXPORT_ALL_DYNAMIC_SYMBOLS_FLAG', self.ld_export_dynamic_flag)
  1615. emit_big('''
  1616. NO_EXPORT_DYNAMIC_SYMBOLS=
  1617. EXPORTS_VALUE=$LD_EXPORT_ALL_DYNAMIC_SYMBOLS_FLAG
  1618. when ($EXPORTS_FILE) {
  1619. EXPORTS_VALUE=$LD_EXPORT_ALL_DYNAMIC_SYMBOLS_FLAG -Wl,--version-script=${input:EXPORTS_FILE}
  1620. }
  1621. when ($NO_EXPORT_DYNAMIC_SYMBOLS == "yes") {
  1622. EXPORTS_VALUE=
  1623. }''')
  1624. emit('LINKER_SCRIPT_VALUE', '${ext=.ld;pre=-T:SRCS_GLOBAL}')
  1625. linker_time_trace_requested = is_positive('TIME_TRACE') or is_positive('LINKER_TIME_TRACE')
  1626. linker_supports_time_trace = self.type == Linker.LLD # XXX: Should really check the linker version if we had one
  1627. if linker_time_trace_requested and linker_supports_time_trace:
  1628. linker_time_trace_granularity = preset('TIME_TRACE_GRANULARITY', '500')
  1629. emit('LINKER_TIME_TRACE_FLAG', ' '.join([
  1630. '-Wl,--time-trace',
  1631. '-Wl,--time-trace-granularity=' + linker_time_trace_granularity,
  1632. '-Wl,--time-trace-file=${output;rootrel;pre=$MODULE_PREFIX;suf=$MODULE_SUFFIX.time_trace.json:REALPRJNAME}',
  1633. ]))
  1634. else:
  1635. emit('LINKER_TIME_TRACE_FLAG')
  1636. exe_flags = [
  1637. '$C_FLAGS_PLATFORM', '$BEFORE_PEERS', self.start_group, '${rootrel:PEERS}', self.end_group, '$AFTER_PEERS',
  1638. '$EXPORTS_VALUE $LINKER_SCRIPT_VALUE $LDFLAGS $LDFLAGS_GLOBAL $OBJADDE $OBJADDE_LIB',
  1639. '$C_LIBRARY_PATH $C_SYSTEM_LIBRARIES_INTERCEPT $C_SYSTEM_LIBRARIES $STRIP_FLAG $DCE_FLAG $ICF_FLAG $LINKER_TIME_TRACE_FLAG']
  1640. arch_flag = '--arch={arch}'.format(arch=self.target.os_compat)
  1641. soname_flag = '-Wl,{option},${{_SONAME}}'.format(option=self.soname_option)
  1642. shared_flag = '-shared'
  1643. exec_shared_flag = '-pie -fPIE -Wl,--unresolved-symbols=ignore-all -rdynamic' if self.target.is_linux else ''
  1644. if self.whole_archive:
  1645. srcs_globals = self.whole_archive + ' ${rootrel;ext=.a:SRCS_GLOBAL} ' + self.no_whole_archive \
  1646. + ' ${rootrel;ext=.o:SRCS_GLOBAL} ${rootrel;ext=.supp:SRCS_GLOBAL}'
  1647. else:
  1648. srcs_globals = '--start-wa ${rootrel;ext=.a:SRCS_GLOBAL} --end-wa ${rootrel;ext=.o:SRCS_GLOBAL} ${rootrel;ext=.supp:SRCS_GLOBAL}'
  1649. ld_env_style = '${cwd:ARCADIA_BUILD_ROOT} $TOOLCHAIN_ENV ${kv;hide:"p LD"} ${requirements;hide:LD_REQUIREMENTS} ${kv;hide:"pc light-blue"} ${kv;hide:"show_out"}'
  1650. # Program
  1651. emit(
  1652. "GENERATE_MF_CMD",
  1653. '$YMAKE_PYTHON', '${input:"build/scripts/generate_mf.py"}',
  1654. '--build-root $ARCADIA_BUILD_ROOT --module-name $REALPRJNAME -o ${output;pre=$MODULE_PREFIX;suf=$MODULE_SUFFIX.mf:REALPRJNAME}',
  1655. '-t $MODULE_TYPE --ya-start-command-file -Ya,lics $LICENSE_NAMES -Ya,peers ${rootrel:PEERS} -Ya,credits ${input:CREDITS_TEXTS_FILE} $CREDITS_FLAGS --ya-end-command-file',
  1656. )
  1657. if is_positive("TIDY"):
  1658. emit(
  1659. 'REAL_LINK_EXE',
  1660. '$YMAKE_PYTHON ${input:"build/scripts/clang_tidy_arch.py"}',
  1661. '--build-root $ARCADIA_BUILD_ROOT',
  1662. '--source-root $ARCADIA_ROOT',
  1663. '--output-file',
  1664. '$TARGET',
  1665. '$AUTO_INPUT',
  1666. ld_env_style
  1667. )
  1668. else:
  1669. emit('LINK_SCRIPT_EXE_FLAGS')
  1670. emit('REAL_LINK_EXE_CMDLINE',
  1671. '$YMAKE_PYTHON ${input:"build/scripts/link_exe.py"}',
  1672. '--source-root $ARCADIA_ROOT',
  1673. '--linker-output ${output;pre=$MODULE_PREFIX;suf=$MODULE_SUFFIX.linker.txt:REALPRJNAME}' if self.save_linker_output else '',
  1674. '${pre=--whole-archive-peers :WHOLE_ARCHIVE_PEERS}',
  1675. '${pre=--whole-archive-libs :_WHOLE_ARCHIVE_LIBS_VALUE_GLOBAL}',
  1676. arch_flag,
  1677. '$LINK_SCRIPT_EXE_FLAGS',
  1678. '$CXX_COMPILER',
  1679. srcs_globals,
  1680. '$VCS_C_OBJ $AUTO_INPUT -o $TARGET',
  1681. exe_flags,
  1682. ld_env_style,
  1683. )
  1684. emit('REAL_LINK_EXE', '$REAL_LINK_EXE_IMPL($_WHOLE_ARCHIVE_PEERS_VALUE)')
  1685. # Executable Shared Library
  1686. emit('REAL_LINK_EXEC_DYN_LIB_CMDLINE',
  1687. '$YMAKE_PYTHON ${input:"build/scripts/link_dyn_lib.py"}',
  1688. '--target $TARGET',
  1689. '--linker-output ${output;pre=$MODULE_PREFIX;suf=$MODULE_SUFFIX.linker.txt:REALPRJNAME}' if self.save_linker_output else '',
  1690. '${pre=--whole-archive-peers :WHOLE_ARCHIVE_PEERS}',
  1691. '${pre=--whole-archive-libs :_WHOLE_ARCHIVE_LIBS_VALUE_GLOBAL}',
  1692. arch_flag,
  1693. '$LINK_DYN_LIB_FLAGS',
  1694. '$CXX_COMPILER',
  1695. srcs_globals,
  1696. '$VCS_C_OBJ $AUTO_INPUT -o $TARGET',
  1697. exec_shared_flag,
  1698. soname_flag,
  1699. exe_flags,
  1700. ld_env_style,
  1701. )
  1702. emit('REAL_LINK_EXEC_DYN_LIB', '$REAL_LINK_EXEC_DYN_LIB_IMPL($_WHOLE_ARCHIVE_PEERS_VALUE)')
  1703. # Shared Library
  1704. emit('LINK_DYN_LIB_FLAGS')
  1705. emit('REAL_LINK_DYN_LIB_CMDLINE',
  1706. '$YMAKE_PYTHON ${input:"build/scripts/link_dyn_lib.py"}',
  1707. '--target $TARGET',
  1708. '--linker-output ${output;pre=$MODULE_PREFIX;suf=$MODULE_SUFFIX$MODULE_VERSION.linker.txt:REALPRJNAME}' if self.save_linker_output else '',
  1709. '${pre=--whole-archive-peers :WHOLE_ARCHIVE_PEERS}',
  1710. '${pre=--whole-archive-libs :_WHOLE_ARCHIVE_LIBS_VALUE_GLOBAL}',
  1711. arch_flag,
  1712. '$LINK_DYN_LIB_FLAGS',
  1713. '$CXX_COMPILER',
  1714. srcs_globals,
  1715. '$VCS_C_OBJ $AUTO_INPUT -o $TARGET',
  1716. shared_flag,
  1717. soname_flag,
  1718. exe_flags,
  1719. ld_env_style)
  1720. emit('REAL_LINK_DYN_LIB', '$REAL_LINK_DYN_LIB_IMPL($_WHOLE_ARCHIVE_PEERS_VALUE)')
  1721. if self.dwarf_command is None or self.target.is_ios:
  1722. emit('DWARF_COMMAND')
  1723. else:
  1724. emit('DWARF_COMMAND', self.dwarf_command, ld_env_style)
  1725. if is_positive("TIDY"):
  1726. emit('LINK_EXE', '$REAL_LINK_EXE')
  1727. else:
  1728. emit('LINK_EXE', '$GENERATE_MF && $GENERATE_VCS_C_INFO_NODEP && $REAL_LINK_EXE && $DWARF_COMMAND && $LINK_ADDITIONAL_SECTIONS_COMMAND && $PACK_IOS_CMD')
  1729. if is_positive("TIDY"):
  1730. emit('LINK_DYN_LIB', "$REAL_LINK_EXE")
  1731. else:
  1732. emit('LINK_DYN_LIB', '$GENERATE_MF && $GENERATE_VCS_C_INFO_NODEP && $REAL_LINK_DYN_LIB && $DWARF_COMMAND && $LINK_ADDITIONAL_SECTIONS_COMMAND')
  1733. emit('LINK_EXEC_DYN_LIB', '$GENERATE_MF && $GENERATE_VCS_C_INFO_NODEP && $REAL_LINK_EXEC_DYN_LIB && $DWARF_COMMAND && $LINK_ADDITIONAL_SECTIONS_COMMAND')
  1734. emit('SWIG_DLL_JAR_CMD', '$GENERATE_MF && $GENERATE_VCS_C_INFO_NODEP && $REAL_SWIG_DLL_JAR_CMD && $DWARF_COMMAND')
  1735. tail_link_lib = '$AUTO_INPUT ${requirements;hide:LIB_REQUIREMENTS} ${kv;hide:"p AR"} $TOOLCHAIN_ENV ${kv;hide:"pc light-red"} ${kv;hide:"show_out"}'
  1736. if is_positive("TIDY"):
  1737. archiver = '$YMAKE_PYTHON ${input:"build/scripts/clang_tidy_arch.py"} --source-root $ARCADIA_ROOT --build-root $ARCADIA_BUILD_ROOT --output-file'
  1738. emit('LINK_LIB', archiver, "$TARGET", tail_link_lib)
  1739. else:
  1740. archiver = '$YMAKE_PYTHON ${input:"build/scripts/link_lib.py"} ${quo:AR_TOOL} $AR_TYPE %s $ARCADIA_BUILD_ROOT %s' % (self.llvm_ar_format, self.ar_plugin or 'None')
  1741. # Static Library
  1742. emit('LINK_LIB', '$GENERATE_MF &&', archiver, '$TARGET', tail_link_lib)
  1743. emit('GLOBAL_LINK_LIB', archiver, '$GLOBAL_TARGET', tail_link_lib)
  1744. # "Fat Object" : pre-linked global objects and static library with all dependencies
  1745. def emit_link_fat_obj(cmd_name, need_wa_option, *extended_flags):
  1746. prefix = ['$GENERATE_MF && $GENERATE_VCS_C_INFO_NODEP &&',
  1747. '$YMAKE_PYTHON ${input:"build/scripts/link_fat_obj.py"} --build-root $ARCADIA_BUILD_ROOT']
  1748. globals_libs = srcs_globals if need_wa_option else '${rootrel;ext=.a:SRCS_GLOBAL} ${rootrel;ext=.o:SRCS_GLOBAL}'
  1749. suffix = [arch_flag,
  1750. '-Ya,input $AUTO_INPUT $VCS_C_OBJ -Ya,global_srcs', globals_libs, '-Ya,peers $PEERS',
  1751. '-Ya,linker $CXX_COMPILER $LDFLAGS_GLOBAL $C_FLAGS_PLATFORM', self.ld_sdk, '-Ya,archiver', archiver,
  1752. '$TOOLCHAIN_ENV ${kv;hide:"p LD"} ${requirements;hide:LD_REQUIREMENTS} ${kv;hide:"pc light-blue"} ${kv;hide:"show_out"}']
  1753. emit(cmd_name, *(prefix + list(extended_flags) + suffix))
  1754. # TODO(somov): Проверить, не нужны ли здесь все остальные флаги компоновки (LDFLAGS и т. д.).
  1755. emit_link_fat_obj('LINK_FAT_OBJECT', True, '--obj=$TARGET', '--lib=${output:REALPRJNAME.a}')
  1756. emit_link_fat_obj('LINK_RECURSIVE_LIBRARY', False, '--lib=$TARGET', '--with-own-obj', '--with-global-srcs')
  1757. emit_link_fat_obj('LINK_FAT_OBJECT_LIBRARY', False, '--lib=$TARGET', '$FAT_OBJECT_ARGS', '$FAT_OBJECT_OUTS')
  1758. emit('LIBRT', '-lrt')
  1759. emit('MD5LIB', '-lcrypt')
  1760. emit('LIBRESOLV', self.libresolv)
  1761. emit('PROFFLAG', '-pg')
  1762. class MSVCToolchainOptions(ToolchainOptions):
  1763. def __init__(self, build, detector):
  1764. super(MSVCToolchainOptions, self).__init__(build, detector)
  1765. # C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.14.26428
  1766. self.vc_root = None
  1767. # C:\Program Files (x86)\Windows Kits\10\Include\10.0.14393.0
  1768. self.kit_includes = None
  1769. # C:\Program Files (x86)\Windows Kits\10\Lib\10.0.14393.0
  1770. self.kit_libs = None
  1771. self.under_wine = 'wine' in self.params
  1772. self.system_msvc = 'system_msvc' in self.params
  1773. self.ide_msvs = 'ide_msvs' in self.params
  1774. self.use_clang = self.params.get('use_clang', False)
  1775. self.use_arcadia_toolchain = self.params.get('use_arcadia_toolchain', False)
  1776. self.sdk_version = None
  1777. if build.host.is_windows:
  1778. self.under_wine = False
  1779. if self.ide_msvs:
  1780. bindir = '$(VC_ExecutablePath_x64_x64)\\'
  1781. self.c_compiler = bindir + 'cl.exe'
  1782. self.cxx_compiler = self.c_compiler
  1783. self.link = bindir + 'link.exe'
  1784. self.lib = bindir + 'lib.exe'
  1785. self.masm_compiler = bindir + 'ml64.exe'
  1786. self.vc_root = None
  1787. sdk_dir = '$(WindowsSdkDir)'
  1788. self.sdk_version = '$(WindowsTargetPlatformVersion)'
  1789. self.kit_includes = os.path.join(sdk_dir, 'Include', self.sdk_version)
  1790. self.kit_libs = os.path.join(sdk_dir, 'Lib', self.sdk_version)
  1791. elif detector:
  1792. self.masm_compiler = which('ml64.exe')
  1793. self.link = which('link.exe')
  1794. self.lib = which('lib.exe')
  1795. sdk_dir = os.environ.get('WindowsSdkDir')
  1796. self.sdk_version = os.environ.get('WindowsSDKVersion').replace('\\', '')
  1797. vc_install_dir = os.environ.get('VCToolsInstallDir')
  1798. # fix for cxx_std detection problem introduced in r7740071 when running in native VS toolkit commandline:
  1799. # in that case ya make gets 'system_cxx' configuration name and cxx_std is obviously missing in that config
  1800. # so default 'c++20' is substituted and we need to hotfix it here
  1801. self.cxx_std = 'c++latest'
  1802. if any([x is None for x in (sdk_dir, self.sdk_version, vc_install_dir)]):
  1803. raise ConfigureError('No %WindowsSdkDir%, %WindowsSDKVersion% or %VCINSTALLDIR% present. Please, run vcvars64.bat to setup preferred environment.')
  1804. self.vc_root = os.path.normpath(vc_install_dir)
  1805. self.kit_includes = os.path.normpath(os.path.join(sdk_dir, 'Include', self.sdk_version))
  1806. self.kit_libs = os.path.normpath(os.path.join(sdk_dir, 'Lib', self.sdk_version))
  1807. # TODO(somov): Определять автоматически self.version в этом случае
  1808. else:
  1809. if self.version_at_least(2019):
  1810. self.sdk_version = '10.0.18362.0'
  1811. sdk_dir = '$(WINDOWS_KITS-sbr:1939557911)'
  1812. if is_positive('MSVC20'): # XXX: temporary flag, remove after DTCC-123 is completed
  1813. self.cxx_std = 'c++latest'
  1814. else:
  1815. self.sdk_version = '10.0.16299.0'
  1816. sdk_dir = '$(WINDOWS_KITS-sbr:1379398385)'
  1817. self.vc_root = self.name_marker if not self.use_clang else '$MSVC_FOR_CLANG_RESOURCE_GLOBAL'
  1818. self.kit_includes = os.path.join(sdk_dir, 'Include', self.sdk_version)
  1819. self.kit_libs = os.path.join(sdk_dir, 'Lib', self.sdk_version)
  1820. bindir = os.path.join(self.vc_root, 'bin', 'Hostx64')
  1821. tools_name = select(selectors=[
  1822. (build.target.is_x86, 'x86'),
  1823. (build.target.is_x86_64, 'x64'),
  1824. (build.target.is_armv7, 'arm'),
  1825. ])
  1826. asm_name = select(selectors=[
  1827. (build.target.is_x86, 'ml.exe'),
  1828. (build.target.is_x86_64, 'ml64.exe'),
  1829. (build.target.is_armv7, 'armasm.exe'),
  1830. ])
  1831. def prefix(_type, _path):
  1832. if not self.under_wine:
  1833. return _path
  1834. return '{wine} {type} $WINE_ENV ${{ARCADIA_ROOT}} ${{ARCADIA_BUILD_ROOT}} {path}'.format(
  1835. wine='${YMAKE_PYTHON} ${input:\"build/scripts/run_msvc_wine.py\"} $(WINE_TOOL-sbr:1093314933)/bin/wine64 -v140',
  1836. type=_type,
  1837. path=_path
  1838. )
  1839. self.masm_compiler = prefix('masm', os.path.join(bindir, tools_name, asm_name))
  1840. self.link = prefix('link', os.path.join(bindir, tools_name, 'link.exe'))
  1841. self.lib = prefix('lib', os.path.join(bindir, tools_name, 'lib.exe'))
  1842. class MSVC(object):
  1843. # noinspection PyPep8Naming
  1844. class WIN32_WINNT(object):
  1845. Macro = '_WIN32_WINNT'
  1846. Windows7 = '0x0601'
  1847. Windows8 = '0x0602'
  1848. def __init__(self, tc, build):
  1849. """
  1850. :type tc: MSVCToolchainOptions
  1851. :type build: Build
  1852. """
  1853. if not isinstance(tc, MSVCToolchainOptions):
  1854. raise TypeError('Got {} ({}) instead of an MSVCToolchainOptions'.format(tc, type(tc)))
  1855. self.build = build
  1856. self.tc = tc
  1857. class MSVCToolchain(MSVC, Toolchain):
  1858. def __init__(self, tc, build):
  1859. """
  1860. :type tc: MSVCToolchainOptions
  1861. :param build: Build
  1862. """
  1863. Toolchain.__init__(self, tc, build)
  1864. MSVC.__init__(self, tc, build)
  1865. if self.tc.from_arcadia and not self.tc.ide_msvs:
  1866. self.platform_projects.append('build/platform/msvc')
  1867. if tc.under_wine:
  1868. self.platform_projects.append('build/platform/wine')
  1869. def print_toolchain(self):
  1870. super(MSVCToolchain, self).print_toolchain()
  1871. emit('TOOLCHAIN_ENV', format_env(self.tc.get_env(), list_separator=';'))
  1872. if self.tc.sdk_version:
  1873. emit('WINDOWS_KITS_VERSION', self.tc.sdk_version)
  1874. # TODO(somov): Заглушка для тех мест, где C_FLAGS_PLATFORM используется
  1875. # для любых платформ. Нужно унифицировать с GnuToolchain.
  1876. emit('C_FLAGS_PLATFORM')
  1877. if self.tc.under_wine:
  1878. emit('WINE_ENV', format_env({'WINEPREFIX_SUFFIX': '4.0'}))
  1879. class MSVCCompiler(MSVC, Compiler):
  1880. def __init__(self, tc, build):
  1881. Compiler.__init__(self, tc, 'MSVC')
  1882. MSVC.__init__(self, tc, build)
  1883. def print_compiler(self):
  1884. super(MSVCCompiler, self).print_compiler()
  1885. target = self.build.target
  1886. win32_winnt = self.WIN32_WINNT.Windows7
  1887. warns_enabled = [
  1888. 4018, # 'expression' : signed/unsigned mismatch
  1889. 4265, # 'class' : class has virtual functions, but destructor is not virtual
  1890. 4296, # 'operator' : expression is always false
  1891. 4431, # missing type specifier - int assumed
  1892. ]
  1893. warns_as_error = [
  1894. 4013, # 'function' undefined; assuming extern returning int
  1895. ]
  1896. warns_disabled = [
  1897. 4127, # conditional expression is constant
  1898. 4200, # nonstandard extension used : zero-sized array in struct/union
  1899. 4201, # nonstandard extension used : nameless struct/union
  1900. 4351, # elements of array will be default initialized
  1901. 4355, # 'this' : used in base member initializer list
  1902. 4503, # decorated name length exceeded, name was truncated
  1903. 4510, # default constructor could not be generated
  1904. 4511, # copy constructor could not be generated
  1905. 4512, # assignment operator could not be generated
  1906. 4554, # check operator precedence for possible error; use parentheses to clarify precedence
  1907. 4610, # 'object' can never be instantiated - user defined constructor required
  1908. 4706, # assignment within conditional expression
  1909. 4800, # forcing value to bool 'true' or 'false' (performance warning)
  1910. 4996, # The POSIX name for this item is deprecated
  1911. 4714, # function marked as __forceinline not inlined
  1912. 4197, # 'TAtomic' : top-level volatile in cast is ignored
  1913. 4245, # 'initializing' : conversion from 'int' to 'ui32', signed/unsigned mismatch
  1914. 4324, # 'ystd::function<void (uint8_t *)>': structure was padded due to alignment specifier
  1915. 5033, # 'register' is no longer a supported storage class
  1916. ]
  1917. defines = [
  1918. '/DARCADIA_ROOT=${ARCADIA_ROOT}',
  1919. '/DARCADIA_BUILD_ROOT=${ARCADIA_BUILD_ROOT}',
  1920. '/DFAKEID=$CPP_FAKEID',
  1921. '/DWIN32',
  1922. '/D_WIN32',
  1923. '/D_WINDOWS',
  1924. '/D_CRT_SECURE_NO_WARNINGS',
  1925. '/D_CRT_NONSTDC_NO_WARNINGS',
  1926. '/D_USE_MATH_DEFINES',
  1927. '/D__STDC_CONSTANT_MACROS',
  1928. '/D__STDC_FORMAT_MACROS',
  1929. '/D_USING_V110_SDK71_',
  1930. '/D_LIBCPP_ENABLE_CXX17_REMOVED_FEATURES',
  1931. '/DNOMINMAX',
  1932. '/DWIN32_LEAN_AND_MEAN',
  1933. ]
  1934. cxx_defines = [
  1935. # Use builtin offsetof implementation
  1936. # instead of a crutcy macro defined in ucrt/stddef.h.
  1937. # The latter can not be used in constexpr statements.
  1938. '/D_CRT_USE_BUILTIN_OFFSETOF',
  1939. ]
  1940. if target.is_x86_64:
  1941. defines.extend(('/D_WIN64', '/DWIN64'))
  1942. if target.is_armv7:
  1943. defines.extend(('/D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE', '/D__arm__'))
  1944. winapi_unicode = False
  1945. emit_big('''
  1946. MSVC_INLINE_OPTIMIZED=yes
  1947. when ($MSVC_INLINE_OPTIMIZED == "yes") {
  1948. MSVC_INLINE_FLAG=/Zc:inline
  1949. }
  1950. when ($MSVC_INLINE_OPTIMIZED == "no") {
  1951. MSVC_INLINE_FLAG=/Zc:inline-
  1952. }''')
  1953. flags = [
  1954. '/nologo', '/Zm500', '/GR', '/bigobj', '/FC', '/EHs', '/errorReport:prompt', '$MSVC_INLINE_FLAG', '/utf-8',
  1955. # enable standard conforming mode
  1956. '/permissive-'
  1957. ]
  1958. flags += self.tc.arch_opt
  1959. c_warnings = ['/we{}'.format(code) for code in warns_as_error]
  1960. c_warnings += ['/w1{}'.format(code) for code in warns_enabled]
  1961. c_warnings += ['/wd{}'.format(code) for code in warns_disabled]
  1962. cxx_warnings = []
  1963. flags_debug = ['/Ob0', '/Od', '/D_DEBUG']
  1964. flags_release = ['/Ox', '/Ob2', '/Oi', '/DNDEBUG']
  1965. flags_c_only = []
  1966. cxx_flags = [
  1967. # Provide proper __cplusplus value
  1968. # https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/
  1969. "/Zc:__cplusplus"
  1970. ]
  1971. if self.tc.use_clang:
  1972. flags += [
  1973. # Allow <windows.h> to be included via <Windows.h> in case-sensitive file-systems.
  1974. '-fcase-insensitive-paths',
  1975. # Enable standard-conforming behavior and generate duplicate symbol error in case of duplicated global constants.
  1976. # See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85678#c0
  1977. '-fno-common',
  1978. ]
  1979. if target.is_x86:
  1980. flags.append('-m32')
  1981. if target.is_x86_64:
  1982. flags.append('-m64')
  1983. c_warnings.extend((
  1984. '-Wno-bitwise-op-parentheses',
  1985. '-Wno-dll-attribute-on-redeclaration',
  1986. '-Wno-extern-initializer',
  1987. '-Wno-format',
  1988. '-Wno-ignored-pragma-optimize',
  1989. '-Wno-inconsistent-dllimport',
  1990. '-Wno-int-conversion',
  1991. '-Wno-logical-op-parentheses',
  1992. '-Wno-macro-redefined',
  1993. '-Wno-parentheses',
  1994. '-Wno-pragma-pack',
  1995. '-Wno-tautological-constant-out-of-range-compare',
  1996. '-Wno-unknown-argument',
  1997. '-Wno-unknown-warning-option',
  1998. ))
  1999. cxx_warnings += [
  2000. '-Woverloaded-virtual',
  2001. '-Wimport-preprocessor-directive-pedantic',
  2002. '-Wno-undefined-var-template',
  2003. ]
  2004. if self.tc.version_at_least(2019):
  2005. cxx_warnings += [
  2006. '-Wno-deprecated-volatile',
  2007. '-Wno-deprecated-anon-enum-enum-conversion',
  2008. '-Wno-defaulted-function-deleted',
  2009. '-Wno-deprecated-enum-enum-conversion',
  2010. '-Wno-ambiguous-reversed-operator',
  2011. '-Wno-deprecated-enum-float-conversion',
  2012. ]
  2013. # heretic: на момент коммита в нашей конфигурации указано, что тулчейн clang11-windows - аналог msvc 2019
  2014. # https://a.yandex-team.ru/arc/trunk/arcadia/build/ya.conf.json?rev=r7910792#L2185
  2015. # сам clang11 по дефолту представляется msvc2017 (#define _MSC_VER 1911)
  2016. # https://a.yandex-team.ru/arc/trunk/arcadia/contrib/libs/clang11/lib/Driver/ToolChains/MSVC.cpp?rev=r7913127#L1352
  2017. # вручную заставляем его представляться msvc2019 (#define _MSC_VER 1921)
  2018. # значение версии взято вот отсюда:
  2019. # https://a.yandex-team.ru/arc/trunk/arcadia/contrib/libs/llvm11/include/llvm/Support/Compiler.h?blame=true&rev=r7913127#L89
  2020. if self.tc.version_exactly(2019):
  2021. flags.append('-fms-compatibility-version=19.21')
  2022. if self.tc.ide_msvs:
  2023. cxx_warnings += [
  2024. '-Wno-unused-command-line-argument',
  2025. ]
  2026. if target.is_armv7:
  2027. masm_io = '-o ${output;suf=${OBJECT_SUF}:SRC} ${input;msvs_source:SRC}'
  2028. else:
  2029. masm_io = '/nologo /c /Fo${output;suf=${OBJECT_SUF}:SRC} ${input;msvs_source:SRC}'
  2030. emit('OBJ_CROSS_SUF', '$OBJ_SUF')
  2031. emit('OBJECT_SUF', '$OBJ_SUF.obj')
  2032. emit('WIN32_WINNT', '{value}'.format(value=win32_winnt))
  2033. defines.append('/D{name}=$WIN32_WINNT'.format(name=self.WIN32_WINNT.Macro))
  2034. if winapi_unicode:
  2035. defines += ['/DUNICODE', '/D_UNICODE']
  2036. else:
  2037. defines += ['/D_MBCS']
  2038. # https://msdn.microsoft.com/en-us/library/abx4dbyh.aspx
  2039. if is_positive('DLL_RUNTIME'): # XXX
  2040. flags_debug += ['/MDd']
  2041. flags_release += ['/MD']
  2042. else:
  2043. flags_debug += ['/MTd']
  2044. flags_release += ['/MT']
  2045. vc_include = os.path.join(self.tc.vc_root, 'include') if not self.tc.ide_msvs else "$(VC_VC_IncludePath.Split(';')[0].Replace('\\','/'))"
  2046. if not self.tc.ide_msvs:
  2047. def include_flag(path):
  2048. return '{flag}"{path}"'.format(path=path, flag='/I ' if not self.tc.use_clang else '-imsvc')
  2049. for name in ('shared', 'ucrt', 'um', 'winrt'):
  2050. flags.append(include_flag(os.path.join(self.tc.kit_includes, name)))
  2051. flags.append(include_flag(vc_include))
  2052. flags_msvs_only = []
  2053. if self.tc.ide_msvs:
  2054. if not self.tc.use_clang:
  2055. flags_msvs_only += ['/FD', '/MP']
  2056. debug_info_flags = '/Zi /FS'
  2057. else:
  2058. debug_info_flags = '/Z7'
  2059. if self.tc.use_clang:
  2060. emit('CLANG_CL', 'yes')
  2061. if self.tc.ide_msvs:
  2062. emit('IDE_MSVS', 'yes')
  2063. if self.tc.use_arcadia_toolchain:
  2064. emit('USE_ARCADIA_TOOLCHAIN', 'yes')
  2065. emit('CXX_COMPILER', self.tc.cxx_compiler)
  2066. emit('C_COMPILER', self.tc.c_compiler)
  2067. emit('MASM_COMPILER', self.tc.masm_compiler)
  2068. append('C_DEFINES', defines)
  2069. emit('CFLAGS_DEBUG', flags_debug)
  2070. emit('CFLAGS_RELEASE', flags_release)
  2071. emit('MASMFLAGS', '')
  2072. emit('DEBUG_INFO_FLAGS', debug_info_flags)
  2073. append('C_WARNING_OPTS', c_warnings)
  2074. append('CXX_WARNING_OPTS', cxx_warnings)
  2075. if self.build.is_release:
  2076. emit('CFLAGS_PER_TYPE', '$CFLAGS_RELEASE')
  2077. if self.build.is_debug:
  2078. emit('CFLAGS_PER_TYPE', '$CFLAGS_DEBUG')
  2079. if self.build.is_ide:
  2080. emit('CFLAGS_PER_TYPE', '@[debug|$CFLAGS_DEBUG]@[release|$CFLAGS_RELEASE]')
  2081. append('CFLAGS', flags, flags_msvs_only, '$CFLAGS_PER_TYPE', '$DEBUG_INFO_FLAGS', '$C_WARNING_OPTS', '$C_DEFINES', '$USER_CFLAGS', '$USER_CFLAGS_GLOBAL')
  2082. append('CXXFLAGS', '$CFLAGS', '/std:' + self.tc.cxx_std, cxx_flags, cxx_defines, '$CXX_WARNING_OPTS', '$USER_CXXFLAGS', '$USER_CXXFLAGS_GLOBAL')
  2083. append('CONLYFLAGS', flags_c_only, '$USER_CONLYFLAGS', '$USER_CONLYFLAGS_GLOBAL')
  2084. append('BC_CFLAGS', '$CFLAGS')
  2085. append('BC_CXXFLAGS', '$BC_CFLAGS', '$CXXFLAGS')
  2086. ucrt_include = os.path.join(self.tc.kit_includes, 'ucrt') if not self.tc.ide_msvs else "$(UniversalCRT_IncludePath.Split(';')[0].Replace('\\','/'))"
  2087. # clang-cl has '#include_next', and MSVC hasn't. It needs separately specified CRT and VC include directories for libc++ to include second in order standard C and C++ headers.
  2088. if not self.tc.use_clang:
  2089. append('CFLAGS', '/DY_UCRT_INCLUDE="%s"' % ucrt_include)
  2090. append('CFLAGS', '/DY_MSVC_INCLUDE="%s"' % vc_include)
  2091. emit_big('''
  2092. when ($NO_WSHADOW == "yes") {
  2093. C_WARNING_OPTS += /wd4456 /wd4457
  2094. }''')
  2095. if self.tc.use_clang:
  2096. # Though /w is intended to switch off all the warnings,
  2097. # it does not switch at least -Wregister and -Wreserved-user-defined-literal under clang-cl.
  2098. #
  2099. # Use -Wno-everything to force warning suppression.
  2100. emit_big('''
  2101. when ($NO_COMPILER_WARNINGS == "yes") {
  2102. C_WARNING_OPTS = /w
  2103. CXX_WARNING_OPTS = -Wno-everything
  2104. }''')
  2105. else:
  2106. emit_big('''
  2107. when ($NO_COMPILER_WARNINGS == "yes") {
  2108. C_WARNING_OPTS = /w
  2109. CXX_WARNING_OPTS =
  2110. }''')
  2111. emit_big('''
  2112. when ($NO_OPTIMIZE == "yes") {
  2113. OPTIMIZE = /Od
  2114. }''')
  2115. emit('SFDL_FLAG', ['/E', '/C', '/P', '/TP', '/Fi$SFDL_TMP_OUT'])
  2116. emit('WERROR_FLAG', '/WX')
  2117. emit('WERROR_MODE', self.tc.werror_mode)
  2118. if not self.tc.under_wine:
  2119. emit('CL_WRAPPER', '${YMAKE_PYTHON}', '${input:"build/scripts/fix_msvc_output.py"}', 'cl')
  2120. emit('ML_WRAPPER', '${YMAKE_PYTHON}', '${input:"build/scripts/fix_msvc_output.py"}', 'ml')
  2121. else:
  2122. emit('CL_WRAPPER')
  2123. emit('ML_WRAPPER')
  2124. emit('_SRC_C_NODEPS_CMD',
  2125. '${TOOLCHAIN_ENV} ${CL_WRAPPER} ${C_COMPILER} /c /Fo${OUTFILE} ${SRC} ${EXTRA_C_FLAGS} ${pre=/I :INC} '
  2126. '${CFLAGS} ${requirements;hide:CC_REQUIREMENTS} ${hide;kv:"soe"} ${hide;kv:"p CC"} ${hide;kv:"pc yellow"}'
  2127. )
  2128. emit('_SRC_CPP_CMD',
  2129. '${TOOLCHAIN_ENV} ${CL_WRAPPER} ${CXX_COMPILER} /c /Fo$_COMPILE_OUTPUTS ${input;msvs_source:SRC} '
  2130. '${EXTRA_C_FLAGS} ${pre=/I :_C__INCLUDE} ${CXXFLAGS} ${SRCFLAGS} ${_LANG_CFLAGS_VALUE} ${requirements;hide:CC_REQUIREMENTS} '
  2131. '${hide;kv:"soe"} ${hide;kv:"p CC"} ${hide;kv:"pc yellow"}'
  2132. )
  2133. emit('_SRC_C_CMD',
  2134. '${TOOLCHAIN_ENV} ${CL_WRAPPER} ${C_COMPILER} /c /Fo$_COMPILE_OUTPUTS ${input;msvs_source:SRC} '
  2135. '${EXTRA_C_FLAGS} ${pre=/I :_C__INCLUDE} ${CFLAGS} ${CONLYFLAGS} ${SRCFLAGS} ${requirements;hide:CC_REQUIREMENTS} '
  2136. '${hide;kv:"soe"} ${hide;kv:"p CC"} ${hide;kv:"pc yellow"}'
  2137. )
  2138. emit('_SRC_M_CMD', '$_EMPTY_CMD')
  2139. emit('_SRC_MASM_CMD',
  2140. '${cwd:ARCADIA_BUILD_ROOT} ${TOOLCHAIN_ENV} ${ML_WRAPPER} ${MASM_COMPILER} ${MASMFLAGS} ${SRCFLAGS} ' +
  2141. masm_io + '${requirements;hide:CC_REQUIREMENTS} ${kv;hide:"p AS"} ${kv;hide:"pc yellow"}'
  2142. )
  2143. class MSVCLinker(MSVC, Linker):
  2144. def __init__(self, tc, build):
  2145. MSVC.__init__(self, tc, build)
  2146. Linker.__init__(self, tc, build)
  2147. def print_linker(self):
  2148. super(MSVCLinker, self).print_linker()
  2149. target = self.build.target
  2150. linker = self.tc.link
  2151. linker_lib = self.tc.lib
  2152. arch = select(no_default=True, selectors=(
  2153. (target.is_x86, 'x86'),
  2154. (target.is_x86_64, 'x64'),
  2155. (target.is_armv7, 'arm'),
  2156. ))
  2157. libpaths = []
  2158. if not self.tc.ide_msvs:
  2159. if self.tc.kit_libs:
  2160. libpaths.extend([os.path.join(self.tc.kit_libs, name, arch) for name in ('um', 'ucrt')])
  2161. libpaths.append(os.path.join(self.tc.vc_root, 'lib', arch))
  2162. ignored_errors = [
  2163. 4221
  2164. ]
  2165. flag_machine = '/MACHINE:{}'.format(arch.upper())
  2166. flags_ignore = ['/IGNORE:{}'.format(code) for code in ignored_errors]
  2167. flags_common = ['/NOLOGO', '/ERRORREPORT:PROMPT', '/SUBSYSTEM:CONSOLE', '/TLBID:1', '$MSVC_DYNAMICBASE', '/NXCOMPAT']
  2168. flags_common += flags_ignore
  2169. flags_common += [flag_machine]
  2170. flags_debug_only = []
  2171. flags_release_only = []
  2172. if self.tc.ide_msvs:
  2173. flags_common += ['/INCREMENTAL']
  2174. else:
  2175. flags_common += ['/INCREMENTAL:NO']
  2176. if self.tc.use_clang:
  2177. flags_debug_only.append('/STACK:4194304')
  2178. if is_negative_str(preset('NO_DEBUGINFO', 'no')):
  2179. if self.tc.ide_msvs:
  2180. flags_debug_only.append('/DEBUG:FASTLINK' if not self.tc.use_clang else '/DEBUG')
  2181. flags_release_only.append('/DEBUG')
  2182. else:
  2183. # No FASTLINK for ya make, because resulting PDB would require .obj files (build_root's) to persist
  2184. flags_common.append('/DEBUG')
  2185. if not self.tc.ide_msvs:
  2186. flags_common += ['/LIBPATH:"{}"'.format(path) for path in libpaths]
  2187. link_flags_debug = flags_common + flags_debug_only
  2188. link_flags_release = flags_common + flags_release_only
  2189. link_flags_lib = flags_ignore + [flag_machine]
  2190. stdlibs = [
  2191. 'advapi32.lib',
  2192. 'comdlg32.lib',
  2193. 'crypt32.lib',
  2194. 'dnsapi.lib',
  2195. 'gdi32.lib',
  2196. 'iphlpapi.lib',
  2197. 'kernel32.lib',
  2198. 'mswsock.lib',
  2199. 'ole32.lib',
  2200. 'oleaut32.lib',
  2201. 'psapi.lib',
  2202. 'rpcrt4.lib',
  2203. 'secur32.lib',
  2204. 'shell32.lib',
  2205. 'shlwapi.lib',
  2206. 'user32.lib',
  2207. 'userenv.lib',
  2208. 'uuid.lib',
  2209. 'version.lib',
  2210. 'winmm.lib',
  2211. 'winspool.lib',
  2212. 'ws2_32.lib',
  2213. ]
  2214. emit('LINK_LIB_CMD', linker_lib)
  2215. emit('LINK_EXE_CMD', linker)
  2216. emit('LINK_LIB_FLAGS', link_flags_lib)
  2217. emit('LINK_EXE_FLAGS_RELEASE', link_flags_release)
  2218. emit('LINK_EXE_FLAGS_DEBUG', link_flags_debug)
  2219. emit('LINK_STDLIBS', stdlibs)
  2220. emit('LDFLAGS_GLOBAL', '')
  2221. emit('LDFLAGS', '')
  2222. emit('OBJADDE', '')
  2223. if self.build.is_release:
  2224. emit('LINK_EXE_FLAGS_PER_TYPE', '$LINK_EXE_FLAGS_RELEASE')
  2225. if self.build.is_debug:
  2226. emit('LINK_EXE_FLAGS_PER_TYPE', '$LINK_EXE_FLAGS_DEBUG')
  2227. if self.build.is_ide and self.tc.ide_msvs:
  2228. emit('LINK_EXE_FLAGS_PER_TYPE', '@[debug|$LINK_EXE_FLAGS_DEBUG]@[release|$LINK_EXE_FLAGS_RELEASE]')
  2229. emit('LINK_EXE_FLAGS', '$LINK_EXE_FLAGS_PER_TYPE')
  2230. emit('LINK_IMPLIB_VALUE')
  2231. emit('LINK_IMPLIB', '/IMPLIB:${output;noext;rootrel;pre=$MODULE_PREFIX:REALPRJNAME.lib}')
  2232. if is_negative_str(preset('NO_DEBUGINFO', 'no')):
  2233. emit('LINK_EXTRA_OUTPUT', '/PDB:${output;noext;rootrel;pre=$MODULE_PREFIX:REALPRJNAME.pdb}')
  2234. else:
  2235. emit('LINK_EXTRA_OUTPUT')
  2236. if not self.tc.under_wine:
  2237. emit('LIB_WRAPPER', '${YMAKE_PYTHON}', '${input:"build/scripts/fix_msvc_output.py"}', 'lib')
  2238. emit('LINK_WRAPPER', '${YMAKE_PYTHON}', '${input:"build/scripts/fix_msvc_output.py"}', 'link')
  2239. else:
  2240. emit('LIB_WRAPPER')
  2241. emit('LINK_WRAPPER')
  2242. emit('LINK_WRAPPER_DYNLIB', '${YMAKE_PYTHON}', '${input:"build/scripts/link_dyn_lib.py"}', '--arch', 'WINDOWS', '--target', '$TARGET')
  2243. emit_big('''
  2244. EXPORTS_VALUE=
  2245. when ($EXPORTS_FILE) {
  2246. LINK_IMPLIB_VALUE=$LINK_IMPLIB
  2247. EXPORTS_VALUE=/DEF:${input:EXPORTS_FILE}
  2248. }''')
  2249. emit("GENERATE_MF_CMD", '$YMAKE_PYTHON ${input:"build/scripts/generate_mf.py"}',
  2250. '--build-root $ARCADIA_BUILD_ROOT --module-name $REALPRJNAME -o ${output;pre=$MODULE_PREFIX;suf=$MODULE_SUFFIX.mf:REALPRJNAME}',
  2251. '-t $MODULE_TYPE --ya-start-command-file -Ya,lics $LICENSE_NAMES -Ya,peers ${rootrel:PEERS} -Ya,credits ${input:CREDITS_TEXTS_FILE} $CREDITS_FLAGS --ya-end-command-file',
  2252. )
  2253. # we split srcs_global into two groups: libs and objs
  2254. # # each group can be in its own command file
  2255. # first group need /WHOLEARCHIVE: prefix which will be added in fix_msvc_output.py or run_msvc_wine.py
  2256. # the tail of link commands will be added in the third command file
  2257. srcs_globals = '--start-wa --ya-start-command-file ${qe;rootrel;ext=.lib:SRCS_GLOBAL} --ya-end-command-file --end-wa \
  2258. --ya-start-command-file ${qe;rootrel;ext=.obj:SRCS_GLOBAL} --ya-end-command-file'
  2259. emit('REAL_LINK_DYN_LIB_CMDLINE', '${TOOLCHAIN_ENV} ${cwd:ARCADIA_BUILD_ROOT} ${LINK_WRAPPER} ${LINK_WRAPPER_DYNLIB} ${LINK_EXE_CMD} \
  2260. ${LINK_IMPLIB_VALUE} /DLL /OUT:${qe;rootrel:TARGET} ${LINK_EXTRA_OUTPUT} ${EXPORTS_VALUE} \
  2261. ${pre=--whole-archive-peers :WHOLE_ARCHIVE_PEERS} \
  2262. ${pre=--whole-archive-libs :_WHOLE_ARCHIVE_LIBS_VALUE_GLOBAL}',
  2263. srcs_globals, '--ya-start-command-file ${VCS_C_OBJ_RR} ${qe;rootrel:AUTO_INPUT} ${qe;rootrel;ext=.lib:PEERS} ${qe;rootrel;ext=.dll;noext;suf=.lib:PEERS} \
  2264. $LINK_EXE_FLAGS $LINK_STDLIBS $LDFLAGS $LDFLAGS_GLOBAL $OBJADDE --ya-end-command-file')
  2265. emit('REAL_LINK_DYN_LIB', '$REAL_LINK_DYN_LIB_IMPL($_WHOLE_ARCHIVE_PEERS_VALUE)')
  2266. emit('SWIG_DLL_JAR_CMD', '$GENERATE_MF && $GENERATE_VCS_C_INFO_NODEP && $REAL_SWIG_DLL_JAR_CMD')
  2267. head_link_lib = '${TOOLCHAIN_ENV} ${cwd:ARCADIA_BUILD_ROOT} ${LIB_WRAPPER} ${LINK_LIB_CMD}'
  2268. tail_link_lib = '--ya-start-command-file ${qe;rootrel:AUTO_INPUT} $LINK_LIB_FLAGS --ya-end-command-file \
  2269. ${requirements;hide:LIB_REQUIREMENTS} ${hide;kv:"soe"} ${hide;kv:"p AR"} ${hide;kv:"pc light-red"}'
  2270. emit('LINK_LIB', '${GENERATE_MF} &&', head_link_lib, '/OUT:${qe;rootrel:TARGET}', tail_link_lib)
  2271. emit('GLOBAL_LINK_LIB', head_link_lib, '/OUT:${qe;rootrel:GLOBAL_TARGET}', tail_link_lib)
  2272. emit('LINK_EXE_CMDLINE', '${GENERATE_MF} && $GENERATE_VCS_C_INFO_NODEP && ${TOOLCHAIN_ENV} ${cwd:ARCADIA_BUILD_ROOT} ${LINK_WRAPPER}',
  2273. '${LINK_EXE_CMD} /OUT:${qe;rootrel:TARGET} \
  2274. ${pre=--whole-archive-peers :WHOLE_ARCHIVE_PEERS} \
  2275. ${pre=--whole-archive-libs :_WHOLE_ARCHIVE_LIBS_VALUE_GLOBAL} ',
  2276. '${LINK_EXTRA_OUTPUT}', srcs_globals, '--ya-start-command-file ${VCS_C_OBJ_RR} ${qe;rootrel:AUTO_INPUT} $LINK_EXE_FLAGS $LINK_STDLIBS $LDFLAGS $LDFLAGS_GLOBAL $OBJADDE \
  2277. ${qe;rootrel;ext=.lib:PEERS} ${qe;rootrel;ext=.dll;noext;suf=.lib:PEERS} --ya-end-command-file \
  2278. ${hide;kv:"soe"} ${hide;kv:"p LD"} ${requirements;hide:LD_REQUIREMENTS} ${hide;kv:"pc blue"}')
  2279. emit('LINK_EXE', '$LINK_EXE_IMPL($_WHOLE_ARCHIVE_PEERS_VALUE)')
  2280. emit('LINK_DYN_LIB', '${GENERATE_MF} && $GENERATE_VCS_C_INFO_NODEP && $REAL_LINK_DYN_LIB ${hide;kv:"soe"} ${hide;kv:"p LD"} ${requirements;hide:LD_REQUIREMENTS} ${hide;kv:"pc blue"}')
  2281. emit('LINK_EXEC_DYN_LIB_CMDLINE', '${GENERATE_MF} && $GENERATE_VCS_C_INFO_NODEP && ${TOOLCHAIN_ENV} ${cwd:ARCADIA_BUILD_ROOT} ${LINK_WRAPPER} ${LINK_WRAPPER_DYNLIB} ${LINK_EXE_CMD} \
  2282. /OUT:${qe;rootrel:TARGET} ${LINK_EXTRA_OUTPUT} ${EXPORTS_VALUE} \
  2283. ${pre=--whole-archive-peers :WHOLE_ARCHIVE_PEERS} \
  2284. ${pre=--whole-archive-libs :_WHOLE_ARCHIVE_LIBS_VALUE_GLOBAL}', srcs_globals,
  2285. '--ya-start-command-file ${VCS_C_OBJ_RR} ${qe;rootrel:AUTO_INPUT} ${qe;rootrel;ext=.lib:PEERS} ${qe;rootrel;ext=.dll;noext;suf=.lib:PEERS} \
  2286. $LINK_EXE_FLAGS $LINK_STDLIBS $LDFLAGS $LDFLAGS_GLOBAL $OBJADDE --ya-end-command-file \
  2287. ${hide;kv:"soe"} ${hide;kv:"p LD"} ${requirements;hide:LD_REQUIREMENTS} ${hide;kv:"pc blue"}')
  2288. emit('LINK_EXEC_DYN_LIB', '$LINK_EXEC_DYN_LIB_IMPL($_WHOLE_ARCHIVE_PEERS_VALUE)')
  2289. emit('LINK_GLOBAL_FAT_OBJECT', '${TOOLCHAIN_ENV} ${cwd:ARCADIA_BUILD_ROOT} ${LIB_WRAPPER} ${LINK_LIB_CMD} /OUT:${qe;rootrel:TARGET} \
  2290. --ya-start-command-file ${qe;rootrel;ext=.lib:SRCS_GLOBAL} ${qe;rootrel;ext=.obj:SRCS_GLOBAL} ${qe;rootrel:AUTO_INPUT} $LINK_LIB_FLAGS --ya-end-command-file')
  2291. emit('LINK_PEERS_FAT_OBJECT', '${TOOLCHAIN_ENV} ${cwd:ARCADIA_BUILD_ROOT} ${LIB_WRAPPER} ${LINK_LIB_CMD} /OUT:${qe;rootrel;output:REALPRJNAME.lib} \
  2292. --ya-start-command-file ${qe;rootrel:PEERS} $LINK_LIB_FLAGS --ya-end-command-file')
  2293. emit('LINK_FAT_OBJECT', '${GENERATE_MF} && $GENERATE_VCS_C_INFO_NODEP && $LINK_GLOBAL_FAT_OBJECT && $LINK_PEERS_FAT_OBJECT ${kv;hide:"p LD"} ${requirements;hide:LD_REQUIREMENTS} ${kv;hide:"pc light-blue"} ${kv;hide:"show_out"}') # noqa E501
  2294. # TODO(somov): Rename!
  2295. Compilers = {
  2296. 'gnu': (GnuToolchain, GnuCompiler, LD),
  2297. 'clang': (GnuToolchain, GnuCompiler, LD),
  2298. 'xcode': (GnuToolchain, GnuCompiler, LD),
  2299. 'msvc': (MSVCToolchain, MSVCCompiler, MSVCLinker),
  2300. }
  2301. class Ragel(object):
  2302. def __init__(self):
  2303. self.rlgen_flags = []
  2304. self.ragel_flags = []
  2305. self.ragel6_flags = []
  2306. def configure_toolchain(self, build, compiler):
  2307. if isinstance(compiler, MSVCCompiler):
  2308. self.set_default_flags(optimized=False)
  2309. elif isinstance(compiler, GnuCompiler):
  2310. self.set_default_flags(optimized=build.is_release and not build.is_sanitized)
  2311. else:
  2312. raise ConfigureError('Unexpected compiler {}'.format(compiler))
  2313. def set_default_flags(self, optimized):
  2314. if optimized:
  2315. self.rlgen_flags.append('-G2')
  2316. self.ragel6_flags.append('-CG2')
  2317. else:
  2318. self.rlgen_flags.append('-T0')
  2319. self.ragel6_flags.append('-CT0')
  2320. def print_variables(self):
  2321. emit('RLGEN_FLAGS', self.rlgen_flags)
  2322. emit('RAGEL_FLAGS', self.ragel_flags)
  2323. emit('RAGEL6_FLAGS', self.ragel6_flags)
  2324. class Python(object):
  2325. def __init__(self, tc):
  2326. self.python = None
  2327. self.flags = None
  2328. self.ldflags = None
  2329. self.libraries = None
  2330. self.includes = None
  2331. self.tc = tc
  2332. def configure_posix(self, python=None, python_config=None):
  2333. python = python or preset('PYTHON_BIN') or which('python')
  2334. python_config = python_config or preset('PYTHON_CONFIG') or which('python-config')
  2335. if python is None or python_config is None:
  2336. return
  2337. # python-config dumps each option on one line in the specified order
  2338. config = get_stdout([python_config, '--cflags', '--ldflags', '--includes']) or ''
  2339. config = config.split('\n')
  2340. if len(config) < 3:
  2341. return
  2342. self.python = python
  2343. self.flags = config[0]
  2344. self.ldflags = config[1]
  2345. self.includes = config[2]
  2346. # Do not split libraries from ldflags.
  2347. # They are not used separately and get overriden together, so it is safe.
  2348. # TODO(somov): Удалить эту переменную и PYTHON_LIBRARIES из makelist-ов.
  2349. self.libraries = ''
  2350. if preset('USE_ARCADIA_PYTHON') == 'no' and not preset('USE_SYSTEM_PYTHON') and not self.tc.os_sdk_local:
  2351. raise Exception("Use fixed python (see https://clubs.at.yandex-team.ru/arcadia/15392) or set OS_SDK=local flag")
  2352. def print_variables(self):
  2353. variables = Variables({
  2354. 'PYTHON_BIN': self.python,
  2355. 'PYTHON_FLAGS': self.flags,
  2356. 'PYTHON_LDFLAGS': self.ldflags,
  2357. 'PYTHON_LIBRARIES': self.libraries,
  2358. 'PYTHON_INCLUDE': self.includes
  2359. })
  2360. variables.update_from_presets()
  2361. variables.reset_if_any(reset_value='PYTHON-NOT-FOUND')
  2362. variables.emit()
  2363. class Perl(object):
  2364. # Parse (key, value) from "version='5.26.0';" lines
  2365. PERL_CONFIG_RE = re.compile(r"^(?P<key>\w+)='(?P<value>.*)';$", re.MULTILINE)
  2366. def __init__(self):
  2367. self.perl = None
  2368. self.version = None
  2369. self.privlib = None
  2370. self.archlib = None
  2371. def configure_local(self, perl=None):
  2372. self.perl = perl or preset('PERL') or which('perl')
  2373. if self.perl is None:
  2374. return
  2375. # noinspection PyTypeChecker
  2376. config = dict(self._iter_config(['version', 'privlibexp', 'archlibexp']))
  2377. self.version = config.get('version')
  2378. self.privlib = config.get('privlibexp')
  2379. self.archlib = config.get('archlibexp')
  2380. def print_variables(self, prefix=''):
  2381. variables = Variables({
  2382. prefix + 'PERL': self.perl,
  2383. prefix + 'PERL_VERSION': self.version,
  2384. prefix + 'PERL_PRIVLIB': self.privlib,
  2385. prefix + 'PERL_ARCHLIB': self.archlib,
  2386. })
  2387. variables.reset_if_any(reset_value='PERL-NOT-FOUND')
  2388. variables.emit(with_ignore_comment=variables.keys())
  2389. def _iter_config(self, config_keys):
  2390. # Run perl -V:version -V:etc...
  2391. perl_config = [self.perl] + ['-V:{}'.format(key) for key in config_keys]
  2392. config = six.ensure_str(get_stdout(perl_config) or '')
  2393. start = 0
  2394. while True:
  2395. match = Perl.PERL_CONFIG_RE.search(config, start)
  2396. if match is None:
  2397. break
  2398. yield match.group('key', 'value')
  2399. start = match.end()
  2400. class Setting(object):
  2401. def __init__(self, key, auto=None, convert=None, rewrite=False):
  2402. self.key = key
  2403. self.auto = auto
  2404. self.convert = convert
  2405. self.preset = preset(key)
  2406. self.from_user = self.preset is not None
  2407. self.rewrite = rewrite
  2408. self._value = Setting.no_value
  2409. @property
  2410. def value(self):
  2411. if self._value is Setting.no_value:
  2412. self._value = self.calculate_value()
  2413. return self._value
  2414. def calculate_value(self):
  2415. if not self.from_user:
  2416. return self.auto if not callable(self.auto) else self.auto()
  2417. else:
  2418. return self.preset if not self.convert else self.convert(self.preset)
  2419. @value.setter
  2420. def value(self, value):
  2421. if self.from_user:
  2422. raise ConfigureError("Variable {key} already set by user to {old}. Can not change it's value to {new}".format(key=self.key, old=self._value, new=value))
  2423. self._value = value
  2424. def emit(self):
  2425. if not self.from_user or self.rewrite:
  2426. emit(self.key, self.value)
  2427. no_value = object()
  2428. class Cuda(object):
  2429. def __init__(self, build):
  2430. """
  2431. :type build: Build
  2432. """
  2433. self.build = build
  2434. self.have_cuda = Setting('HAVE_CUDA', auto=self.auto_have_cuda, convert=to_bool)
  2435. self.cuda_root = Setting('CUDA_ROOT')
  2436. self.cuda_version = Setting('CUDA_VERSION', auto=self.auto_cuda_version, convert=self.convert_major_version, rewrite=True)
  2437. self.use_arcadia_cuda = Setting('USE_ARCADIA_CUDA', auto=self.auto_use_arcadia_cuda, convert=to_bool)
  2438. self.use_arcadia_cuda_host_compiler = Setting('USE_ARCADIA_CUDA_HOST_COMPILER', auto=self.auto_use_arcadia_cuda_host_compiler, convert=to_bool)
  2439. self.cuda_use_clang = Setting('CUDA_USE_CLANG', auto=False, convert=to_bool)
  2440. self.cuda_host_compiler = Setting('CUDA_HOST_COMPILER', auto=self.auto_cuda_host_compiler)
  2441. self.cuda_host_compiler_env = Setting('CUDA_HOST_COMPILER_ENV')
  2442. self.cuda_host_msvc_version = Setting('CUDA_HOST_MSVC_VERSION')
  2443. self.cuda_nvcc_flags = Setting('CUDA_NVCC_FLAGS', auto=[])
  2444. self.peerdirs = ['build/platform/cuda']
  2445. self.nvcc_std = '-std=c++14'
  2446. if self.build.tc.type == 'msvc':
  2447. self.nvcc_std = self.nvcc_std.replace('-std=', '/std:')
  2448. self.nvcc_flags = []
  2449. if not self.have_cuda.value:
  2450. return
  2451. if self.cuda_host_compiler.value:
  2452. self.nvcc_flags.append('--compiler-bindir=$CUDA_HOST_COMPILER')
  2453. if self.use_arcadia_cuda.value:
  2454. self.cuda_root.value = '$CUDA_RESOURCE_GLOBAL'
  2455. if self.build.target.is_linux_x86_64 and self.build.tc.is_clang:
  2456. # TODO(somov): Эта настройка должна приезжать сюда автоматически из другого места
  2457. self.nvcc_flags.append('-I$OS_SDK_ROOT/usr/include/x86_64-linux-gnu')
  2458. def print_(self):
  2459. self.print_variables()
  2460. self.print_macros()
  2461. def print_variables(self):
  2462. self.have_cuda.emit()
  2463. if not self.have_cuda.value:
  2464. return
  2465. if self.use_arcadia_cuda.value and self.cuda_host_compiler.value is None:
  2466. logger.warning('$USE_ARCADIA_CUDA is set, but no $CUDA_HOST_COMPILER')
  2467. self.setup_vc_root()
  2468. self.cuda_root.emit()
  2469. self.cuda_version.emit()
  2470. self.use_arcadia_cuda.emit()
  2471. self.use_arcadia_cuda_host_compiler.emit()
  2472. self.cuda_use_clang.emit()
  2473. self.cuda_host_compiler.emit()
  2474. self.cuda_host_compiler_env.emit()
  2475. self.cuda_host_msvc_version.emit()
  2476. self.cuda_nvcc_flags.emit()
  2477. emit('NVCC_UNQUOTED', self.build.host.exe('$CUDA_ROOT', 'bin', 'nvcc'))
  2478. emit('NVCC', '${quo:NVCC_UNQUOTED}')
  2479. emit('NVCC_STD', self.nvcc_std)
  2480. emit('NVCC_FLAGS', self.nvcc_flags, '$CUDA_NVCC_FLAGS')
  2481. emit('NVCC_OBJ_EXT', '.o' if not self.build.target.is_windows else '.obj')
  2482. def print_macros(self):
  2483. if not self.cuda_use_clang.value:
  2484. cmd = '$YMAKE_PYTHON ${input:"build/scripts/compile_cuda.py"} ${tool:"tools/mtime0"} $NVCC $NVCC_FLAGS -c ${input:SRC} -o ${output;suf=${OBJ_SUF}${NVCC_OBJ_EXT}:SRC} ${pre=-I:_C__INCLUDE} --cflags $C_FLAGS_PLATFORM $CXXFLAGS $NVCC_STD $SRCFLAGS ${input;hide:"build/platform/cuda/cuda_runtime_include.h"} $CUDA_HOST_COMPILER_ENV ${requirements;hide:CC_REQUIREMENTS} ${kv;hide:"p CC"} ${kv;hide:"pc light-green"}' # noqa E501
  2485. else:
  2486. cmd = '$CXX_COMPILER --cuda-path=$CUDA_ROOT $C_FLAGS_PLATFORM -c ${input:SRC} -o ${output;suf=${OBJ_SUF}${NVCC_OBJ_EXT}:SRC} ${pre=-I:_C__INCLUDE} $CXXFLAGS $SRCFLAGS $TOOLCHAIN_ENV ${requirements;hide:CC_REQUIREMENTS} ${kv;hide:"p CU"} ${kv;hide:"pc green"}' # noqa E501
  2487. emit('_SRC_CU_CMD', cmd)
  2488. emit('_SRC_CU_PEERDIR', ' '.join(sorted(self.peerdirs)))
  2489. def have_cuda_in_arcadia(self):
  2490. host, target = self.build.host_target
  2491. if not any((host.is_linux_x86_64, host.is_macos_x86_64, host.is_windows_x86_64, host.is_linux_powerpc)):
  2492. return False
  2493. if host != target:
  2494. if not(host.is_linux_x86_64 and target.is_linux_armv8):
  2495. return False
  2496. if not self.cuda_version.from_user:
  2497. return False
  2498. if self.cuda_version.value not in ('11.3',):
  2499. raise ConfigureError('Only CUDA 11.3 are available for cross compilation from linux-x86 to linux-aarch64.\nUse -DCUDA_VERSION=11.3 flag.')
  2500. if self.cuda_version.value in ('8.0', '9.0', '9.1', '9.2', '10.0'):
  2501. raise ConfigureError('CUDA versions 8.x, 9.x and 10.0 are no longer supported.\nSee DEVTOOLS-7108.')
  2502. if self.cuda_version.value in ('10.1', '11.0', '11.1', '11.3', '11.4'):
  2503. return True
  2504. return False
  2505. def auto_have_cuda(self):
  2506. if is_positive('MUSL'):
  2507. return False
  2508. if self.build.is_sanitized:
  2509. return False
  2510. return self.cuda_root.from_user or self.use_arcadia_cuda.value and self.have_cuda_in_arcadia()
  2511. def auto_cuda_version(self):
  2512. if self.use_arcadia_cuda.value:
  2513. return '10.1'
  2514. if not self.have_cuda.value:
  2515. return None
  2516. nvcc_exe = self.build.host.exe(os.path.expanduser(self.cuda_root.value), 'bin', 'nvcc')
  2517. def error():
  2518. raise ConfigureError('Failed to get CUDA version from {}'.format(nvcc_exe))
  2519. version_output = get_stdout([nvcc_exe, '--version']) or error()
  2520. match = re.search(r'^Cuda compilation tools, release (\d+)\.\d+,', version_output, re.MULTILINE) or error()
  2521. return match.group(1)
  2522. def convert_major_version(self, value):
  2523. if value == '10':
  2524. return '10.1'
  2525. elif value == '11':
  2526. return '11.3'
  2527. else:
  2528. return value
  2529. def auto_use_arcadia_cuda(self):
  2530. return not self.cuda_root.from_user
  2531. def auto_use_arcadia_cuda_host_compiler(self):
  2532. return not self.cuda_host_compiler.from_user and not self.cuda_use_clang.value
  2533. def auto_cuda_host_compiler(self):
  2534. if not self.use_arcadia_cuda_host_compiler.value:
  2535. return None
  2536. host, target = self.build.host_target
  2537. if host.is_windows_x86_64 and target.is_windows_x86_64:
  2538. return self.cuda_windows_host_compiler()
  2539. return select((
  2540. (host.is_linux_x86_64 and target.is_linux_x86_64, '$CUDA_HOST_TOOLCHAIN_RESOURCE_GLOBAL/bin/clang'),
  2541. (host.is_linux_x86_64 and target.is_linux_armv8, '$CUDA_HOST_TOOLCHAIN_RESOURCE_GLOBAL/bin/clang'),
  2542. (host.is_linux_powerpc and target.is_linux_powerpc, '$CUDA_HOST_TOOLCHAIN_RESOURCE_GLOBAL/bin/clang'),
  2543. (host.is_macos_x86_64 and target.is_macos_x86_64, '$CUDA_HOST_TOOLCHAIN_RESOURCE_GLOBAL/usr/bin/clang'),
  2544. ))
  2545. def cuda_windows_host_compiler(self):
  2546. vc_version = '14.28.29910'
  2547. env = {
  2548. 'Y_VC_Version': vc_version,
  2549. 'Y_VC_Root': '$CUDA_HOST_TOOLCHAIN_RESOURCE_GLOBAL/VC/Tools/MSVC/{}'.format(vc_version),
  2550. 'Y_SDK_Version': self.build.tc.sdk_version,
  2551. 'Y_SDK_Root': '$WINDOWS_KITS_RESOURCE_GLOBAL',
  2552. }
  2553. if not self.build.tc.ide_msvs:
  2554. self.peerdirs.append('build/platform/msvc')
  2555. self.cuda_host_compiler_env.value = format_env(env)
  2556. self.cuda_host_msvc_version.value = vc_version
  2557. return '%(Y_VC_Root)s/bin/HostX64/x64/cl.exe' % env
  2558. def setup_vc_root(self):
  2559. if not self.cuda_host_compiler.from_user:
  2560. return # Already set in cuda_windows_host_compiler()
  2561. if self.cuda_host_compiler_env.from_user:
  2562. return # We won't override user setting
  2563. def is_root(dir):
  2564. return all(os.path.isdir(os.path.join(dir, name)) for name in ('bin', 'include', 'lib'))
  2565. def get_root():
  2566. path, old_path = os.path.normpath(self.cuda_host_compiler.value), None
  2567. while path != old_path:
  2568. if is_root(path):
  2569. return path
  2570. path, old_path = os.path.dirname(path), path
  2571. vc_root = get_root()
  2572. if vc_root:
  2573. self.cuda_host_compiler_env.value = format_env({'Y_VC_Root': vc_root})
  2574. class CuDNN(object):
  2575. def __init__(self, cuda):
  2576. """
  2577. :type cuda: Cuda
  2578. """
  2579. self.cuda = cuda
  2580. self.cudnn_version = Setting('CUDNN_VERSION', auto=self.auto_cudnn_version)
  2581. def have_cudnn(self):
  2582. return self.cudnn_version.value in ('7.6.5', '8.0.5')
  2583. def auto_cudnn_version(self):
  2584. return '7.6.5'
  2585. def print_(self):
  2586. if self.cuda.have_cuda.value and self.have_cudnn():
  2587. self.cudnn_version.emit()
  2588. def print_swig_config():
  2589. def get_swig_tool():
  2590. tool = preset('USER_SWIG_TOOL')
  2591. if not tool:
  2592. tool = which('swig')
  2593. if not tool:
  2594. raise ConfigureError('SWIG_TOOL is not specified and "swig" is not found in PATH')
  2595. return os.path.abspath(tool)
  2596. def get_swig_library(tool):
  2597. library = preset('USER_SWIG_LIBRARY')
  2598. if not library:
  2599. library, code = get_stdout_and_code((tool, '-swiglib'))
  2600. if code != 0:
  2601. raise ConfigureError('SWIG_LIBRARY is not specified and "{} -swiglib" failed'.format(tool))
  2602. library = library.split('\n')[0]
  2603. return os.path.abspath(library)
  2604. use_local_swig = to_bool(preset('USER_USE_LOCAL_SWIG'), False) or bool(preset('USER_SWIG_TOOL'))
  2605. if use_local_swig:
  2606. tool = get_swig_tool()
  2607. library = get_swig_library(tool)
  2608. emit('USE_LOCAL_SWIG', True)
  2609. emit('SWIG_TOOL', tool)
  2610. emit('SWIG_LIBRARY', library)
  2611. def main():
  2612. options = opts()
  2613. arcadia = Arcadia(options.arcadia_root)
  2614. ymake = YMake(arcadia)
  2615. ymake.print_core_conf()
  2616. ymake.print_presets()
  2617. ymake.print_settings()
  2618. build = Build(arcadia, options.build_type, options.toolchain_params, force_ignore_local_files=not options.local_distbuild)
  2619. build.print_build()
  2620. emit_with_ignore_comment('CONF_SCRIPT_DEPENDS', __file__)
  2621. if __name__ == '__main__':
  2622. main()