d.py 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806
  1. # Copyright 2012-2017 The Meson development team
  2. # Licensed under the Apache License, Version 2.0 (the "License");
  3. # you may not use this file except in compliance with the License.
  4. # You may obtain a copy of the License at
  5. # http://www.apache.org/licenses/LICENSE-2.0
  6. # Unless required by applicable law or agreed to in writing, software
  7. # distributed under the License is distributed on an "AS IS" BASIS,
  8. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. # See the License for the specific language governing permissions and
  10. # limitations under the License.
  11. import os.path, subprocess
  12. import typing as T
  13. from ..mesonlib import (
  14. EnvironmentException, MachineChoice, version_compare,
  15. )
  16. from .compilers import (
  17. d_dmd_buildtype_args,
  18. d_gdc_buildtype_args,
  19. d_ldc_buildtype_args,
  20. clike_debug_args,
  21. Compiler,
  22. CompilerArgs,
  23. )
  24. from .mixins.gnu import GnuCompiler
  25. if T.TYPE_CHECKING:
  26. from ..envconfig import MachineInfo
  27. d_feature_args = {'gcc': {'unittest': '-funittest',
  28. 'debug': '-fdebug',
  29. 'version': '-fversion',
  30. 'import_dir': '-J'
  31. },
  32. 'llvm': {'unittest': '-unittest',
  33. 'debug': '-d-debug',
  34. 'version': '-d-version',
  35. 'import_dir': '-J'
  36. },
  37. 'dmd': {'unittest': '-unittest',
  38. 'debug': '-debug',
  39. 'version': '-version',
  40. 'import_dir': '-J'
  41. }
  42. }
  43. ldc_optimization_args = {'0': [],
  44. 'g': [],
  45. '1': ['-O1'],
  46. '2': ['-O2'],
  47. '3': ['-O3'],
  48. 's': ['-Os'],
  49. }
  50. dmd_optimization_args = {'0': [],
  51. 'g': [],
  52. '1': ['-O'],
  53. '2': ['-O'],
  54. '3': ['-O'],
  55. 's': ['-O'],
  56. }
  57. class DmdLikeCompilerMixin:
  58. LINKER_PREFIX = '-L='
  59. def get_output_args(self, target):
  60. return ['-of=' + target]
  61. def get_linker_output_args(self, target):
  62. return ['-of=' + target]
  63. def get_include_args(self, path, is_system):
  64. return ['-I=' + path]
  65. def compute_parameters_with_absolute_paths(self, parameter_list, build_dir):
  66. for idx, i in enumerate(parameter_list):
  67. if i[:3] == '-I=':
  68. parameter_list[idx] = i[:3] + os.path.normpath(os.path.join(build_dir, i[3:]))
  69. if i[:4] == '-L-L':
  70. parameter_list[idx] = i[:4] + os.path.normpath(os.path.join(build_dir, i[4:]))
  71. if i[:5] == '-L=-L':
  72. parameter_list[idx] = i[:5] + os.path.normpath(os.path.join(build_dir, i[5:]))
  73. if i[:6] == '-Wl,-L':
  74. parameter_list[idx] = i[:6] + os.path.normpath(os.path.join(build_dir, i[6:]))
  75. return parameter_list
  76. def get_warn_args(self, level):
  77. return ['-wi']
  78. def get_werror_args(self):
  79. return ['-w']
  80. def get_dependency_gen_args(self, outtarget, outfile):
  81. # DMD and LDC does not currently return Makefile-compatible dependency info.
  82. return []
  83. def get_coverage_args(self):
  84. return ['-cov']
  85. def get_coverage_link_args(self):
  86. return []
  87. def get_preprocess_only_args(self):
  88. return ['-E']
  89. def get_compile_only_args(self):
  90. return ['-c']
  91. def depfile_for_object(self, objfile):
  92. return objfile + '.' + self.get_depfile_suffix()
  93. def get_depfile_suffix(self):
  94. return 'deps'
  95. def get_pic_args(self):
  96. if self.info.is_windows():
  97. return []
  98. return ['-fPIC']
  99. def get_feature_args(self, kwargs, build_to_src):
  100. res = []
  101. if 'unittest' in kwargs:
  102. unittest = kwargs.pop('unittest')
  103. unittest_arg = d_feature_args[self.id]['unittest']
  104. if not unittest_arg:
  105. raise EnvironmentException('D compiler %s does not support the "unittest" feature.' % self.name_string())
  106. if unittest:
  107. res.append(unittest_arg)
  108. if 'debug' in kwargs:
  109. debug_level = -1
  110. debugs = kwargs.pop('debug')
  111. if not isinstance(debugs, list):
  112. debugs = [debugs]
  113. debug_arg = d_feature_args[self.id]['debug']
  114. if not debug_arg:
  115. raise EnvironmentException('D compiler %s does not support conditional debug identifiers.' % self.name_string())
  116. # Parse all debug identifiers and the largest debug level identifier
  117. for d in debugs:
  118. if isinstance(d, int):
  119. if d > debug_level:
  120. debug_level = d
  121. elif isinstance(d, str) and d.isdigit():
  122. if int(d) > debug_level:
  123. debug_level = int(d)
  124. else:
  125. res.append('{0}={1}'.format(debug_arg, d))
  126. if debug_level >= 0:
  127. res.append('{0}={1}'.format(debug_arg, debug_level))
  128. if 'versions' in kwargs:
  129. version_level = -1
  130. versions = kwargs.pop('versions')
  131. if not isinstance(versions, list):
  132. versions = [versions]
  133. version_arg = d_feature_args[self.id]['version']
  134. if not version_arg:
  135. raise EnvironmentException('D compiler %s does not support conditional version identifiers.' % self.name_string())
  136. # Parse all version identifiers and the largest version level identifier
  137. for v in versions:
  138. if isinstance(v, int):
  139. if v > version_level:
  140. version_level = v
  141. elif isinstance(v, str) and v.isdigit():
  142. if int(v) > version_level:
  143. version_level = int(v)
  144. else:
  145. res.append('{0}={1}'.format(version_arg, v))
  146. if version_level >= 0:
  147. res.append('{0}={1}'.format(version_arg, version_level))
  148. if 'import_dirs' in kwargs:
  149. import_dirs = kwargs.pop('import_dirs')
  150. if not isinstance(import_dirs, list):
  151. import_dirs = [import_dirs]
  152. import_dir_arg = d_feature_args[self.id]['import_dir']
  153. if not import_dir_arg:
  154. raise EnvironmentException('D compiler %s does not support the "string import directories" feature.' % self.name_string())
  155. for idir_obj in import_dirs:
  156. basedir = idir_obj.get_curdir()
  157. for idir in idir_obj.get_incdirs():
  158. # Avoid superfluous '/.' at the end of paths when d is '.'
  159. if idir not in ('', '.'):
  160. expdir = os.path.join(basedir, idir)
  161. else:
  162. expdir = basedir
  163. srctreedir = os.path.join(build_to_src, expdir)
  164. res.append('{0}{1}'.format(import_dir_arg, srctreedir))
  165. if kwargs:
  166. raise EnvironmentException('Unknown D compiler feature(s) selected: %s' % ', '.join(kwargs.keys()))
  167. return res
  168. def get_buildtype_linker_args(self, buildtype):
  169. if buildtype != 'plain':
  170. return self.get_target_arch_args()
  171. return []
  172. def get_std_exe_link_args(self):
  173. return []
  174. def gen_import_library_args(self, implibname):
  175. return self.linker.import_library_args(implibname)
  176. def build_rpath_args(self, env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
  177. if self.info.is_windows():
  178. return []
  179. # GNU ld, solaris ld, and lld acting like GNU ld
  180. if self.linker.id.startswith('ld'):
  181. # The way that dmd and ldc pass rpath to gcc is different than we would
  182. # do directly, each argument -rpath and the value to rpath, need to be
  183. # split into two separate arguments both prefaced with the -L=.
  184. args = []
  185. for r in super().build_rpath_args(
  186. env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
  187. if ',' in r:
  188. a, b = r.split(',', maxsplit=1)
  189. args.append(a)
  190. args.append(self.LINKER_PREFIX + b)
  191. else:
  192. args.append(r)
  193. return args
  194. return super().build_rpath_args(
  195. env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath)
  196. def translate_args_to_nongnu(self, args):
  197. dcargs = []
  198. # Translate common arguments to flags the LDC/DMD compilers
  199. # can understand.
  200. # The flags might have been added by pkg-config files,
  201. # and are therefore out of the user's control.
  202. for arg in args:
  203. # Translate OS specific arguments first.
  204. osargs = []
  205. if self.info.is_windows():
  206. osargs = self.translate_arg_to_windows(arg)
  207. elif self.info.is_darwin():
  208. osargs = self.translate_arg_to_osx(arg)
  209. if osargs:
  210. dcargs.extend(osargs)
  211. continue
  212. # Translate common D arguments here.
  213. if arg == '-pthread':
  214. continue
  215. if arg.startswith('-fstack-protector'):
  216. continue
  217. if arg.startswith('-D'):
  218. continue
  219. if arg.startswith('-Wl,'):
  220. # Translate linker arguments here.
  221. linkargs = arg[arg.index(',') + 1:].split(',')
  222. for la in linkargs:
  223. dcargs.append('-L=' + la.strip())
  224. continue
  225. elif arg.startswith(('-link-defaultlib', '-linker', '-link-internally', '-linkonce-templates', '-lib')):
  226. # these are special arguments to the LDC linker call,
  227. # arguments like "-link-defaultlib-shared" do *not*
  228. # denote a library to be linked, but change the default
  229. # Phobos/DRuntime linking behavior, while "-linker" sets the
  230. # default linker.
  231. dcargs.append(arg)
  232. continue
  233. elif arg.startswith('-l'):
  234. # translate library link flag
  235. dcargs.append('-L=' + arg)
  236. continue
  237. elif arg.startswith('-isystem'):
  238. # translate -isystem system include path
  239. # this flag might sometimes be added by C library Cflags via
  240. # pkg-config.
  241. # NOTE: -isystem and -I are not 100% equivalent, so this is just
  242. # a workaround for the most common cases.
  243. if arg.startswith('-isystem='):
  244. dcargs.append('-I=' + arg[9:])
  245. else:
  246. dcargs.append('-I' + arg[8:])
  247. continue
  248. elif arg.startswith('-idirafter'):
  249. # same as -isystem, but appends the path instead
  250. if arg.startswith('-idirafter='):
  251. dcargs.append('-I=' + arg[11:])
  252. else:
  253. dcargs.append('-I' + arg[10:])
  254. continue
  255. elif arg.startswith('-L/') or arg.startswith('-L./'):
  256. # we need to handle cases where -L is set by e.g. a pkg-config
  257. # setting to select a linker search path. We can however not
  258. # unconditionally prefix '-L' with '-L' because the user might
  259. # have set this flag too to do what it is intended to for this
  260. # compiler (pass flag through to the linker)
  261. # Hence, we guess here whether the flag was intended to pass
  262. # a linker search path.
  263. # Make sure static library files are passed properly to the linker.
  264. if arg.endswith('.a') or arg.endswith('.lib'):
  265. if arg.startswith('-L='):
  266. farg = arg[3:]
  267. else:
  268. farg = arg[2:]
  269. if len(farg) > 0 and not farg.startswith('-'):
  270. dcargs.append('-L=' + farg)
  271. continue
  272. dcargs.append('-L=' + arg)
  273. continue
  274. elif not arg.startswith('-') and arg.endswith(('.a', '.lib')):
  275. # ensure static libraries are passed through to the linker
  276. dcargs.append('-L=' + arg)
  277. continue
  278. else:
  279. dcargs.append(arg)
  280. return dcargs
  281. @classmethod
  282. def translate_arg_to_windows(cls, arg):
  283. args = []
  284. if arg.startswith('-Wl,'):
  285. # Translate linker arguments here.
  286. linkargs = arg[arg.index(',') + 1:].split(',')
  287. for la in linkargs:
  288. if la.startswith('--out-implib='):
  289. # Import library name
  290. args.append('-L=/IMPLIB:' + la[13:].strip())
  291. elif arg.startswith('-mscrtlib='):
  292. args.append(arg)
  293. mscrtlib = arg[10:].lower()
  294. if cls is LLVMDCompiler:
  295. # Default crt libraries for LDC2 must be excluded for other
  296. # selected crt options.
  297. if mscrtlib != 'libcmt':
  298. args.append('-L=/NODEFAULTLIB:libcmt')
  299. args.append('-L=/NODEFAULTLIB:libvcruntime')
  300. # Fixes missing definitions for printf-functions in VS2017
  301. if mscrtlib.startswith('msvcrt'):
  302. args.append('-L=/DEFAULTLIB:legacy_stdio_definitions.lib')
  303. return args
  304. @classmethod
  305. def translate_arg_to_osx(cls, arg):
  306. args = []
  307. if arg.startswith('-install_name'):
  308. args.append('-L=' + arg)
  309. return args
  310. def get_debug_args(self, is_debug):
  311. ddebug_args = []
  312. if is_debug:
  313. ddebug_args = [d_feature_args[self.id]['debug']]
  314. return clike_debug_args[is_debug] + ddebug_args
  315. def get_crt_args(self, crt_val, buildtype):
  316. if not self.info.is_windows():
  317. return []
  318. if crt_val in self.mscrt_args:
  319. return self.mscrt_args[crt_val]
  320. assert(crt_val == 'from_buildtype')
  321. # Match what build type flags used to do.
  322. if buildtype == 'plain':
  323. return []
  324. elif buildtype == 'debug':
  325. return self.mscrt_args['mdd']
  326. elif buildtype == 'debugoptimized':
  327. return self.mscrt_args['md']
  328. elif buildtype == 'release':
  329. return self.mscrt_args['md']
  330. elif buildtype == 'minsize':
  331. return self.mscrt_args['md']
  332. else:
  333. assert(buildtype == 'custom')
  334. raise EnvironmentException('Requested C runtime based on buildtype, but buildtype is "custom".')
  335. def get_soname_args(self, *args, **kwargs) -> T.List[str]:
  336. # LDC and DMD actually do use a linker, but they proxy all of that with
  337. # their own arguments
  338. if self.linker.id.startswith('ld.'):
  339. soargs = []
  340. for arg in super().get_soname_args(*args, **kwargs):
  341. a, b = arg.split(',', maxsplit=1)
  342. soargs.append(a)
  343. soargs.append(self.LINKER_PREFIX + b)
  344. return soargs
  345. elif self.linker.id.startswith('ld64'):
  346. soargs = []
  347. for arg in super().get_soname_args(*args, **kwargs):
  348. if not arg.startswith(self.LINKER_PREFIX):
  349. soargs.append(self.LINKER_PREFIX + arg)
  350. else:
  351. soargs.append(arg)
  352. return soargs
  353. else:
  354. return super().get_soname_args(*args, **kwargs)
  355. def get_allow_undefined_link_args(self) -> T.List[str]:
  356. args = self.linker.get_allow_undefined_args()
  357. if self.info.is_darwin():
  358. # On macOS we're passing these options to the C compiler, but
  359. # they're linker options and need -Wl, so clang/gcc knows what to
  360. # do with them. I'm assuming, but don't know for certain, that
  361. # ldc/dmd do some kind of mapping internally for arguments they
  362. # understand, but pass arguments they don't understand directly.
  363. args = [a.replace('-L=', '-Xcc=-Wl,') for a in args]
  364. return args
  365. class DCompiler(Compiler):
  366. mscrt_args = {
  367. 'none': ['-mscrtlib='],
  368. 'md': ['-mscrtlib=msvcrt'],
  369. 'mdd': ['-mscrtlib=msvcrtd'],
  370. 'mt': ['-mscrtlib=libcmt'],
  371. 'mtd': ['-mscrtlib=libcmtd'],
  372. }
  373. language = 'd'
  374. def __init__(self, exelist, version, for_machine: MachineChoice,
  375. info: 'MachineInfo', arch, is_cross, exe_wrapper, **kwargs):
  376. super().__init__(exelist, version, for_machine, info, **kwargs)
  377. self.id = 'unknown'
  378. self.arch = arch
  379. self.exe_wrapper = exe_wrapper
  380. self.is_cross = is_cross
  381. def sanity_check(self, work_dir, environment):
  382. source_name = os.path.join(work_dir, 'sanity.d')
  383. output_name = os.path.join(work_dir, 'dtest')
  384. with open(source_name, 'w') as ofile:
  385. ofile.write('''void main() { }''')
  386. pc = subprocess.Popen(self.exelist + self.get_output_args(output_name) + self.get_target_arch_args() + [source_name], cwd=work_dir)
  387. pc.wait()
  388. if pc.returncode != 0:
  389. raise EnvironmentException('D compiler %s can not compile programs.' % self.name_string())
  390. if self.is_cross:
  391. if self.exe_wrapper is None:
  392. # Can't check if the binaries run so we have to assume they do
  393. return
  394. cmdlist = self.exe_wrapper.get_command() + [output_name]
  395. else:
  396. cmdlist = [output_name]
  397. if subprocess.call(cmdlist) != 0:
  398. raise EnvironmentException('Executables created by D compiler %s are not runnable.' % self.name_string())
  399. def needs_static_linker(self):
  400. return True
  401. def depfile_for_object(self, objfile):
  402. return objfile + '.' + self.get_depfile_suffix()
  403. def get_depfile_suffix(self):
  404. return 'deps'
  405. def get_pic_args(self):
  406. if self.info.is_windows():
  407. return []
  408. return ['-fPIC']
  409. def get_feature_args(self, kwargs, build_to_src):
  410. res = []
  411. if 'unittest' in kwargs:
  412. unittest = kwargs.pop('unittest')
  413. unittest_arg = d_feature_args[self.id]['unittest']
  414. if not unittest_arg:
  415. raise EnvironmentException('D compiler %s does not support the "unittest" feature.' % self.name_string())
  416. if unittest:
  417. res.append(unittest_arg)
  418. if 'debug' in kwargs:
  419. debug_level = -1
  420. debugs = kwargs.pop('debug')
  421. if not isinstance(debugs, list):
  422. debugs = [debugs]
  423. debug_arg = d_feature_args[self.id]['debug']
  424. if not debug_arg:
  425. raise EnvironmentException('D compiler %s does not support conditional debug identifiers.' % self.name_string())
  426. # Parse all debug identifiers and the largest debug level identifier
  427. for d in debugs:
  428. if isinstance(d, int):
  429. if d > debug_level:
  430. debug_level = d
  431. elif isinstance(d, str) and d.isdigit():
  432. if int(d) > debug_level:
  433. debug_level = int(d)
  434. else:
  435. res.append('{0}={1}'.format(debug_arg, d))
  436. if debug_level >= 0:
  437. res.append('{0}={1}'.format(debug_arg, debug_level))
  438. if 'versions' in kwargs:
  439. version_level = -1
  440. versions = kwargs.pop('versions')
  441. if not isinstance(versions, list):
  442. versions = [versions]
  443. version_arg = d_feature_args[self.id]['version']
  444. if not version_arg:
  445. raise EnvironmentException('D compiler %s does not support conditional version identifiers.' % self.name_string())
  446. # Parse all version identifiers and the largest version level identifier
  447. for v in versions:
  448. if isinstance(v, int):
  449. if v > version_level:
  450. version_level = v
  451. elif isinstance(v, str) and v.isdigit():
  452. if int(v) > version_level:
  453. version_level = int(v)
  454. else:
  455. res.append('{0}={1}'.format(version_arg, v))
  456. if version_level >= 0:
  457. res.append('{0}={1}'.format(version_arg, version_level))
  458. if 'import_dirs' in kwargs:
  459. import_dirs = kwargs.pop('import_dirs')
  460. if not isinstance(import_dirs, list):
  461. import_dirs = [import_dirs]
  462. import_dir_arg = d_feature_args[self.id]['import_dir']
  463. if not import_dir_arg:
  464. raise EnvironmentException('D compiler %s does not support the "string import directories" feature.' % self.name_string())
  465. for idir_obj in import_dirs:
  466. basedir = idir_obj.get_curdir()
  467. for idir in idir_obj.get_incdirs():
  468. # Avoid superfluous '/.' at the end of paths when d is '.'
  469. if idir not in ('', '.'):
  470. expdir = os.path.join(basedir, idir)
  471. else:
  472. expdir = basedir
  473. srctreedir = os.path.join(build_to_src, expdir)
  474. res.append('{0}{1}'.format(import_dir_arg, srctreedir))
  475. if kwargs:
  476. raise EnvironmentException('Unknown D compiler feature(s) selected: %s' % ', '.join(kwargs.keys()))
  477. return res
  478. def get_buildtype_linker_args(self, buildtype):
  479. if buildtype != 'plain':
  480. return self.get_target_arch_args()
  481. return []
  482. def get_std_exe_link_args(self):
  483. return []
  484. def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'):
  485. if callable(extra_args):
  486. extra_args = extra_args(mode)
  487. if extra_args is None:
  488. extra_args = []
  489. elif isinstance(extra_args, str):
  490. extra_args = [extra_args]
  491. if dependencies is None:
  492. dependencies = []
  493. elif not isinstance(dependencies, list):
  494. dependencies = [dependencies]
  495. # Collect compiler arguments
  496. args = CompilerArgs(self)
  497. for d in dependencies:
  498. # Add compile flags needed by dependencies
  499. args += d.get_compile_args()
  500. if mode == 'link':
  501. # Add link flags needed to find dependencies
  502. args += d.get_link_args()
  503. if mode == 'compile':
  504. # Add DFLAGS from the env
  505. args += env.coredata.get_external_args(self.for_machine, self.language)
  506. elif mode == 'link':
  507. # Add LDFLAGS from the env
  508. args += env.coredata.get_external_link_args(self.for_machine, self.language)
  509. # extra_args must override all other arguments, so we add them last
  510. args += extra_args
  511. return args
  512. def compiles(self, code, env, *, extra_args=None, dependencies=None, mode='compile'):
  513. args = self._get_compiler_check_args(env, extra_args, dependencies, mode)
  514. with self.cached_compile(code, env.coredata, extra_args=args, mode=mode) as p:
  515. return p.returncode == 0, p.cached
  516. def has_multi_arguments(self, args, env):
  517. return self.compiles('int i;\n', env, extra_args=args)
  518. def get_target_arch_args(self):
  519. # LDC2 on Windows targets to current OS architecture, but
  520. # it should follow the target specified by the MSVC toolchain.
  521. if self.info.is_windows():
  522. if self.arch == 'x86_64':
  523. return ['-m64']
  524. return ['-m32']
  525. return []
  526. def get_crt_compile_args(self, crt_val, buildtype):
  527. return []
  528. def get_crt_link_args(self, crt_val, buildtype):
  529. return []
  530. def thread_link_flags(self, env):
  531. return self.linker.thread_flags(env)
  532. def name_string(self):
  533. return ' '.join(self.exelist)
  534. class GnuDCompiler(GnuCompiler, DCompiler):
  535. # we mostly want DCompiler, but that gives us the Compiler.LINKER_PREFIX instead
  536. LINKER_PREFIX = GnuCompiler.LINKER_PREFIX
  537. def __init__(self, exelist, version, for_machine: MachineChoice,
  538. info: 'MachineInfo', is_cross, exe_wrapper, arch, **kwargs):
  539. DCompiler.__init__(self, exelist, version, for_machine, info, is_cross, exe_wrapper, arch, **kwargs)
  540. GnuCompiler.__init__(self, {})
  541. self.id = 'gcc'
  542. default_warn_args = ['-Wall', '-Wdeprecated']
  543. self.warn_args = {'0': [],
  544. '1': default_warn_args,
  545. '2': default_warn_args + ['-Wextra'],
  546. '3': default_warn_args + ['-Wextra', '-Wpedantic']}
  547. self.base_options = ['b_colorout', 'b_sanitize', 'b_staticpic', 'b_vscrt', 'b_coverage']
  548. self._has_color_support = version_compare(self.version, '>=4.9')
  549. # dependencies were implemented before, but broken - support was fixed in GCC 7.1+
  550. # (and some backported versions)
  551. self._has_deps_support = version_compare(self.version, '>=7.1')
  552. def get_colorout_args(self, colortype):
  553. if self._has_color_support:
  554. super().get_colorout_args(colortype)
  555. return []
  556. def get_dependency_gen_args(self, outtarget, outfile):
  557. if self._has_deps_support:
  558. return super().get_dependency_gen_args(outtarget, outfile)
  559. return []
  560. def get_warn_args(self, level):
  561. return self.warn_args[level]
  562. def get_buildtype_args(self, buildtype):
  563. return d_gdc_buildtype_args[buildtype]
  564. def compute_parameters_with_absolute_paths(self, parameter_list, build_dir):
  565. for idx, i in enumerate(parameter_list):
  566. if i[:2] == '-I' or i[:2] == '-L':
  567. parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:]))
  568. return parameter_list
  569. def get_allow_undefined_link_args(self) -> T.List[str]:
  570. return self.linker.get_allow_undefined_args()
  571. def get_linker_always_args(self) -> T.List[str]:
  572. args = super().get_linker_always_args()
  573. if self.info.is_windows():
  574. return args
  575. return args + ['-shared-libphobos']
  576. class LLVMDCompiler(DmdLikeCompilerMixin, DCompiler):
  577. def __init__(self, exelist, version, for_machine: MachineChoice,
  578. info: 'MachineInfo', arch, **kwargs):
  579. DCompiler.__init__(self, exelist, version, for_machine, info, arch, False, None, **kwargs)
  580. self.id = 'llvm'
  581. self.base_options = ['b_coverage', 'b_colorout', 'b_vscrt']
  582. def get_colorout_args(self, colortype):
  583. if colortype == 'always':
  584. return ['-enable-color']
  585. return []
  586. def get_warn_args(self, level):
  587. if level == '2' or level == '3':
  588. return ['-wi', '-dw']
  589. elif level == '1':
  590. return ['-wi']
  591. else:
  592. return []
  593. def get_buildtype_args(self, buildtype):
  594. if buildtype != 'plain':
  595. return self.get_target_arch_args() + d_ldc_buildtype_args[buildtype]
  596. return d_ldc_buildtype_args[buildtype]
  597. def get_pic_args(self):
  598. return ['-relocation-model=pic']
  599. def get_crt_link_args(self, crt_val, buildtype):
  600. return self.get_crt_args(crt_val, buildtype)
  601. def unix_args_to_native(self, args):
  602. return self.translate_args_to_nongnu(args)
  603. def get_optimization_args(self, optimization_level):
  604. return ldc_optimization_args[optimization_level]
  605. @classmethod
  606. def use_linker_args(cls, linker: str) -> T.List[str]:
  607. return ['-linker={}'.format(linker)]
  608. def get_linker_always_args(self) -> T.List[str]:
  609. args = super().get_linker_always_args()
  610. if self.info.is_windows():
  611. return args
  612. return args + ['-link-defaultlib-shared']
  613. class DmdDCompiler(DmdLikeCompilerMixin, DCompiler):
  614. def __init__(self, exelist, version, for_machine: MachineChoice,
  615. info: 'MachineInfo', arch, **kwargs):
  616. DCompiler.__init__(self, exelist, version, for_machine, info, arch, False, None, **kwargs)
  617. self.id = 'dmd'
  618. self.base_options = ['b_coverage', 'b_colorout', 'b_vscrt']
  619. def get_colorout_args(self, colortype):
  620. if colortype == 'always':
  621. return ['-color=on']
  622. return []
  623. def get_buildtype_args(self, buildtype):
  624. if buildtype != 'plain':
  625. return self.get_target_arch_args() + d_dmd_buildtype_args[buildtype]
  626. return d_dmd_buildtype_args[buildtype]
  627. def get_std_exe_link_args(self):
  628. if self.info.is_windows():
  629. # DMD links against D runtime only when main symbol is found,
  630. # so these needs to be inserted when linking static D libraries.
  631. if self.arch == 'x86_64':
  632. return ['phobos64.lib']
  633. elif self.arch == 'x86_mscoff':
  634. return ['phobos32mscoff.lib']
  635. return ['phobos.lib']
  636. return []
  637. def get_std_shared_lib_link_args(self):
  638. libname = 'libphobos2.so'
  639. if self.info.is_windows():
  640. if self.arch == 'x86_64':
  641. libname = 'phobos64.lib'
  642. elif self.arch == 'x86_mscoff':
  643. libname = 'phobos32mscoff.lib'
  644. else:
  645. libname = 'phobos.lib'
  646. return ['-shared', '-defaultlib=' + libname]
  647. def get_target_arch_args(self):
  648. # DMD32 and DMD64 on 64-bit Windows defaults to 32-bit (OMF).
  649. # Force the target to 64-bit in order to stay consistent
  650. # across the different platforms.
  651. if self.info.is_windows():
  652. if self.arch == 'x86_64':
  653. return ['-m64']
  654. elif self.arch == 'x86_mscoff':
  655. return ['-m32mscoff']
  656. return ['-m32']
  657. return []
  658. def get_crt_compile_args(self, crt_val, buildtype):
  659. return self.get_crt_args(crt_val, buildtype)
  660. def unix_args_to_native(self, args):
  661. return self.translate_args_to_nongnu(args)
  662. def get_optimization_args(self, optimization_level):
  663. return dmd_optimization_args[optimization_level]
  664. def can_linker_accept_rsp(self) -> bool:
  665. return False
  666. def get_linker_always_args(self) -> T.List[str]:
  667. args = super().get_linker_always_args()
  668. if self.info.is_windows():
  669. return args
  670. return args + ['-defaultlib=phobos2', '-debuglib=phobos2']