1/*
2 *
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)
7 *
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)
13 */
14
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>
20#include <iostream>
21
22//
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.
25//
26
27static std::map<std::string, boost::regex> scanner;
28
29static std::map<std::string, std::set<std::string> > free_function_names;
30static std::map<std::string, std::set<std::string> > class_names;
31static std::map<std::string, std::set<std::string> > variable_names;
32
33static void init_library_scanner(const fs::path& p, bool cvs_mode, const std::string& libname, bool recurse = false)
34{
35 /*
36 if(free_function_names.count(libname) == 0)
37 {
38 free_function_names[libname] = "[\\x0]";
39 class_names[libname] = "[\\x0]";
40 variable_names[libname] = "[\\x0]";
41 }
42 */
43 //
44 // Don't add files created by build system:
45 //
46 if((p.leaf() == "bin") || (p.leaf() == "bin-stage"))
47 return;
48 //
49 // Don't add version control directories:
50 //
51 if((p.leaf() == "CVS") || (p.leaf() == ".svn"))
52 return;
53 //
54 // don't add directories not under version control:
55 //
56 if(cvs_mode && !fs::exists(p: p / "CVS/Entries"))
57 return;
58 if(cvs_mode && !fs::exists(p: p / ".svn/entries"))
59 return;
60 //
61 // Enumerate files and directories:
62 //
63 fs::directory_iterator i(p);
64 fs::directory_iterator j;
65 while(i != j)
66 {
67 if(fs::is_directory(p: *i))
68 init_library_scanner(p: *i, cvs_mode, libname, recurse: true);
69 if(bcp_implementation::is_source_file(p: *i))
70 {
71 static boost::regex function_scanner(
72 "(?|" // Branch reset group
73 "(?:\\<\\w+\\>[^>;{},:]*)" // Return type
74 "(?:"
75 "(\\<\\w+\\>)" // Maybe class name
76 "\\s*"
77 "(?:<[^>;{]*>)?" // Maybe template specialisation
78 "::\\s*)?"
79 "(\\<(?!throw|if|while|for|catch)\\w+\\>)" // function name
80 "\\s*"
81 "\\("
82 "[^\\(\\);{}]*" // argument list
83 "\\)"
84 "\\s*(?:BOOST[_A-Z]+\\s*)?"
85 "\\{" // start of definition
86 "|"
87 "(\\<\\w+\\>)" // Maybe class name
88 "\\s*"
89 "(?:<[^>;{]*>)?" // Maybe template specialisation
90 "::\\s*"
91 "~?\\1" // function name, same as class name
92 "\\s*"
93 "\\("
94 "[^\\(\\);{}]*" // argument list
95 "\\)"
96 "\\s*(?:BOOST[_A-Z]+\\s*)?"
97 "\\{" // start of definition
98 ")" // end branch reset
99 );
100 fileview view(*i);
101 boost::regex_iterator<const char*> a(view.begin(), view.end(), function_scanner);
102 boost::regex_iterator<const char*> b;
103 while(a != b)
104 {
105 if((*a)[1].matched)
106 {
107 std::string n = a->str(sub: 1);
108 class_names[libname].insert(x: n);
109 }
110 else
111 {
112 std::string n = a->str(sub: 2);
113 free_function_names[libname].insert(x: n);
114 }
115 ++a;
116 }
117 }
118 ++i;
119 }
120
121 if(recurse == false)
122 {
123 //
124 // Build the regular expressions:
125 //
126 const char* e1 =
127 "^(?>[[:blank:]]*)(?!#)[^;{}\\r\\n]*"
128 "(?|"
129 "(?:class|struct)[^:;{}#]*"
130 "(";
131 // list of class names goes here...
132 const char* e2 =
133 ")\\s*(?:<[^;{>]*>\\s*)?(?::[^;{]*)?\\{"
134 "|"
135 "\\<(?!return)\\w+\\>[^:;{}#=<>!~%.\\w]*(";
136 // List of function names goes here...
137 const char* e3 =
138 ")\\s*\\([^;()]*\\)\\s*(?:BOOST[_A-Z]+\\s*)?;)";
139
140 std::string class_name_list;
141 std::set<std::string>::const_iterator i = class_names[libname].begin(), j = class_names[libname].end();
142 if(i != j)
143 {
144 class_name_list = *i;
145 ++i;
146 while(i != j)
147 {
148 class_name_list += "|" + *i;
149 ++i;
150 }
151 }
152 else
153 {
154 class_name_list = "[\\x0]";
155 }
156 std::string function_name_list;
157 i = free_function_names[libname].begin();
158 j = free_function_names[libname].end();
159 if(i != j)
160 {
161 function_name_list = *i;
162 ++i;
163 while(i != j)
164 {
165 function_name_list += "|" + *i;
166 ++i;
167 }
168 }
169 else
170 {
171 function_name_list = "[\\x0]";
172 }
173
174 scanner[libname] = boost::regex(e1 + class_name_list + e2 + function_name_list + e3);
175 }
176}
177
178void bcp_implementation::add_dependent_lib(const std::string& libname, const fs::path& p, const fileview& view)
179{
180 //
181 // if the boost library libname has source associated with it
182 // then add the source to our list:
183 //
184 if(fs::exists(p: m_boost_path / "libs" / libname / "src"))
185 {
186 if(!m_dependencies.count(x: fs::path("libs") / libname / "src"))
187 {
188 if(scanner.count(x: libname) == 0)
189 init_library_scanner(p: m_boost_path / "libs" / libname / "src", cvs_mode: m_cvs_mode, libname);
190 boost::cmatch what;
191 if(regex_search(first: view.begin(), last: view.end(), m&: what, e: scanner[libname]))
192 {
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(p: fs::path("libs") / libname / "src");
198
199 if(fs::exists(p: m_boost_path / "libs" / libname / "build"))
200 {
201 if(!m_dependencies.count(x: fs::path("libs") / libname / "build"))
202 {
203 m_dependencies[fs::path("libs") / libname / "build"] = p; // set up dependency tree
204 add_path(p: 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(p: fs::path("Jamroot"));
209 //m_dependencies[fs::path("tools/build")] = p;
210 //add_path(fs::path("tools/build"));
211 }
212 }
213 }
214 }
215 }
216}
217

source code of boost/tools/bcp/add_dependent_lib.cpp