diff --git a/src/FilenameList.cc b/src/FilenameList.cc index 09f4232..6dce1c9 100644 --- a/src/FilenameList.cc +++ b/src/FilenameList.cc @@ -41,7 +41,7 @@ FilenameList::FilenameList(Tokenizer& tokenizer, Type type) { force_build = (type == Type::BUILD); while (true) { - auto word = FilenameWord{tokenizer}; + auto word = FilenameWord{tokenizer, force_build}; if (!word.empty()) { words.emplace_back(word); } diff --git a/src/FilenameWord.cc b/src/FilenameWord.cc index e16e7c1..4330aff 100644 --- a/src/FilenameWord.cc +++ b/src/FilenameWord.cc @@ -35,7 +35,7 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FilenameVariable.h" -FilenameWord::FilenameWord(Tokenizer& tokenizer) { +FilenameWord::FilenameWord(Tokenizer& tokenizer, bool force_build): force_build{force_build} { std::string string; auto first = true; @@ -97,6 +97,7 @@ FilenameWord::FilenameWord(Tokenizer& tokenizer) { } void FilenameWord::resolve(const ResolveContext& context) { + auto contains_filename_variable = false; for (auto& element : elements) { if (std::holds_alternative(element)) { auto& variable_reference = std::get(element); @@ -104,51 +105,67 @@ void FilenameWord::resolve(const ResolveContext& context) { if (variable_reference.is_text_variable()) { element = variable_reference.variable->string(); } + else { + contains_filename_variable = true; + } } } + if (!contains_filename_variable) { + auto name = std::string(); + for (const auto& element: elements) { + name += std::get(element); + } + filename = Filename{force_build ? Filename::Type::BUILD : Filename::Type::UNKNOWN, name}; + filename->resolve(context); + } } void FilenameWord::collect_filenames(std::vector& filenames) const { - std::string prefix; - std::string postfix; - auto current_string = &prefix; - const FilenameVariable* filename_variable{}; - - for (auto& element: elements) { - if (std::holds_alternative(element)) { - *current_string += std::get(element); - } - else { - auto variable = std::get(element); - if (variable.is_filename_variable()) { - if (filename_variable) { - throw Exception("multiple filename variables in filename not allowed"); + if (filename) { + filenames.emplace_back(*filename); + } + else { + std::string prefix; + std::string postfix; + auto current_string = &prefix; + const FilenameVariable* filename_variable{}; + + for (auto& element : elements) { + if (std::holds_alternative(element)) { + *current_string += std::get(element); + } + else { + auto variable = std::get(element); + if (variable.is_filename_variable()) { + if (filename_variable) { + throw Exception("multiple filename variables in filename not allowed"); + } + else { + filename_variable = variable.variable->as_filename(); + current_string = &postfix; + } } else { - filename_variable = variable.variable->as_filename(); - current_string = &postfix; + *current_string += variable.variable->string(); } } - else { - *current_string += variable.variable->string(); - } } - } - if (filename_variable) { - if (prefix.empty() && postfix.empty()) { - filename_variable->collect_filenames(filenames); + if (filename_variable) { + if (prefix.empty() && postfix.empty()) { + filename_variable->collect_filenames(filenames); + } + else { + std::vector inner_filenames; + filename_variable->collect_filenames(inner_filenames); + for (auto& filename : inner_filenames) { + filename.name = prefix + filename.name + postfix; + } + filenames.insert(filenames.end(), inner_filenames.begin(), inner_filenames.end()); + } } else { - std::vector inner_filenames; - filename_variable->collect_filenames(inner_filenames); - for (auto& filename : inner_filenames) { - filename.name = prefix + filename.name + postfix; - } - filenames.insert(filenames.end(), inner_filenames.begin(), inner_filenames.end()); + filenames.emplace_back(prefix); } } - else { - filenames.emplace_back(prefix); - } } diff --git a/src/FilenameWord.h b/src/FilenameWord.h index 22c7d1d..4660a00 100644 --- a/src/FilenameWord.h +++ b/src/FilenameWord.h @@ -40,7 +40,7 @@ class FilenameList; class FilenameWord { public: - explicit FilenameWord(Tokenizer& tokenizer); + explicit FilenameWord(Tokenizer& tokenizer, bool force_build = false); explicit FilenameWord(std::string word): elements{std::move(word)} {} [[nodiscard]] bool empty() const {return elements.empty();} @@ -50,6 +50,8 @@ class FilenameWord { private: std::vector> elements; + std::optional filename; + bool force_build{false}; }; #endif // EXPLICITFILENAME_H diff --git a/src/Text.cc b/src/Text.cc index 9a51a9b..df5128b 100644 --- a/src/Text.cc +++ b/src/Text.cc @@ -66,8 +66,8 @@ void Text::resolve(const ResolveContext& context) { std::string Text::string() const { auto result = std::string{}; - for (auto& element : words) { - result += element.string(); + for (auto& word : words) { + result += word.string(); } return result; diff --git a/tests/explicit-filename.test b/tests/explicit-filename.test new file mode 100644 index 0000000..2d5cd6f --- /dev/null +++ b/tests/explicit-filename.test @@ -0,0 +1,27 @@ +arguments .. +file input <> +input +end-of-inline-data +file build.fninja <> +rule a + command = {{input}} $in $out + flags = --verbose + +build output: a input +end-of-inline-data +file build/build.ninja {} <> +# This file is automatically created by fast-ninja from ../build.fninja +# Do not edit. + +rule a + command = ../input $in $out + flags = --verbose + +rule fast-ninja + command = fast-ninja .. + generator = 1 + +build output : a ../input + +build build.ninja : fast-ninja ../build.fninja +end-of-inline-data