c.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  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
  12. import typing as T
  13. from .. import coredata
  14. from ..mesonlib import MachineChoice, MesonException, mlog, version_compare
  15. from ..linkers import LinkerEnvVarsMixin
  16. from .c_function_attributes import C_FUNC_ATTRIBUTES
  17. from .mixins.clike import CLikeCompiler
  18. from .mixins.ccrx import CcrxCompiler
  19. from .mixins.xc16 import Xc16Compiler
  20. from .mixins.c2000 import C2000Compiler
  21. from .mixins.arm import ArmCompiler, ArmclangCompiler
  22. from .mixins.visualstudio import MSVCCompiler, ClangClCompiler
  23. from .mixins.gnu import GnuCompiler
  24. from .mixins.intel import IntelGnuLikeCompiler, IntelVisualStudioLikeCompiler
  25. from .mixins.clang import ClangCompiler
  26. from .mixins.elbrus import ElbrusCompiler
  27. from .mixins.pgi import PGICompiler
  28. from .mixins.emscripten import EmscriptenMixin
  29. from .compilers import (
  30. gnu_winlibs,
  31. msvc_winlibs,
  32. Compiler,
  33. )
  34. if T.TYPE_CHECKING:
  35. from ..envconfig import MachineInfo
  36. class CCompiler(CLikeCompiler, Compiler):
  37. @staticmethod
  38. def attribute_check_func(name):
  39. try:
  40. return C_FUNC_ATTRIBUTES[name]
  41. except KeyError:
  42. raise MesonException('Unknown function attribute "{}"'.format(name))
  43. language = 'c'
  44. def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool,
  45. info: 'MachineInfo', exe_wrapper: T.Optional[str] = None, **kwargs):
  46. # If a child ObjC or CPP class has already set it, don't set it ourselves
  47. Compiler.__init__(self, exelist, version, for_machine, info, **kwargs)
  48. CLikeCompiler.__init__(self, is_cross, exe_wrapper)
  49. def get_no_stdinc_args(self):
  50. return ['-nostdinc']
  51. def sanity_check(self, work_dir, environment):
  52. code = 'int main(void) { int class=0; return class; }\n'
  53. return self.sanity_check_impl(work_dir, environment, 'sanitycheckc.c', code)
  54. def has_header_symbol(self, hname, symbol, prefix, env, *, extra_args=None, dependencies=None):
  55. fargs = {'prefix': prefix, 'header': hname, 'symbol': symbol}
  56. t = '''{prefix}
  57. #include <{header}>
  58. int main(void) {{
  59. /* If it's not defined as a macro, try to use as a symbol */
  60. #ifndef {symbol}
  61. {symbol};
  62. #endif
  63. return 0;
  64. }}'''
  65. return self.compiles(t.format(**fargs), env, extra_args=extra_args,
  66. dependencies=dependencies)
  67. class ClangCCompiler(ClangCompiler, CCompiler):
  68. _C17_VERSION = '>=6.0.0'
  69. _C18_VERSION = '>=8.0.0'
  70. def __init__(self, exelist, version, for_machine: MachineChoice,
  71. is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs):
  72. CCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs)
  73. ClangCompiler.__init__(self)
  74. default_warn_args = ['-Wall', '-Winvalid-pch']
  75. self.warn_args = {'0': [],
  76. '1': default_warn_args,
  77. '2': default_warn_args + ['-Wextra'],
  78. '3': default_warn_args + ['-Wextra', '-Wpedantic']}
  79. def get_options(self):
  80. opts = CCompiler.get_options(self)
  81. c_stds = ['c89', 'c99', 'c11']
  82. g_stds = ['gnu89', 'gnu99', 'gnu11']
  83. # https://releases.llvm.org/6.0.0/tools/clang/docs/ReleaseNotes.html
  84. # https://en.wikipedia.org/wiki/Xcode#Latest_versions
  85. if version_compare(self.version, self._C17_VERSION):
  86. c_stds += ['c17']
  87. g_stds += ['gnu17']
  88. if version_compare(self.version, self._C18_VERSION):
  89. c_stds += ['c18']
  90. g_stds += ['gnu18']
  91. opts.update({
  92. 'std': coredata.UserComboOption(
  93. 'C language standard to use',
  94. ['none'] + c_stds + g_stds,
  95. 'none',
  96. ),
  97. })
  98. if self.info.is_windows() or self.info.is_cygwin():
  99. opts.update({
  100. 'winlibs': coredata.UserArrayOption(
  101. 'Standard Win libraries to link against',
  102. gnu_winlibs,
  103. ),
  104. })
  105. return opts
  106. def get_option_compile_args(self, options):
  107. args = []
  108. std = options['std']
  109. if std.value != 'none':
  110. args.append('-std=' + std.value)
  111. return args
  112. def get_option_link_args(self, options):
  113. if self.info.is_windows() or self.info.is_cygwin():
  114. return options['winlibs'].value[:]
  115. return []
  116. class AppleClangCCompiler(ClangCCompiler):
  117. """Handle the differences between Apple Clang and Vanilla Clang.
  118. Right now this just handles the differences between the versions that new
  119. C standards were added.
  120. """
  121. _C17_VERSION = '>=10.0.0'
  122. _C18_VERSION = '>=11.0.0'
  123. class EmscriptenCCompiler(EmscriptenMixin, LinkerEnvVarsMixin, ClangCCompiler):
  124. def __init__(self, exelist, version, for_machine: MachineChoice,
  125. is_cross: bool, info: 'MachineInfo', exe_wrapper=None, **kwargs):
  126. if not is_cross:
  127. raise MesonException('Emscripten compiler can only be used for cross compilation.')
  128. ClangCCompiler.__init__(self, exelist=exelist, version=version,
  129. for_machine=for_machine, is_cross=is_cross,
  130. info=info, exe_wrapper=exe_wrapper, **kwargs)
  131. self.id = 'emscripten'
  132. class ArmclangCCompiler(ArmclangCompiler, CCompiler):
  133. def __init__(self, exelist, version, for_machine: MachineChoice,
  134. is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs):
  135. CCompiler.__init__(self, exelist, version, for_machine, is_cross,
  136. info, exe_wrapper, **kwargs)
  137. ArmclangCompiler.__init__(self)
  138. default_warn_args = ['-Wall', '-Winvalid-pch']
  139. self.warn_args = {'0': [],
  140. '1': default_warn_args,
  141. '2': default_warn_args + ['-Wextra'],
  142. '3': default_warn_args + ['-Wextra', '-Wpedantic']}
  143. def get_options(self):
  144. opts = CCompiler.get_options(self)
  145. opts.update({
  146. 'std': coredata.UserComboOption(
  147. 'C language standard to use',
  148. ['none', 'c90', 'c99', 'c11', 'gnu90', 'gnu99', 'gnu11'],
  149. 'none',
  150. ),
  151. })
  152. return opts
  153. def get_option_compile_args(self, options):
  154. args = []
  155. std = options['std']
  156. if std.value != 'none':
  157. args.append('-std=' + std.value)
  158. return args
  159. def get_option_link_args(self, options):
  160. return []
  161. class GnuCCompiler(GnuCompiler, CCompiler):
  162. def __init__(self, exelist, version, for_machine: MachineChoice,
  163. is_cross, info: 'MachineInfo', exe_wrapper=None,
  164. defines=None, **kwargs):
  165. CCompiler.__init__(self, exelist, version, for_machine, is_cross,
  166. info, exe_wrapper, **kwargs)
  167. GnuCompiler.__init__(self, defines)
  168. default_warn_args = ['-Wall', '-Winvalid-pch']
  169. self.warn_args = {'0': [],
  170. '1': default_warn_args,
  171. '2': default_warn_args + ['-Wextra'],
  172. '3': default_warn_args + ['-Wextra', '-Wpedantic']}
  173. def get_options(self):
  174. opts = CCompiler.get_options(self)
  175. c_stds = ['c89', 'c99', 'c11']
  176. g_stds = ['gnu89', 'gnu99', 'gnu11']
  177. v = '>=8.0.0'
  178. if version_compare(self.version, v):
  179. c_stds += ['c17', 'c18']
  180. g_stds += ['gnu17', 'gnu18']
  181. opts.update({
  182. 'std': coredata.UserComboOption(
  183. 'C language standard to use',
  184. ['none'] + c_stds + g_stds,
  185. 'none',
  186. ),
  187. })
  188. if self.info.is_windows() or self.info.is_cygwin():
  189. opts.update({
  190. 'winlibs': coredata.UserArrayOption(
  191. 'Standard Win libraries to link against',
  192. gnu_winlibs,
  193. ),
  194. })
  195. return opts
  196. def get_option_compile_args(self, options):
  197. args = []
  198. std = options['std']
  199. if std.value != 'none':
  200. args.append('-std=' + std.value)
  201. return args
  202. def get_option_link_args(self, options):
  203. if self.info.is_windows() or self.info.is_cygwin():
  204. return options['winlibs'].value[:]
  205. return []
  206. def get_pch_use_args(self, pch_dir, header):
  207. return ['-fpch-preprocess', '-include', os.path.basename(header)]
  208. class PGICCompiler(PGICompiler, CCompiler):
  209. def __init__(self, exelist, version, for_machine: MachineChoice,
  210. is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs):
  211. CCompiler.__init__(self, exelist, version, for_machine, is_cross,
  212. info, exe_wrapper, **kwargs)
  213. PGICompiler.__init__(self)
  214. class ElbrusCCompiler(GnuCCompiler, ElbrusCompiler):
  215. def __init__(self, exelist, version, for_machine: MachineChoice,
  216. is_cross, info: 'MachineInfo', exe_wrapper=None,
  217. defines=None, **kwargs):
  218. GnuCCompiler.__init__(self, exelist, version, for_machine, is_cross,
  219. info, exe_wrapper, defines, **kwargs)
  220. ElbrusCompiler.__init__(self)
  221. # It does support some various ISO standards and c/gnu 90, 9x, 1x in addition to those which GNU CC supports.
  222. def get_options(self):
  223. opts = CCompiler.get_options(self)
  224. opts.update({
  225. 'std': coredata.UserComboOption(
  226. 'C language standard to use',
  227. [
  228. 'none', 'c89', 'c90', 'c9x', 'c99', 'c1x', 'c11',
  229. 'gnu89', 'gnu90', 'gnu9x', 'gnu99', 'gnu1x', 'gnu11',
  230. 'iso9899:2011', 'iso9899:1990', 'iso9899:199409', 'iso9899:1999',
  231. ],
  232. 'none',
  233. ),
  234. })
  235. return opts
  236. # Elbrus C compiler does not have lchmod, but there is only linker warning, not compiler error.
  237. # So we should explicitly fail at this case.
  238. def has_function(self, funcname, prefix, env, *, extra_args=None, dependencies=None):
  239. if funcname == 'lchmod':
  240. return False, False
  241. else:
  242. return super().has_function(funcname, prefix, env,
  243. extra_args=extra_args,
  244. dependencies=dependencies)
  245. class IntelCCompiler(IntelGnuLikeCompiler, CCompiler):
  246. def __init__(self, exelist, version, for_machine: MachineChoice,
  247. is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs):
  248. CCompiler.__init__(self, exelist, version, for_machine, is_cross,
  249. info, exe_wrapper, **kwargs)
  250. IntelGnuLikeCompiler.__init__(self)
  251. self.lang_header = 'c-header'
  252. default_warn_args = ['-Wall', '-w3', '-diag-disable:remark']
  253. self.warn_args = {'0': [],
  254. '1': default_warn_args,
  255. '2': default_warn_args + ['-Wextra'],
  256. '3': default_warn_args + ['-Wextra']}
  257. def get_options(self):
  258. opts = CCompiler.get_options(self)
  259. c_stds = ['c89', 'c99']
  260. g_stds = ['gnu89', 'gnu99']
  261. if version_compare(self.version, '>=16.0.0'):
  262. c_stds += ['c11']
  263. opts.update({
  264. 'std': coredata.UserComboOption(
  265. 'C language standard to use',
  266. ['none'] + c_stds + g_stds,
  267. 'none',
  268. ),
  269. })
  270. return opts
  271. def get_option_compile_args(self, options):
  272. args = []
  273. std = options['std']
  274. if std.value != 'none':
  275. args.append('-std=' + std.value)
  276. return args
  277. class VisualStudioLikeCCompilerMixin:
  278. """Shared methods that apply to MSVC-like C compilers."""
  279. def get_options(self):
  280. opts = super().get_options()
  281. opts.update({
  282. 'winlibs': coredata.UserArrayOption(
  283. 'Windows libs to link against.',
  284. msvc_winlibs,
  285. ),
  286. })
  287. return opts
  288. def get_option_link_args(self, options):
  289. return options['winlibs'].value[:]
  290. class VisualStudioCCompiler(MSVCCompiler, VisualStudioLikeCCompilerMixin, CCompiler):
  291. def __init__(self, exelist, version, for_machine: MachineChoice,
  292. is_cross, info: 'MachineInfo', exe_wrap, target: str,
  293. **kwargs):
  294. CCompiler.__init__(self, exelist, version, for_machine, is_cross,
  295. info, exe_wrap, **kwargs)
  296. MSVCCompiler.__init__(self, target)
  297. class ClangClCCompiler(ClangClCompiler, VisualStudioLikeCCompilerMixin, CCompiler):
  298. def __init__(self, exelist, version, for_machine: MachineChoice,
  299. is_cross, info: 'MachineInfo', exe_wrap, target, **kwargs):
  300. CCompiler.__init__(self, exelist, version, for_machine, is_cross,
  301. info, exe_wrap, **kwargs)
  302. ClangClCompiler.__init__(self, target)
  303. class IntelClCCompiler(IntelVisualStudioLikeCompiler, VisualStudioLikeCCompilerMixin, CCompiler):
  304. """Intel "ICL" compiler abstraction."""
  305. def __init__(self, exelist, version, for_machine: MachineChoice,
  306. is_cross, info: 'MachineInfo', exe_wrap, target, **kwargs):
  307. CCompiler.__init__(self, exelist, version, for_machine, is_cross,
  308. info, exe_wrap, **kwargs)
  309. IntelVisualStudioLikeCompiler.__init__(self, target)
  310. def get_options(self):
  311. opts = super().get_options()
  312. c_stds = ['none', 'c89', 'c99', 'c11']
  313. opts.update({
  314. 'std': coredata.UserComboOption(
  315. 'C language standard to use',
  316. c_stds,
  317. 'none',
  318. ),
  319. })
  320. return opts
  321. def get_option_compile_args(self, options):
  322. args = []
  323. std = options['std']
  324. if std.value == 'c89':
  325. mlog.warning("ICL doesn't explicitly implement c89, setting the standard to 'none', which is close.", once=True)
  326. elif std.value != 'none':
  327. args.append('/Qstd:' + std.value)
  328. return args
  329. class ArmCCompiler(ArmCompiler, CCompiler):
  330. def __init__(self, exelist, version, for_machine: MachineChoice,
  331. is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs):
  332. CCompiler.__init__(self, exelist, version, for_machine, is_cross,
  333. info, exe_wrapper, **kwargs)
  334. ArmCompiler.__init__(self)
  335. def get_options(self):
  336. opts = CCompiler.get_options(self)
  337. opts.update({
  338. 'std': coredata.UserComboOption(
  339. 'C language standard to use',
  340. ['none', 'c90', 'c99'],
  341. 'none',
  342. ),
  343. })
  344. return opts
  345. def get_option_compile_args(self, options):
  346. args = []
  347. std = options['std']
  348. if std.value != 'none':
  349. args.append('--' + std.value)
  350. return args
  351. class CcrxCCompiler(CcrxCompiler, CCompiler):
  352. def __init__(self, exelist, version, for_machine: MachineChoice,
  353. is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs):
  354. CCompiler.__init__(self, exelist, version, for_machine, is_cross,
  355. info, exe_wrapper, **kwargs)
  356. CcrxCompiler.__init__(self)
  357. # Override CCompiler.get_always_args
  358. def get_always_args(self):
  359. return ['-nologo']
  360. def get_options(self):
  361. opts = CCompiler.get_options(self)
  362. opts.update({
  363. 'std': coredata.UserComboOption(
  364. 'C language standard to use',
  365. ['none', 'c89', 'c99'],
  366. 'none',
  367. ),
  368. })
  369. return opts
  370. def get_no_stdinc_args(self):
  371. return []
  372. def get_option_compile_args(self, options):
  373. args = []
  374. std = options['std']
  375. if std.value == 'c89':
  376. args.append('-lang=c')
  377. elif std.value == 'c99':
  378. args.append('-lang=c99')
  379. return args
  380. def get_compile_only_args(self):
  381. return []
  382. def get_no_optimization_args(self):
  383. return ['-optimize=0']
  384. def get_output_args(self, target):
  385. return ['-output=obj=%s' % target]
  386. def get_werror_args(self):
  387. return ['-change_message=error']
  388. def get_include_args(self, path, is_system):
  389. if path == '':
  390. path = '.'
  391. return ['-include=' + path]
  392. class Xc16CCompiler(Xc16Compiler, CCompiler):
  393. def __init__(self, exelist, version, for_machine: MachineChoice,
  394. is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs):
  395. CCompiler.__init__(self, exelist, version, for_machine, is_cross,
  396. info, exe_wrapper, **kwargs)
  397. Xc16Compiler.__init__(self)
  398. def get_options(self):
  399. opts = CCompiler.get_options(self)
  400. opts.update({'c_std': coredata.UserComboOption('C language standard to use',
  401. ['none', 'c89', 'c99', 'gnu89', 'gnu99'],
  402. 'none')})
  403. return opts
  404. def get_no_stdinc_args(self):
  405. return []
  406. def get_option_compile_args(self, options):
  407. args = []
  408. std = options['c_std']
  409. if std.value != 'none':
  410. args.append('-ansi')
  411. args.append('-std=' + std.value)
  412. return args
  413. def get_compile_only_args(self):
  414. return []
  415. def get_no_optimization_args(self):
  416. return ['-O0']
  417. def get_output_args(self, target):
  418. return ['-o%s' % target]
  419. def get_werror_args(self):
  420. return ['-change_message=error']
  421. def get_include_args(self, path, is_system):
  422. if path == '':
  423. path = '.'
  424. return ['-I' + path]
  425. class C2000CCompiler(C2000Compiler, CCompiler):
  426. def __init__(self, exelist, version, for_machine: MachineChoice,
  427. is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs):
  428. CCompiler.__init__(self, exelist, version, for_machine, is_cross,
  429. info, exe_wrapper, **kwargs)
  430. C2000Compiler.__init__(self)
  431. # Override CCompiler.get_always_args
  432. def get_always_args(self):
  433. return []
  434. def get_options(self):
  435. opts = CCompiler.get_options(self)
  436. opts.update({'c_std': coredata.UserComboOption('C language standard to use',
  437. ['none', 'c89', 'c99', 'c11'],
  438. 'none')})
  439. return opts
  440. def get_no_stdinc_args(self):
  441. return []
  442. def get_option_compile_args(self, options):
  443. args = []
  444. std = options['c_std']
  445. if std.value != 'none':
  446. args.append('--' + std.value)
  447. return args
  448. def get_compile_only_args(self):
  449. return []
  450. def get_no_optimization_args(self):
  451. return ['-Ooff']
  452. def get_output_args(self, target):
  453. return ['--output_file=%s' % target]
  454. def get_werror_args(self):
  455. return ['-change_message=error']
  456. def get_include_args(self, path, is_system):
  457. if path == '':
  458. path = '.'
  459. return ['--include_path=' + path]