Skip to content

Commit 7d27c28

Browse files
author
mike
committed
Fixed failing tests due to implicit project languages (internal list empty)
1 parent 5a0eda7 commit 7d27c28

File tree

1 file changed

+68
-0
lines changed

1 file changed

+68
-0
lines changed

src/cmake_generator.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@
1414
namespace cmkr {
1515
namespace gen {
1616

17+
using LanguageExtensions = std::vector<std::string>;
18+
static tsl::ordered_map<std::string, LanguageExtensions> known_languages = {
19+
{"C", {".c", ".m"}},
20+
{"CXX", {".C", ".M", ".c++", ".cc", ".cpp", ".cxx", ".mm", ".CPP"}},
21+
{"CSharp", {".cs"}},
22+
};
23+
1724
static std::string format(const char *format, tsl::ordered_map<std::string, std::string> variables) {
1825
std::string s = format;
1926
for (const auto &itr : variables) {
@@ -510,6 +517,13 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
510517
auto is_root_project = parent_project == nullptr;
511518

512519
parser::Project project(parent_project, path, false);
520+
521+
for (auto const &lang : project.project_languages) {
522+
if (known_languages.find(lang) == known_languages.end()) {
523+
throw std::runtime_error("Unknown language specified: " + lang);
524+
}
525+
}
526+
513527
Generator gen(project);
514528

515529
// Helper lambdas for more convenient CMake generation
@@ -946,6 +960,60 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
946960
auto source_key = condition.empty() ? "sources" : (condition + ".sources");
947961
throw std::runtime_error(target.name + " " + source_key + " wildcard found 0 files");
948962
}
963+
964+
// For non-interface targets, ensure there is a source file linked for the project's languages.
965+
if (target.type != parser::target_interface) {
966+
// The implicit default is ["C", "CXX"], so make sure this list isn't
967+
// empty or projects without languages explicitly defined will error.
968+
auto proj_languages = project.project_languages;
969+
if (proj_languages.empty())
970+
proj_languages = {"C", "CXX"};
971+
972+
// All acceptable extensions based off our given languages.
973+
tsl::ordered_set<std::string> proj_extensions = [&]() {
974+
tsl::ordered_set<std::string> exts;
975+
for (auto it = known_languages.begin(); it != known_languages.end(); ++it) {
976+
if (std::find(proj_languages.begin(), proj_languages.end(), it->first) == proj_languages.end()) {
977+
continue;
978+
}
979+
// Add all extensions of this language into the list
980+
for (auto const &ext : it->second) {
981+
exts.insert(ext);
982+
}
983+
}
984+
return exts;
985+
}();
986+
987+
bool has_hit_def = false;
988+
for (auto &source : sources) {
989+
fs::path path = source;
990+
if (!path.has_extension()) {
991+
continue;
992+
}
993+
994+
auto ext = path.extension().string();
995+
996+
// Only test lower-case variant of the extension
997+
static auto asciitolower = [](char in) -> char {
998+
if (in <= 'Z' && in >= 'A')
999+
return in - ('Z' - 'z');
1000+
return in;
1001+
};
1002+
1003+
std::transform(ext.begin(), ext.end(), ext.begin(), asciitolower);
1004+
1005+
// Check if we've hit an acceptable project extensions
1006+
if (std::find(proj_extensions.begin(), proj_extensions.end(), ext) != proj_extensions.end()) {
1007+
has_hit_def = true;
1008+
break;
1009+
}
1010+
}
1011+
1012+
if (!has_hit_def) {
1013+
throw std::runtime_error("There were no source files linked within the target " + target.name);
1014+
}
1015+
}
1016+
9491017
if (sources_with_set) {
9501018
// This is a sanity check to make sure the unconditional sources are first
9511019
if (!condition.empty()) {

0 commit comments

Comments
 (0)