|
Go to the documentation of this file.
49 const std::size_t pos = file_name.find_last_of( "/\\");
50 if (pos == std::string::npos)
52 return file_name.substr(0,pos);
56std::string filename( const std::string& file_name)
58 const std::size_t pos = file_name.find_last_of( "/\\");
59 return file_name.substr(pos+1);
63std::vector<std::string> filenames( const std::vector<std::string>& file_names)
65 std::vector<std::string> result(file_names.size());
66 std::transform(file_names.begin(), file_names.end(), result.begin(), filename);
73 if (FILE *file = std::fopen(name.c_str(), "r")) {
82 return s.insert(element).second;
85 std::set<std::string> s;
90 return s.insert( filename(element)).second;
93 std::set<std::string> s;
97template < typename Predicate = decltype(Is_not_duplicate())>
99 const std::vector<std::string>& vec,
102 std::vector<std::string> unique_vector;
104 std::copy_if(vec.begin(), vec.end(), std::back_inserter(unique_vector),
105 [&pred] ( const std::string& f) { return pred(f); });
107 return unique_vector;
113 const std::string no_ext(str.substr(0, str.find_last_of( '.')));
114 return no_ext + '.' + ext;
118bool starts_with( const std::string& str, const std::string& prefix)
120 return str.compare(0, prefix.size(), prefix) == 0;
126 std::cout << "Usage: " << program_name << " [options] filename\n"
129 " -I<path> Search for header files in <path>\n"
130 " -MF <file> Write dependencies to <file>\n"
131 " -MG Add missing headers to dependency list\n"
132 " -MI Ignore errors of non-existing header(s)\n"
133 " -MM Ignore system headers enclosed by < and >\n"
134 " -MMD <file> Equivalent to -MM -MF <file>\n"
135 " -MP Add phony target for each dependency other than main file\n"
136 " -MT <target> Set name of the target\n"
137 " -o <file> Equivalent to -MF <file>\n"
138 " --help,-h Print this help message and exit\n"
140 "Unsupported options:\n"
141 " -M Add system headers to dependency list\n"
142 " -MD <file> Equivalent to -M -MF <file>\n"
143 " -MQ <target> Same as -MT <traget> but quote characters special to make\n";
148 const std::string& target_name,
149 const std::vector<std::string>& dependencies)
151 ostr << target_name << ':';
153 for ( const auto& d: dependencies)
162 for ( const auto& d: dependencies)
163 ostr << '\n' << d << ":\n";
167template < class OutputIterator>
170 if (!s || !*s) return;
173 while (*s && std::isspace(*s)) s++;
176 if (*s && *s == '#') s++;
180 while (*s && std::isspace(*s)) s++;
183 if (*s && std::strncmp(s, "include", 7) == 0) s += 7;
187 if (*s) s = std::strchr(s, '"');
191 const char* pos1 = s;
193 if (*s) s = std::strchr(s, '"');
196 const char* pos2 = s;
198 const std::ptrdiff_t len = pos2 - pos1;
201 *it = std::string(pos1, len);
209 std::ifstream istr(file_name);
210 std::vector<std::string> includes;
213 while (std::getline(istr, line)) {
221std::vector<std::string> prepend( const std::string& str,
222 const std::vector<std::string>& strings)
224 std::vector<std::string> result;
225 result.reserve(strings.size());
227 for ( const auto& s: strings) {
228 result.push_back(str + s);
236 const std::vector<std::string>& strings,
237 const std::string& str)
239 auto result = strings;
240 result.insert(result.begin(), str);
246template < class Predicate>
248 const std::vector<std::string>& vec,
249 const Predicate& pred)
251 std::vector<std::string> match;
253 std::copy_if(vec.begin(), vec.end(),
254 std::back_inserter(match), pred);
260template < class Predicate>
262 const std::string& dir,
263 const std::vector<std::string>& files,
264 const Predicate& pred)
266 const std::string dirname(dir.empty() || dir == "." ? "" : dir + '/');
267 const auto files_in_dir = prepend(dirname, files);
269 return filter(files_in_dir, pred);
274 const std::vector<std::string>& v1,
275 const std::vector<std::string>& v2)
280 std::sort(tv1.begin(), tv1.end());
281 std::sort(tv2.begin(), tv2.end());
283 std::vector<std::string> diff;
285 std::set_difference(tv1.begin(), tv1.end(),
286 tv2.begin(), tv2.end(),
287 std::back_inserter(diff));
294std::string concat( const std::vector<std::string>& strings, const T& separator)
298 for ( const auto& s: strings)
299 result += s + separator;
307 std::vector<std::string>& result,
310 if (max_depth <= 0) {
311 throw std::runtime_error(
312 "Error: #include nested too deeply (maximum depth: "
313 + std::to_string(max_depth) + "): " + config. file_name);
318 const auto includes =
322 std::vector<std::string> existing;
325 existing.insert(existing.end(), existing_in_path.cbegin(), existing_in_path.cend());
326 result.insert(result.end(), existing_in_path.cbegin(), existing_in_path.cend());
330 for ( const auto& f: existing) {
337 const auto non_existing =
341 !non_existing.empty()) {
342 throw std::runtime_error(
343 "Error: cannot find the following header file(s): " +
344 concat(non_existing, ' '));
348 result.insert(result.end(), non_existing.cbegin(), non_existing.cend());
356 std::vector<std::string> result;
364int main( int argc, char* argv[])
369 std::cerr << "Error: no input file\n";
370 print_usage(argv[0]);
376 for ( int i = 1; i < argc; i++) {
377 const std::string arg(argv[i]);
378 if (starts_with(arg, "-D")) {
381 if (starts_with(arg, "-I") && arg.length() > 2) {
382 config. search_paths.push_back(arg.substr(std::strlen( "-I")));
398 std::cerr << "Warning: ignoring unsupported option " << arg << '\n';
401 if (arg == "-MD" || arg == "-MQ") {
402 std::cerr << "Warning: ignoring unsupported option " << arg << '\n';
410 if (arg == "-MT" && i + 1 < argc) {
414 if (arg == "-MF" || arg == "-MMD" || arg == "-o") {
417 const std::string of(argv[i + 1]);
418 if (!starts_with(of, "-I") && !starts_with(of, "-M") &&
419 !starts_with(of, "-D") && of != "-o") {
423 std::cerr << "Error: " << arg << " expects a file name argument\n";
429 if (arg == "--help" || arg == "-h") {
430 print_usage(argv[0]);
437 std::cerr << "Error: file does not exist: " << config. file_name << '\n';
443 std::cerr << "Error: unknown option: " << arg << '\n';
444 print_usage(argv[0]);
449 std::cerr << "Error: no input file\n";
455 std::ostream* ostr = &std::cout;
459 std::cerr << "Error: cannot write to file " << config. output_file << '\n';
472 const auto dependencies
474 search_includes(config),
479 replace_extension(filename(config. file_name), "o");
484 insert_at_front(dependencies, config. file_name));
487 print_empty_phony_targets(*ostr, dependencies);
489 } catch ( const std::exception& e) {
490 std::cerr << e.what() << '\n';
int main(int argc, char *argv[])
std::string replace_extension(const std::string &str, const std::string &ext) replace file name extension by ‘ext’
bool file_exists(const std::string &name) checks if given file exists
void print_usage(const std::string &program_name) print usage message
std::vector< std::string > get_included_files(const std::string &file_name) extract include statements from file (ignoring system headers)
void print_dependencies(std::ostream &ostr, const std::string &target_name, const std::vector< std::string > &dependencies) print dependency list
std::vector< std::string > prepend(const std::string &str, const std::vector< std::string > &strings) prepend ‘str’ to all strings
std::vector< std::string > complement(const std::vector< std::string > &v1, const std::vector< std::string > &v2) returns all elements of ‘v1’, which are not ‘v2’
std::vector< std::string > filenames(const std::vector< std::string > &file_names) returns file names w/o directory
void get_filename_from_include(const char *s, OutputIterator it) extracts file name from include "..." statement
std::vector< std::string > insert_at_front(const std::vector< std::string > &strings, const std::string &str) insert ‘str’ at the beginning of vector
std::vector< std::string > filter_files(const std::string &dir, const std::vector< std::string > &files, const Predicate &pred) returns files in directory ‘dir’ for which pred(f) == true
std::string concat(const std::vector< std::string > &strings, const T &separator) concatenate strings with separator
std::vector< std::string > filter(const std::vector< std::string > &vec, const Predicate &pred) returns elements of ‘vec’ for which pred(f) == true
std::string filename(const std::string &file_name) returns file name w/o directory
std::string directory(const std::string &file_name) returns directory from file name
bool starts_with(const std::string &str, const std::string &prefix) tests whether ‘str’ starts with ‘prefix’
void search_includes(const Config &config, std::vector< std::string > &result, int max_depth)
std::vector< std::string > delete_duplicates(const std::vector< std::string > &vec, Predicate pred=Is_not_duplicate()) deletes duplicate elements from a vector (preseves order)
void print_empty_phony_targets(std::ostream &ostr, const std::vector< std::string > &dependencies) print empty phony targets for each dependency
std::complex< double > f(double tau) noexcept
bool ignore_non_existing -MI
bool include_non_existing -MG
bool add_empty_phony_targets -MP
std::vector< std::string > search_paths
bool operator()(const std::string &element)
std::set< std::string > s
bool operator()(const std::string &element)
std::set< std::string > s
|