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)
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: "
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";
376 for (
int i = 1; i < argc; i++) {
377 const std::string
arg(argv[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]);
423 std::cerr <<
"Error: " <<
arg <<
" expects a file name argument\n";
429 if (
arg ==
"--help" ||
arg ==
"-h") {
437 std::cerr <<
"Error: file does not exist: " << config.
file_name <<
'\n';
443 std::cerr <<
"Error: unknown option: " <<
arg <<
'\n';
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
489 }
catch (
const std::exception&
e) {
490 std::cerr <<
e.what() <<
'\n';
int main(int argc, char *argv[])
void sort(double &x, double &y)
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
std::vector< std::string > search_includes(const Config &config, int max_depth=100)
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
constexpr T arg(const Complex< T > &z) noexcept
std::string to_string(char a)
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