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