generate.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. // (C) Copyright John Maddock 2004.
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. //
  6. // This progam scans for *.ipp files in the libs/config/test
  7. // directory and then generates the *.cpp test files from them
  8. // along with config_test.cpp and a Jamfile.
  9. //
  10. #include <boost/regex.hpp>
  11. #include <boost/filesystem/path.hpp>
  12. #include <boost/filesystem/operations.hpp>
  13. #include <boost/filesystem/fstream.hpp>
  14. #include <boost/detail/lightweight_main.hpp>
  15. #include <iostream>
  16. #include <sstream>
  17. #include <string>
  18. #include <set>
  19. #include <ctime>
  20. namespace fs = boost::filesystem;
  21. fs::path config_path;
  22. std::string copyright(
  23. "// Copyright John Maddock 2002-4.\n"
  24. "// Use, modification and distribution are subject to the \n"
  25. "// Boost Software License, Version 1.0. (See accompanying file \n"
  26. "// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n"
  27. "\n"
  28. "// See http://www.boost.org/libs/config for the most recent version."
  29. "//\n// Revision $Id$\n//\n");
  30. std::stringstream config_test1;
  31. std::stringstream config_test1a;
  32. std::stringstream config_test2;
  33. std::stringstream jamfile;
  34. std::stringstream jamfile_v2;
  35. std::stringstream build_config_test;
  36. std::stringstream build_config_jamfile;
  37. std::set<std::string> macro_list;
  38. std::set<std::string> feature_list;
  39. void write_config_info()
  40. {
  41. // load the file into memory so we can scan it:
  42. fs::ifstream ifs(config_path / "config_info.cpp");
  43. std::string file_text;
  44. std::copy(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>(), std::back_inserter(file_text));
  45. ifs.close();
  46. // create macro list:
  47. std::stringstream ss;
  48. for(std::set<std::string>::const_iterator i(macro_list.begin()), j(macro_list.end());
  49. i != j;
  50. ++i)
  51. {
  52. ss << " PRINT_MACRO(" << *i << ");\n";
  53. }
  54. std::string macros = ss.str();
  55. // scan for Boost macro block:
  56. boost::regex re("BEGIN\\s+GENERATED\\s+BLOCK\\s+DO\\s+NOT\\s+EDIT\\s+THIS[^\\n]+\\n(.*?)\\n\\s+//\\s*END\\s+GENERATED\\s+BLOCK");
  57. boost::smatch what;
  58. if(boost::regex_search(file_text, what, re))
  59. {
  60. std::string new_text;
  61. new_text.append(what.prefix().first, what[1].first);
  62. new_text.append(macros);
  63. new_text.append(what[1].second, what.suffix().second);
  64. fs::ofstream ofs(config_path / "config_info.cpp");
  65. ofs << new_text;
  66. }
  67. }
  68. void write_config_test()
  69. {
  70. fs::ofstream ofs(config_path / "config_test.cpp");
  71. time_t t = std::time(0);
  72. ofs << "// This file was automatically generated on " << std::ctime(&t);
  73. ofs << "// by libs/config/tools/generate.cpp\n" << copyright << std::endl;
  74. ofs << "// Test file for config setup\n"
  75. "// This file should compile, if it does not then\n"
  76. "// one or more macros need to be defined.\n"
  77. "// see boost_*.ipp for more details\n\n"
  78. "// Do not edit this file, it was generated automatically by\n\n"
  79. "#include <boost/config.hpp>\n#include <iostream>\n#include \"test.hpp\"\n\n"
  80. "int error_count = 0;\n\n";
  81. ofs << config_test1.str() << std::endl;
  82. ofs << config_test1a.str() << std::endl;
  83. ofs << "int main( int, char *[] )\n{\n" << config_test2.str() << " return error_count;\n}\n\n";
  84. }
  85. void write_jamfile_v2()
  86. {
  87. fs::ofstream ofs(config_path / "all" / "Jamfile.v2");
  88. time_t t = std::time(0);
  89. ofs << "#\n# Regression test Jamfile for boost configuration setup.\n# *** DO NOT EDIT THIS FILE BY HAND ***\n"
  90. "# This file was automatically generated on " << std::ctime(&t);
  91. ofs << "# by libs/config/tools/generate.cpp\n"
  92. "# Copyright John Maddock.\n"
  93. "# Use, modification and distribution are subject to the \n"
  94. "# Boost Software License, Version 1.0. (See accompanying file \n"
  95. "# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n"
  96. "#\n# If you need to alter build preferences then set them in\n"
  97. "# the template defined in options_v2.jam.\n#\n"
  98. "path-constant DOT : . ;\n"
  99. "include $(DOT)/options_v2.jam ;\n\n"
  100. "run ../config_info.cpp : : : <threading>single <toolset>msvc:<runtime-link>static <toolset>msvc:<link>static ;\n"
  101. "run ../config_info.cpp : : : <threading>multi : config_info_threaded ;\n"
  102. "run ../math_info.cpp : : : <toolset>borland:<runtime-link>static <toolset>borland:<link>static ;\n"
  103. "run ../config_test.cpp : : : <threading>single <toolset>msvc:<runtime-link>static <toolset>msvc:<link>static ;\n"
  104. "run ../config_test.cpp : : : <threading>multi : config_test_threaded ;\n"
  105. "run ../limits_test.cpp ../../../test/build//boost_test_exec_monitor ;\n"
  106. "run ../abi/abi_test.cpp ../abi/main.cpp ;\n\n";
  107. ofs << jamfile_v2.str() << std::endl;
  108. }
  109. void write_test_file(const fs::path& file,
  110. const std::string& macro_name,
  111. const std::string& namespace_name,
  112. const std::string& header_file,
  113. bool positive_test,
  114. bool expect_success)
  115. {
  116. if(!fs::exists(file))
  117. {
  118. std::cout << "Writing test file " << file.string() << std::endl;
  119. fs::ofstream ofs(file);
  120. std::time_t t = std::time(0);
  121. ofs << "// This file was automatically generated on " << std::ctime(&t);
  122. ofs << "// by libs/config/tools/generate.cpp\n" << copyright << std::endl;
  123. ofs << "\n// Test file for macro " << macro_name << std::endl;
  124. if(expect_success)
  125. {
  126. ofs << "// This file should compile, if it does not then\n"
  127. "// " << macro_name << " should ";
  128. if(positive_test)
  129. ofs << "not ";
  130. ofs << "be defined.\n";
  131. }
  132. else
  133. {
  134. ofs << "// This file should not compile, if it does then\n"
  135. "// " << macro_name << " should ";
  136. if(!positive_test)
  137. ofs << "not ";
  138. ofs << "be defined.\n";
  139. }
  140. ofs << "// See file " << header_file << " for details\n\n";
  141. ofs << "// Must not have BOOST_ASSERT_CONFIG set; it defeats\n"
  142. "// the objective of this file:\n"
  143. "#ifdef BOOST_ASSERT_CONFIG\n"
  144. "# undef BOOST_ASSERT_CONFIG\n"
  145. "#endif\n\n";
  146. static const boost::regex tr1_exp("BOOST_HAS_TR1.*");
  147. ofs << "#include <boost/config.hpp>\n";
  148. ofs << "#include \"test.hpp\"\n\n"
  149. "#if";
  150. if(positive_test != expect_success)
  151. ofs << "n";
  152. ofs << "def " << macro_name <<
  153. "\n#include \"" << header_file <<
  154. "\"\n#else\n";
  155. if(expect_success)
  156. ofs << "namespace " << namespace_name << " = empty_boost;\n";
  157. else
  158. ofs << "#error \"this file should not compile\"\n";
  159. ofs << "#endif\n\n";
  160. ofs << "int main( int, char *[] )\n{\n return " << namespace_name << "::test();\n}\n\n";
  161. }
  162. else
  163. {
  164. std::cout << "Skipping existing test file " << file.string() << std::endl;
  165. }
  166. }
  167. void write_build_tests()
  168. {
  169. fs::ofstream ofs(config_path / ".." / "checks" / "test_case.cpp");
  170. time_t t = std::time(0);
  171. ofs << "// This file was automatically generated on " << std::ctime(&t);
  172. ofs << "// by libs/config/tools/generate.cpp\n" << copyright << std::endl;
  173. ofs << "#include <boost/config.hpp>\n\n";
  174. ofs << build_config_test.str() << std::endl;
  175. ofs << "int main( int, char *[] )\n{\n" << " return 0;\n}\n\n";
  176. }
  177. void write_build_check_jamfile()
  178. {
  179. fs::ofstream ofs(config_path / ".." / "checks" / "Jamfile.v2");
  180. time_t t = std::time(0);
  181. ofs << "#\n# *** DO NOT EDIT THIS FILE BY HAND ***\n"
  182. "# This file was automatically generated on " << std::ctime(&t);
  183. ofs << "# by libs/config/tools/generate.cpp\n"
  184. "# Copyright John Maddock.\n"
  185. "# Use, modification and distribution are subject to the \n"
  186. "# Boost Software License, Version 1.0. (See accompanying file \n"
  187. "# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n\n"
  188. "import modules ;\nimport path ; \n\n"
  189. "\n"
  190. ;
  191. ofs << build_config_jamfile.str() << std::endl;
  192. }
  193. void process_ipp_file(const fs::path& file, bool positive_test)
  194. {
  195. std::cout << "Info: Scanning file: " << file.string() << std::endl;
  196. // our variables:
  197. std::string file_text;
  198. std::string macro_name;
  199. std::string namespace_name;
  200. fs::path positive_file;
  201. fs::path negative_file;
  202. // load the file into memory so we can scan it:
  203. fs::ifstream ifs(file);
  204. std::copy(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>(), std::back_inserter(file_text));
  205. ifs.close();
  206. // scan for the macro name:
  207. boost::regex macro_regex("//\\s*MACRO\\s*:\\s*(\\w+)");
  208. boost::smatch macro_match;
  209. if(boost::regex_search(file_text, macro_match, macro_regex))
  210. {
  211. macro_name = macro_match[1];
  212. macro_list.insert(macro_name);
  213. namespace_name = boost::regex_replace(file_text, macro_regex, "\\L$1", boost::format_first_only | boost::format_no_copy);
  214. }
  215. if(macro_name.empty())
  216. {
  217. std::cout << "Error: no macro definition found in " << file.string();
  218. }
  219. else
  220. {
  221. std::cout << "Info: Macroname: " << macro_name << std::endl;
  222. }
  223. // get the output filesnames:
  224. boost::regex file_regex("boost_([^.]+)\\.ipp");
  225. positive_file = file.branch_path() / boost::regex_replace(file.leaf().string(), file_regex, "$1_pass.cpp");
  226. negative_file = file.branch_path() / boost::regex_replace(file.leaf().string(), file_regex, "$1_fail.cpp");
  227. write_test_file(positive_file, macro_name, namespace_name, file.leaf().string(), positive_test, true);
  228. write_test_file(negative_file, macro_name, namespace_name, file.leaf().string(), positive_test, false);
  229. // always create config_test data,
  230. // positive and negative tests go to separate streams, because for some
  231. // reason some compilers choke unless we put them in a particular order...
  232. std::ostream* pout = positive_test ? &config_test1a : &config_test1;
  233. *pout << "#if";
  234. if(!positive_test)
  235. *pout << "n";
  236. *pout << "def " << macro_name
  237. << "\n#include \"" << file.leaf().string() << "\"\n#else\nnamespace "
  238. << namespace_name << " = empty_boost;\n#endif\n";
  239. config_test2 << " if(0 != " << namespace_name << "::test())\n"
  240. " {\n"
  241. " std::cerr << \"Failed test for " << macro_name << " at: \" << __FILE__ << \":\" << __LINE__ << std::endl;\n"
  242. " ++error_count;\n"
  243. " }\n";
  244. // always generate the jamfile data:
  245. jamfile << "test-suite \"" << macro_name << "\" : \n"
  246. "[ run " << positive_file.leaf().string() << " <template>config_options ]\n"
  247. "[ compile-fail " << negative_file.leaf().string() << " <template>config_options ] ;\n";
  248. jamfile_v2 << "test-suite \"" << macro_name << "\" : \n"
  249. "[ run ../" << positive_file.leaf().string() << " ]\n"
  250. "[ compile-fail ../" << negative_file.leaf().string() << " ] ;\n";
  251. // Generate data for the Build-checks test file:
  252. build_config_test << "#ifdef TEST_" << macro_name << std::endl;
  253. if (positive_test)
  254. {
  255. build_config_test << "# ifndef " << macro_name << "\n# error \"Feature macro " << macro_name << " is not defined.\"\n# endif\n";
  256. }
  257. else
  258. {
  259. build_config_test << "# ifdef " << macro_name << "\n# error \"Defect macro " << macro_name << " is defined.\"\n# endif\n";
  260. }
  261. build_config_test << "#endif\n";
  262. // Generate data for the build-checks Jamfile:
  263. static const boost::regex feature_regex("boost_(?:no|has)_(.*)");
  264. std::string feature_name = boost::regex_replace(namespace_name, feature_regex, "\\1");
  265. if(feature_list.find(feature_name) == feature_list.end())
  266. build_config_jamfile << "obj " << feature_name << " : test_case.cpp : <define>TEST_" << macro_name << " ;\n";
  267. feature_list.insert(feature_name);
  268. }
  269. void write_std_check(std::string macroname, int min_value, std::string header, int std_version, bool primary = true)
  270. {
  271. std::string test_name(macroname);
  272. while (test_name[0] == '_')
  273. test_name.erase(0, 1);
  274. std::string test_basename = test_name;
  275. test_name.append("_");
  276. test_name.append(1, std_version > 10 ? std_version / 10 + '0' : '0');
  277. test_name.append(1, std_version % 10 + '0');
  278. fs::ofstream ofs(config_path / ".." / "checks" / "std" / (test_name + ".cpp"));
  279. time_t t = std::time(0);
  280. ofs << "// This file was automatically generated on " << std::ctime(&t);
  281. ofs << "// by libs/config/tools/generate.cpp\n" << copyright << std::endl;
  282. ofs << "#ifdef __has_include\n#if __has_include(<version>)\n#include <version>\n#endif\n#endif\n\n";
  283. if (header.size())
  284. {
  285. ofs << "#include <" << header << ">\n\n";
  286. }
  287. ofs << "#ifndef " << macroname << "\n#error \"Macro << " << macroname << " is not set\"\n#endif\n\n";
  288. ofs << "#if " << macroname << " < " << min_value << "\n#error \"Macro " << macroname << " had too low a value\"\n#endif\n\n";
  289. ofs << "int main( int, char *[] )\n{\n" << " return 0;\n}\n\n";
  290. build_config_jamfile << "obj " << test_name << " : std/" << test_name << ".cpp ;\n";
  291. if(primary)
  292. build_config_jamfile << "alias " << test_basename << " : " << test_name << " ;\n";
  293. }
  294. void write_std_config_checks()
  295. {
  296. // C++20
  297. write_std_check("__cpp_impl_destroying_delete", 201806, "", 20);
  298. write_std_check("__cpp_lib_destroying_delete", 201806, "new", 20);
  299. write_std_check("__cpp_char8_t", 201811, "", 20);
  300. write_std_check("__cpp_impl_three_way_comparison", 201711, "", 20);
  301. write_std_check("__cpp_lib_three_way_comparison", 201711, "compare", 20);
  302. write_std_check("__cpp_conditional_explicit", 201806, "", 20);
  303. write_std_check("__cpp_nontype_template_parameter_class", 201806, "", 20);
  304. write_std_check("__cpp_lib_char8_t", 201811, "atomic", 20);
  305. write_std_check("__cpp_lib_concepts", 201806, "concepts", 20);
  306. write_std_check("__cpp_lib_constexpr_swap_algorithms", 201806, "algorithm", 20);
  307. write_std_check("__cpp_lib_constexpr_misc", 201811, "array", 20);
  308. write_std_check("__cpp_lib_bind_front", 201811, "functional", 20);
  309. write_std_check("__cpp_lib_is_constant_evaluated", 201811, "type_traits", 20);
  310. write_std_check("__cpp_lib_erase_if", 201811, "string", 20);
  311. write_std_check("__cpp_lib_list_remove_return_type", 201806, "forward_list", 20);
  312. write_std_check("__cpp_lib_generic_unordered_lookup", 201811, "unordered_map", 20);
  313. write_std_check("__cpp_lib_ranges", 201811, "algorithm", 20);
  314. write_std_check("__cpp_lib_bit_cast", 201806, "bit", 20);
  315. write_std_check("__cpp_lib_atomic_ref", 201806, "atomic", 20);
  316. // C++17
  317. write_std_check("__cpp_hex_float", 201603, "", 17);
  318. write_std_check("__cpp_inline_variables", 201606, "", 17);
  319. write_std_check("__cpp_aligned_new", 201606, "", 17);
  320. write_std_check("__cpp_guaranteed_copy_elision", 201606, "", 17);
  321. write_std_check("__cpp_noexcept_function_type", 201510, "", 17);
  322. write_std_check("__cpp_fold_expressions", 201603, "", 17);
  323. write_std_check("__cpp_capture_star_this", 201603, "", 17);
  324. write_std_check("__cpp_constexpr", 201603, "", 17, false);
  325. write_std_check("__cpp_if_constexpr", 201606, "", 17);
  326. write_std_check("__cpp_range_based_for", 201603, "", 17, false);
  327. write_std_check("__cpp_static_assert", 201411, "", 17, false);
  328. write_std_check("__cpp_deduction_guides", 201611, "", 17); // NOTE: this is the pre-std version number used by gcc-8, is this OK???
  329. write_std_check("__cpp_nontype_template_parameter_auto", 201606, "", 17);
  330. write_std_check("__cpp_namespace_attributes", 201411, "", 17);
  331. write_std_check("__cpp_enumerator_attributes", 201411, "", 17);
  332. write_std_check("__cpp_inheriting_constructors", 201511, "", 17, false);
  333. write_std_check("__cpp_variadic_using", 201611, "", 17);
  334. write_std_check("__cpp_structured_bindings", 201606, "", 17);
  335. write_std_check("__cpp_aggregate_bases", 201603, "", 17);
  336. write_std_check("__cpp_nontype_template_args", 201411, "", 17);
  337. write_std_check("__cpp_template_template_args", 201611, "", 17);
  338. write_std_check("__cpp_lib_byte", 201603, "cstddef", 17);
  339. write_std_check("__cpp_lib_hardware_interference_size", 201703, "new", 17);
  340. write_std_check("__cpp_lib_launder", 201606, "new", 17);
  341. write_std_check("__cpp_lib_uncaught_exceptions", 201411, "exception", 17);
  342. write_std_check("__cpp_lib_as_const", 201510, "utility", 17);
  343. write_std_check("__cpp_lib_make_from_tuple", 201606, "tuple", 17);
  344. write_std_check("__cpp_lib_apply", 201603, "tuple", 17);
  345. write_std_check("__cpp_lib_optional", 201606, "optional", 17);
  346. write_std_check("__cpp_lib_variant", 201606, "variant", 17);
  347. write_std_check("__cpp_lib_any", 201606, "any", 17);
  348. write_std_check("__cpp_lib_addressof_constexpr", 201603, "memory", 17);
  349. write_std_check("__cpp_lib_raw_memory_algorithms", 201606, "memory", 17);
  350. write_std_check("__cpp_lib_transparent_operators", 201510, "memory", 17, false);
  351. write_std_check("__cpp_lib_enable_shared_from_this", 201603, "memory", 17);
  352. write_std_check("__cpp_lib_shared_ptr_weak_type", 201606, "memory", 17);
  353. write_std_check("__cpp_lib_shared_ptr_arrays", 201611, "memory", 17);
  354. write_std_check("__cpp_lib_memory_resource", 201603, "memory_resource", 17);
  355. write_std_check("__cpp_lib_boyer_moore_searcher", 201603, "functional", 17);
  356. write_std_check("__cpp_lib_invoke", 201411, "functional", 17);
  357. write_std_check("__cpp_lib_not_fn", 201603, "functional", 17);
  358. write_std_check("__cpp_lib_void_t", 201411, "type_traits", 17);
  359. write_std_check("__cpp_lib_bool_constant", 201505, "type_traits", 17);
  360. write_std_check("__cpp_lib_type_trait_variable_templates", 201510, "type_traits", 17);
  361. write_std_check("__cpp_lib_logical_traits", 201510, "type_traits", 17);
  362. write_std_check("__cpp_lib_is_swappable", 201603, "type_traits", 17);
  363. write_std_check("__cpp_lib_is_invocable", 201703, "type_traits", 17);
  364. write_std_check("__cpp_lib_has_unique_object_representations", 201606, "type_traits", 17);
  365. write_std_check("__cpp_lib_is_aggregate", 201703, "type_traits", 17);
  366. write_std_check("__cpp_lib_chrono", 201611, "chrono", 17);
  367. write_std_check("__cpp_lib_execution", 201603, "execution", 17);
  368. write_std_check("__cpp_lib_parallel_algorithm", 201603, "algorithm", 17);
  369. write_std_check("__cpp_lib_to_chars", 201611, "utility", 17);
  370. write_std_check("__cpp_lib_string_view", 201606, "string", 17);
  371. write_std_check("__cpp_lib_allocator_traits_is_always_equal", 201411, "memory", 17);
  372. write_std_check("__cpp_lib_incomplete_container_elements", 201505, "forward_list", 17);
  373. write_std_check("__cpp_lib_map_try_emplace", 201411, "map", 17);
  374. write_std_check("__cpp_lib_unordered_map_try_emplace", 201411, "unordered_map", 17);
  375. write_std_check("__cpp_lib_node_extract", 201606, "map", 17);
  376. write_std_check("__cpp_lib_array_constexpr", 201603, "iterator", 17);
  377. write_std_check("__cpp_lib_nonmember_container_access", 201411, "iterator", 17);
  378. write_std_check("__cpp_lib_sample", 201603, "algorithm", 17);
  379. write_std_check("__cpp_lib_clamp", 201603, "algorithm", 17);
  380. write_std_check("__cpp_lib_gcd_lcm", 201606, "numeric", 17);
  381. write_std_check("__cpp_lib_hypot", 201603, "cmath", 17);
  382. write_std_check("__cpp_lib_math_special_functions", 201603, "cmath", 17);
  383. write_std_check("__cpp_lib_filesystem", 201703, "filesystem", 17);
  384. write_std_check("__cpp_lib_atomic_is_always_lock_free", 201603, "atomic", 17);
  385. write_std_check("__cpp_lib_shared_mutex", 201505, "shared_mutex", 17);
  386. write_std_check("__cpp_lib_scoped_lock", 201703, "mutex", 17);
  387. // C++14
  388. write_std_check("__cpp_binary_literals", 201304, "", 14);
  389. write_std_check("__cpp_init_captures", 201304, "", 14);
  390. write_std_check("__cpp_generic_lambdas", 201304, "", 14);
  391. write_std_check("__cpp_sized_deallocation", 201309, "", 14);
  392. write_std_check("__cpp_constexpr", 201304, "", 14, false);
  393. write_std_check("__cpp_decltype_auto", 201304, "", 14);
  394. write_std_check("__cpp_return_type_deduction", 201304, "", 14);
  395. write_std_check("__cpp_aggregate_nsdmi", 201304, "", 14);
  396. write_std_check("__cpp_variable_templates", 201304, "", 14);
  397. write_std_check("__cpp_lib_integer_sequence", 201304, "utility", 14);
  398. write_std_check("__cpp_lib_exchange_function", 201304, "utility", 14);
  399. write_std_check("__cpp_lib_tuples_by_type", 201304, "utility", 14);
  400. write_std_check("__cpp_lib_tuple_element_t", 201402, "tuple", 14);
  401. write_std_check("__cpp_lib_make_unique", 201304, "memory", 14);
  402. write_std_check("__cpp_lib_transparent_operators", 201210, "functional", 14);
  403. write_std_check("__cpp_lib_integral_constant_callable", 201304, "type_traits", 14);
  404. write_std_check("__cpp_lib_transformation_trait_aliases", 201304, "type_traits", 14);
  405. write_std_check("__cpp_lib_result_of_sfinae", 201210, "functional", 14);
  406. write_std_check("__cpp_lib_is_final", 201402, "type_traits", 14);
  407. write_std_check("__cpp_lib_is_null_pointer", 201309, "type_traits", 14);
  408. write_std_check("__cpp_lib_chrono_udls", 201304, "chrono", 14);
  409. write_std_check("__cpp_lib_string_udls", 201304, "string", 14);
  410. write_std_check("__cpp_lib_generic_associative_lookup", 201304, "map", 14);
  411. write_std_check("__cpp_lib_null_iterators", 201304, "iterator", 14);
  412. write_std_check("__cpp_lib_make_reverse_iterator", 201402, "iterator", 14);
  413. write_std_check("__cpp_lib_robust_nonmodifying_seq_ops", 201304, "algorithm", 14);
  414. write_std_check("__cpp_lib_complex_udls", 201309, "complex", 14);
  415. write_std_check("__cpp_lib_quoted_string_io", 201304, "iomanip", 14);
  416. write_std_check("__cpp_lib_shared_timed_mutex", 201402, "shared_mutex", 14);
  417. // C++11
  418. write_std_check("__cpp_unicode_characters", 200704, "", 11);
  419. write_std_check("__cpp_raw_strings", 200710, "", 11);
  420. write_std_check("__cpp_unicode_literals", 200710, "", 11);
  421. write_std_check("__cpp_user_defined_literals", 200809, "", 11);
  422. write_std_check("__cpp_threadsafe_static_init", 200806, "", 11);
  423. write_std_check("__cpp_lambdas", 200907, "", 11);
  424. write_std_check("__cpp_constexpr", 200704, "", 11);
  425. write_std_check("__cpp_range_based_for", 200907, "", 11);
  426. write_std_check("__cpp_static_assert", 200410, "", 11);
  427. write_std_check("__cpp_decltype", 200707, "", 11);
  428. write_std_check("__cpp_attributes", 200809, "", 11);
  429. write_std_check("__cpp_rvalue_references", 200610, "", 11);
  430. write_std_check("__cpp_variadic_templates", 200704, "", 11);
  431. write_std_check("__cpp_initializer_lists", 200806, "", 11);
  432. write_std_check("__cpp_explicit_conversion", 200710, "", 11);
  433. write_std_check("__cpp_delegating_constructors", 200604, "", 11);
  434. write_std_check("__cpp_nsdmi", 200809, "", 11);
  435. write_std_check("__cpp_inheriting_constructors", 200802, "", 11);
  436. write_std_check("__cpp_ref_qualifiers", 200710, "", 11);
  437. write_std_check("__cpp_alias_templates", 200704, "", 11);
  438. // C++98
  439. write_std_check("__cpp_rtti", 199711, "", 03);
  440. write_std_check("__cpp_exceptions", 199711, "", 03);
  441. }
  442. int cpp_main(int argc, char* argv[])
  443. {
  444. //
  445. // get the boost path to begin with:
  446. //
  447. if(argc > 1)
  448. {
  449. fs::path p(argv[1]);
  450. config_path = p / "libs" / "config" / "test" ;
  451. }
  452. else
  453. {
  454. // try __FILE__:
  455. fs::path p(__FILE__);
  456. config_path = p.branch_path().branch_path() / "test";
  457. }
  458. std::cout << "Info: Boost.Config test path set as: " << config_path.string() << std::endl;
  459. // enumerate *.ipp files and store them in a map for now:
  460. boost::regex ipp_mask("boost_(?:(has)|no).*\\.ipp");
  461. boost::smatch ipp_match;
  462. fs::directory_iterator i(config_path), j;
  463. std::map<fs::path, bool> files_to_process;
  464. while(i != j)
  465. {
  466. if(boost::regex_match(i->path().leaf().string(), ipp_match, ipp_mask))
  467. {
  468. files_to_process[*i] = ipp_match[1].matched;
  469. }
  470. ++i;
  471. }
  472. // Enumerate the files and process them, by defering this until now
  473. // the results are always alphabetized which reduces churn in the
  474. // generated files.
  475. for(std::map<fs::path, bool>::const_iterator pos = files_to_process.begin(); pos != files_to_process.end(); ++pos)
  476. {
  477. process_ipp_file(pos->first, pos->second);
  478. }
  479. write_config_test();
  480. write_jamfile_v2();
  481. write_config_info();
  482. write_std_config_checks();
  483. write_build_tests();
  484. write_build_check_jamfile();
  485. return 0;
  486. }