generate_feature_test_macro_components.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990
  1. #!/usr/bin/env python
  2. import os
  3. import tempfile
  4. def get_libcxx_paths():
  5. utils_path = os.path.dirname(os.path.abspath(__file__))
  6. script_name = os.path.basename(__file__)
  7. assert os.path.exists(utils_path)
  8. src_root = os.path.dirname(utils_path)
  9. include_path = os.path.join(src_root, 'include')
  10. assert os.path.exists(include_path)
  11. docs_path = os.path.join(src_root, 'docs')
  12. assert os.path.exists(docs_path)
  13. macro_test_path = os.path.join(src_root, 'test', 'std', 'language.support',
  14. 'support.limits', 'support.limits.general')
  15. assert os.path.exists(macro_test_path)
  16. assert os.path.exists(os.path.join(macro_test_path, 'version.version.pass.cpp'))
  17. return script_name, src_root, include_path, docs_path, macro_test_path
  18. script_name, source_root, include_path, docs_path, macro_test_path = get_libcxx_paths()
  19. def has_header(h):
  20. h_path = os.path.join(include_path, h)
  21. return os.path.exists(h_path)
  22. def add_version_header(tc):
  23. tc["headers"].append("version")
  24. return tc
  25. feature_test_macros = sorted([ add_version_header(x) for x in [
  26. # C++14 macros
  27. {"name": "__cpp_lib_integer_sequence",
  28. "values": {
  29. "c++14": 201304L
  30. },
  31. "headers": ["utility"],
  32. },
  33. {"name": "__cpp_lib_exchange_function",
  34. "values": {
  35. "c++14": 201304L
  36. },
  37. "headers": ["utility"],
  38. },
  39. {"name": "__cpp_lib_tuples_by_type",
  40. "values": {
  41. "c++14": 201304L
  42. },
  43. "headers": ["utility", "tuple"],
  44. },
  45. {"name": "__cpp_lib_tuple_element_t",
  46. "values": {
  47. "c++14": 201402L
  48. },
  49. "headers": ["tuple"],
  50. },
  51. {"name": "__cpp_lib_make_unique",
  52. "values": {
  53. "c++14": 201304L
  54. },
  55. "headers": ["memory"],
  56. },
  57. {"name": "__cpp_lib_transparent_operators",
  58. "values": {
  59. "c++14": 201210L,
  60. "c++17": 201510L,
  61. },
  62. "headers": ["functional"],
  63. },
  64. {"name": "__cpp_lib_integral_constant_callable",
  65. "values": {
  66. "c++14": 201304L
  67. },
  68. "headers": ["type_traits"],
  69. },
  70. {"name": "__cpp_lib_transformation_trait_aliases",
  71. "values": {
  72. "c++14": 201304L,
  73. },
  74. "headers": ["type_traits"]
  75. },
  76. {"name": "__cpp_lib_result_of_sfinae",
  77. "values": {
  78. "c++14": 201210L,
  79. },
  80. "headers": ["functional", "type_traits"]
  81. },
  82. {"name": "__cpp_lib_is_final",
  83. "values": {
  84. "c++14": 201402L,
  85. },
  86. "headers": ["type_traits"]
  87. },
  88. {"name": "__cpp_lib_is_null_pointer",
  89. "values": {
  90. "c++14": 201309L,
  91. },
  92. "headers": ["type_traits"]
  93. },
  94. {"name": "__cpp_lib_chrono_udls",
  95. "values": {
  96. "c++14": 201304L,
  97. },
  98. "headers": ["chrono"]
  99. },
  100. {"name": "__cpp_lib_string_udls",
  101. "values": {
  102. "c++14": 201304L,
  103. },
  104. "headers": ["string"]
  105. },
  106. {"name": "__cpp_lib_generic_associative_lookup",
  107. "values": {
  108. "c++14": 201304L,
  109. },
  110. "headers": ["map", "set"]
  111. },
  112. {"name": "__cpp_lib_null_iterators",
  113. "values": {
  114. "c++14": 201304L,
  115. },
  116. "headers": ["iterator"]
  117. },
  118. {"name": "__cpp_lib_make_reverse_iterator",
  119. "values": {
  120. "c++14": 201402L,
  121. },
  122. "headers": ["iterator"]
  123. },
  124. {"name": "__cpp_lib_robust_nonmodifying_seq_ops",
  125. "values": {
  126. "c++14": 201304L,
  127. },
  128. "headers": ["algorithm"]
  129. },
  130. {"name": "__cpp_lib_complex_udls",
  131. "values": {
  132. "c++14": 201309L,
  133. },
  134. "headers": ["complex"]
  135. },
  136. {"name": "__cpp_lib_quoted_string_io",
  137. "values": {
  138. "c++14": 201304L,
  139. },
  140. "headers": ["iomanip"]
  141. },
  142. {"name": "__cpp_lib_shared_timed_mutex",
  143. "values": {
  144. "c++14": 201402L,
  145. },
  146. "headers": ["shared_mutex"],
  147. "depends": "!defined(_LIBCPP_HAS_NO_THREADS)",
  148. "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS)",
  149. },
  150. # C++17 macros
  151. {"name": "__cpp_lib_atomic_is_always_lock_free",
  152. "values": {
  153. "c++17": 201603L,
  154. },
  155. "headers": ["atomic"],
  156. "depends": "!defined(_LIBCPP_HAS_NO_THREADS)",
  157. "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS)",
  158. },
  159. {"name": "__cpp_lib_filesystem",
  160. "values": {
  161. "c++17": 201703L,
  162. },
  163. "headers": ["filesystem"]
  164. },
  165. {"name": "__cpp_lib_invoke",
  166. "values": {
  167. "c++17": 201411L,
  168. },
  169. "headers": ["functional"]
  170. },
  171. {"name": "__cpp_lib_void_t",
  172. "values": {
  173. "c++17": 201411L,
  174. },
  175. "headers": ["type_traits"]
  176. },
  177. {"name": "__cpp_lib_node_extract",
  178. "values": {
  179. "c++17": 201606L,
  180. },
  181. "headers": ["map", "set", "unordered_map", "unordered_set"]
  182. },
  183. {"name": "__cpp_lib_byte",
  184. "values": {
  185. "c++17": 201603L,
  186. },
  187. "headers": ["cstddef"],
  188. },
  189. {"name": "__cpp_lib_hardware_interference_size",
  190. "values": {
  191. "c++17": 201703L,
  192. },
  193. "headers": ["new"],
  194. },
  195. {"name": "__cpp_lib_launder",
  196. "values": {
  197. "c++17": 201606L,
  198. },
  199. "headers": ["new"],
  200. },
  201. {"name": "__cpp_lib_uncaught_exceptions",
  202. "values": {
  203. "c++17": 201411L,
  204. },
  205. "headers": ["exception"],
  206. },
  207. {"name": "__cpp_lib_as_const",
  208. "values": {
  209. "c++17": 201510L,
  210. },
  211. "headers": ["utility"],
  212. },
  213. {"name": "__cpp_lib_make_from_tuple",
  214. "values": {
  215. "c++17": 201606L,
  216. },
  217. "headers": ["tuple"],
  218. },
  219. {"name": "__cpp_lib_apply",
  220. "values": {
  221. "c++17": 201603L,
  222. },
  223. "headers": ["tuple"],
  224. },
  225. {"name": "__cpp_lib_optional",
  226. "values": {
  227. "c++17": 201606L,
  228. },
  229. "headers": ["optional"],
  230. },
  231. {"name": "__cpp_lib_variant",
  232. "values": {
  233. "c++17": 201606L,
  234. },
  235. "headers": ["variant"],
  236. },
  237. {"name": "__cpp_lib_any",
  238. "values": {
  239. "c++17": 201606L,
  240. },
  241. "headers": ["any"],
  242. },
  243. {"name": "__cpp_lib_addressof_constexpr",
  244. "values": {
  245. "c++17": 201603L,
  246. },
  247. "headers": ["memory"],
  248. "depends": "TEST_HAS_BUILTIN(__builtin_addressof) || TEST_GCC_VER >= 700",
  249. "internal_depends": "!defined(_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF)",
  250. },
  251. {"name": "__cpp_lib_raw_memory_algorithms",
  252. "values": {
  253. "c++17": 201606L,
  254. },
  255. "headers": ["memory"],
  256. },
  257. {"name": "__cpp_lib_enable_shared_from_this",
  258. "values": {
  259. "c++17": 201603L,
  260. },
  261. "headers": ["memory"],
  262. },
  263. {"name": "__cpp_lib_shared_ptr_weak_type",
  264. "values": {
  265. "c++17": 201606L,
  266. },
  267. "headers": ["memory"],
  268. },
  269. {"name": "__cpp_lib_shared_ptr_arrays",
  270. "values": {
  271. "c++17": 201611L,
  272. },
  273. "headers": ["memory"],
  274. "unimplemented": True,
  275. },
  276. {"name": "__cpp_lib_memory_resource",
  277. "values": {
  278. "c++17": 201603L,
  279. },
  280. "headers": ["memory_resource"],
  281. "unimplemented": True,
  282. },
  283. {"name": "__cpp_lib_boyer_moore_searcher",
  284. "values": {
  285. "c++17": 201603L,
  286. },
  287. "headers": ["functional"],
  288. "unimplemented": True,
  289. },
  290. {"name": "__cpp_lib_not_fn",
  291. "values": {
  292. "c++17": 201603L,
  293. },
  294. "headers": ["functional"],
  295. },
  296. {"name": "__cpp_lib_bool_constant",
  297. "values": {
  298. "c++17": 201505L,
  299. },
  300. "headers": ["type_traits"],
  301. },
  302. {"name": "__cpp_lib_type_trait_variable_templates",
  303. "values": {
  304. "c++17": 201510L,
  305. },
  306. "headers": ["type_traits"],
  307. },
  308. {"name": "__cpp_lib_logical_traits",
  309. "values": {
  310. "c++17": 201510L,
  311. },
  312. "headers": ["type_traits"],
  313. },
  314. {"name": "__cpp_lib_is_swappable",
  315. "values": {
  316. "c++17": 201603L,
  317. },
  318. "headers": ["type_traits"],
  319. },
  320. {"name": "__cpp_lib_is_invocable",
  321. "values": {
  322. "c++17": 201703L,
  323. },
  324. "headers": ["type_traits"],
  325. },
  326. {"name": "__cpp_lib_has_unique_object_representations",
  327. "values": {
  328. "c++17": 201606L,
  329. },
  330. "headers": ["type_traits"],
  331. "depends": "TEST_HAS_BUILTIN_IDENTIFIER(__has_unique_object_representations) || TEST_GCC_VER >= 700",
  332. "internal_depends": "defined(_LIBCPP_HAS_UNIQUE_OBJECT_REPRESENTATIONS)",
  333. },
  334. {"name": "__cpp_lib_is_aggregate",
  335. "values": {
  336. "c++17": 201703L,
  337. },
  338. "headers": ["type_traits"],
  339. "depends": "TEST_HAS_BUILTIN_IDENTIFIER(__is_aggregate) || TEST_GCC_VER_NEW >= 7001",
  340. "internal_depends": "!defined(_LIBCPP_HAS_NO_IS_AGGREGATE)",
  341. },
  342. {"name": "__cpp_lib_chrono",
  343. "values": {
  344. "c++17": 201611L,
  345. },
  346. "headers": ["chrono"],
  347. },
  348. {"name": "__cpp_lib_execution",
  349. "values": {
  350. "c++17": 201603L,
  351. },
  352. "headers": ["execution"],
  353. "unimplemented": True
  354. },
  355. {"name": "__cpp_lib_parallel_algorithm",
  356. "values": {
  357. "c++17": 201603L,
  358. },
  359. "headers": ["algorithm", "numeric"],
  360. "unimplemented": True,
  361. },
  362. {"name": "__cpp_lib_to_chars",
  363. "values": {
  364. "c++17": 201611L,
  365. },
  366. "headers": ["utility"],
  367. "unimplemented": True,
  368. },
  369. {"name": "__cpp_lib_string_view",
  370. "values": {
  371. "c++17": 201606L,
  372. },
  373. "headers": ["string", "string_view"],
  374. },
  375. {"name": "__cpp_lib_allocator_traits_is_always_equal",
  376. "values": {
  377. "c++17": 201411L,
  378. },
  379. "headers": ["memory", "scoped_allocator", "string", "deque", "forward_list", "list", "vector", "map", "set", "unordered_map", "unordered_set"],
  380. },
  381. {"name": "__cpp_lib_incomplete_container_elements",
  382. "values": {
  383. "c++17": 201505L,
  384. },
  385. "headers": ["forward_list", "list", "vector"],
  386. },
  387. {"name": "__cpp_lib_map_try_emplace",
  388. "values": {
  389. "c++17": 201411L,
  390. },
  391. "headers": ["map"],
  392. },
  393. {"name": "__cpp_lib_unordered_map_try_emplace",
  394. "values": {
  395. "c++17": 201411L,
  396. },
  397. "headers": ["unordered_map"],
  398. },
  399. {"name": "__cpp_lib_array_constexpr",
  400. "values": {
  401. "c++17": 201603L,
  402. },
  403. "headers": ["iterator", "array"],
  404. },
  405. {"name": "__cpp_lib_nonmember_container_access",
  406. "values": {
  407. "c++17": 201411L,
  408. },
  409. "headers": ["iterator", "array", "deque", "forward_list", "list", "map", "regex",
  410. "set", "string", "unordered_map", "unordered_set", "vector"],
  411. },
  412. {"name": "__cpp_lib_sample",
  413. "values": {
  414. "c++17": 201603L,
  415. },
  416. "headers": ["algorithm"],
  417. },
  418. {"name": "__cpp_lib_clamp",
  419. "values": {
  420. "c++17": 201603L,
  421. },
  422. "headers": ["algorithm"],
  423. },
  424. {"name": "__cpp_lib_gcd_lcm",
  425. "values": {
  426. "c++17": 201606L,
  427. },
  428. "headers": ["numeric"],
  429. },
  430. {"name": "__cpp_lib_hypot",
  431. "values": {
  432. "c++17": 201603L,
  433. },
  434. "headers": ["cmath"],
  435. },
  436. {"name": "__cpp_lib_math_special_functions",
  437. "values": {
  438. "c++17": 201603L,
  439. },
  440. "headers": ["cmath"],
  441. "unimplemented": True,
  442. },
  443. {"name": "__cpp_lib_shared_mutex",
  444. "values": {
  445. "c++17": 201505L,
  446. },
  447. "headers": ["shared_mutex"],
  448. "depends": "!defined(_LIBCPP_HAS_NO_THREADS)",
  449. "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS)",
  450. },
  451. {"name": "__cpp_lib_scoped_lock",
  452. "values": {
  453. "c++17": 201703L,
  454. },
  455. "headers": ["mutex"],
  456. },
  457. # C++2a
  458. {"name": "__cpp_lib_char8_t",
  459. "values": {
  460. "c++2a": 201811L,
  461. },
  462. "headers": ["atomic", "filesystem", "istream", "limits", "locale", "ostream",
  463. "string", "string_view"],
  464. "depends": "defined(__cpp_char8_t)",
  465. "internal_depends": "!defined(_LIBCPP_NO_HAS_CHAR8_T)",
  466. },
  467. {"name": "__cpp_lib_erase_if",
  468. "values": {
  469. "c++2a": 201811L,
  470. },
  471. "headers": ["string", "deque", "forward_list", "list", "vector", "map",
  472. "set", "unordered_map", "unordered_set"]
  473. },
  474. {"name": "__cpp_lib_destroying_delete",
  475. "values": {
  476. "c++2a": 201806L,
  477. },
  478. "headers": ["new"],
  479. "depends":
  480. "TEST_STD_VER > 17"
  481. " && defined(__cpp_impl_destroying_delete)"
  482. " && __cpp_impl_destroying_delete >= 201806L",
  483. "internal_depends":
  484. "_LIBCPP_STD_VER > 17"
  485. " && defined(__cpp_impl_destroying_delete)"
  486. " && __cpp_impl_destroying_delete >= 201806L",
  487. },
  488. {"name": "__cpp_lib_three_way_comparison",
  489. "values": {
  490. "c++2a": 201711L,
  491. },
  492. "headers": ["compare"],
  493. "unimplemented": True,
  494. },
  495. {"name": "__cpp_lib_concepts",
  496. "values": {
  497. "c++2a": 201806L,
  498. },
  499. "headers": ["concepts"],
  500. "unimplemented": True,
  501. },
  502. {"name": "__cpp_lib_constexpr_swap_algorithms",
  503. "values": {
  504. "c++2a": 201806L,
  505. },
  506. "headers": ["algorithm"],
  507. "unimplemented": True,
  508. },
  509. {"name": "__cpp_lib_constexpr_misc",
  510. "values": {
  511. "c++2a": 201811L,
  512. },
  513. "headers": ["array", "functional", "iterator", "string_view", "tuple", "utility"],
  514. "unimplemented": True,
  515. },
  516. {"name": "__cpp_lib_bind_front",
  517. "values": {
  518. "c++2a": 201811L,
  519. },
  520. "headers": ["functional"],
  521. "unimplemented": True,
  522. },
  523. {"name": "__cpp_lib_is_constant_evaluated",
  524. "values": {
  525. "c++2a": 201811L,
  526. },
  527. "headers": ["type_traits"],
  528. "depends": "TEST_HAS_BUILTIN(__builtin_is_constant_evaluated) || TEST_GCC_VER >= 900",
  529. "internal_depends": "!defined(_LIBCPP_HAS_NO_BUILTIN_IS_CONSTANT_EVALUATED)",
  530. },
  531. {"name": "__cpp_lib_list_remove_return_type",
  532. "values": {
  533. "c++2a": 201806L,
  534. },
  535. "headers": ["forward_list", "list"],
  536. "unimplemented": True,
  537. },
  538. {"name": "__cpp_lib_generic_unordered_lookup",
  539. "values": {
  540. "c++2a": 201811L,
  541. },
  542. "headers": ["unordered_map", "unordered_set"],
  543. "unimplemented": True,
  544. },
  545. {"name": "__cpp_lib_ranges",
  546. "values": {
  547. "c++2a": 201811L,
  548. },
  549. "headers": ["algorithm", "functional", "iterator", "memory", "ranges"],
  550. "unimplemented": True,
  551. },
  552. {"name": "__cpp_lib_bit_cast",
  553. "values": {
  554. "c++2a": 201806L,
  555. },
  556. "headers": ["bit"],
  557. "unimplemented": True,
  558. },
  559. {"name": "__cpp_lib_atomic_ref",
  560. "values": {
  561. "c++2a": 201806L,
  562. },
  563. "headers": ["atomic"],
  564. "unimplemented": True,
  565. "depends": "!defined(_LIBCPP_HAS_NO_THREADS)",
  566. "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS)",
  567. },
  568. {"name": "__cpp_lib_interpolate",
  569. "values": {
  570. "c++2a": 201902L,
  571. },
  572. "headers": ["numeric"],
  573. },
  574. ]], key=lambda tc: tc["name"])
  575. def get_std_dialects():
  576. std_dialects = ['c++14', 'c++17', 'c++2a']
  577. return list(std_dialects)
  578. def get_first_std(d):
  579. for s in get_std_dialects():
  580. if s in d.keys():
  581. return s
  582. return None
  583. def get_last_std(d):
  584. rev_dialects = get_std_dialects()
  585. rev_dialects.reverse()
  586. for s in rev_dialects:
  587. if s in d.keys():
  588. return s
  589. return None
  590. def get_std_before(d, std):
  591. std_dialects = get_std_dialects()
  592. candidates = std_dialects[0:std_dialects.index(std)]
  593. candidates.reverse()
  594. for cand in candidates:
  595. if cand in d.keys():
  596. return cand
  597. return None
  598. def get_value_before(d, std):
  599. new_std = get_std_before(d, std)
  600. if new_std is None:
  601. return None
  602. return d[new_std]
  603. def get_for_std(d, std):
  604. # This catches the C++11 case for which there should be no defined feature
  605. # test macros.
  606. std_dialects = get_std_dialects()
  607. if std not in std_dialects:
  608. return None
  609. # Find the value for the newest C++ dialect between C++14 and std
  610. std_list = list(std_dialects[0:std_dialects.index(std)+1])
  611. std_list.reverse()
  612. for s in std_list:
  613. if s in d.keys():
  614. return d[s]
  615. return None
  616. """
  617. Functions to produce the <version> header
  618. """
  619. def produce_macros_definition_for_std(std):
  620. result = ""
  621. indent = 56
  622. for tc in feature_test_macros:
  623. if std not in tc["values"]:
  624. continue
  625. inner_indent = 1
  626. if 'depends' in tc.keys():
  627. assert 'internal_depends' in tc.keys()
  628. result += "# if %s\n" % tc["internal_depends"]
  629. inner_indent += 2
  630. if get_value_before(tc["values"], std) is not None:
  631. assert 'depends' not in tc.keys()
  632. result += "# undef %s\n" % tc["name"]
  633. line = "#%sdefine %s" % ((" " * inner_indent), tc["name"])
  634. line += " " * (indent - len(line))
  635. line += "%sL" % tc["values"][std]
  636. if 'unimplemented' in tc.keys():
  637. line = "// " + line
  638. result += line
  639. result += "\n"
  640. if 'depends' in tc.keys():
  641. result += "# endif\n"
  642. return result
  643. def chunks(l, n):
  644. """Yield successive n-sized chunks from l."""
  645. for i in range(0, len(l), n):
  646. yield l[i:i + n]
  647. def produce_version_synopsis():
  648. indent = 56
  649. header_indent = 56 + len("20XXYYL ")
  650. result = ""
  651. def indent_to(s, val):
  652. if len(s) >= val:
  653. return s
  654. s += " " * (val - len(s))
  655. return s
  656. line = indent_to("Macro name", indent) + "Value"
  657. line = indent_to(line, header_indent) + "Headers"
  658. result += line + "\n"
  659. for tc in feature_test_macros:
  660. prev_defined_std = get_last_std(tc["values"])
  661. line = "{name: <{indent}}{value}L ".format(name=tc['name'], indent=indent,
  662. value=tc["values"][prev_defined_std])
  663. headers = list(tc["headers"])
  664. headers.remove("version")
  665. for chunk in chunks(headers, 3):
  666. line = indent_to(line, header_indent)
  667. chunk = ['<%s>' % header for header in chunk]
  668. line += ' '.join(chunk)
  669. result += line
  670. result += "\n"
  671. line = ""
  672. while True:
  673. prev_defined_std = get_std_before(tc["values"], prev_defined_std)
  674. if prev_defined_std is None:
  675. break
  676. result += "%s%sL // %s\n" % (indent_to("", indent), tc["values"][prev_defined_std],
  677. prev_defined_std.replace("c++", "C++"))
  678. return result
  679. def produce_version_header():
  680. template="""// -*- C++ -*-
  681. //===--------------------------- version ----------------------------------===//
  682. //
  683. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  684. // See https://llvm.org/LICENSE.txt for license information.
  685. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  686. //
  687. //===----------------------------------------------------------------------===//
  688. #ifndef _LIBCPP_VERSIONH
  689. #define _LIBCPP_VERSIONH
  690. /*
  691. version synopsis
  692. {synopsis}
  693. */
  694. #include <__config>
  695. #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
  696. #pragma GCC system_header
  697. #endif
  698. #if _LIBCPP_STD_VER > 11
  699. {cxx14_macros}
  700. #endif
  701. #if _LIBCPP_STD_VER > 14
  702. {cxx17_macros}
  703. #endif
  704. #if _LIBCPP_STD_VER > 17
  705. {cxx2a_macros}
  706. #endif
  707. #endif // _LIBCPP_VERSIONH
  708. """
  709. return template.format(
  710. synopsis=produce_version_synopsis().strip(),
  711. cxx14_macros=produce_macros_definition_for_std('c++14').strip(),
  712. cxx17_macros=produce_macros_definition_for_std('c++17').strip(),
  713. cxx2a_macros=produce_macros_definition_for_std('c++2a').strip())
  714. """
  715. Functions to produce test files
  716. """
  717. test_types = {
  718. "undefined": """
  719. # ifdef {name}
  720. # error "{name} should not be defined before {std_first}"
  721. # endif
  722. """,
  723. "depends": """
  724. # if {depends}
  725. # ifndef {name}
  726. # error "{name} should be defined in {std}"
  727. # endif
  728. # if {name} != {value}
  729. # error "{name} should have the value {value} in {std}"
  730. # endif
  731. # else
  732. # ifdef {name}
  733. # error "{name} should not be defined when {depends} is not defined!"
  734. # endif
  735. # endif
  736. """,
  737. "unimplemented": """
  738. # if !defined(_LIBCPP_VERSION)
  739. # ifndef {name}
  740. # error "{name} should be defined in {std}"
  741. # endif
  742. # if {name} != {value}
  743. # error "{name} should have the value {value} in {std}"
  744. # endif
  745. # else // _LIBCPP_VERSION
  746. # ifdef {name}
  747. # error "{name} should not be defined because it is unimplemented in libc++!"
  748. # endif
  749. # endif
  750. """,
  751. "defined":"""
  752. # ifndef {name}
  753. # error "{name} should be defined in {std}"
  754. # endif
  755. # if {name} != {value}
  756. # error "{name} should have the value {value} in {std}"
  757. # endif
  758. """
  759. }
  760. def generate_std_test(test_list, std):
  761. result = ""
  762. for tc in test_list:
  763. val = get_for_std(tc["values"], std)
  764. if val is not None:
  765. val = "%sL" % val
  766. if val is None:
  767. result += test_types["undefined"].format(name=tc["name"], std_first=get_first_std(tc["values"]))
  768. elif 'unimplemented' in tc.keys():
  769. result += test_types["unimplemented"].format(name=tc["name"], value=val, std=std)
  770. elif "depends" in tc.keys():
  771. result += test_types["depends"].format(name=tc["name"], value=val, std=std, depends=tc["depends"])
  772. else:
  773. result += test_types["defined"].format(name=tc["name"], value=val, std=std)
  774. return result
  775. def generate_synopsis(test_list):
  776. max_name_len = max([len(tc["name"]) for tc in test_list])
  777. indent = max_name_len + 8
  778. def mk_line(prefix, suffix):
  779. return "{prefix: <{max_len}}{suffix}\n".format(prefix=prefix, suffix=suffix,
  780. max_len=indent)
  781. result = ""
  782. result += mk_line("/* Constant", "Value")
  783. for tc in test_list:
  784. prefix = " %s" % tc["name"]
  785. for std in [s for s in get_std_dialects() if s in tc["values"].keys()]:
  786. result += mk_line(prefix, "%sL [%s]" % (tc["values"][std], std.replace("c++", "C++")))
  787. prefix = ""
  788. result += "*/"
  789. return result
  790. def is_threading_header_unsafe_to_include(h):
  791. # NOTE: "<mutex>" does not blow up when included without threads.
  792. return h in ['atomic', 'shared_mutex']
  793. def produce_tests():
  794. headers = set([h for tc in feature_test_macros for h in tc["headers"]])
  795. for h in headers:
  796. test_list = [tc for tc in feature_test_macros if h in tc["headers"]]
  797. if not has_header(h):
  798. for tc in test_list:
  799. assert 'unimplemented' in tc.keys()
  800. continue
  801. test_tags = ""
  802. if is_threading_header_unsafe_to_include(h):
  803. test_tags += '\n// UNSUPPORTED: libcpp-has-no-threads\n'
  804. test_body = \
  805. """//===----------------------------------------------------------------------===//
  806. //
  807. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  808. // See https://llvm.org/LICENSE.txt for license information.
  809. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  810. //
  811. //===----------------------------------------------------------------------===//
  812. //
  813. // WARNING: This test was generated by {script_name}
  814. // and should not be edited manually.
  815. {test_tags}
  816. // <{header}>
  817. // Test the feature test macros defined by <{header}>
  818. {synopsis}
  819. #include <{header}>
  820. #include "test_macros.h"
  821. #if TEST_STD_VER < 14
  822. {cxx11_tests}
  823. #elif TEST_STD_VER == 14
  824. {cxx14_tests}
  825. #elif TEST_STD_VER == 17
  826. {cxx17_tests}
  827. #elif TEST_STD_VER > 17
  828. {cxx2a_tests}
  829. #endif // TEST_STD_VER > 17
  830. int main(int, char**) {{ return 0; }}
  831. """.format(script_name=script_name,
  832. header=h,
  833. test_tags=test_tags,
  834. synopsis=generate_synopsis(test_list),
  835. cxx11_tests=generate_std_test(test_list, 'c++11').strip(),
  836. cxx14_tests=generate_std_test(test_list, 'c++14').strip(),
  837. cxx17_tests=generate_std_test(test_list, 'c++17').strip(),
  838. cxx2a_tests=generate_std_test(test_list, 'c++2a').strip())
  839. test_name = "{header}.version.pass.cpp".format(header=h)
  840. out_path = os.path.join(macro_test_path, test_name)
  841. with open(out_path, 'w') as f:
  842. f.write(test_body)
  843. """
  844. Produce documentation for the feature test macros
  845. """
  846. def make_widths(grid):
  847. widths = []
  848. for i in range(0, len(grid[0])):
  849. cell_width = 2 + max(reduce(lambda x,y: x+y, [[len(row[i])] for row in grid], []))
  850. widths += [cell_width]
  851. return widths
  852. def create_table(grid, indent):
  853. indent_str = ' '*indent
  854. col_widths = make_widths(grid)
  855. num_cols = len(grid[0])
  856. result = indent_str + add_divider(col_widths, 2)
  857. header_flag = 2
  858. for row_i in xrange(0, len(grid)):
  859. row = grid[row_i]
  860. result = result + indent_str + ' '.join([pad_cell(row[i], col_widths[i]) for i in range(0, len(row))]) + '\n'
  861. is_cxx_header = row[0].startswith('**')
  862. if row_i == len(grid) - 1:
  863. header_flag = 2
  864. result = result + indent_str + add_divider(col_widths, 1 if is_cxx_header else header_flag)
  865. header_flag = 0
  866. return result
  867. def add_divider(widths, header_flag):
  868. if header_flag == 2:
  869. return ' '.join(['='*w for w in widths]) + '\n'
  870. if header_flag == 1:
  871. return '-'.join(['-'*w for w in widths]) + '\n'
  872. else:
  873. return ' '.join(['-'*w for w in widths]) + '\n'
  874. def pad_cell(s, length, left_align=True):
  875. padding = ((length - len(s)) * ' ')
  876. return s + padding
  877. def get_status_table():
  878. table = [["Macro Name", "Value"]]
  879. for std in get_std_dialects():
  880. table += [["**" + std.replace("c++", "C++ ") + "**", ""]]
  881. for tc in feature_test_macros:
  882. if std not in tc["values"].keys():
  883. continue
  884. value = "``%sL``" % tc["values"][std]
  885. if 'unimplemented' in tc.keys():
  886. value = '*unimplemented*'
  887. table += [["``%s``" % tc["name"], value]]
  888. return table
  889. def produce_docs():
  890. doc_str = """.. _FeatureTestMacroTable:
  891. ==========================
  892. Feature Test Macro Support
  893. ==========================
  894. .. contents::
  895. :local:
  896. Overview
  897. ========
  898. This file documents the feature test macros currently supported by libc++.
  899. .. _feature-status:
  900. Status
  901. ======
  902. .. table:: Current Status
  903. :name: feature-status-table
  904. :widths: auto
  905. {status_tables}
  906. """.format(status_tables=create_table(get_status_table(), 4))
  907. table_doc_path = os.path.join(docs_path, 'FeatureTestMacroTable.rst')
  908. with open(table_doc_path, 'w') as f:
  909. f.write(doc_str)
  910. def main():
  911. with tempfile.NamedTemporaryFile(mode='w', prefix='version.', delete=False) as tmp_file:
  912. print("producing new <version> header as %s" % tmp_file.name)
  913. tmp_file.write(produce_version_header())
  914. produce_tests()
  915. produce_docs()
  916. if __name__ == '__main__':
  917. main()