ymake_conf.py 97 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573
  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', 'armv7ahf', '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', 'armv7ahf', 'armv7a_cortex_a9', 'armv7ahf_cortex_a35', 'armv7ahf_cortex_a53')
  48. self.is_armv7hf = self.arch in ('armv7ahf', 'armv7ahf_cortex_a35', 'armv7ahf_cortex_a53')
  49. self.is_rv32imc = self.arch in ('riscv32_esp',)
  50. self.is_riscv32 = self.is_rv32imc
  51. self.is_nds32 = self.arch in ('nds32le_elf_mculib_v5f',)
  52. self.armv7_float_abi = None
  53. if self.is_armv7:
  54. if self.is_armv7hf:
  55. self.armv7_float_abi = 'hard'
  56. else:
  57. self.armv7_float_abi = 'softfp'
  58. self.is_cortex_a9 = self.arch in ('armv7a_cortex_a9',)
  59. self.is_cortex_a35 = self.arch in ('armv7ahf_cortex_a35', 'armv8a_cortex_a35')
  60. self.is_cortex_a53 = self.arch in ('armv7ahf_cortex_a53', 'armv8a_cortex_a53')
  61. self.is_cortex_m33 = self.arch in ('armv8m_cortex_m33',)
  62. self.is_power8le = self.arch == 'ppc64le'
  63. self.is_power9le = self.arch == 'power9le'
  64. self.is_powerpc = self.is_power8le or self.is_power9le
  65. self.is_32_bit = self.is_x86 or self.is_armv7 or self.is_armv8m or self.is_riscv32 or self.is_nds32
  66. self.is_64_bit = self.is_x86_64 or self.is_armv8 or self.is_powerpc
  67. assert self.is_32_bit or self.is_64_bit
  68. assert not (self.is_32_bit and self.is_64_bit)
  69. self.is_linux = self.os == 'linux' or 'yocto' in self.os
  70. self.is_linux_x86_64 = self.is_linux and self.is_x86_64
  71. self.is_linux_armv8 = self.is_linux and self.is_armv8
  72. self.is_linux_armv7 = self.is_linux and self.is_armv7
  73. self.is_linux_power8le = self.is_linux and self.is_power8le
  74. self.is_linux_power9le = self.is_linux and self.is_power9le
  75. self.is_linux_powerpc = self.is_linux_power8le or self.is_linux_power9le
  76. self.is_macos = self.os == 'macos'
  77. self.is_macos_x86_64 = self.is_macos and self.is_x86_64
  78. self.is_macos_arm64 = self.is_macos and self.is_arm64
  79. self.is_iossim = self.os == 'iossim' or (self.os == 'ios' and self.is_intel)
  80. self.is_ios = self.os == 'ios' or self.is_iossim
  81. self.is_apple = self.is_macos or self.is_ios
  82. self.is_windows = self.os == 'windows'
  83. self.is_windows_x86_64 = self.is_windows and self.is_x86_64
  84. self.is_android = self.os == 'android'
  85. if self.is_android:
  86. # This is default Android API level unless `-DANDROID_API` is specified in cmdline
  87. default_android_api = 21
  88. self.android_api = int(preset('ANDROID_API', default_android_api))
  89. self.is_cygwin = self.os == 'cygwin'
  90. self.is_yocto = self.os == 'yocto'
  91. self.is_none = self.os == 'none'
  92. self.is_posix = self.is_linux or self.is_apple or self.is_android or self.is_cygwin or self.is_yocto
  93. @staticmethod
  94. def from_json(data):
  95. name = data.get('visible_name', data['toolchain'])
  96. return Platform(name, os=data['os'], arch=data['arch'])
  97. @property
  98. def os_variables(self):
  99. # 'LINUX' variable, for backward compatibility
  100. yield self.os.upper()
  101. # 'OS_LINUX' variable
  102. yield 'OS_{}'.format(self.os.upper())
  103. # yocto is linux
  104. if 'yocto' in self.os:
  105. yield 'LINUX'
  106. yield 'OS_LINUX'
  107. if self.is_macos:
  108. yield 'DARWIN'
  109. yield 'OS_DARWIN'
  110. if self.is_iossim:
  111. yield 'IOS'
  112. yield 'OS_IOS'
  113. yield 'OS_IOSSIM'
  114. @property
  115. def arch_variables(self):
  116. return select_multiple((
  117. (self.is_i386 or self.is_i686, 'ARCH_I386'),
  118. (self.is_i686, 'ARCH_I686'),
  119. (self.is_x86_64, 'ARCH_X86_64'),
  120. (self.is_armv7, 'ARCH_ARM7'),
  121. (self.is_armv7_neon, 'ARCH_ARM7_NEON'),
  122. (self.is_armv8, 'ARCH_ARM64'),
  123. (self.is_armv8m, 'ARCH_ARM8M'),
  124. (self.is_arm, 'ARCH_ARM'),
  125. (self.is_linux_armv8 or self.is_macos_arm64, 'ARCH_AARCH64'),
  126. (self.is_powerpc, 'ARCH_PPC64LE'),
  127. (self.is_power8le, 'ARCH_POWER8LE'),
  128. (self.is_power9le, 'ARCH_POWER9LE'),
  129. (self.is_riscv32, 'ARCH_RISCV32'),
  130. (self.is_nds32, 'ARCH_NDS32'),
  131. (self.is_32_bit, 'ARCH_TYPE_32'),
  132. (self.is_64_bit, 'ARCH_TYPE_64'),
  133. ))
  134. @property
  135. def library_path_variables(self):
  136. return ['LD_LIBRARY_PATH', 'DYLD_LIBRARY_PATH']
  137. def find_in_dict(self, dict_, default=None):
  138. if dict_ is None:
  139. return default
  140. for key in six.iterkeys(dict_):
  141. if self._parse_os(key) == self.os:
  142. return dict_[key]
  143. return default
  144. @property
  145. def os_compat(self):
  146. if self.is_macos:
  147. return 'DARWIN'
  148. else:
  149. return self.os.upper()
  150. @property
  151. def canonized_platform(self):
  152. os = None
  153. if self.os == 'macos':
  154. os = 'darwin'
  155. elif self.os == 'windows':
  156. os = 'win32'
  157. else:
  158. os = self.os
  159. if self.arch != 'x86_64':
  160. return '-'.join([os, self.arch])
  161. else:
  162. return os
  163. def exe(self, *paths):
  164. if self.is_windows:
  165. return ntpath.join(*itertools.chain(paths[:-1], (paths[-1] + '.exe',)))
  166. else:
  167. return posixpath.join(*paths)
  168. def __str__(self):
  169. return '{name}-{os}-{arch}'.format(name=self.name, os=self.os, arch=self.arch)
  170. def __cmp__(self, other):
  171. return cmp((self.name, self.os, self.arch), (other.name, other.os, other.arch))
  172. def __hash__(self):
  173. return hash((self.name, self.os, self.arch))
  174. @staticmethod
  175. def _parse_os(os):
  176. os = os.lower()
  177. if os == 'darwin':
  178. return 'macos'
  179. if os in ('win', 'win32', 'win64'):
  180. return 'windows'
  181. if os.startswith('cygwin'):
  182. return 'cygwin'
  183. return os
  184. def which(prog):
  185. if os.path.exists(prog) and os.access(prog, os.X_OK):
  186. return prog
  187. # Ищем в $PATH только простые команды, без путей.
  188. if os.path.dirname(prog) != '':
  189. return None
  190. path = os.getenv('PATH', '')
  191. pathext = os.environ.get('PATHEXT')
  192. # На Windows %PATHEXT% указывает на список расширений, которые нужно проверять
  193. # при поиске команды в пути. Точное совпадение без расширения имеет приоритет.
  194. pathext = [''] if pathext is None else [''] + pathext.lower().split(os.pathsep)
  195. for dir_ in path.split(os.path.pathsep):
  196. for ext in pathext:
  197. p = os.path.join(dir_, prog + ext)
  198. if os.path.exists(p) and os.path.isfile(p) and os.access(p, os.X_OK):
  199. return p
  200. return None
  201. def get_stdout(command):
  202. stdout, code = get_stdout_and_code(command)
  203. return stdout if code == 0 else None
  204. def get_stdout_and_code(command):
  205. # noinspection PyBroadException
  206. try:
  207. process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  208. stdout, _ = process.communicate()
  209. return stdout, process.returncode
  210. except Exception as e:
  211. logger.info("While run: `%s`", e)
  212. return None, None
  213. def to_strings(o):
  214. if isinstance(o, (list, tuple)):
  215. for s in o:
  216. for ss in to_strings(s):
  217. yield ss
  218. else:
  219. if o is not None:
  220. if isinstance(o, bool):
  221. yield 'yes' if o else 'no'
  222. elif isinstance(o, (str, int)):
  223. yield str(o)
  224. else:
  225. raise ConfigureError('Unexpected value {} {}'.format(type(o), o))
  226. def emit(key, *value):
  227. print('{0}={1}'.format(key, ' '.join(to_strings(value))))
  228. def emit_with_comment(comment, key, *value):
  229. print('# {}'.format(comment))
  230. emit(key, *value)
  231. def emit_with_ignore_comment(key, *value):
  232. emit_with_comment('IGNORE YMAKE CONF CONTEXT', key, *value)
  233. def append(key, *value):
  234. print('{0}+={1}'.format(key, ' '.join(to_strings(value))))
  235. def emit_big(text):
  236. prefix = None
  237. first = True
  238. for line in text.split('\n'):
  239. if prefix is None:
  240. if not line:
  241. continue
  242. prefix = 0
  243. while prefix < len(line) and line[prefix] == ' ':
  244. prefix += 1
  245. if first: # Be pretty, prepend an empty line before the output
  246. print()
  247. first = False
  248. print(line[prefix:])
  249. class Variables(dict):
  250. def emit(self, with_ignore_comment=[]):
  251. with_ignore_comment_set = set(with_ignore_comment)
  252. for k in sorted(self.keys()):
  253. if k in with_ignore_comment_set:
  254. emit_with_ignore_comment(k, self[k])
  255. else:
  256. emit(k, self[k])
  257. def update_from_presets(self):
  258. for k in six.iterkeys(self):
  259. v = preset(k)
  260. if v is not None:
  261. self[k] = v
  262. def reset_if_any(self, value_check=None, reset_value=None):
  263. if value_check is None:
  264. def value_check(v_):
  265. return v_ is None
  266. if any(map(value_check, six.itervalues(self))):
  267. for k in six.iterkeys(self):
  268. self[k] = reset_value
  269. def format_env(env, list_separator=':'):
  270. def format_value(value):
  271. return value if isinstance(value, str) else ('\\' + list_separator).join(value)
  272. def format(kv):
  273. return '${env:"%s=%s"}' % (kv[0], format_value(kv[1]))
  274. return ' '.join(map(format, sorted(six.iteritems(env))))
  275. # TODO(somov): Проверить, используется ли это. Может быть, выпилить.
  276. def userify_presets(presets, keys):
  277. for key in keys:
  278. user_key = 'USER_{}'.format(key)
  279. values = [presets.pop(key, None), presets.get(user_key)]
  280. presets[user_key] = ' '.join(filter(None, values))
  281. def preset(key, default=None):
  282. return opts().presets.get(key, default)
  283. def is_positive(key):
  284. return is_positive_str(preset(key, ''))
  285. def is_positive_str(s):
  286. return s.lower() in ('yes', 'true', 'on', '1')
  287. def is_negative(key):
  288. return is_negative_str(preset(key, ''))
  289. def is_negative_str(s):
  290. return s.lower() in ('no', 'false', 'off', '0')
  291. def to_bool(s, default=None):
  292. if isinstance(s, six.string_types):
  293. if is_positive_str(s):
  294. return True
  295. if is_negative_str(s):
  296. return False
  297. if default is None:
  298. raise ConfigureError('{} is not a bool value'.format(s))
  299. return default
  300. def select(selectors, default=None, no_default=False):
  301. for enabled, value in selectors:
  302. if enabled:
  303. return value
  304. if no_default:
  305. raise ConfigureError()
  306. return default
  307. def select_multiple(selectors):
  308. for enabled, value in selectors:
  309. if enabled:
  310. yield value
  311. def unique(it):
  312. known = set()
  313. for i in it:
  314. if i not in known:
  315. known.add(i)
  316. yield i
  317. class Options(object):
  318. def __init__(self, argv):
  319. def parse_presets(raw_presets):
  320. presets = {}
  321. for p in raw_presets:
  322. toks = p.split('=', 1)
  323. name = toks[0]
  324. value = toks[1] if len(toks) >= 2 else ''
  325. presets[name] = value
  326. return presets
  327. parser = optparse.OptionParser(add_help_option=False)
  328. opt_group = optparse.OptionGroup(parser, 'Conf script options')
  329. opt_group.add_option('--toolchain-params', dest='toolchain_params', action='store', help='Set toolchain params via file')
  330. opt_group.add_option('-D', '--preset', dest='presets', action='append', default=[], help='set or override presets')
  331. opt_group.add_option('-l', '--local-distbuild', dest='local_distbuild', action='store_true', default=False, help='conf for local distbuild')
  332. parser.add_option_group(opt_group)
  333. self.options, self.arguments = parser.parse_args(argv)
  334. argv = self.arguments
  335. if len(argv) < 4:
  336. print('Usage: ArcRoot, --BuildType--, Verbosity, [Path to local.ymake]', file=sys.stderr)
  337. sys.exit(1)
  338. self.arcadia_root = argv[1]
  339. init_logger(argv[3] == 'verbose')
  340. # Эти переменные не надо использоваться напрямую. Их значения уже разбираются в других местах.
  341. self.build_type = argv[2].lower()
  342. self.local_distbuild = self.options.local_distbuild
  343. self.toolchain_params = self.options.toolchain_params
  344. self.presets = parse_presets(self.options.presets)
  345. userify_presets(self.presets, ('CFLAGS', 'CXXFLAGS', 'CONLYFLAGS', 'LDFLAGS', 'GO_COMPILE_FLAGS', 'GO_LINK_FLAGS', 'USE_LOCAL_SWIG', 'SWIG_TOOL', 'SWIG_LIBRARY'))
  346. Instance = None
  347. def opts():
  348. if Options.Instance is None:
  349. Options.Instance = Options(sys.argv)
  350. return Options.Instance
  351. class Profiler(object):
  352. Generic = 'generic'
  353. GProf = 'gprof'
  354. class Arcadia(object):
  355. def __init__(self, root):
  356. self.root = root
  357. class Build(object):
  358. def __init__(self, arcadia, build_type, toolchain_params, force_ignore_local_files=False):
  359. self.arcadia = arcadia
  360. self.params = self._load_json_from_base64(toolchain_params)
  361. self.build_type = build_type
  362. platform = self.params['platform']
  363. self.host = Platform.from_json(platform['host'])
  364. self.target = Platform.from_json(platform['target'])
  365. self.tc = self._get_toolchain_options()
  366. # TODO(somov): Удалить, когда перестанет использоваться.
  367. self.build_system = 'ymake'
  368. self.ignore_local_files = False
  369. dist_prefix = 'dist-'
  370. if self.build_type.startswith(dist_prefix):
  371. self.build_system = 'distbuild'
  372. self.build_type = self.build_type[len(dist_prefix):]
  373. if force_ignore_local_files:
  374. self.ignore_local_files = True
  375. if self.is_ide_build_type(self.build_type):
  376. self.ignore_local_files = True
  377. self.pic = not is_positive('FORCE_NO_PIC')
  378. @property
  379. def host_target(self):
  380. return self.host, self.target
  381. def print_build(self):
  382. self._print_build_settings()
  383. host_os = System(self.host)
  384. host_os.print_host_settings()
  385. target_os = System(self.target)
  386. target_os.print_target_settings()
  387. if self.pic:
  388. emit('PIC', 'yes')
  389. emit('COMPILER_ID', self.tc.type.upper())
  390. if self.is_valgrind:
  391. emit('WITH_VALGRIND', 'yes')
  392. if self.is_coverage:
  393. emit('_BUILD_COVERAGE', 'yes')
  394. if self.is_debug:
  395. emit('_BUILD_DEBUG', 'yes')
  396. if self.is_fast_debug:
  397. emit('_BUILD_FAST_DEBUG', 'yes')
  398. if self.is_release:
  399. emit('_BUILD_RELEASE', 'yes')
  400. if self.is_sanitized:
  401. emit('_BUILD_SANITIZED', 'yes')
  402. if self.is_size_optimized:
  403. emit('_BUILD_SIZE_OPTIMIZED', 'yes')
  404. if self.with_ndebug:
  405. emit('_BUILD_WITH_NDEBUG', 'yes')
  406. toolchain_type, compiler_type, linker_type = Compilers[self.tc.type]
  407. toolchain = toolchain_type(self.tc, self)
  408. compiler = compiler_type(self.tc, self)
  409. linker = linker_type(self.tc, self)
  410. toolchain.print_toolchain()
  411. compiler.print_compiler()
  412. linker.print_linker()
  413. self._print_other_settings(compiler)
  414. def _print_build_settings(self):
  415. emit('BUILD_TYPE', self.build_type.upper())
  416. emit('BT_' + self.build_type.upper().replace('-', '_'), 'yes')
  417. if self.build_system == 'distbuild':
  418. emit('DISTBUILD', 'yes')
  419. elif self.build_system != 'ymake':
  420. raise ConfigureError()
  421. python_bin = preset('BUILD_PYTHON_BIN', '$(PYTHON)/python')
  422. emit('YMAKE_PYTHON', python_bin)
  423. emit('YMAKE_UNPICKLER', python_bin, '$ARCADIA_ROOT/build/plugins/_unpickler.py')
  424. @property
  425. def is_release(self):
  426. # TODO(somov): Проверить, бывают ли тут суффиксы на самом деле
  427. return self.build_type in ('release', 'relwithdebinfo', 'minsizerel', 'profile', 'gprof') or self.build_type.endswith('-release')
  428. @property
  429. def is_debug(self):
  430. return self.build_type in ('debug', 'debugnoasserts', 'fastdebug') or self.build_type.endswith('-debug')
  431. @property
  432. def is_fast_debug(self):
  433. return self.build_type == 'fastdebug'
  434. @property
  435. def is_size_optimized(self):
  436. return self.build_type == 'minsizerel'
  437. @property
  438. def is_coverage(self):
  439. return self.build_type == 'coverage'
  440. @property
  441. def is_sanitized(self):
  442. sanitizer = preset('SANITIZER_TYPE')
  443. return bool(sanitizer) and not is_negative_str(sanitizer)
  444. @property
  445. def with_ndebug(self):
  446. return self.build_type in ('release', 'minsizerel', 'valgrind-release', 'profile', 'gprof', 'debugnoasserts')
  447. @property
  448. def is_valgrind(self):
  449. return self.build_type == 'valgrind' or self.build_type == 'valgrind-release'
  450. @property
  451. def is_ide(self):
  452. return self.is_ide_build_type(self.build_type)
  453. @property
  454. def profiler_type(self):
  455. if self.build_type == 'profile':
  456. return Profiler.Generic
  457. elif self.build_type == 'gprof':
  458. return Profiler.GProf
  459. else:
  460. return None
  461. @staticmethod
  462. def is_ide_build_type(build_type):
  463. return build_type == 'nobuild'
  464. def _configure_runtime_versions(self):
  465. res = subprocess.check_output(['xcrun', 'simctl', 'list', '--json', 'runtimes'])
  466. raw_object = json.loads(res)
  467. raw_object = raw_object['runtimes']
  468. for runtime in raw_object:
  469. if runtime['isAvailable']:
  470. if "iOS" in runtime['identifier']:
  471. emit('DEFAULT_IOS_RUNTIME', '{}'.format(runtime['identifier']))
  472. def _get_toolchain_options(self):
  473. type_ = self.params['params']['type']
  474. if self.params['params'].get('local') and type_ == 'xcode':
  475. detector = CompilerDetector()
  476. detector.detect(self.params['params']['c_compiler'], self.params['params']['cxx_compiler'])
  477. emit('LOCAL_XCODE_TOOLS', 'yes')
  478. emit('XCODE', 'yes')
  479. emit('ACTOOL_PATH', self.params['params']['actool'])
  480. emit('IBTOOL_PATH', self.params['params']['ibtool'])
  481. self._configure_runtime_versions()
  482. elif type_ == 'system_cxx':
  483. detector = CompilerDetector()
  484. detector.detect(self.params['params'].get('c_compiler'), self.params['params'].get('cxx_compiler'))
  485. type_ = detector.type
  486. else:
  487. detector = None
  488. if type_ == 'msvc':
  489. return MSVCToolchainOptions(self, detector)
  490. else:
  491. return GnuToolchainOptions(self, detector)
  492. def _print_other_settings(self, compiler):
  493. host = self.host
  494. emit('USE_LOCAL_TOOLS', 'no' if self.ignore_local_files else 'yes')
  495. ragel = Ragel()
  496. ragel.configure_toolchain(self, compiler)
  497. ragel.print_variables()
  498. perl = Perl()
  499. perl.configure_local()
  500. perl.print_variables('LOCAL_')
  501. swiftc = SwiftCompiler(self)
  502. swiftc.configure()
  503. swiftc.print_compiler()
  504. if host.is_linux or host.is_macos or host.is_cygwin:
  505. if is_negative('USE_ARCADIA_PYTHON'):
  506. python = Python(self.tc)
  507. python.configure_posix()
  508. python.print_variables()
  509. cuda = Cuda(self)
  510. cuda.print_()
  511. CuDNN(cuda).print_()
  512. print_swig_config()
  513. if self.ignore_local_files or host.is_windows or is_positive('NO_SVN_DEPENDS'):
  514. emit_with_ignore_comment('SVN_DEPENDS')
  515. emit_with_ignore_comment('SVN_DEPENDS_CACHE__NO_UID__')
  516. else:
  517. def find_svn():
  518. for i in range(0, 3):
  519. for path in (['.svn', 'wc.db'], ['.svn', 'entries'], ['.git', 'logs', 'HEAD']):
  520. path_parts = [os.pardir] * i + path
  521. full_path = os.path.join(self.arcadia.root, *path_parts)
  522. # HACK(somov): No "normpath" here. ymake fails with the "source file name is outside the build tree" error
  523. # when .svn/wc.db found in "trunk" instead of "arcadia". But $ARCADIA_ROOT/../.svn/wc.db is ok.
  524. if os.path.exists(full_path):
  525. out_path = os.path.join('${ARCADIA_ROOT}', *path_parts)
  526. return '${input;hide:"%s"}' % out_path
  527. # Special processing for arc repository since .arc may be a symlink.
  528. dot_arc = os.path.realpath(os.path.join(self.arcadia.root, '.arc'))
  529. full_path = os.path.join(dot_arc, 'TREE')
  530. if os.path.exists(full_path):
  531. out_path = os.path.join('${ARCADIA_ROOT}', os.path.relpath(full_path, self.arcadia.root))
  532. return '${input;hide:"%s"}' % out_path
  533. return ''
  534. emit_with_ignore_comment('SVN_DEPENDS', find_svn())
  535. emit_with_ignore_comment('SVN_DEPENDS_CACHE__NO_UID__', '${hide;kv:"disable_cache"}')
  536. @staticmethod
  537. def _load_json_from_base64(base64str):
  538. """
  539. :rtype: dict[str, Any]
  540. """
  541. def un_unicode(o):
  542. if isinstance(o, six.text_type):
  543. return six.ensure_str(o)
  544. if isinstance(o, list):
  545. return [un_unicode(oo) for oo in o]
  546. if isinstance(o, dict):
  547. return {un_unicode(k): un_unicode(v) for k, v in six.iteritems(o)}
  548. return o
  549. return un_unicode(json.loads(base64.b64decode(base64str)))
  550. class YMake(object):
  551. def __init__(self, arcadia):
  552. self.arcadia = arcadia
  553. def print_presets(self):
  554. presets = opts().presets
  555. if presets and 'YMAKE_JAVA_MODULES' not in presets:
  556. presets['YMAKE_JAVA_MODULES'] = 'yes'
  557. if presets and 'YMAKE_JAVA_MODULES' in presets and presets['YMAKE_JAVA_MODULES'] == "yes":
  558. print('@import "${CONF_ROOT}/conf/java.ymake.conf"')
  559. else:
  560. print('@import "${CONF_ROOT}/conf/jbuild.ymake.conf"')
  561. if is_positive_str(presets.get('EXPORT_GRADLE', 'no')):
  562. print('@import "${CONF_ROOT}/conf/export_gradle.yes.conf"')
  563. else:
  564. print('@import "${CONF_ROOT}/conf/export_gradle.no.conf"')
  565. if presets.get('COVERAGE_TARGET_REGEXP', None) is None:
  566. print('@import "${CONF_ROOT}/conf/coverage_full_instrumentation.conf"')
  567. else:
  568. print('@import "${CONF_ROOT}/conf/coverage_selective_instrumentation.conf"')
  569. if presets:
  570. print('# Variables set from command line by -D options')
  571. for key in sorted(presets):
  572. if key in ('MY_YMAKE_BIN', 'REAL_YMAKE_BIN'):
  573. emit_with_ignore_comment(key, opts().presets[key])
  574. elif key == 'YMAKE_JAVA_MODULES':
  575. continue
  576. else:
  577. emit(key, opts().presets[key])
  578. @staticmethod
  579. def _print_conf_content(path):
  580. with open(path, 'r') as fin:
  581. print(fin.read())
  582. def print_core_conf(self):
  583. emit('YMAKE_YNDEXER_IGNORE_BUILD_ROOT', 'yes')
  584. print('@import "${CONF_ROOT}/ymake.core.conf"')
  585. def print_settings(self):
  586. emit_with_ignore_comment('ARCADIA_ROOT', self.arcadia.root)
  587. @staticmethod
  588. def _find_conf(conf_file):
  589. script_dir = os.path.dirname(__file__)
  590. full_path = os.path.join(script_dir, conf_file)
  591. if os.path.exists(full_path):
  592. return full_path
  593. return None
  594. def _find_core_conf(self):
  595. return self._find_conf('ymake.core.conf')
  596. class System(object):
  597. def __init__(self, platform):
  598. """
  599. :type platform: Platform
  600. """
  601. self.platform = platform
  602. def print_windows_target_const(self):
  603. # TODO(somov): Remove this variables, use generic OS/arch variables in makelists.
  604. emit('WINDOWS', 'yes')
  605. emit('WIN32', 'yes')
  606. if self.platform.is_64_bit == 64:
  607. emit('WIN64', 'yes')
  608. def print_nix_target_const(self):
  609. emit('JAVA_INCLUDE', '-I{0}/include -I{0}/include/{1}'.format('/usr/lib/jvm/default-java', self.platform.os_compat))
  610. emit('UNIX', 'yes')
  611. emit('REALPRJNAME')
  612. emit('SONAME')
  613. def print_target_settings(self):
  614. emit('TARGET_PLATFORM', self.platform.os_compat)
  615. emit('CANONIZED_TARGET_PLATFORM', self.platform.canonized_platform)
  616. emit('HARDWARE_ARCH', '32' if self.platform.is_32_bit else '64')
  617. emit('HARDWARE_TYPE', self.platform.arch)
  618. for variable in self.platform.arch_variables:
  619. emit(variable, 'yes')
  620. for variable in self.platform.os_variables:
  621. emit(variable, 'yes')
  622. if self.platform.is_armv7:
  623. emit('ARM7_FLOAT_ABI', self.platform.armv7_float_abi)
  624. if self.platform.is_android:
  625. emit('ANDROID_API', str(self.platform.android_api))
  626. if self.platform.is_posix:
  627. self.print_nix_target_const()
  628. elif self.platform.is_windows:
  629. self.print_windows_target_const()
  630. def print_host_settings(self):
  631. emit('HOST_PLATFORM', self.platform.os_compat)
  632. emit('CANONIZED_HOST_PLATFORM', self.platform.canonized_platform)
  633. for variable in itertools.chain(self.platform.os_variables, self.platform.arch_variables):
  634. emit('HOST_{var}'.format(var=variable), 'yes')
  635. class CompilerDetector(object):
  636. def __init__(self):
  637. self.type = None
  638. self.c_compiler = None
  639. self.cxx_compiler = None
  640. self.version_list = None
  641. @staticmethod
  642. def preprocess_source(compiler, source):
  643. # noinspection PyBroadException
  644. try:
  645. fd, path = tempfile.mkstemp(suffix='.cpp')
  646. try:
  647. with os.fdopen(fd, 'w') as output:
  648. output.write(source)
  649. stdout, code = get_stdout_and_code([compiler, '-E', path])
  650. except Exception as e:
  651. logger.info("While writing: `%s`", e)
  652. finally:
  653. os.remove(path)
  654. return stdout, code
  655. except Exception as e:
  656. logger.debug('Preprocessing failed: %s', e)
  657. return None, None
  658. @staticmethod
  659. def get_compiler_vars(compiler, names):
  660. prefix = '____YA_VAR_'
  661. source = '\n'.join(['{prefix}{name}={name}\n'.format(prefix=prefix, name=n) for n in names])
  662. # Некоторые препроцессоры возвращают ненулевой код возврата. Поэтому его проверять нельзя.
  663. # Мы можем только удостовериться после разбора stdout, что в нём
  664. # присутствовала хотя бы одна подставленная переменная.
  665. # TODO(somov): Исследовать, можно ли проверять ограниченный набор кодов возврата.
  666. # TODO(v-korovin): Нормально прокидывать Exception-ы, оно и так упадёт
  667. stdout, _ = CompilerDetector.preprocess_source(compiler, source)
  668. if stdout is None:
  669. return None
  670. vars_ = {}
  671. for line in six.ensure_str(stdout).split('\n'):
  672. parts = line.split('=', 1)
  673. if len(parts) == 2 and parts[0].startswith(prefix):
  674. name, value = parts[0][len(prefix):], parts[1]
  675. if value == name:
  676. continue # Preprocessor variable was not substituted
  677. vars_[name] = value
  678. return vars_
  679. def detect(self, c_compiler=None, cxx_compiler=None):
  680. c_compiler = c_compiler or os.environ.get('CC')
  681. cxx_compiler = cxx_compiler or os.environ.get('CXX') or c_compiler
  682. c_compiler = c_compiler or cxx_compiler
  683. logger.debug('e=%s', os.environ)
  684. if c_compiler is None:
  685. raise ConfigureError('Custom compiler was requested but not specified')
  686. c_compiler_path = which(c_compiler)
  687. clang_vars = ['__clang_major__', '__clang_minor__', '__clang_patchlevel__']
  688. gcc_vars = ['__GNUC__', '__GNUC_MINOR__', '__GNUC_PATCHLEVEL__']
  689. msvc_vars = ['_MSC_VER']
  690. apple_var = '__apple_build_version__'
  691. compiler_vars = self.get_compiler_vars(c_compiler_path, clang_vars + [apple_var] + gcc_vars + msvc_vars)
  692. if not compiler_vars:
  693. raise ConfigureError('Could not determine custom compiler version: {}'.format(c_compiler))
  694. def version(version_names):
  695. def iter_version():
  696. for name in version_names:
  697. yield int(compiler_vars[name])
  698. # noinspection PyBroadException
  699. try:
  700. return list(iter_version())
  701. except Exception:
  702. return None
  703. clang_version = version(clang_vars)
  704. apple_build = apple_var in compiler_vars
  705. # TODO(somov): Учитывать номера версий сборки Apple компилятора Clang.
  706. _ = apple_build
  707. gcc_version = version(gcc_vars)
  708. msvc_version = version(msvc_vars)
  709. if clang_version:
  710. logger.debug('Detected Clang version %s', clang_version)
  711. self.type = 'clang'
  712. elif gcc_version:
  713. logger.debug('Detected GCC version %s', gcc_version)
  714. # TODO(somov): Переименовать в gcc.
  715. self.type = 'gnu'
  716. elif msvc_version:
  717. logger.debug('Detected MSVC version %s', msvc_version)
  718. self.type = 'msvc'
  719. else:
  720. raise ConfigureError('Could not determine custom compiler type: {}'.format(c_compiler))
  721. self.version_list = clang_version or gcc_version or msvc_version
  722. self.c_compiler = c_compiler_path
  723. self.cxx_compiler = cxx_compiler and which(cxx_compiler) or c_compiler_path
  724. class ToolchainOptions(object):
  725. def __init__(self, build, detector):
  726. """
  727. :type build: Build
  728. """
  729. self.host = build.host
  730. self.target = build.target
  731. tc_json = build.params
  732. logger.debug('Toolchain host %s', self.host)
  733. logger.debug('Toolchain target %s', self.target)
  734. logger.debug('Toolchain json %s', DebugString(lambda: json.dumps(tc_json, indent=4, sort_keys=True)))
  735. self.params = tc_json['params']
  736. self._name = tc_json.get('name', 'theyknow')
  737. if detector:
  738. self.type = detector.type
  739. self.from_arcadia = False
  740. self.c_compiler = detector.c_compiler
  741. self.cxx_compiler = detector.cxx_compiler
  742. self.compiler_version_list = detector.version_list
  743. self.compiler_version = '.'.join(map(lambda part: six.ensure_str(str(part)), self.compiler_version_list))
  744. else:
  745. self.type = self.params['type']
  746. self.from_arcadia = True
  747. self.c_compiler = self.params['c_compiler']
  748. self.cxx_compiler = self.params['cxx_compiler']
  749. # TODO(somov): Требовать номер версии всегда.
  750. self.compiler_version = self.params.get('gcc_version') or self.params.get('version') or '0'
  751. self.compiler_version_list = list(map(int, self.compiler_version.split('.')))
  752. # TODO(somov): Посмотреть, можно ли спрятать это поле.
  753. self.name_marker = '$(%s)' % self.params.get('match_root', self._name.upper())
  754. self.arch_opt = self.params.get('arch_opt', [])
  755. self.triplet_opt = self.params.get('triplet_opt', {})
  756. self.target_opt = self.params.get('target_opt', [])
  757. # TODO(somov): Убрать чтение настройки из os.environ.
  758. self.werror_mode = preset('WERROR_MODE') or os.environ.get('WERROR_MODE') or self.params.get('werror_mode') or 'compiler_specific'
  759. # default C++ standard is set here, some older toolchains might need to redefine it in ya.conf.json
  760. self.cxx_std = self.params.get('cxx_std', 'c++20')
  761. self._env = tc_json.get('env', {})
  762. self.android_ndk_version = self.params.get('android_ndk_version', None)
  763. logger.debug('c_compiler=%s', self.c_compiler)
  764. logger.debug('cxx_compiler=%s', self.cxx_compiler)
  765. self.compiler_platform_projects = self.target.find_in_dict(self.params.get('platform'), [])
  766. def version_at_least(self, *args):
  767. return args <= tuple(self.compiler_version_list)
  768. def version_exactly(self, *args):
  769. if not args or len(args) > len(self.compiler_version_list):
  770. return False
  771. for l, r in zip(args, list(self.compiler_version_list)[:len(args)]):
  772. if l != r:
  773. return False
  774. return True
  775. @property
  776. def is_gcc(self):
  777. return self.type == 'gnu'
  778. @property
  779. def is_clang(self):
  780. return self.type in ('clang', 'xcode')
  781. @property
  782. def is_xcode(self):
  783. return self.type == 'xcode'
  784. @property
  785. def is_from_arcadia(self):
  786. return self.from_arcadia
  787. @property
  788. def is_system_cxx(self):
  789. return self._name == "system_cxx"
  790. def get_env(self, convert_list=None):
  791. convert_list = convert_list or (lambda x: x)
  792. r = {}
  793. for k, v in six.iteritems(self._env):
  794. if isinstance(v, str):
  795. r[k] = v
  796. elif isinstance(v, list):
  797. r[k] = convert_list(v)
  798. else:
  799. logger.debug('Unexpected values in environment: %s', self._env)
  800. raise ConfigureError('Internal error')
  801. return r
  802. class GnuToolchainOptions(ToolchainOptions):
  803. def __init__(self, build, detector):
  804. super(GnuToolchainOptions, self).__init__(build, detector)
  805. self.ar = self.params.get('ar')
  806. self.ar_plugin = self.params.get('ar_plugin')
  807. self.inplace_tools = self.params.get('inplace_tools', False)
  808. self.strip = self.params.get('strip')
  809. self.objcopy = self.params.get('objcopy')
  810. self.objdump = self.params.get('objdump')
  811. self.isystem = self.params.get('isystem')
  812. self.dwarf_tool = self.target.find_in_dict(self.params.get('dwarf_tool'))
  813. # TODO(somov): Унифицировать формат sys_lib
  814. self.sys_lib = self.params.get('sys_lib', {})
  815. if isinstance(self.sys_lib, dict):
  816. self.sys_lib = self.target.find_in_dict(self.sys_lib, [])
  817. self.os_sdk = preset('OS_SDK') or self._default_os_sdk()
  818. self.os_sdk_local = self.os_sdk == 'local'
  819. def _default_os_sdk(self):
  820. if self.target.is_linux:
  821. if self.target.is_armv8:
  822. return 'ubuntu-16'
  823. if self.target.is_armv7 and self.target.armv7_float_abi == 'hard':
  824. return 'ubuntu-16'
  825. if self.target.is_armv7 and self.target.armv7_float_abi == 'softfp':
  826. return 'ubuntu-18'
  827. if self.target.is_powerpc:
  828. return 'ubuntu-14'
  829. # Default OS SDK for Linux builds
  830. return 'ubuntu-14'
  831. class Toolchain(object):
  832. def __init__(self, tc, build):
  833. """
  834. :type tc: ToolchainOptions
  835. :type build: Build
  836. """
  837. self.tc = tc
  838. self.build = build
  839. self.platform_projects = self.tc.compiler_platform_projects
  840. def print_toolchain(self):
  841. if self.platform_projects:
  842. emit('COMPILER_PLATFORM', list(unique(self.platform_projects)))
  843. class Compiler(object):
  844. def __init__(self, tc, compiler_variable):
  845. self.compiler_variable = compiler_variable
  846. self.tc = tc
  847. def print_compiler(self):
  848. # CLANG and CLANG_VER variables
  849. emit(self.compiler_variable, 'yes')
  850. emit('{}_VER'.format(self.compiler_variable), self.tc.compiler_version)
  851. if self.tc.is_xcode:
  852. emit('XCODE', 'yes')
  853. class GnuToolchain(Toolchain):
  854. def __init__(self, tc, build):
  855. """
  856. :type tc: GnuToolchainOptions
  857. :type build: Build
  858. """
  859. def get_os_sdk(target):
  860. sdk_native_version = 10.11 if not preset('EXPERIMENTAL_MACOS_M1_SUPPORT') else '11.1'
  861. if target.is_macos:
  862. return '$MACOS_SDK_RESOURCE_GLOBAL/MacOSX{}.sdk'.format(sdk_native_version)
  863. elif target.is_yocto:
  864. return '$YOCTO_SDK_RESOURCE_GLOBAL'
  865. return '$OS_SDK_ROOT_RESOURCE_GLOBAL'
  866. super(GnuToolchain, self).__init__(tc, build)
  867. self.tc = tc
  868. host = build.host
  869. target = build.target
  870. self.c_flags_platform = list(tc.target_opt)
  871. self.default_os_sdk_root = get_os_sdk(target)
  872. self.env = self.tc.get_env()
  873. self.env_go = {}
  874. if self.tc.is_clang and not self.tc.is_system_cxx:
  875. self.env_go = {'PATH': ['{}/bin'.format(self.tc.name_marker)]}
  876. if self.tc.is_gcc:
  877. self.env_go = {'PATH': ['{}/gcc/bin'.format(self.tc.name_marker)]}
  878. if 'PATH' in self.env_go:
  879. if target.is_linux:
  880. self.env_go['PATH'].append('$OS_SDK_ROOT_RESOURCE_GLOBAL/usr/bin')
  881. elif target.is_macos:
  882. self.env_go['PATH'].extend([
  883. '$MACOS_SDK_RESOURCE_GLOBAL/usr/bin',
  884. '$CCTOOLS_ROOT_RESOURCE_GLOBAL/bin',
  885. '$GO_FAKE_XCRUN_RESOURCE_GLOBAL',
  886. ])
  887. self.swift_flags_platform = []
  888. self.swift_lib_path = None
  889. if self.tc.is_from_arcadia:
  890. for lib_path in build.host.library_path_variables:
  891. self.env.setdefault(lib_path, []).append('{}/lib'.format(self.tc.name_marker))
  892. macos_version_min = '11.0'
  893. ios_version_min = '11.0'
  894. # min ios simulator version for Metal App is 13.0
  895. # https://developer.apple.com/documentation/metal/supporting_simulator_in_a_metal_app
  896. # Mapkit (MAPSMOBI_BUILD_TARGET) uses Metal Framework
  897. if preset('MAPSMOBI_BUILD_TARGET') and target.is_iossim and target.is_armv8:
  898. ios_version_min = '13.0'
  899. # Mapkit uses SecTrustEvaluateWithError function and these are min versions for it
  900. elif preset('MAPSMOBI_BUILD_TARGET'):
  901. ios_version_min = '12.0'
  902. swift_target = select(default=None, selectors=[
  903. (target.is_iossim and target.is_x86_64, 'x86_64-apple-ios{}-simulator'.format(ios_version_min)),
  904. (target.is_iossim and target.is_x86, 'i386-apple-ios{}-simulator'.format(ios_version_min)),
  905. (target.is_iossim and target.is_armv8, 'arm64-apple-ios{}-simulator'.format(ios_version_min)),
  906. (not target.is_iossim and target.is_ios and target.is_armv8, 'arm64-apple-ios9'),
  907. (not target.is_iossim and target.is_ios and target.is_armv7, 'armv7-apple-ios9'),
  908. ])
  909. if swift_target:
  910. self.swift_flags_platform += ['-target', swift_target]
  911. if self.tc.is_from_arcadia:
  912. self.swift_lib_path = select(default=None, selectors=[
  913. (host.is_macos and target.is_iossim, '$SWIFT_XCODE_TOOLCHAIN_ROOT_RESOURCE_GLOBAL/usr/lib/swift/iphonesimulator'),
  914. (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'),
  915. ])
  916. if self.tc.is_clang:
  917. target_triple = self.tc.triplet_opt.get(target.arch, None)
  918. if not target_triple:
  919. target_triple = select(default=None, selectors=[
  920. (target.is_linux and target.is_x86_64, 'x86_64-linux-gnu'),
  921. (target.is_linux and target.is_armv8, 'aarch64-linux-gnu'),
  922. (target.is_linux and target.is_armv7 and target.armv7_float_abi == 'hard', 'armv7-linux-gnueabihf'),
  923. (target.is_linux and target.is_armv7 and target.armv7_float_abi == 'softfp', 'armv7-linux-gnueabi'),
  924. (target.is_linux and target.is_powerpc, 'powerpc64le-linux-gnu'),
  925. (target.is_iossim and target.is_arm64, 'arm64-apple-ios{}-simulator'.format(ios_version_min)),
  926. (target.is_apple and target.is_x86, 'i386-apple-darwin14'),
  927. (target.is_apple and target.is_x86_64, 'x86_64-apple-darwin14'),
  928. (target.is_apple and target.is_macos_arm64, 'arm64-apple-macos11'),
  929. (target.is_apple and target.is_armv7, 'armv7-apple-darwin14'),
  930. (target.is_apple and target.is_armv8, 'arm64-apple-darwin14'),
  931. (target.is_yocto and target.is_armv7, 'arm-poky-linux-gnueabi'),
  932. (target.is_android and target.is_x86, 'i686-linux-android'),
  933. (target.is_android and target.is_x86_64, 'x86_64-linux-android'),
  934. (target.is_android and target.is_armv7, 'armv7a-linux-androideabi'),
  935. (target.is_android and target.is_armv8, 'aarch64-linux-android'),
  936. ])
  937. if target.is_android:
  938. # Android NDK allows specification of API level in target triple, e.g.:
  939. # armv7a-linux-androideabi16, aarch64-linux-android21
  940. target_triple += str(target.android_api)
  941. if target_triple:
  942. self.c_flags_platform.append('--target={}'.format(target_triple))
  943. if self.tc.isystem:
  944. for root in list(self.tc.isystem):
  945. self.c_flags_platform.extend(['-isystem', root])
  946. if target.is_android:
  947. self.c_flags_platform.extend(['-isystem', '{}/sources/cxx-stl/llvm-libc++abi/include'.format(self.tc.name_marker)])
  948. if target.is_cortex_a9:
  949. self.c_flags_platform.append('-mcpu=cortex-a9')
  950. if target.is_cortex_a35:
  951. self.c_flags_platform.append('-mcpu=cortex-a35')
  952. elif target.is_cortex_a53:
  953. self.c_flags_platform.append('-mcpu=cortex-a53')
  954. elif target.is_cortex_m33:
  955. self.c_flags_platform.append('-mcpu=cortex-m33 -mfpu=fpv5-sp-d16')
  956. elif target.is_armv7_neon:
  957. self.c_flags_platform.append('-mfpu=neon')
  958. if (target.is_armv7 or target.is_armv8m) and build.is_size_optimized:
  959. # Enable ARM Thumb2 variable-length instruction encoding
  960. # to reduce code size
  961. self.c_flags_platform.append('-mthumb')
  962. if target.is_arm or target.is_powerpc:
  963. # On linux, ARM and PPC default to unsigned char
  964. # However, Arcadia requires char to be signed
  965. self.c_flags_platform.append('-fsigned-char')
  966. if target.is_rv32imc:
  967. self.c_flags_platform.append('-march=rv32imc')
  968. if self.tc.is_clang or self.tc.is_gcc and self.tc.version_at_least(8, 2):
  969. target_flags = select(default=[], selectors=[
  970. (target.is_linux and target.is_power8le, ['-mcpu=power8', '-mtune=power8', '-maltivec']),
  971. (target.is_linux and target.is_power9le, ['-mcpu=power9', '-mtune=power9', '-maltivec']),
  972. (target.is_linux and target.is_armv8, ['-march=armv8a']),
  973. (target.is_macos, ['-mmacosx-version-min={}'.format(macos_version_min)]),
  974. (target.is_ios and not target.is_iossim, ['-mios-version-min={}'.format(ios_version_min)]),
  975. (target.is_iossim, ['-mios-simulator-version-min={}'.format(ios_version_min)]),
  976. (target.is_android and target.is_armv7, ['-march=armv7-a', '-mfloat-abi=softfp']),
  977. (target.is_android and target.is_armv8, ['-march=armv8-a']),
  978. (target.is_yocto and target.is_armv7, ['-march=armv7-a', '-mfpu=neon', '-mfloat-abi=hard', '-mcpu=cortex-a9', '-O1'])
  979. ])
  980. if target_flags:
  981. self.c_flags_platform.extend(target_flags)
  982. if target.is_ios:
  983. self.c_flags_platform.append('-D__IOS__=1')
  984. if self.tc.is_from_arcadia or self.tc.is_system_cxx:
  985. if target.is_apple:
  986. if target.is_ios:
  987. self.setup_sdk(project='build/platform/ios_sdk', var='${IOS_SDK_ROOT_RESOURCE_GLOBAL}')
  988. self.platform_projects.append('build/platform/macos_system_stl')
  989. if target.is_macos:
  990. self.setup_sdk(project='build/platform/macos_sdk', var='${MACOS_SDK_RESOURCE_GLOBAL}')
  991. self.platform_projects.append('build/platform/macos_system_stl')
  992. if not self.tc.inplace_tools:
  993. self.setup_tools(project='build/platform/cctools', var='${CCTOOLS_ROOT_RESOURCE_GLOBAL}', bin='bin', ldlibs=None)
  994. if target.is_linux:
  995. if not tc.os_sdk_local:
  996. self.setup_sdk(project='build/platform/linux_sdk', var='$OS_SDK_ROOT_RESOURCE_GLOBAL')
  997. if target.is_x86_64:
  998. if host.is_linux and not self.tc.is_gcc:
  999. self.setup_tools(project='build/platform/linux_sdk', var='$OS_SDK_ROOT_RESOURCE_GLOBAL', bin='usr/bin', ldlibs='usr/lib/x86_64-linux-gnu')
  1000. elif host.is_macos:
  1001. self.setup_tools(project='build/platform/binutils', var='$BINUTILS_ROOT_RESOURCE_GLOBAL', bin='x86_64-linux-gnu/bin', ldlibs=None)
  1002. elif target.is_powerpc:
  1003. 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')
  1004. elif target.is_armv8:
  1005. self.setup_tools(project='build/platform/linux_sdk', var='$OS_SDK_ROOT_RESOURCE_GLOBAL', bin='usr/bin', ldlibs='usr/lib/x86_64-linux-gnu')
  1006. if target.is_yocto:
  1007. self.setup_sdk(project='build/platform/yocto_sdk/yocto_sdk', var='${YOCTO_SDK_ROOT_RESOURCE_GLOBAL}')
  1008. elif self.tc.params.get('local'):
  1009. if target.is_apple:
  1010. if not tc.os_sdk_local:
  1011. if target.is_ios:
  1012. self.setup_sdk(project='build/platform/ios_sdk', var='${IOS_SDK_ROOT_RESOURCE_GLOBAL}')
  1013. self.platform_projects.append('build/platform/macos_system_stl')
  1014. if target.is_macos:
  1015. self.setup_sdk(project='build/platform/macos_sdk', var='${MACOS_SDK_RESOURCE_GLOBAL}')
  1016. self.platform_projects.append('build/platform/macos_system_stl')
  1017. else:
  1018. if target.is_iossim:
  1019. self.env.setdefault('SDKROOT', subprocess.check_output(['xcrun', '-sdk', 'iphonesimulator', '--show-sdk-path']).strip())
  1020. elif target.is_ios:
  1021. self.env.setdefault('SDKROOT', subprocess.check_output(['xcrun', '-sdk', 'iphoneos', '--show-sdk-path']).strip())
  1022. elif target.is_macos:
  1023. self.env.setdefault('SDKROOT', subprocess.check_output(['xcrun', '-sdk', 'macosx', '--show-sdk-path']).strip())
  1024. def setup_sdk(self, project, var):
  1025. self.platform_projects.append(project)
  1026. self.c_flags_platform.append('--sysroot={}'.format(var))
  1027. self.swift_flags_platform += ['-sdk', var]
  1028. # noinspection PyShadowingBuiltins
  1029. def setup_tools(self, project, var, bin, ldlibs):
  1030. self.platform_projects.append(project)
  1031. self.c_flags_platform.append('-B{}/{}'.format(var, bin))
  1032. if ldlibs:
  1033. for lib_path in self.build.host.library_path_variables:
  1034. self.env.setdefault(lib_path, []).append('{}/{}'.format(var, ldlibs))
  1035. def print_toolchain(self):
  1036. super(GnuToolchain, self).print_toolchain()
  1037. emit('TOOLCHAIN_ENV', format_env(self.env, list_separator=':'))
  1038. emit('_GO_TOOLCHAIN_ENV_PATH', format_env(self.env_go, list_separator=':'))
  1039. emit('C_FLAGS_PLATFORM', self.c_flags_platform)
  1040. emit('SWIFT_FLAGS_PLATFORM', self.swift_flags_platform)
  1041. emit('SWIFT_LD_FLAGS', '-L{}'.format(self.swift_lib_path) if self.swift_lib_path else '')
  1042. emit('PERL_SDK', preset('OS_SDK') or self.tc.os_sdk)
  1043. if preset('OS_SDK') is None:
  1044. emit('OS_SDK', self.tc.os_sdk)
  1045. emit('OS_SDK_ROOT', None if self.tc.os_sdk_local else self.default_os_sdk_root)
  1046. class GnuCompiler(Compiler):
  1047. def __init__(self, tc, build):
  1048. """
  1049. :type tc: GnuToolchainOptions
  1050. :type build: Build
  1051. """
  1052. compiler_variable = 'CLANG' if tc.is_clang else 'GCC'
  1053. super(GnuCompiler, self).__init__(tc, compiler_variable)
  1054. self.build = build
  1055. self.host = self.build.host
  1056. self.target = self.build.target
  1057. self.tc = tc
  1058. self.c_foptions = [
  1059. # Enable C++ exceptions (and allow them to be throw through pure C code)
  1060. '-fexceptions',
  1061. # Enable standard-conforming behavior and generate duplicate symbol error in case of duplicated global constants.
  1062. # See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85678#c0
  1063. '-fno-common',
  1064. ]
  1065. if self.tc.is_clang and self.target.is_linux:
  1066. # Use .init_array instead of .ctors (default for old clang versions)
  1067. # See: https://maskray.me/blog/2021-11-07-init-ctors-init-array
  1068. self.c_foptions.append('-fuse-init-array')
  1069. if self.tc.is_clang:
  1070. self.c_foptions += [
  1071. # Set up output colorization
  1072. '-fcolor-diagnostics',
  1073. # Enable aligned allocation
  1074. '-faligned-allocation',
  1075. '-fdebug-default-version=4',
  1076. ]
  1077. elif self.tc.is_gcc:
  1078. self.c_foptions += [
  1079. # Set up output colorization
  1080. '-fdiagnostics-color=always',
  1081. # It looks like there is no way to enable aligned allocation in gcc
  1082. ]
  1083. self.c_warnings = [
  1084. # Enable default warnings subset
  1085. '-Wall',
  1086. '-Wextra',
  1087. ]
  1088. self.cxx_warnings = [
  1089. # Issue a warning if certain overload is hidden due to inheritance
  1090. '-Woverloaded-virtual',
  1091. ]
  1092. # Disable some warnings which will fail compilation at the time
  1093. self.c_warnings += [
  1094. '-Wno-parentheses',
  1095. ]
  1096. self.c_defines = ['-DFAKEID=$CPP_FAKEID']
  1097. if self.target.is_android:
  1098. self.c_defines.append('-DANDROID_FAKEID=$ANDROID_FAKEID')
  1099. self.c_defines.extend([
  1100. '-DARCADIA_ROOT=${ARCADIA_ROOT}',
  1101. '-DARCADIA_BUILD_ROOT=${ARCADIA_BUILD_ROOT}',
  1102. ])
  1103. self.c_defines.extend([
  1104. '-D_THREAD_SAFE', '-D_PTHREADS', '-D_REENTRANT', '-D_LIBCPP_ENABLE_CXX17_REMOVED_FEATURES',
  1105. '-D_LARGEFILE_SOURCE', '-D__STDC_CONSTANT_MACROS', '-D__STDC_FORMAT_MACROS',
  1106. ])
  1107. if not self.target.is_android:
  1108. # There is no usable _FILE_OFFSET_BITS=64 support in Androids until API 21. And it's incomplete until at least API 24.
  1109. # https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md
  1110. # Arcadia have API 16 for 32-bit Androids.
  1111. self.c_defines.append('-D_FILE_OFFSET_BITS=64')
  1112. if self.target.is_linux or self.target.is_android or self.target.is_cygwin or self.target.is_none:
  1113. self.c_defines.append('-D_GNU_SOURCE')
  1114. if self.tc.is_clang and self.target.is_linux and self.target.is_x86_64:
  1115. self.c_defines.append('-D_YNDX_LIBUNWIND_ENABLE_EXCEPTION_BACKTRACE')
  1116. if self.target.is_ios:
  1117. self.c_defines.extend(['-D_XOPEN_SOURCE', '-D_DARWIN_C_SOURCE'])
  1118. self.c_flags = ['$CL_DEBUG_INFO', '$CL_DEBUG_INFO_DISABLE_CACHE__NO_UID__']
  1119. self.c_flags += self.tc.arch_opt + ['-pipe']
  1120. self.sfdl_flags = ['-E', '-C', '-x', 'c++']
  1121. if self.target.is_x86:
  1122. self.c_flags.append('-m32')
  1123. if self.target.is_x86_64:
  1124. self.c_flags.append('-m64')
  1125. self.debug_info_flags = ['-g']
  1126. if self.target.is_linux:
  1127. self.debug_info_flags.append('-ggnu-pubnames')
  1128. self.cross_suffix = '' if is_positive('FORCE_NO_PIC') else '.pic'
  1129. self.optimize = None
  1130. self.configure_build_type()
  1131. if self.tc.is_clang:
  1132. self.sfdl_flags.append('-Qunused-arguments')
  1133. self.c_warnings += [
  1134. '-Wno-implicit-const-int-float-conversion',
  1135. # For nvcc to accept the above.
  1136. '-Wno-unknown-warning-option',
  1137. ]
  1138. self.cxx_warnings += [
  1139. '-Wimport-preprocessor-directive-pedantic',
  1140. '-Wno-ambiguous-reversed-operator',
  1141. '-Wno-defaulted-function-deleted',
  1142. '-Wno-deprecated-anon-enum-enum-conversion',
  1143. '-Wno-deprecated-enum-enum-conversion',
  1144. '-Wno-deprecated-enum-float-conversion',
  1145. '-Wno-deprecated-volatile',
  1146. '-Wno-pessimizing-move',
  1147. '-Wno-return-std-move',
  1148. '-Wno-undefined-var-template',
  1149. ]
  1150. elif self.tc.is_gcc:
  1151. self.c_foptions.append('-fno-delete-null-pointer-checks')
  1152. self.c_foptions.append('-fabi-version=8')
  1153. # Split all functions and data into separate sections for DCE and ICF linker passes
  1154. # NOTE: iOS build uses -fembed-bitcode which conflicts with -ffunction-sections (only relevant for ELF targets)
  1155. if not self.target.is_ios:
  1156. self.c_foptions.extend(['-ffunction-sections', '-fdata-sections'])
  1157. def configure_build_type(self):
  1158. if self.build.is_valgrind:
  1159. self.c_defines.append('-DWITH_VALGRIND=1')
  1160. if self.build.is_debug:
  1161. self.c_foptions.append('$FSTACK')
  1162. if self.build.is_fast_debug:
  1163. self.c_flags.append('-Og')
  1164. if self.build.is_release:
  1165. self.c_flags.append('$OPTIMIZE')
  1166. if self.build.is_size_optimized:
  1167. # -Oz is clang's more size-aggressive version of -Os
  1168. # For ARM specifically, clang -Oz is on par with gcc -Os:
  1169. # https://github.com/android/ndk/issues/133#issuecomment-365763507
  1170. if self.tc.is_clang:
  1171. self.optimize = '-Oz'
  1172. else:
  1173. self.optimize = '-Os'
  1174. # Generate sections with address significance tables for ICF linker pass
  1175. if self.tc.is_clang:
  1176. self.c_foptions.extend(['-faddrsig'])
  1177. else:
  1178. self.optimize = '-O3'
  1179. if self.build.with_ndebug:
  1180. self.c_defines.append('-DNDEBUG')
  1181. else:
  1182. self.c_defines.append('-UNDEBUG')
  1183. if self.build.profiler_type in (Profiler.Generic, Profiler.GProf):
  1184. self.c_foptions.append('-fno-omit-frame-pointer')
  1185. if self.build.profiler_type == Profiler.GProf:
  1186. self.c_flags.append('-pg')
  1187. def print_compiler(self):
  1188. super(GnuCompiler, self).print_compiler()
  1189. emit('C_COMPILER_UNQUOTED', self.tc.c_compiler)
  1190. emit('OPTIMIZE', self.optimize)
  1191. emit('WERROR_MODE', self.tc.werror_mode)
  1192. emit('_C_FLAGS', self.c_flags)
  1193. emit('_C_FOPTIONS', self.c_foptions)
  1194. emit('_CXX_STD', '-std={}'.format(self.tc.cxx_std))
  1195. append('C_DEFINES', self.c_defines)
  1196. append('C_WARNING_OPTS', self.c_warnings)
  1197. append('CXX_WARNING_OPTS', self.cxx_warnings)
  1198. emit('CXX_COMPILER_UNQUOTED', self.tc.cxx_compiler)
  1199. # TODO(somov): Убрать чтение настройки из os.environ
  1200. emit('USE_ARC_PROFILE', 'yes' if preset('USE_ARC_PROFILE') or os.environ.get('USE_ARC_PROFILE') else 'no')
  1201. emit('DEBUG_INFO_FLAGS', self.debug_info_flags)
  1202. if self.build.is_coverage:
  1203. emit('_IS_COVERAGE', 'yes')
  1204. if self.tc.is_clang and self.tc.version_at_least(9):
  1205. emit('_HAS_TIME_TRACE', 'yes')
  1206. print('@import "${CONF_ROOT}/conf/compilers/gnu_compiler.conf"')
  1207. class SwiftCompiler(object):
  1208. def __init__(self, build):
  1209. self.host = build.host
  1210. self.compiler = None
  1211. def configure(self):
  1212. if self.host.is_macos:
  1213. self.compiler = '$SWIFT_XCODE_TOOLCHAIN_ROOT_RESOURCE_GLOBAL/usr/bin/swiftc'
  1214. def print_compiler(self):
  1215. emit('SWIFT_COMPILER', self.compiler or '')
  1216. class Linker(object):
  1217. BFD = 'bfd'
  1218. LLD = 'lld'
  1219. GOLD = 'gold'
  1220. def __init__(self, tc, build):
  1221. """
  1222. :type tc: ToolchainOptions
  1223. :type build: Build
  1224. """
  1225. self.tc = tc
  1226. self.build = build
  1227. self.type = self._get_default_linker_type()
  1228. def _get_default_linker_type(self):
  1229. if not self.tc.is_from_arcadia or is_positive('EXPORT_CMAKE'):
  1230. # External (e.g. system) toolchain: disable linker selection logic
  1231. return None
  1232. if self.build.target.is_android:
  1233. # Android toolchain is NDK, LLD works on all supported platforms
  1234. return Linker.LLD
  1235. elif self.build.target.is_linux:
  1236. return Linker.LLD
  1237. # There is no linker choice on Darwin (ld64) or Windows (link.exe)
  1238. return None
  1239. def print_linker(self):
  1240. self._print_linker_selector()
  1241. def _print_linker_selector(self):
  1242. # if self.type is None then _DEFAULT_LINKER is set to empty string value
  1243. emit('_DEFAULT_LINKER_ID', self.type)
  1244. class LD(Linker):
  1245. def __init__(self, tc, build):
  1246. """
  1247. :type tc: GnuToolchainOptions
  1248. :type build: Build
  1249. """
  1250. super(LD, self).__init__(tc, build)
  1251. self.build = build
  1252. self.host = self.build.host
  1253. self.target = self.build.target
  1254. self.tc = tc
  1255. target = self.target
  1256. self.ar = preset('AR') or self.tc.ar
  1257. self.ar_plugin = self.tc.ar_plugin
  1258. self.strip = self.tc.strip
  1259. self.objcopy = self.tc.objcopy
  1260. self.objdump = self.tc.objdump
  1261. self.musl = Setting('MUSL', convert=to_bool)
  1262. if self.ar is None:
  1263. if target.is_apple:
  1264. # Use libtool. cctools ar does not understand -M needed for archive merging
  1265. self.ar = '${CCTOOLS_ROOT_RESOURCE_GLOBAL}/bin/libtool'
  1266. elif self.tc.is_from_arcadia:
  1267. if self.tc.is_clang:
  1268. self.ar = '{}/bin/llvm-ar'.format(self.tc.name_marker)
  1269. if self.tc.is_gcc:
  1270. self.ar = '{}/gcc/bin/gcc-ar'.format(self.tc.name_marker)
  1271. else:
  1272. self.ar = 'ar'
  1273. self.ar_type = 'GNU_AR'
  1274. self.llvm_ar_format = 'None'
  1275. if 'libtool' in self.ar:
  1276. self.ar_type = 'LIBTOOL'
  1277. elif 'llvm-ar' in self.ar:
  1278. self.ar_type = 'LLVM_AR'
  1279. if target.is_apple:
  1280. self.llvm_ar_format="darwin"
  1281. else:
  1282. self.llvm_ar_format="gnu"
  1283. self.ld_flags = []
  1284. if self.musl.value:
  1285. self.ld_flags.extend(['-Wl,--no-as-needed'])
  1286. elif target.is_linux:
  1287. self.ld_flags.extend(['-ldl', '-lrt', '-Wl,--no-as-needed'])
  1288. if self.tc.is_gcc:
  1289. self.ld_flags.extend(('-Wl,-Bstatic', '-latomic', '-Wl,-Bdynamic'))
  1290. elif target.is_android:
  1291. self.ld_flags.extend(['-ldl', '-Wl,--no-as-needed'])
  1292. elif target.is_macos:
  1293. self.ld_flags.append('-Wl,-no_deduplicate')
  1294. if not self.tc.is_clang:
  1295. self.ld_flags.append('-Wl,-no_compact_unwind')
  1296. if target.is_android and target.android_api < 29:
  1297. emit('_ANDROID_API_LESS_THEN_29', 'yes')
  1298. self.ld_sdk = select(default=None, selectors=[
  1299. (target.is_macos_arm64, '-Wl,-sdk_version,11.0'),
  1300. (target.is_macos, '-Wl,-sdk_version,10.15'),
  1301. (not target.is_iossim and target.is_ios, '-Wl,-sdk_version,13.1'),
  1302. (target.is_iossim, '-Wl,-sdk_version,14.5'),
  1303. ])
  1304. if self.build.profiler_type == Profiler.GProf:
  1305. self.ld_flags.append('-pg')
  1306. if self.ld_sdk:
  1307. self.ld_flags.append(self.ld_sdk)
  1308. self.sys_lib = self.tc.sys_lib
  1309. if target.is_android:
  1310. if target.is_armv7 and self.type != Linker.LLD:
  1311. self.sys_lib.append('-Wl,--fix-cortex-a8')
  1312. # NDK r23 onwards has stopped using libgcc:
  1313. # - https://github.com/android/ndk/wiki/Changelog-r23#changes
  1314. # - https://github.com/android/ndk/issues/1230
  1315. # LLVM's libunwind is now used instead of libgcc for all architectures rather than just 32-bit Arm.
  1316. # - https://github.com/android/ndk/issues/1231
  1317. # LLVM's libclang_rt.builtins is now used instead of libgcc.
  1318. if self.tc.android_ndk_version >= 23:
  1319. # Use toolchain defaults to link with libunwind/clang_rt.builtins
  1320. self.use_stdlib = '-nostdlib++'
  1321. else:
  1322. # Preserve old behaviour: specify runtime libs manually
  1323. self.use_stdlib = '-nodefaultlibs'
  1324. if target.is_armv7:
  1325. self.sys_lib.append('-lunwind')
  1326. self.sys_lib.append('-lgcc')
  1327. if self.tc.is_clang and not self.tc.version_at_least(4, 0) and target.is_linux_x86_64:
  1328. self.sys_lib.append('-L/usr/lib/x86_64-linux-gnu')
  1329. def print_linker(self):
  1330. super(LD, self).print_linker()
  1331. emit('AR_TOOL', self.ar)
  1332. emit('AR_TYPE', self.ar_type)
  1333. emit('_LD_LLVM_AR_FORMAT', self.llvm_ar_format)
  1334. emit('_LD_AR_PLUGIN', self.ar_plugin or 'None')
  1335. emit('STRIP_TOOL_VENDOR', self.strip)
  1336. emit('OBJCOPY_TOOL_VENDOR', self.objcopy)
  1337. emit('OBJDUMP_TOOL_VENDOR', self.objdump)
  1338. emit('_LD_FLAGS', self.ld_flags)
  1339. emit('_LD_SYS_LIB', self.sys_lib)
  1340. emit('LD_SDK_VERSION', self.ld_sdk)
  1341. dwarf_tool = self.tc.dwarf_tool
  1342. if dwarf_tool is None and self.tc.is_clang and (self.target.is_macos or self.target.is_ios):
  1343. dsymutil = '{}/bin/{}dsymutil'.format(self.tc.name_marker, '' if self.tc.version_at_least(7) else 'llvm-')
  1344. dwarf_tool = '${YMAKE_PYTHON} ${input:"build/scripts/run_llvm_dsymutil.py"} ' + dsymutil
  1345. if self.tc.version_at_least(5, 0):
  1346. dwarf_tool += ' -flat'
  1347. if dwarf_tool is not None:
  1348. emit('DWARF_TOOL', dwarf_tool)
  1349. arch_flag = '--arch={arch}'.format(arch=self.target.os_compat)
  1350. emit('_LD_ARCH_FLAG', arch_flag)
  1351. print('@import "${CONF_ROOT}/conf/linkers/ld.conf"')
  1352. class MSVCToolchainOptions(ToolchainOptions):
  1353. def __init__(self, build, detector):
  1354. super(MSVCToolchainOptions, self).__init__(build, detector)
  1355. # C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.14.26428
  1356. self.vc_root = None
  1357. # C:\Program Files (x86)\Windows Kits\10\Include\10.0.14393.0
  1358. self.kit_includes = None
  1359. # C:\Program Files (x86)\Windows Kits\10\Lib\10.0.14393.0
  1360. self.kit_libs = None
  1361. self.under_wine = 'wine' in self.params
  1362. self.system_msvc = 'system_msvc' in self.params
  1363. self.ide_msvs = 'ide_msvs' in self.params
  1364. self.use_clang = self.params.get('use_clang', False)
  1365. self.use_arcadia_toolchain = self.params.get('use_arcadia_toolchain', False)
  1366. self.sdk_version = None
  1367. if build.host.is_windows:
  1368. self.under_wine = False
  1369. if self.ide_msvs:
  1370. bindir = '$(VC_ExecutablePath_x64_x64)\\'
  1371. self.c_compiler = bindir + 'cl.exe'
  1372. self.cxx_compiler = self.c_compiler
  1373. self.link = bindir + 'link.exe'
  1374. self.lib = bindir + 'lib.exe'
  1375. self.masm_compiler = bindir + 'ml64.exe'
  1376. self.vc_root = None
  1377. sdk_dir = '$(WindowsSdkDir)'
  1378. self.sdk_version = '$(WindowsTargetPlatformVersion)'
  1379. self.kit_includes = os.path.join(sdk_dir, 'Include', self.sdk_version)
  1380. self.kit_libs = os.path.join(sdk_dir, 'Lib', self.sdk_version)
  1381. elif detector:
  1382. self.masm_compiler = which('ml64.exe')
  1383. self.link = which('link.exe')
  1384. self.lib = which('lib.exe')
  1385. sdk_dir = os.environ.get('WindowsSdkDir')
  1386. self.sdk_version = os.environ.get('WindowsSDKVersion').replace('\\', '')
  1387. vc_install_dir = os.environ.get('VCToolsInstallDir')
  1388. # fix for cxx_std detection problem introduced in r7740071 when running in native VS toolkit commandline:
  1389. # in that case ya make gets 'system_cxx' configuration name and cxx_std is obviously missing in that config
  1390. # so default 'c++20' is substituted and we need to hotfix it here
  1391. self.cxx_std = 'c++latest'
  1392. if any([x is None for x in (sdk_dir, self.sdk_version, vc_install_dir)]):
  1393. raise ConfigureError('No %WindowsSdkDir%, %WindowsSDKVersion% or %VCINSTALLDIR% present. Please, run vcvars64.bat to setup preferred environment.')
  1394. self.vc_root = os.path.normpath(vc_install_dir)
  1395. self.kit_includes = os.path.normpath(os.path.join(sdk_dir, 'Include', self.sdk_version))
  1396. self.kit_libs = os.path.normpath(os.path.join(sdk_dir, 'Lib', self.sdk_version))
  1397. # TODO(somov): Определять автоматически self.version в этом случае
  1398. else:
  1399. if self.version_at_least(2019):
  1400. self.sdk_version = '10.0.18362.0'
  1401. sdk_dir = '$(WINDOWS_KITS-sbr:1939557911)'
  1402. if is_positive('MSVC20'): # XXX: temporary flag, remove after DTCC-123 is completed
  1403. self.cxx_std = 'c++latest'
  1404. else:
  1405. self.sdk_version = '10.0.16299.0'
  1406. sdk_dir = '$(WINDOWS_KITS-sbr:1379398385)'
  1407. self.vc_root = self.name_marker if not self.use_clang else '$MSVC_FOR_CLANG_RESOURCE_GLOBAL'
  1408. self.kit_includes = os.path.join(sdk_dir, 'Include', self.sdk_version)
  1409. self.kit_libs = os.path.join(sdk_dir, 'Lib', self.sdk_version)
  1410. bindir = os.path.join(self.vc_root, 'bin', 'Hostx64')
  1411. tools_name = select(selectors=[
  1412. (build.target.is_x86, 'x86'),
  1413. (build.target.is_x86_64, 'x64'),
  1414. (build.target.is_armv7, 'arm'),
  1415. ])
  1416. asm_name = select(selectors=[
  1417. (build.target.is_x86, 'ml.exe'),
  1418. (build.target.is_x86_64, 'ml64.exe'),
  1419. (build.target.is_armv7, 'armasm.exe'),
  1420. ])
  1421. def prefix(_type, _path):
  1422. if not self.under_wine:
  1423. return _path
  1424. return '{wine} {type} $WINE_ENV ${{ARCADIA_ROOT}} ${{ARCADIA_BUILD_ROOT}} {path}'.format(
  1425. wine='${YMAKE_PYTHON} ${input:\"build/scripts/run_msvc_wine.py\"} $(WINE_TOOL-sbr:1093314933)/bin/wine64 -v140 ' +
  1426. '${input;hide:\"build/scripts/process_command_files.py\"} ${input;hide:\"build/scripts/process_whole_archive_option.py\"}',
  1427. type=_type,
  1428. path=_path
  1429. )
  1430. self.masm_compiler = prefix('masm', os.path.join(bindir, tools_name, asm_name))
  1431. self.link = prefix('link', os.path.join(bindir, tools_name, 'link.exe'))
  1432. self.lib = prefix('lib', os.path.join(bindir, tools_name, 'lib.exe'))
  1433. class MSVC(object):
  1434. # noinspection PyPep8Naming
  1435. class WindowsVersion(object):
  1436. """
  1437. Predefined values for _WIN32_WINNT macro.
  1438. This macro specifies minimal Windows version required by the binary being build.
  1439. A complete list of the values supported by the Windows SDK can be found at
  1440. https://docs.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt
  1441. """
  1442. Windows7 = '0x0601'
  1443. Windows8 = '0x0602'
  1444. def __init__(self, tc, build):
  1445. """
  1446. :type tc: MSVCToolchainOptions
  1447. :type build: Build
  1448. """
  1449. if not isinstance(tc, MSVCToolchainOptions):
  1450. raise TypeError('Got {} ({}) instead of an MSVCToolchainOptions'.format(tc, type(tc)))
  1451. self.build = build
  1452. self.tc = tc
  1453. class MSVCToolchain(MSVC, Toolchain):
  1454. def __init__(self, tc, build):
  1455. """
  1456. :type tc: MSVCToolchainOptions
  1457. :param build: Build
  1458. """
  1459. Toolchain.__init__(self, tc, build)
  1460. MSVC.__init__(self, tc, build)
  1461. if self.tc.from_arcadia and not self.tc.ide_msvs:
  1462. self.platform_projects.append('build/platform/msvc')
  1463. if tc.under_wine:
  1464. self.platform_projects.append('build/platform/wine')
  1465. def print_toolchain(self):
  1466. super(MSVCToolchain, self).print_toolchain()
  1467. emit('TOOLCHAIN_ENV', format_env(self.tc.get_env(), list_separator=';'))
  1468. if self.tc.sdk_version:
  1469. emit('WINDOWS_KITS_VERSION', self.tc.sdk_version)
  1470. if self.tc.under_wine:
  1471. emit('_UNDER_WINE', 'yes')
  1472. if self.tc.use_clang:
  1473. emit('CLANG_CL', 'yes')
  1474. if self.tc.ide_msvs:
  1475. emit('IDE_MSVS', 'yes')
  1476. if self.tc.use_arcadia_toolchain:
  1477. emit('USE_ARCADIA_TOOLCHAIN', 'yes')
  1478. emit('_MSVC_TC_KIT_LIBS', self.tc.kit_libs)
  1479. emit('_MSVC_TC_VC_ROOT', self.tc.vc_root)
  1480. print('@import "${CONF_ROOT}/conf/toolchains/msvc_toolchain.conf"')
  1481. class MSVCCompiler(MSVC, Compiler):
  1482. def __init__(self, tc, build):
  1483. Compiler.__init__(self, tc, 'MSVC')
  1484. MSVC.__init__(self, tc, build)
  1485. def print_compiler(self):
  1486. super(MSVCCompiler, self).print_compiler()
  1487. target = self.build.target
  1488. warns_enabled = [
  1489. 4018, # 'expression' : signed/unsigned mismatch
  1490. 4265, # 'class' : class has virtual functions, but destructor is not virtual
  1491. 4296, # 'operator' : expression is always false
  1492. 4431, # missing type specifier - int assumed
  1493. ]
  1494. warns_as_error = [
  1495. 4013, # 'function' undefined; assuming extern returning int
  1496. ]
  1497. warns_disabled = [
  1498. # While this warning corresponds to enabled-by-default -Wmacro-redefinition,
  1499. # it floods clog with abundant amount of log lines,
  1500. # as yvals_core.h from Windows SDK redefines certain
  1501. # which macros logically belong to libcxx
  1502. 4005, # '__cpp_lib_*': macro redefinition.
  1503. # Ne need to recheck this, but it looks like _CRT_USE_BUILTIN_OFFSETOF still makes sense
  1504. 4117, # macro name '_CRT_USE_BUILTIN_OFFSETOF' is reserved, '#define' ignored
  1505. 4127, # conditional expression is constant
  1506. 4200, # nonstandard extension used : zero-sized array in struct/union
  1507. 4201, # nonstandard extension used : nameless struct/union
  1508. 4351, # elements of array will be default initialized
  1509. 4355, # 'this' : used in base member initializer list
  1510. 4503, # decorated name length exceeded, name was truncated
  1511. 4510, # default constructor could not be generated
  1512. 4511, # copy constructor could not be generated
  1513. 4512, # assignment operator could not be generated
  1514. 4554, # check operator precedence for possible error; use parentheses to clarify precedence
  1515. 4610, # 'object' can never be instantiated - user defined constructor required
  1516. 4706, # assignment within conditional expression
  1517. 4800, # forcing value to bool 'true' or 'false' (performance warning)
  1518. 4996, # The POSIX name for this item is deprecated
  1519. 4714, # function marked as __forceinline not inlined
  1520. 4197, # 'TAtomic' : top-level volatile in cast is ignored
  1521. 4245, # 'initializing' : conversion from 'int' to 'ui32', signed/unsigned mismatch
  1522. 4324, # 'ystd::function<void (uint8_t *)>': structure was padded due to alignment specifier
  1523. 5033, # 'register' is no longer a supported storage class
  1524. ]
  1525. defines = [
  1526. # FIXME: This is quick fix to let catboost build from MSVS IDE
  1527. # This place is questionable overall, see YMAKE-437
  1528. '/DARCADIA_ROOT=' + ('${ARCADIA_ROOT}' if not self.tc.ide_msvs else '.'),
  1529. '/DARCADIA_BUILD_ROOT=' + ('${ARCADIA_BUILD_ROOT}' if not self.tc.ide_msvs else '.'),
  1530. '/DFAKEID=$CPP_FAKEID',
  1531. '/DWIN32',
  1532. '/D_WIN32',
  1533. '/D_WINDOWS',
  1534. # Define _CRT_*_NO_WARNINGS macros to prevent ucrt from issuing a warning whenever
  1535. # a POSIX-style function is used instead of the alternative Microsoft suggests as a secure / standard replacement
  1536. # (e. g. `strncpy()` instead of `strncpy_s()`, `access()` instead of `_access()`)
  1537. # For details see:
  1538. # https://docs.microsoft.com/en-us/cpp/c-runtime-library/security-features-in-the-crt
  1539. '/D_CRT_SECURE_NO_WARNINGS',
  1540. '/D_CRT_NONSTDC_NO_WARNINGS',
  1541. # Math constants (such as M_PI, M_E, M_SQRT2) are not defined in standard C / C++
  1542. # In order to get them defined by Windows ucrt library,
  1543. # you must first define _USE_MATH_DEFINES before #including <cmath> or math.h>.
  1544. # (NB: glibc defines these macros whenever _XOPEN_SOURCE is defined)
  1545. '/D_USE_MATH_DEFINES',
  1546. '/D__STDC_CONSTANT_MACROS',
  1547. '/D__STDC_FORMAT_MACROS',
  1548. '/D_USING_V110_SDK71_',
  1549. '/D_LIBCPP_ENABLE_CXX17_REMOVED_FEATURES',
  1550. # Below defines are covered at
  1551. # https://docs.microsoft.com/en-us/windows/win32/winprog/using-the-windows-headers#faster-builds-with-smaller-header-files
  1552. # Exclude APIs such as Cryptography, DDE, RPC, Shell, and Windows Sockets (while including <windows.h>)
  1553. '/DWIN32_LEAN_AND_MEAN',
  1554. # Define NOMINMAX to avoid min() and max() macros definition (while including <windows.h>)
  1555. '/DNOMINMAX',
  1556. ]
  1557. cxx_defines = [
  1558. # Use builtin offsetof implementation
  1559. # instead of a crutcy macro defined in ucrt/stddef.h.
  1560. # The latter can not be used in constexpr statements.
  1561. '/D_CRT_USE_BUILTIN_OFFSETOF',
  1562. ]
  1563. if target.is_x86_64:
  1564. defines.extend(('/D_WIN64', '/DWIN64'))
  1565. if target.is_armv7:
  1566. defines.extend(('/D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE', '/D__arm__'))
  1567. winapi_unicode = False
  1568. flags = [
  1569. '/nologo', '/Zm500', '/GR', '/bigobj', '/FC', '/EHs', '/errorReport:prompt', '$MSVC_INLINE_FLAG', '/utf-8',
  1570. # enable standard conforming mode
  1571. '/permissive-'
  1572. ]
  1573. flags += self.tc.arch_opt
  1574. c_warnings = ['/we{}'.format(code) for code in warns_as_error]
  1575. c_warnings += ['/w1{}'.format(code) for code in warns_enabled]
  1576. c_warnings += ['/wd{}'.format(code) for code in warns_disabled]
  1577. cxx_warnings = []
  1578. if self.tc.use_clang:
  1579. flags += [
  1580. # Allow <windows.h> to be included via <Windows.h> in case-sensitive file-systems.
  1581. '-fcase-insensitive-paths',
  1582. # At the time clang-cl identifies itself as MSVC 19.11:
  1583. # (actual value can be found in clang/lib/Driver/ToolChains/MSVC.cpp, the syntax would be like
  1584. # ```
  1585. # MSVT = VersionTuple(19, 11);
  1586. # ```
  1587. #
  1588. # We override this value to match current value of the actual MSVC being used.
  1589. '-fms-compatibility-version=19.21',
  1590. # for msvc compatibility
  1591. # https://clang.llvm.org/docs/UsersManual.html#microsoft-extensions
  1592. '-fdelayed-template-parsing',
  1593. ]
  1594. if target.is_x86:
  1595. flags.append('-m32')
  1596. elif target.is_x86_64:
  1597. flags.append('-m64')
  1598. c_warnings.extend((
  1599. '-Wno-format',
  1600. '-Wno-parentheses',
  1601. '-Wno-unknown-warning-option',
  1602. ))
  1603. cxx_warnings += [
  1604. '-Wimport-preprocessor-directive-pedantic',
  1605. '-Woverloaded-virtual',
  1606. '-Wno-ambiguous-reversed-operator',
  1607. '-Wno-defaulted-function-deleted',
  1608. '-Wno-deprecated-anon-enum-enum-conversion',
  1609. '-Wno-deprecated-enum-enum-conversion',
  1610. '-Wno-deprecated-enum-float-conversion',
  1611. '-Wno-deprecated-volatile',
  1612. '-Wno-undefined-var-template',
  1613. ]
  1614. if self.tc.ide_msvs:
  1615. cxx_warnings += [
  1616. '-Wno-unused-command-line-argument',
  1617. ]
  1618. win_version_min = self.WindowsVersion.Windows7
  1619. defines.append('/D_WIN32_WINNT={0}'.format(win_version_min))
  1620. if winapi_unicode:
  1621. defines += ['/DUNICODE', '/D_UNICODE']
  1622. else:
  1623. defines += ['/D_MBCS']
  1624. vc_include = os.path.join(self.tc.vc_root, 'include') if not self.tc.ide_msvs else "$(VC_VC_IncludePath.Split(';')[0].Replace('\\','/'))"
  1625. if not self.tc.ide_msvs:
  1626. def include_flag(path):
  1627. return '{flag}"{path}"'.format(path=path, flag='/I ' if not self.tc.use_clang else '-imsvc')
  1628. for name in ('shared', 'ucrt', 'um', 'winrt'):
  1629. flags.append(include_flag(os.path.join(self.tc.kit_includes, name)))
  1630. flags.append(include_flag(vc_include))
  1631. if self.tc.use_clang:
  1632. emit('CLANG_CL', 'yes')
  1633. if self.tc.ide_msvs:
  1634. emit('IDE_MSVS', 'yes')
  1635. if self.tc.use_arcadia_toolchain:
  1636. emit('USE_ARCADIA_TOOLCHAIN', 'yes')
  1637. emit('CXX_COMPILER', self.tc.cxx_compiler)
  1638. emit('C_COMPILER', self.tc.c_compiler)
  1639. emit('MASM_COMPILER', self.tc.masm_compiler)
  1640. append('C_DEFINES', defines)
  1641. append('C_WARNING_OPTS', c_warnings)
  1642. emit('_CXX_DEFINES', cxx_defines)
  1643. append('CXX_WARNING_OPTS', cxx_warnings)
  1644. if self.build.is_release:
  1645. emit('CFLAGS_PER_TYPE', '$CFLAGS_RELEASE')
  1646. if self.build.is_debug:
  1647. emit('CFLAGS_PER_TYPE', '$CFLAGS_DEBUG')
  1648. if self.build.is_ide:
  1649. emit('CFLAGS_PER_TYPE', '@[debug|$CFLAGS_DEBUG]@[release|$CFLAGS_RELEASE]')
  1650. emit('_STD_CXX', '/std:{}'.format(self.tc.cxx_std))
  1651. emit('_MSVC_FLAGS', flags)
  1652. ucrt_include = os.path.join(self.tc.kit_includes, 'ucrt') if not self.tc.ide_msvs else "$(UniversalCRT_IncludePath.Split(';')[0].Replace('\\','/'))"
  1653. # 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.
  1654. if not self.tc.use_clang:
  1655. emit('_CFLAGS_UCRT_VC_INCLUDES', '/DY_UCRT_INCLUDE="%s"' % ucrt_include, '/DY_MSVC_INCLUDE="%s"' % vc_include)
  1656. else:
  1657. emit('_CFLAGS_UCRT_VC_INCLUDES')
  1658. emit('WERROR_MODE', self.tc.werror_mode)
  1659. print('@import "${CONF_ROOT}/conf/compilers/msvc_compiler.conf"')
  1660. class MSVCLinker(MSVC, Linker):
  1661. def __init__(self, tc, build):
  1662. MSVC.__init__(self, tc, build)
  1663. Linker.__init__(self, tc, build)
  1664. def print_linker(self):
  1665. super(MSVCLinker, self).print_linker()
  1666. linker = self.tc.link
  1667. linker_lib = self.tc.lib
  1668. emit('LINK_LIB_CMD', linker_lib)
  1669. emit('LINK_EXE_CMD', linker)
  1670. if self.build.is_release:
  1671. emit('LINK_EXE_FLAGS_PER_TYPE', '$LINK_EXE_FLAGS_RELEASE')
  1672. if self.build.is_debug:
  1673. emit('LINK_EXE_FLAGS_PER_TYPE', '$LINK_EXE_FLAGS_DEBUG')
  1674. if self.build.is_ide and self.tc.ide_msvs:
  1675. emit('LINK_EXE_FLAGS_PER_TYPE', '@[debug|$LINK_EXE_FLAGS_DEBUG]@[release|$LINK_EXE_FLAGS_RELEASE]')
  1676. print('@import "${CONF_ROOT}/conf/linkers/msvc_linker.conf"')
  1677. # TODO(somov): Rename!
  1678. Compilers = {
  1679. 'gnu': (GnuToolchain, GnuCompiler, LD),
  1680. 'clang': (GnuToolchain, GnuCompiler, LD),
  1681. 'xcode': (GnuToolchain, GnuCompiler, LD),
  1682. 'msvc': (MSVCToolchain, MSVCCompiler, MSVCLinker),
  1683. }
  1684. class Ragel(object):
  1685. def __init__(self):
  1686. self.rlgen_flags = []
  1687. self.ragel_flags = []
  1688. self.ragel6_flags = []
  1689. def configure_toolchain(self, build, compiler):
  1690. if isinstance(compiler, MSVCCompiler):
  1691. self.set_default_flags(optimized=False)
  1692. elif isinstance(compiler, GnuCompiler):
  1693. self.set_default_flags(optimized=build.is_release and not build.is_sanitized)
  1694. else:
  1695. raise ConfigureError('Unexpected compiler {}'.format(compiler))
  1696. def set_default_flags(self, optimized):
  1697. if optimized:
  1698. self.rlgen_flags.append('-G2')
  1699. self.ragel6_flags.append('-CG2')
  1700. else:
  1701. self.rlgen_flags.append('-T0')
  1702. self.ragel6_flags.append('-CT0')
  1703. def print_variables(self):
  1704. emit('RLGEN_FLAGS', self.rlgen_flags)
  1705. emit('RAGEL_FLAGS', self.ragel_flags)
  1706. emit('RAGEL6_FLAGS', self.ragel6_flags)
  1707. class Python(object):
  1708. def __init__(self, tc):
  1709. self.python = None
  1710. self.flags = None
  1711. self.ldflags = None
  1712. self.libraries = None
  1713. self.includes = None
  1714. self.tc = tc
  1715. def configure_posix(self, python=None, python_config=None):
  1716. python = python or preset('PYTHON_BIN') or which('python')
  1717. python_config = python_config or preset('PYTHON_CONFIG') or which('python-config')
  1718. if python is None or python_config is None:
  1719. return
  1720. # python-config dumps each option on one line in the specified order
  1721. config = get_stdout([python_config, '--cflags', '--ldflags', '--includes']) or ''
  1722. config = config.split('\n')
  1723. if len(config) < 3:
  1724. return
  1725. self.python = python
  1726. self.flags = config[0]
  1727. self.ldflags = config[1]
  1728. self.includes = config[2]
  1729. # Do not split libraries from ldflags.
  1730. # They are not used separately and get overriden together, so it is safe.
  1731. # TODO(somov): Удалить эту переменную и PYTHON_LIBRARIES из makelist-ов.
  1732. self.libraries = ''
  1733. if preset('USE_ARCADIA_PYTHON') == 'no' and not preset('USE_SYSTEM_PYTHON') and not self.tc.os_sdk_local:
  1734. raise Exception("Use fixed python (see https://clubs.at.yandex-team.ru/arcadia/15392) or set OS_SDK=local flag")
  1735. def print_variables(self):
  1736. variables = Variables({
  1737. 'PYTHON_BIN': self.python,
  1738. 'PYTHON_FLAGS': self.flags,
  1739. 'PYTHON_LDFLAGS': self.ldflags,
  1740. 'PYTHON_LIBRARIES': self.libraries,
  1741. 'PYTHON_INCLUDE': self.includes
  1742. })
  1743. variables.update_from_presets()
  1744. variables.reset_if_any(reset_value='PYTHON-NOT-FOUND')
  1745. variables.emit()
  1746. class Perl(object):
  1747. # Parse (key, value) from "version='5.26.0';" lines
  1748. PERL_CONFIG_RE = re.compile(r"^(?P<key>\w+)='(?P<value>.*)';$", re.MULTILINE)
  1749. def __init__(self):
  1750. self.perl = None
  1751. self.version = None
  1752. self.privlib = None
  1753. self.archlib = None
  1754. def configure_local(self, perl=None):
  1755. self.perl = perl or preset('PERL') or which('perl')
  1756. if self.perl is None:
  1757. return
  1758. # noinspection PyTypeChecker
  1759. config = dict(self._iter_config(['version', 'privlibexp', 'archlibexp']))
  1760. self.version = config.get('version')
  1761. self.privlib = config.get('privlibexp')
  1762. self.archlib = config.get('archlibexp')
  1763. def print_variables(self, prefix=''):
  1764. variables = Variables({
  1765. prefix + 'PERL': self.perl,
  1766. prefix + 'PERL_VERSION': self.version,
  1767. prefix + 'PERL_PRIVLIB': self.privlib,
  1768. prefix + 'PERL_ARCHLIB': self.archlib,
  1769. })
  1770. variables.reset_if_any(reset_value='PERL-NOT-FOUND')
  1771. variables.emit(with_ignore_comment=variables.keys())
  1772. def _iter_config(self, config_keys):
  1773. # Run perl -V:version -V:etc...
  1774. perl_config = [self.perl] + ['-V:{}'.format(key) for key in config_keys]
  1775. config = six.ensure_str(get_stdout(perl_config) or '')
  1776. start = 0
  1777. while True:
  1778. match = Perl.PERL_CONFIG_RE.search(config, start)
  1779. if match is None:
  1780. break
  1781. yield match.group('key', 'value')
  1782. start = match.end()
  1783. class Setting(object):
  1784. def __init__(self, key, auto=None, convert=None, rewrite=False):
  1785. self.key = key
  1786. self.auto = auto
  1787. self.convert = convert
  1788. self.preset = preset(key)
  1789. self.from_user = self.preset is not None
  1790. self.rewrite = rewrite
  1791. self._value = Setting.no_value
  1792. @property
  1793. def value(self):
  1794. if self._value is Setting.no_value:
  1795. self._value = self.calculate_value()
  1796. return self._value
  1797. def calculate_value(self):
  1798. if not self.from_user:
  1799. return self.auto if not callable(self.auto) else self.auto()
  1800. else:
  1801. return self.preset if not self.convert else self.convert(self.preset)
  1802. @value.setter
  1803. def value(self, value):
  1804. if self.from_user:
  1805. 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))
  1806. self._value = value
  1807. def emit(self):
  1808. if not self.from_user or self.rewrite:
  1809. emit(self.key, self.value)
  1810. no_value = object()
  1811. class Cuda(object):
  1812. def __init__(self, build):
  1813. """
  1814. :type build: Build
  1815. """
  1816. self.build = build
  1817. self.have_cuda = Setting('HAVE_CUDA', auto=self.auto_have_cuda, convert=to_bool)
  1818. self.cuda_root = Setting('CUDA_ROOT')
  1819. self.cuda_version = Setting('CUDA_VERSION', auto=self.auto_cuda_version, convert=self.convert_major_version, rewrite=True)
  1820. self.use_arcadia_cuda = Setting('USE_ARCADIA_CUDA', auto=self.auto_use_arcadia_cuda, convert=to_bool)
  1821. self.use_arcadia_cuda_host_compiler = Setting('USE_ARCADIA_CUDA_HOST_COMPILER', auto=self.auto_use_arcadia_cuda_host_compiler, convert=to_bool)
  1822. self.cuda_use_clang = Setting('CUDA_USE_CLANG', auto=False, convert=to_bool)
  1823. self.cuda_host_compiler = Setting('CUDA_HOST_COMPILER', auto=self.auto_cuda_host_compiler)
  1824. self.cuda_host_compiler_env = Setting('CUDA_HOST_COMPILER_ENV')
  1825. self.cuda_host_msvc_version = Setting('CUDA_HOST_MSVC_VERSION')
  1826. self.cuda_nvcc_flags = Setting('CUDA_NVCC_FLAGS', auto=[])
  1827. self.peerdirs = ['build/platform/cuda']
  1828. self.nvcc_flags = [
  1829. # Allow __host__, __device__ annotations in lambda declaration.
  1830. "--expt-extended-lambda",
  1831. # Allow host code to invoke __device__ constexpr functions and vice versa
  1832. "--expt-relaxed-constexpr",
  1833. ]
  1834. if not self.have_cuda.value:
  1835. return
  1836. if self.cuda_host_compiler.value:
  1837. self.nvcc_flags.append('--compiler-bindir=$CUDA_HOST_COMPILER')
  1838. if self.use_arcadia_cuda.value:
  1839. self.cuda_root.value = '$CUDA_RESOURCE_GLOBAL'
  1840. if self.build.target.is_linux_x86_64 and self.build.tc.is_clang:
  1841. # TODO(somov): Эта настройка должна приезжать сюда автоматически из другого места
  1842. self.nvcc_flags.append('-I$OS_SDK_ROOT/usr/include/x86_64-linux-gnu')
  1843. def print_(self):
  1844. self.print_variables()
  1845. self.print_macros()
  1846. print('@import "${CONF_ROOT}/conf/compilers/nvcc.conf"')
  1847. def print_variables(self):
  1848. self.have_cuda.emit()
  1849. if not self.have_cuda.value:
  1850. return
  1851. if self.use_arcadia_cuda.value and self.cuda_host_compiler.value is None:
  1852. logger.warning('$USE_ARCADIA_CUDA is set, but no $CUDA_HOST_COMPILER')
  1853. self.setup_vc_root()
  1854. self.cuda_root.emit()
  1855. self.cuda_version.emit()
  1856. self.use_arcadia_cuda.emit()
  1857. self.use_arcadia_cuda_host_compiler.emit()
  1858. self.cuda_use_clang.emit()
  1859. self.cuda_host_compiler.emit()
  1860. self.cuda_host_compiler_env.emit()
  1861. self.cuda_host_msvc_version.emit()
  1862. self.cuda_nvcc_flags.emit()
  1863. emit('NVCC_UNQUOTED', self.build.host.exe('$CUDA_ROOT', 'bin', 'nvcc'))
  1864. emit('NVCC', '${quo:NVCC_UNQUOTED}')
  1865. emit('NVCC_FLAGS', self.nvcc_flags, '$CUDA_NVCC_FLAGS')
  1866. emit('NVCC_OBJ_EXT', '.o' if not self.build.target.is_windows else '.obj')
  1867. def print_macros(self):
  1868. mtime = ' '
  1869. if self.build.host_target[1].is_linux:
  1870. mtime = ' --mtime ${tool:"tools/mtime0"} '
  1871. if not self.cuda_use_clang.value:
  1872. cmd = '$YMAKE_PYTHON ${input:"build/scripts/compile_cuda.py"}' + mtime + '$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 $NVCC_CFLAGS $SRCFLAGS ${input;hide:"build/platform/cuda/cuda_runtime_include.h"} $CUDA_HOST_COMPILER_ENV ${kv;hide:"p CC"} ${kv;hide:"pc light-green"}' # noqa E501
  1873. else:
  1874. 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 ${kv;hide:"p CU"} ${kv;hide:"pc green"}' # noqa E501
  1875. emit('_SRC_CU_CMD', cmd)
  1876. emit('_SRC_CU_PEERDIR', ' '.join(sorted(self.peerdirs)))
  1877. def have_cuda_in_arcadia(self):
  1878. host, target = self.build.host_target
  1879. if not any((host.is_linux_x86_64, host.is_macos_x86_64, host.is_windows_x86_64, host.is_linux_powerpc)):
  1880. return False
  1881. if host != target:
  1882. if not(host.is_linux_x86_64 and target.is_linux_armv8):
  1883. return False
  1884. if not self.cuda_version.from_user:
  1885. return False
  1886. if self.cuda_version.value in ('8.0', '9.0', '9.1', '9.2', '10.0'):
  1887. raise ConfigureError('CUDA versions 8.x, 9.x and 10.0 are no longer supported.\nSee DEVTOOLS-7108.')
  1888. if self.cuda_version.value in ('10.1', '11.0', '11.1', '11.3', '11.4'):
  1889. return True
  1890. return False
  1891. def auto_have_cuda(self):
  1892. if is_positive('MUSL'):
  1893. return False
  1894. if self.build.is_sanitized:
  1895. return False
  1896. if self.build.host_target[1].is_macos_x86_64 or self.build.host_target[1].is_macos_arm64:
  1897. # DEVTOOLSSUPPORT-19178 CUDA is rarely needed on Mac. Disable it by default but allow explicit builds with CUDA.
  1898. return False
  1899. return self.cuda_root.from_user or self.use_arcadia_cuda.value and self.have_cuda_in_arcadia()
  1900. def auto_cuda_version(self):
  1901. if self.use_arcadia_cuda.value:
  1902. return '10.1'
  1903. if not self.have_cuda.value:
  1904. return None
  1905. nvcc_exe = self.build.host.exe(os.path.expanduser(self.cuda_root.value), 'bin', 'nvcc')
  1906. def error():
  1907. raise ConfigureError('Failed to get CUDA version from {}'.format(nvcc_exe))
  1908. version_output = get_stdout([nvcc_exe, '--version']) or error()
  1909. match = re.search(r'^Cuda compilation tools, release (\d+)\.\d+,', version_output, re.MULTILINE) or error()
  1910. return match.group(1)
  1911. def convert_major_version(self, value):
  1912. if value == '10':
  1913. return '10.1'
  1914. elif value == '11':
  1915. return '11.3'
  1916. else:
  1917. return value
  1918. def auto_use_arcadia_cuda(self):
  1919. return not self.cuda_root.from_user
  1920. def auto_use_arcadia_cuda_host_compiler(self):
  1921. return not self.cuda_host_compiler.from_user and not self.cuda_use_clang.value
  1922. def auto_cuda_host_compiler(self):
  1923. if not self.use_arcadia_cuda_host_compiler.value:
  1924. return None
  1925. host, target = self.build.host_target
  1926. if host.is_windows_x86_64 and target.is_windows_x86_64:
  1927. return self.cuda_windows_host_compiler()
  1928. return select((
  1929. (host.is_linux_x86_64 and target.is_linux_x86_64, '$CUDA_HOST_TOOLCHAIN_RESOURCE_GLOBAL/bin/clang'),
  1930. (host.is_linux_x86_64 and target.is_linux_armv8, '$CUDA_HOST_TOOLCHAIN_RESOURCE_GLOBAL/bin/clang'),
  1931. (host.is_linux_powerpc and target.is_linux_powerpc, '$CUDA_HOST_TOOLCHAIN_RESOURCE_GLOBAL/bin/clang'),
  1932. (host.is_macos_x86_64 and target.is_macos_x86_64, '$CUDA_HOST_TOOLCHAIN_RESOURCE_GLOBAL/usr/bin/clang'),
  1933. ))
  1934. def cuda_windows_host_compiler(self):
  1935. vc_version = '14.28.29910'
  1936. env = {
  1937. 'Y_VC_Version': vc_version,
  1938. 'Y_VC_Root': '$CUDA_HOST_TOOLCHAIN_RESOURCE_GLOBAL/VC/Tools/MSVC/{}'.format(vc_version),
  1939. 'Y_SDK_Version': self.build.tc.sdk_version,
  1940. 'Y_SDK_Root': '$WINDOWS_KITS_RESOURCE_GLOBAL',
  1941. }
  1942. if not self.build.tc.ide_msvs:
  1943. self.peerdirs.append('build/platform/msvc')
  1944. self.cuda_host_compiler_env.value = format_env(env)
  1945. self.cuda_host_msvc_version.value = vc_version
  1946. return '%(Y_VC_Root)s/bin/HostX64/x64/cl.exe' % env
  1947. def setup_vc_root(self):
  1948. if not self.cuda_host_compiler.from_user:
  1949. return # Already set in cuda_windows_host_compiler()
  1950. if self.cuda_host_compiler_env.from_user:
  1951. return # We won't override user setting
  1952. def is_root(dir):
  1953. return all(os.path.isdir(os.path.join(dir, name)) for name in ('bin', 'include', 'lib'))
  1954. def get_root():
  1955. path, old_path = os.path.normpath(self.cuda_host_compiler.value), None
  1956. while path != old_path:
  1957. if is_root(path):
  1958. return path
  1959. path, old_path = os.path.dirname(path), path
  1960. vc_root = get_root()
  1961. if vc_root:
  1962. self.cuda_host_compiler_env.value = format_env({'Y_VC_Root': vc_root})
  1963. class CuDNN(object):
  1964. def __init__(self, cuda):
  1965. """
  1966. :type cuda: Cuda
  1967. """
  1968. self.cuda = cuda
  1969. self.cudnn_version = Setting('CUDNN_VERSION', auto=self.auto_cudnn_version)
  1970. def have_cudnn(self):
  1971. return self.cudnn_version.value in ('7.6.5', '8.0.5')
  1972. def auto_cudnn_version(self):
  1973. return '7.6.5'
  1974. def print_(self):
  1975. if self.cuda.have_cuda.value and self.have_cudnn():
  1976. self.cudnn_version.emit()
  1977. def print_swig_config():
  1978. def get_swig_tool():
  1979. tool = preset('USER_SWIG_TOOL')
  1980. if not tool:
  1981. tool = which('swig')
  1982. if not tool:
  1983. raise ConfigureError('SWIG_TOOL is not specified and "swig" is not found in PATH')
  1984. return os.path.abspath(tool)
  1985. def get_swig_library(tool):
  1986. library = preset('USER_SWIG_LIBRARY')
  1987. if not library:
  1988. library, code = get_stdout_and_code((tool, '-swiglib'))
  1989. if code != 0:
  1990. raise ConfigureError('SWIG_LIBRARY is not specified and "{} -swiglib" failed'.format(tool))
  1991. library = library.split('\n')[0]
  1992. return os.path.abspath(library)
  1993. use_local_swig = to_bool(preset('USER_USE_LOCAL_SWIG'), False) or bool(preset('USER_SWIG_TOOL'))
  1994. if use_local_swig:
  1995. tool = get_swig_tool()
  1996. library = get_swig_library(tool)
  1997. emit('USE_LOCAL_SWIG', True)
  1998. emit('SWIG_TOOL', tool)
  1999. emit('SWIG_LIBRARY', library)
  2000. def main():
  2001. options = opts()
  2002. arcadia = Arcadia(options.arcadia_root)
  2003. ymake = YMake(arcadia)
  2004. ymake.print_core_conf()
  2005. ymake.print_presets()
  2006. ymake.print_settings()
  2007. build = Build(arcadia, options.build_type, options.toolchain_params, force_ignore_local_files=not options.local_distbuild)
  2008. build.print_build()
  2009. emit_with_ignore_comment('CONF_SCRIPT_DEPENDS', __file__)
  2010. if __name__ == '__main__':
  2011. main()