ymake_conf.py 97 KB

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