3 * Copyright (c) 2009 Dr John Maddock
4 * Use, modification and distribution is subject to the
5 * Boost Software License, Version 1.0. (See accompanying file
6 * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 * This file implements the following:
9 * void bcp_implementation::add_path(const fs::path& p)
10 * void bcp_implementation::add_directory(const fs::path& p)
11 * void bcp_implementation::add_file(const fs::path& p)
12 * void bcp_implementation::add_dependent_lib(const std::string& libname, const fs::path& p, const fileview& view)
15 #include "bcp_imp.hpp"
16 #include "fileview.hpp"
17 #include <boost/regex.hpp>
18 #include <boost/filesystem/operations.hpp>
19 #include <boost/filesystem/exception.hpp>
23 // This file contains the code required to work out whether the source/header file being scanned
24 // is actually dependent upon some library's source code or not.
27 static std::map<std::string, boost::regex> scanner;
29 static std::map<std::string, std::set<std::string> > free_function_names;
30 static std::map<std::string, std::set<std::string> > class_names;
31 static std::map<std::string, std::set<std::string> > variable_names;
33 static void init_library_scanner(const fs::path& p, bool cvs_mode, const std::string& libname, bool recurse = false)
36 if(free_function_names.count(libname) == 0)
38 free_function_names[libname] = "[\\x0]";
39 class_names[libname] = "[\\x0]";
40 variable_names[libname] = "[\\x0]";
44 // Don't add files created by build system:
46 if((p.leaf() == "bin") || (p.leaf() == "bin-stage"))
49 // Don't add version control directories:
51 if((p.leaf() == "CVS") || (p.leaf() == ".svn"))
54 // don't add directories not under version control:
56 if(cvs_mode && !fs::exists(p / "CVS/Entries"))
58 if(cvs_mode && !fs::exists(p / ".svn/entries"))
61 // Enumerate files and directories:
63 fs::directory_iterator i(p);
64 fs::directory_iterator j;
67 if(fs::is_directory(*i))
68 init_library_scanner(*i, cvs_mode, libname, true);
69 if(bcp_implementation::is_source_file(*i))
71 static boost::regex function_scanner(
72 "(?|" // Branch reset group
73 "(?:\\<\\w+\\>[^>;{},:]*)" // Return type
75 "(\\<\\w+\\>)" // Maybe class name
77 "(?:<[^>;{]*>)?" // Maybe template specialisation
79 "(\\<(?!throw|if|while|for|catch)\\w+\\>)" // function name
82 "[^\\(\\);{}]*" // argument list
84 "\\s*(?:BOOST[_A-Z]+\\s*)?"
85 "\\{" // start of definition
87 "(\\<\\w+\\>)" // Maybe class name
89 "(?:<[^>;{]*>)?" // Maybe template specialisation
91 "~?\\1" // function name, same as class name
94 "[^\\(\\);{}]*" // argument list
96 "\\s*(?:BOOST[_A-Z]+\\s*)?"
97 "\\{" // start of definition
98 ")" // end branch reset
101 boost::regex_iterator<const char*> a(view.begin(), view.end(), function_scanner);
102 boost::regex_iterator<const char*> b;
107 std::string n = a->str(1);
108 class_names[libname].insert(n);
112 std::string n = a->str(2);
113 free_function_names[libname].insert(n);
124 // Build the regular expressions:
127 "^(?>[[:blank:]]*)(?!#)[^;{}\\r\\n]*"
129 "(?:class|struct)[^:;{}#]*"
131 // list of class names goes here...
133 ")\\s*(?:<[^;{>]*>\\s*)?(?::[^;{]*)?\\{"
135 "\\<(?!return)\\w+\\>[^:;{}#=<>!~%.\\w]*(";
136 // List of function names goes here...
138 ")\\s*\\([^;()]*\\)\\s*(?:BOOST[_A-Z]+\\s*)?;)";
140 std::string class_name_list;
141 std::set<std::string>::const_iterator i = class_names[libname].begin(), j = class_names[libname].end();
144 class_name_list = *i;
148 class_name_list += "|" + *i;
154 class_name_list = "[\\x0]";
156 std::string function_name_list;
157 i = free_function_names[libname].begin();
158 j = free_function_names[libname].end();
161 function_name_list = *i;
165 function_name_list += "|" + *i;
171 function_name_list = "[\\x0]";
174 scanner[libname] = boost::regex(e1 + class_name_list + e2 + function_name_list + e3);
178 void bcp_implementation::add_dependent_lib(const std::string& libname, const fs::path& p, const fileview& view)
181 // if the boost library libname has source associated with it
182 // then add the source to our list:
184 if(fs::exists(m_boost_path / "libs" / libname / "src"))
186 if(!m_dependencies.count(fs::path("libs") / libname / "src"))
188 if(scanner.count(libname) == 0)
189 init_library_scanner(m_boost_path / "libs" / libname / "src", m_cvs_mode, libname);
191 if(regex_search(view.begin(), view.end(), what, scanner[libname]))
193 std::cout << "INFO: tracking source dependencies of library " << libname
194 << " due to presence of \"" << what << "\" in file " << p << std::endl;
195 //std::cout << "Full text match was: " << what << std::endl;
196 m_dependencies[fs::path("libs") / libname / "src"] = p; // set up dependency tree
197 add_path(fs::path("libs") / libname / "src");
199 if(fs::exists(m_boost_path / "libs" / libname / "build"))
201 if(!m_dependencies.count(fs::path("libs") / libname / "build"))
203 m_dependencies[fs::path("libs") / libname / "build"] = p; // set up dependency tree
204 add_path(fs::path("libs") / libname / "build");
205 //m_dependencies[fs::path("boost-build.jam")] = p;
206 //add_path(fs::path("boost-build.jam"));
207 m_dependencies[fs::path("Jamroot")] = p;
208 add_path(fs::path("Jamroot"));
209 //m_dependencies[fs::path("tools/build")] = p;
210 //add_path(fs::path("tools/build"));
213 if(fs::exists(m_boost_path / "libs" / libname / "config"))
215 if(!m_dependencies.count(fs::path("libs") / libname / "config"))
217 m_dependencies[fs::path("libs") / libname / "config"] = p; // set up dependency tree
218 add_path(fs::path("libs") / libname / "config");
219 //m_dependencies[fs::path("boost-build.jam")] = p;
220 //add_path(fs::path("boost-build.jam"));
221 m_dependencies[fs::path("Jamroot")] = p;
222 add_path(fs::path("Jamroot"));
223 //m_dependencies[fs::path("tools/build")] = p;
224 //add_path(fs::path("tools/build"));