Imported Upstream version 1.72.0
[platform/upstream/boost.git] / tools / bcp / add_dependent_lib.cpp
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
27 static std::map<std::string, boost::regex> scanner;
28
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;
32
33 static 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 / "CVS/Entries"))
57       return;
58    if(cvs_mode && !fs::exists(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(*i))
68          init_library_scanner(*i, cvs_mode, libname, true);
69       if(bcp_implementation::is_source_file(*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(1);
108                class_names[libname].insert(n);
109             }
110             else
111             {
112                std::string n = a->str(2);
113                free_function_names[libname].insert(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
178 void 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(m_boost_path / "libs" / libname / "src"))
185    {
186       if(!m_dependencies.count(fs::path("libs") / libname / "src")) 
187       {
188          if(scanner.count(libname) == 0)
189             init_library_scanner(m_boost_path / "libs" / libname / "src", m_cvs_mode, libname);
190          boost::cmatch what;
191          if(regex_search(view.begin(), view.end(), what, 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(fs::path("libs") / libname / "src");
198
199             if(fs::exists(m_boost_path / "libs" / libname / "build"))
200             {
201                if(!m_dependencies.count(fs::path("libs") / libname / "build")) 
202                {
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"));
211                }
212             }
213             if(fs::exists(m_boost_path / "libs" / libname / "config"))
214             {
215                if(!m_dependencies.count(fs::path("libs") / libname / "config")) 
216                {
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"));
225                }
226             }
227          }
228       }
229    }
230 }