// return the result
std::string
replace_all (const std::string &in,
- const std::string &pattern,
- const std::string &substitute)
+ const std::string &pattern,
+ const std::string &substitute)
{
std::string x = in;
while (x.find(pattern) != std::string::npos)
x.replace (x.find(pattern),
- pattern.size(),
- substitute);
+ pattern.size(),
+ substitute);
return x;
}
-// extract from the start of #in the part of the string that ends with one of
-// the characters in #delim_list. The extracted part is deleted from #in
-// and returned. We skip characters in delim_list if they are preceded
-// by a backslash
+// extract from the start of #in the part of the string that ends with one
+// of the characters in #delim_list. The extracted part is deleted from #in
+// and returned. We skip characters in delim_list if they are preceded by a
+// backslash
std::string
get_substring_with_delim (std::string &in,
- const std::string &delim_list)
+ const std::string &delim_list)
{
std::string x;
while (in.size() != 0)
{
- // stop copying to the result
- // if the current character is
- // a delimiter, but only if the
- // previous character was not a
- // backslash
+ // stop copying to the result if the current character is a
+ // delimiter, but only if the previous character was not a backslash
if ((delim_list.find (in[0]) != std::string::npos)
- &&
- !((x.size() > 0)
- &&
- (x[x.size()-1] == '\\')))
- break;
+ &&
+ !((x.size() > 0)
+ &&
+ (x[x.size()-1] == '\\')))
+ break;
x += in[0];
in.erase (0, 1);
skip_space (std::string &in)
{
while ((in.size() != 0)
- &&
- ((in[0] == ' ') || (in[0] == '\t') || (in[0] == '\n')))
+ &&
+ ((in[0] == ' ') || (in[0] == '\t') || (in[0] == '\n')))
in.erase (0, 1);
}
{
const std::string::size_type slash_star_comment_end = line.find ("*/");
if (slash_star_comment_end == std::string::npos)
- {
- std::cerr << "The program can currently only handle /* block */"
- << "comments that start and end within the same line."
- << std::endl;
- std::exit (1);
- }
+ {
+ std::cerr << "The program can currently only handle /* block */"
+ << "comments that start and end within the same line."
+ << std::endl;
+ std::exit (1);
+ }
line.erase (slash_star_comment_begin,
- slash_star_comment_end - slash_star_comment_begin + 2);
+ slash_star_comment_end - slash_star_comment_begin + 2);
}
return line;
whole_file += remove_comments (line);
whole_file += '\n';
}
- // substitute tabs by spaces, multiple
- // spaces by single ones
+ // substitute tabs by spaces, multiple spaces by single ones
for (unsigned int i=0; i<whole_file.size(); ++i)
if (whole_file[i] == '\t')
whole_file[i] = ' ';
-// split a given string assumed to consist of a list of substrings delimited
-// by a particular character into its components
+// split a given string assumed to consist of a list of substrings
+// delimited by a particular character into its components
std::list<std::string>
split_string_list (const std::string &s,
- const char delimiter)
+ const char delimiter)
{
std::string tmp = s;
std::list<std::string> split_list;
- // split the input list
+ // split the input list
while (tmp.length() != 0)
{
std::string name;
name = tmp;
if (name.find(delimiter) != std::string::npos)
- {
- name.erase (name.find(delimiter), std::string::npos);
- tmp.erase (0, tmp.find(delimiter)+1);
- }
+ {
+ name.erase (name.find(delimiter), std::string::npos);
+ tmp.erase (0, tmp.find(delimiter)+1);
+ }
else
- tmp = "";
+ tmp = "";
skip_space (name);
while ((name.size() != 0) && (name[name.length()-1] == ' '))
- name.erase (name.length()-1, 1);
+ name.erase (name.length()-1, 1);
split_list.push_back (name);
}
-// determine whether a given substring at position #pos and length #length in
-// the string #text is a real token, i.e. not just part of another word
+// determine whether a given substring at position #pos and length #length
+// in the string #text is a real token, i.e. not just part of another word
bool is_real_token (const std::string &text,
- const std::string::size_type pos,
- const std::string::size_type length)
+ const std::string::size_type pos,
+ const std::string::size_type length)
{
static const std::string token_chars ("abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "0123456789"
- "_");
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789"
+ "_");
if ((pos != 0) && (token_chars.find (text[pos-1]) != std::string::npos))
return false;
// substitute all occurrences of #token in #text by #substitute. because a
-// replacement token could be a templated class like std::complex<double> and
-// because the token to the substituted may be a template argument itself, we
-// surround the substitution by a space which shouldn't matter in C++
+// replacement token could be a templated class like std::complex<double>
+// and because the token to the substituted may be a template argument
+// itself, we surround the substitution by a space which shouldn't matter
+// in C++
std::string substitute_tokens (const std::string &text,
- const std::string &token,
- const std::string &substitute)
+ const std::string &token,
+ const std::string &substitute)
{
std::string x_text = text;
std::string::size_type pos = 0;
while ((pos = x_text.find(token, pos)) != std::string::npos)
{
if (is_real_token (x_text, pos, token.size()))
- {
- x_text.replace (pos, token.size(),
- std::string(" ")+substitute+std::string(" "));
- pos += substitute.size()+2;
- }
+ {
+ x_text.replace (pos, token.size(),
+ std::string(" ")+substitute+std::string(" "));
+ pos += substitute.size()+2;
+ }
else
- ++pos;
+ ++pos;
}
return x_text;
// read and parse the expansion lists like
-// REAL_SCALARS := { double; float; long double }
-// as specified at the top of the file and store them in
-// the global expansion_lists variable
+// REAL_SCALARS := { double; float; long double }
+// as specified at the top of the file and store them in the global
+// expansion_lists variable
void read_expansion_lists (const std::string &filename)
{
std::ifstream in (filename.c_str());
if (! in)
{
std::cerr << "Instantiation list file can not be read!"
- << std::endl;
+ << std::endl;
std::exit (1);
}
- // read the entire file into a string for
- // simpler processing. replace end-of-line
- // characters by spaces
+ // read the entire file into a string for simpler processing. replace
+ // end-of-line characters by spaces
std::string whole_file = read_whole_file (in);
- // now process entries of the form
- // NAME := { class1; class2; ...}.
+ // now process entries of the form
+ // NAME := { class1; class2; ...}.
while (whole_file.size() != 0)
{
const std::string
- name = get_substring_with_delim (whole_file, " :");
+ name = get_substring_with_delim (whole_file, " :");
skip_space (whole_file);
if (whole_file.find (":=") != 0)
- {
- std::cerr << "Invalid entry <" << name << '>' << std::endl;
- std::exit (1);
- }
+ {
+ std::cerr << "Invalid entry <" << name << '>' << std::endl;
+ std::exit (1);
+ }
whole_file.erase (0, 2);
skip_space (whole_file);
if (whole_file.find ("{") != 0)
- {
- std::cerr << "Invalid entry <" << name << '>' << std::endl;
- std::exit (1);
- }
+ {
+ std::cerr << "Invalid entry <" << name << '>' << std::endl;
+ std::exit (1);
+ }
whole_file.erase (0, 1);
skip_space (whole_file);
std::string
- expansion = get_substring_with_delim (whole_file, "}");
+ expansion = get_substring_with_delim (whole_file, "}");
if (whole_file.find ("}") != 0)
- {
- std::cerr << "Invalid entry <" << name << '>' << std::endl;
- std::exit (1);
- }
+ {
+ std::cerr << "Invalid entry <" << name << '>' << std::endl;
+ std::exit (1);
+ }
whole_file.erase (0, 1);
skip_space (whole_file);
- // assign but remove empty entries;
- // this may happen if an expansion list
- // ends in a semicolon (then we get an
- // empty entry at the end), or if there
- // are multiple semicolons after each
- // other (this may happen if, for
- // example, we have "Vector<double>;
- // TRILINOS_VECTOR;" and if
- // TRILINOS_VECTOR is an empty
- // expansion after running ./configure)
+ // assign but remove empty entries; this may happen if an expansion
+ // list ends in a semicolon (then we get an empty entry at the end),
+ // or if there are multiple semicolons after each other (this may
+ // happen if, for example, we have "Vector<double>; TRILINOS_VECTOR;"
+ // and if TRILINOS_VECTOR is an empty expansion after running
+ // ./configure)
expansion_lists[name]
- = delete_empty_entries (split_string_list (expansion, ';'));
+ = delete_empty_entries (split_string_list (expansion, ';'));
}
}
// produce all combinations of substitutions of the tokens given in the
// #substitutions list in #text and output it to std::cout
void substitute (const std::string &text,
- const std::list<std::pair<std::string, std::string> > &substitutions)
+ const std::list<std::pair<std::string, std::string> > &substitutions)
{
- // do things recursively: if the list of
- // substitutions has a single entry, then
- // process all of them. otherwise, process
- // the first in the list and call the
- // function recursively with the rest of
- // the substitutions
+ // do things recursively: if the list of substitutions has a single
+ // entry, then process all of them. otherwise, process the first in the
+ // list and call the function recursively with the rest of the
+ // substitutions
if (substitutions.size() > 1)
{
- // do the first substitution, then call
- // function recursively
+ // do the first substitution, then call function recursively
const std::string name = substitutions.front().first,
- pattern = substitutions.front().second;
+ pattern = substitutions.front().second;
const std::list<std::pair<std::string, std::string> >
- rest_of_substitutions (++substitutions.begin(),
- substitutions.end());
+ rest_of_substitutions (++substitutions.begin(),
+ substitutions.end());
for (std::list<std::string>::const_iterator
- expansion = expansion_lists[pattern].begin();
- expansion != expansion_lists[pattern].end();
- ++expansion)
- {
- std::string new_text
- = substitute_tokens (text, name, *expansion);
-
- substitute (new_text, rest_of_substitutions);
- }
+ expansion = expansion_lists[pattern].begin();
+ expansion != expansion_lists[pattern].end();
+ ++expansion)
+ {
+ std::string new_text
+ = substitute_tokens (text, name, *expansion);
+
+ substitute (new_text, rest_of_substitutions);
+ }
}
else if (substitutions.size() == 1)
{
- // do the substitutions
+ // do the substitutions
const std::string name = substitutions.front().first,
- pattern = substitutions.front().second;
+ pattern = substitutions.front().second;
for (std::list<std::string>::const_iterator
- expansion = expansion_lists[pattern].begin();
- expansion != expansion_lists[pattern].end();
- ++expansion)
- std::cout << substitute_tokens (text, name, *expansion)
- << std::endl;
+ expansion = expansion_lists[pattern].begin();
+ expansion != expansion_lists[pattern].end();
+ ++expansion)
+ std::cout << substitute_tokens (text, name, *expansion)
+ << std::endl;
}
else
{
std::cout << text
- << std::endl;
+ << std::endl;
}
}
// process the list of instantiations given in the form
-// --------------------
-// for (u,v:VECTORS; z:SCALARS) { f(u, z, const v &); }
-// --------------------
+// for (u,v:VECTORS; z:SCALARS) { f(u, z, const v &); }
void process_instantiations ()
{
std::string whole_file = read_whole_file (std::cin);
- // process entries of the form
- // for (X:Y; A:B) { INST }
+ // process entries of the form
+ // for (X:Y; A:B) { INST }
while (whole_file.size() != 0)
{
skip_space (whole_file);
if (whole_file.find ("for") != 0)
- {
- std::cerr << "Invalid instantiation list: missing 'for'" << std::endl;
- std::exit (1);
- }
+ {
+ std::cerr << "Invalid instantiation list: missing 'for'" << std::endl;
+ std::exit (1);
+ }
whole_file.erase (0, 3);
skip_space (whole_file);
if (whole_file.find ("(") != 0)
- {
- std::cerr << "Invalid instantiation list: missing '('" << std::endl;
- std::exit (1);
- }
+ {
+ std::cerr << "Invalid instantiation list: missing '('" << std::endl;
+ std::exit (1);
+ }
whole_file.erase (0, 1);
skip_space (whole_file);
const std::list<std::string>
- substitutions_list
- = split_string_list (get_substring_with_delim (whole_file,
- ")"),
- ';');
+ substitutions_list
+ = split_string_list (get_substring_with_delim (whole_file,
+ ")"),
+ ';');
if (whole_file.find (")") != 0)
- {
- std::cerr << "Invalid instantiation list: missing ')'" << std::endl;
- std::exit (1);
- }
+ {
+ std::cerr << "Invalid instantiation list: missing ')'" << std::endl;
+ std::exit (1);
+ }
whole_file.erase (0, 1);
skip_space (whole_file);
- // process the header
+ // process the header
std::list<std::pair<std::string, std::string> >
- substitutions;
+ substitutions;
for (std::list<std::string>::const_iterator
- s = substitutions_list.begin();
- s != substitutions_list.end(); ++s)
- {
- const std::list<std::string>
- names_and_type = split_string_list (*s, ':');
- if (names_and_type.size() != 2)
- {
- std::cerr << "Invalid instantiation header" << std::endl;
- std::exit (1);
- }
-
- const std::list<std::string>
- names = split_string_list (names_and_type.front(), ',');
-
- for (std::list<std::string>::const_iterator
- x = names.begin(); x != names.end(); ++x)
- substitutions.push_back (std::make_pair (*x,
- names_and_type.back()));
- }
-
- // now read the part in {...}
+ s = substitutions_list.begin();
+ s != substitutions_list.end(); ++s)
+ {
+ const std::list<std::string>
+ names_and_type = split_string_list (*s, ':');
+ if (names_and_type.size() != 2)
+ {
+ std::cerr << "Invalid instantiation header" << std::endl;
+ std::exit (1);
+ }
+
+ const std::list<std::string>
+ names = split_string_list (names_and_type.front(), ',');
+
+ for (std::list<std::string>::const_iterator
+ x = names.begin(); x != names.end(); ++x)
+ substitutions.push_back (std::make_pair (*x,
+ names_and_type.back()));
+ }
+
+ // now read the part in {...}
skip_space (whole_file);
if (whole_file.find ("{") != 0)
- {
- std::cerr << "Invalid substitution text" << std::endl;
- std::exit (1);
- }
+ {
+ std::cerr << "Invalid substitution text" << std::endl;
+ std::exit (1);
+ }
whole_file.erase (0, 1);
skip_space (whole_file);
const std::string text_to_substitute
- = get_substring_with_delim (whole_file, "}");
+ = get_substring_with_delim (whole_file, "}");
whole_file.erase (0,1);
skip_space (whole_file);
- // now produce the
- // substitutions. first replace
- // all occurrences of "\{" by
- // "{"
+ // now produce the substitutions. first replace all occurrences of
+ // "\{" by "{"
substitute (replace_all(replace_all(text_to_substitute, "\\{", "{"),
- "\\}", "}"),
- substitutions);
+ "\\}", "}"),
+ substitutions);
}
}
if (argc < 2)
{
std::cerr << "Usage: " << std::endl
- << " expand_instantiations class_list_files < in_file > out_file"
- << std::endl;
+ << " expand_instantiations class_list_files < in_file > out_file"
+ << std::endl;
std::exit (1);
}
#include <cstdlib>
#include <sys/stat.h>
- // base path for object files,
- // including trailing slash if
- // non-empty
+// base path for object files, including trailing slash if non-empty
std::string basepath;
- // list of include directories
+// list of include directories
std::vector<std::string> include_directories;
- // for each file that we ever visit,
- // store the set of other files it
- // includes directly
+// for each file that we ever visit, store the set of other files it
+// includes directly
std::map<std::string,std::set<std::string> > direct_includes;
- // A variable that stores whether
- // we want old-style or new-style format
+// A variable that stores whether we want old-style or new-style format
enum Format
- {
- old_style, new_style
- } format;
+{
+ old_style, new_style
+} format;
-bool file_exists(const std::string & file)
+bool file_exists(const std::string &file)
{
struct stat buf;
int error = stat (file.c_str(), &buf);
- return ((error == 0) &&
- ((buf.st_mode & S_IFMT) == S_IFREG));
+ return ((error == 0) &&
+ ((buf.st_mode & S_IFMT) == S_IFREG));
}
- // for the given file, fill a
- // respective entry in the "direct_includes"
- // map listing the names of those
- // files that are directly included
+// for the given file, fill a respective entry in the "direct_includes" map
+// listing the names of those files that are directly included
void determine_direct_includes (const std::string &file)
{
- // if this file has already been
- // treated, then leave it at this
+ // if this file has already been treated, then leave it at this
if (direct_includes.find (file) != direct_includes.end())
return;
- // otherwise, open the file and go
- // through it line by line to
- // search for other includes. we
- // will have to have the path to
- // the present file later, so get
- // it already here
+ // otherwise, open the file and go through it line by line to search for
+ // other includes. we will have to have the path to the present file
+ // later, so get it already here
std::string present_path;
if (file.find ('/') != std::string::npos)
present_path = std::string (file.begin(),
- file.begin()+file.rfind ('/')+1);
+ file.begin()+file.rfind ('/')+1);
std::ifstream in(file.c_str());
- // If the file does not exist, for
- // instance an ".inst" file which
- // will be generated by make later,
- // just return from this function.
- //
- // As a result, non-existing files
- // are expected to have no
- // dependencies.
+ // If the file does not exist, for instance an ".inst" file which will be
+ // generated by make later, just return from this function.
+ //
+ // As a result, non-existing files are expected to have no dependencies.
if (! ((bool)in))
return;
-
+
std::string line;
while (in)
{
- // get one line, eat whitespace
- // at the beginning and see
- // whether the first
- // non-whitespace is a #
- // character
+ // get one line, eat whitespace at the beginning and see whether the
+ // first non-whitespace is a # character
getline (in, line);
unsigned int pos=0;
for (; pos<line.length(); ++pos)
if ((line[pos] != ' ') && (line[pos] != '\t'))
break;
- // if no non-whitespace, or
- // something other than #: next
- // line
+ // if no non-whitespace, or something other than #: next line
if ((pos == line.length()) || (line[pos] != '#'))
continue;
- // ok, this is a preprocessor
- // line. eat pound sign and
- // again the next couple of
- // whitespaces
+ // ok, this is a preprocessor line. eat pound sign and again the next
+ // couple of whitespaces
++pos;
for (; pos<line.length(); ++pos)
if ((line[pos] != ' ') && (line[pos] != '\t'))
break;
- // and let's see whether the
- // following is the word
- // include
+ // and let's see whether the following is the word include
if ((line.length() < pos+7)
||
(! ((line[pos+0] == 'i') &&
(line[pos+6] == 'e'))))
continue;
- // ok, word found. advance pos
- // and eat more whitespace
+ // ok, word found. advance pos and eat more whitespace
pos += 7;
for (; pos<line.length(); ++pos)
if ((line[pos] != ' ') && (line[pos] != '\t'))
break;
- // check that the next char is
- // either '<' or '"'
+ // check that the next char is either '<' or '"'
if ((line[pos] != '"') && (line[pos] != '<'))
continue;
- // copy out name
+ // copy out name
std::string included_file;
for (unsigned int endpos=pos+1; endpos<line.length(); ++endpos)
if ((line[endpos]=='"') || (line[endpos] == '>'))
break;
}
if (included_file.length() == 0)
- {
- std::cerr << "Include file name empty in file <" << file << "> line: " << std::endl
- << line << std::endl;
- std::abort();
- }
-
-
- bool is_inst_file =
- included_file.size()>5
- && (included_file.rfind(".inst") == (included_file.size()-5));
-
- // .inst files are always relative to
- // the current path. We need a special
- // case, because they might not exist
- // at this point and the next block
- // checks the files for existence.
+ {
+ std::cerr << "Include file name empty in file <" << file << "> line: " << std::endl
+ << line << std::endl;
+ std::abort();
+ }
+
+
+ bool is_inst_file =
+ included_file.size()>5
+ && (included_file.rfind(".inst") == (included_file.size()-5));
+
+ // .inst files are always relative to the current path. We need a
+ // special case, because they might not exist at this point and the
+ // next block checks the files for existence.
if (is_inst_file)
- included_file = present_path+included_file;
-
+ included_file = present_path+included_file;
+
- // next try to locate the file in
- // absolute paths. For includes of the
- // form #include "...", we check the
- // current path first.
+ // next try to locate the file in absolute paths. For includes of the
+ // form #include "...", we check the current path first.
if (included_file[0] != '/' && !is_inst_file)
{
- bool is_relative_path = false;
+ bool is_relative_path = false;
if (line[pos] == '"' && file_exists(present_path+included_file))
- {
- included_file = present_path+included_file;
- is_relative_path = true;
- }
-
+ {
+ included_file = present_path+included_file;
+ is_relative_path = true;
+ }
+
if (is_relative_path == false)
- for (std::vector<std::string>::const_iterator
- include_dir=include_directories.begin();
+ for (std::vector<std::string>::const_iterator
+ include_dir=include_directories.begin();
include_dir!=include_directories.end(); ++include_dir)
- {
- if (file_exists((*include_dir+included_file)))
- {
- included_file = *include_dir+included_file;
- break;
- }
- }
+ {
+ if (file_exists((*include_dir+included_file)))
+ {
+ included_file = *include_dir+included_file;
+ break;
+ }
+ }
}
- // make sure the file exists
- // and that we can read from
- // it, otherwise just ignore
- // the line
+ // make sure the file exists and that we can read from it, otherwise
+ // just ignore the line
+
+ // If this is an ".inst" file, it will be generated by make later, so
+ // we better keep it on the list.
- // If this is an ".inst" file,
- // it will be generated by make
- // later, so we better keep it
- // on the list.
-
if (line[pos] != '"' || !is_inst_file)
- {
- if (!file_exists(included_file))
- continue;
- }
+ {
+ if (!file_exists(included_file))
+ continue;
+ }
- // ok, so we did find an
- // appropriate file. add it to
- // the correct list
+ // ok, so we did find an appropriate file. add it to the correct list
direct_includes[file].insert (included_file);
- // work on the include file
- // recursively. note that the
- // first line of this function
- // saves us from infinite
- // recursions in case of
- // include loops
+ // work on the include file recursively. note that the first line of
+ // this function saves us from infinite recursions in case of include
+ // loops
determine_direct_includes (included_file);
}
}
- // return the set of all included
- // files, directly or indirectly, for
- // the given file. for this purpose,
- // we consider the direct_includes
- // variable to be a representation of
- // a directed graph: given a file (a
- // node in the graph), the elements
- // of the include-set for this file
- // are outgoing edges from this
- // node. to get at all includes,
- // direct and indirect, we keep a
- // list starting with the direct
- // includes, the collect all direct
- // includes of the files in the list,
- // then their include files, etc. We
- // thus march in fronts through the
- // graph.
- //
- // one of the complications we have
- // to keep track of is that the graph
- // may be cyclic (i.e. header files
- // include each other mutually -- in
- // the real program, one of the
- // includes will be guarded by
- // preprocessor #ifdefs, but we don't
- // see them here), so we have to make
- // sure we strip elements from the
- // present front that we have already
- // visited before
- //
- // this function could presumably be
- // made more efficient in the
- // following way: when we have more
- // than one file for which we want to
- // compute dependencies, we presently
- // walk through the graph for each of
- // them. however, they will likely
- // have one or more includes in
- // common, so they will also have
- // parts of the dependency graph in
- // common. if we could precompute the
- // dependency graph for include files
- // in advance, we wouldn't have to
- // walk through _all_ the graph for
- // each file we consider, but could
- // just draw in blocks. the problem
- // with that is that to make this
- // efficient we cannot just compute
- // the whole set of dependencies for
- // _each_ file, but we have to do
- // this on the fly and to avoid again
- // problems with the cyclic nature we
- // have to keep track where we are
- // presently coming from. that's way
- // too complicated for now and I
- // leave it to times when dependency
- // generation becomes again a
- // noticable time hit
- //
- // one of the ideas to solve this
- // problem would be to start at
- // terminal nodes of the graph
- // (i.e. nodes that have no outgoing
- // edges) and fold these nodes into
- // nodes that have only outgoing
- // edges to terminal nodes. store the
- // dependencies of these
- // next-to-terminal nodes and remove
- // the terminal ones. then start over
- // again with the so generated
- // graph. if we consider the files
- // for which we want to compute
- // dependency information as top
- // level nodes (they will _only_ have
- // outgoing nodes), we could
- // presumable roll up the entire
- // graph from the bottom (terminal
- // nodes) and fold it one layer at a
- // time
- //
- // in any case, there is presently no
- // need for this since the actions of
- // this function are presently not
- // really time critical: parsing the
- // files in the function above is a
- // much bigger time-hit.
+// return the set of all included files, directly or indirectly, for the
+// given file. for this purpose, we consider the direct_includes variable
+// to be a representation of a directed graph: given a file (a node in the
+// graph), the elements of the include-set for this file are outgoing edges
+// from this node. to get at all includes, direct and indirect, we keep a
+// list starting with the direct includes, the collect all direct includes
+// of the files in the list, then their include files, etc. We thus march
+// in fronts through the graph.
+//
+// one of the complications we have to keep track of is that the graph may
+// be cyclic (i.e. header files include each other mutually -- in the real
+// program, one of the includes will be guarded by preprocessor #ifdefs,
+// but we don't see them here), so we have to make sure we strip elements
+// from the present front that we have already visited before
+//
+// this function could presumably be made more efficient in the following
+// way: when we have more than one file for which we want to compute
+// dependencies, we presently walk through the graph for each of them.
+// however, they will likely have one or more includes in common, so they
+// will also have parts of the dependency graph in common. if we could
+// precompute the dependency graph for include files in advance, we
+// wouldn't have to walk through _all_ the graph for each file we consider,
+// but could just draw in blocks. the problem with that is that to make
+// this efficient we cannot just compute the whole set of dependencies for
+// _each_ file, but we have to do this on the fly and to avoid again
+// problems with the cyclic nature we have to keep track where we are
+// presently coming from. that's way too complicated for now and I leave it
+// to times when dependency generation becomes again a noticable time hit
+//
+// one of the ideas to solve this problem would be to start at terminal
+// nodes of the graph (i.e. nodes that have no outgoing edges) and fold
+// these nodes into nodes that have only outgoing edges to terminal nodes.
+// store the dependencies of these next-to-terminal nodes and remove the
+// terminal ones. then start over again with the so generated graph. if we
+// consider the files for which we want to compute dependency information
+// as top level nodes (they will _only_ have outgoing nodes), we could
+// presumable roll up the entire graph from the bottom (terminal nodes) and
+// fold it one layer at a time
+//
+// in any case, there is presently no need for this since the actions of
+// this function are presently not really time critical: parsing the files
+// in the function above is a much bigger time-hit.
std::set<std::string>
get_all_includes (const std::string &name)
{
- // start with direct includes
+ // start with direct includes
std::set<std::string> all_includes = direct_includes[name];
std::set<std::string> next_level_includes = all_includes;
while (true)
{
- // traverse all next level
- // includes and get their
- // direct include files. the
- // set makes sure that
- // duplicates are removed
+ // traverse all next level includes and get their direct include
+ // files. the set makes sure that duplicates are removed
std::set<std::string> second_next;
for (std::set<std::string>::const_iterator
- next=next_level_includes.begin();
+ next=next_level_includes.begin();
next!=next_level_includes.end(); ++next)
second_next.insert (direct_includes[*next].begin(),
direct_includes[*next].end());
- // for each of them, if it
- // hasn't been treated then add
- // it to the files of the next
- // level and later add it to
- // the all_includes
+ // for each of them, if it hasn't been treated then add it to the
+ // files of the next level and later add it to the all_includes
next_level_includes.clear ();
for (std::set<std::string>::const_iterator f=second_next.begin();
f!=second_next.end(); ++f)
if (all_includes.find(*f) == all_includes.end())
next_level_includes.insert (*f);
- // if no new includes found no
- // more, then quit
+ // if no new includes found no more, then quit
if (next_level_includes.size() == 0)
return all_includes;
- // otherwise, copy over and
- // start over on the next level
- // of the tree
+ // otherwise, copy over and start over on the next level of the tree
all_includes.insert (next_level_includes.begin(),
next_level_includes.end());
}
{
std::vector<std::string> filenames;
- // parse all arguments (except the
- // name of the executable itself)
+ // parse all arguments (except the name of the executable itself)
for (unsigned int c=1; c<static_cast<unsigned int>(argc); ++c)
{
const std::string arg = argv[c];
- // if string starts with -I,
- // take this as an include path
+ // if string starts with -I, take this as an include path
if ((arg.length()>2) && (arg[0]=='-') && (arg[1]=='I'))
{
std::string dir (arg.begin()+2, arg.end());
- // append a slash if not
- // already there
+ // append a slash if not already there
if (dir[dir.length()-1] != '/')
dir += '/';
- // drop initial ./ if this
- // is there
+ // drop initial ./ if this is there
if ((dir[0]=='.') && (dir[1]=='/'))
dir = std::string(dir.begin()+2, dir.end());
include_directories.push_back (dir);
}
- // if string starts with -B,
- // then this is the base name
- // for object files
+ // if string starts with -B, then this is the base name for object
+ // files
else if ((arg.length()>2) && (arg[0]=='-') && (arg[1]=='B'))
{
basepath = std::string(arg.begin()+2, arg.end());
if (basepath[basepath.size()-1] != '/')
basepath += '/';
}
- // if string is -n,
- // then use new-style format
+ // if string is -n, then use new-style format
else if ((arg.length()==2) && (arg[0]=='-') && (arg[1]=='n'))
- format = new_style;
+ format = new_style;
- // otherwise assume that this
- // is one of the files for
- // input
+ // otherwise assume that this is one of the files for input
else
{
assert (arg.size()>=1);
}
}
- // next iterate through all files
- // and figure out which other files
- // they include
+ // next iterate through all files and figure out which other files they
+ // include
for (std::vector<std::string>::const_iterator file=filenames.begin();
file != filenames.end(); ++file)
determine_direct_includes (*file);
- // now we have all files that are
- // directly or indirectly included
- // into the files given on the
- // command lines. for each of them,
- // we have recorded which files
- // they include themselves. for
- // each file on the command line,
- // we can thus form a complete
- // include tree.
+ // now we have all files that are directly or indirectly included into
+ // the files given on the command lines. for each of them, we have
+ // recorded which files they include themselves. for each file on the
+ // command line, we can thus form a complete include tree.
for (std::vector<std::string>::const_iterator file=filenames.begin();
file != filenames.end(); ++file)
{
- // get base of filename by
- // chipping away .cc extension
- // as well as path
+ // get base of filename by chipping away .cc extension as well as
+ // path
std::string basename;
if (file->find (".cc") != std::string::npos)
basename = std::string (file->begin(),
basename = std::string (basename.begin()+basename.rfind("/")+1,
basename.end());
- // get all direct and indirect
- // includes for this file...
+ // get all direct and indirect includes for this file...
const std::set<std::string> includes = get_all_includes (*file);
- // ...write the rule for the .o
- // file...
+ // ...write the rule for the .o file...
if (format == old_style)
- std::cout << basepath << basename << ".o: \\"
- << std::endl
- << "\t\t" << *file;
+ std::cout << basepath << basename << ".o: \\"
+ << std::endl
+ << "\t\t" << *file;
else
- std::cout << basepath << "optimized/" << basename << ".o: \\"
- << std::endl
- << "\t\t" << *file;
+ std::cout << basepath << "optimized/" << basename << ".o: \\"
+ << std::endl
+ << "\t\t" << *file;
for (std::set<std::string>::const_iterator i=includes.begin();
i!=includes.end(); ++i)
std::cout << "\\\n\t\t" << *i;
std::cout << std::endl;
- // ...and a similar rule for
- // the .o file in debug mode
+ // ...and a similar rule for the .o file in debug mode
if (format == old_style)
- std::cout << basepath << basename << ".g.o: \\"
- << std::endl
- << "\t\t" << *file;
+ std::cout << basepath << basename << ".g.o: \\"
+ << std::endl
+ << "\t\t" << *file;
else
- std::cout << basepath << "debug/" << basename << ".o: \\"
- << std::endl
- << "\t\t" << *file;
+ std::cout << basepath << "debug/" << basename << ".o: \\"
+ << std::endl
+ << "\t\t" << *file;
for (std::set<std::string>::const_iterator i=includes.begin();
i!=includes.end(); ++i)
std::cout << "\\\n\t\t" << *i;