]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/config/tools/generate.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / config / tools / generate.cpp
CommitLineData
7c673cae
FG
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
23namespace fs = boost::filesystem;
24
25fs::path config_path;
26
27std::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
36std::stringstream config_test1;
37std::stringstream config_test1a;
38std::stringstream config_test2;
39std::stringstream jamfile;
40std::stringstream jamfile_v2;
41std::stringstream build_config_test;
42std::stringstream build_config_jamfile;
43std::set<std::string> macro_list;
b32b8144 44std::set<std::string> feature_list;
7c673cae
FG
45
46void 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
76void 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
94void 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
120void 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
7c673cae
FG
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
186void 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;
b32b8144 192 ofs << "#include <boost/config.hpp>\n\n";
7c673cae 193 ofs << build_config_test.str() << std::endl;
b32b8144 194 ofs << "int main( int, char *[] )\n{\n" << " return 0;\n}\n\n";
7c673cae
FG
195}
196
197void 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"
7c673cae
FG
210 ;
211 ofs << build_config_jamfile.str() << std::endl;
212}
213
214void 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;
b32b8144
FG
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";
7c673cae
FG
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");
b32b8144
FG
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);
7c673cae
FG
298}
299
300int cpp_main(int argc, char* argv[])
301{
302 //
303 // get the boost path to begin with:
304 //
305 if(argc > 1)
306 {
307 fs::path p(argv[1]);
308 config_path = p / "libs" / "config" / "test" ;
309 }
310 else
311 {
312 // try __FILE__:
313 fs::path p(__FILE__);
314 config_path = p.branch_path().branch_path() / "test";
315 }
316 std::cout << "Info: Boost.Config test path set as: " << config_path.string() << std::endl;
317
318 // enumerate *.ipp files and store them in a map for now:
319 boost::regex ipp_mask("boost_(?:(has)|no).*\\.ipp");
320 boost::smatch ipp_match;
321 fs::directory_iterator i(config_path), j;
322 std::map<fs::path, bool> files_to_process;
323 while(i != j)
324 {
325 if(boost::regex_match(i->path().leaf().string(), ipp_match, ipp_mask))
326 {
327 files_to_process[*i] = ipp_match[1].matched;
328 }
329 ++i;
330 }
331 // Enumerate the files and process them, by defering this until now
332 // the results are always alphabetized which reduces churn in the
333 // generated files.
334 for(std::map<fs::path, bool>::const_iterator pos = files_to_process.begin(); pos != files_to_process.end(); ++pos)
335 {
336 process_ipp_file(pos->first, pos->second);
337 }
338 write_config_test();
339 write_jamfile_v2();
340 write_config_info();
341 write_build_tests();
342 write_build_check_jamfile();
343 return 0;
344}
345