Skip to content

Commit 58a5a93

Browse files
committed
Add a bunch of missing languages and extensions and refactor
1 parent 7d27c28 commit 58a5a93

File tree

3 files changed

+68
-53
lines changed

3 files changed

+68
-53
lines changed

include/project_parser.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ struct Project {
180180
std::string project_version;
181181
std::string project_description;
182182
std::vector<std::string> project_languages;
183+
bool project_allow_unknown_languages = false;
183184
MsvcRuntimeType project_msvc_runtime = msvc_last;
184185
Condition<std::string> cmake_before;
185186
Condition<std::string> cmake_after;

src/cmake_generator.cpp

Lines changed: 66 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,33 @@
1414
namespace cmkr {
1515
namespace gen {
1616

17-
using LanguageExtensions = std::vector<std::string>;
18-
static tsl::ordered_map<std::string, LanguageExtensions> known_languages = {
17+
/*
18+
Location: CMake/share/cmake-3.26/Modules
19+
rg "set\(CMAKE_(.+)_SOURCE_FILE_EXTENSIONS"
20+
21+
Links:
22+
- https://gitlab.kitware.com/cmake/cmake/-/issues/24340
23+
- https://cmake.org/cmake/help/latest/command/enable_language.html
24+
*/
25+
26+
static tsl::ordered_map<std::string, std::vector<std::string>> known_languages = {
27+
{"ASM", {".s", ".S", ".asm", ".abs", ".msa", ".s90", ".s43", ".s85", ".s51"}},
28+
{"ASM-ATT", {".s", ".asm"}},
29+
{"ASM_MARMASM", {".asm"}},
30+
{"ASM_MASM", {".asm"}},
31+
{"ASM_NASM", {".nasm", ".asm"}},
1932
{"C", {".c", ".m"}},
20-
{"CXX", {".C", ".M", ".c++", ".cc", ".cpp", ".cxx", ".mm", ".CPP"}},
2133
{"CSharp", {".cs"}},
34+
{"CUDA", {".cu"}},
35+
{"CXX", {".C", ".M", ".c++", ".cc", ".cpp", ".cxx", ".m", ".mm", ".mpp", ".CPP", ".ixx", ".cppm"}},
36+
{"Fortran", {".f", ".F", ".fpp", ".FPP", ".f77", ".F77", ".f90", ".F90", ".for", ".For", ".FOR", ".f95", ".F95", ".cuf", ".CUF"}},
37+
{"HIP", {".hip"}},
38+
{"ISPC", {".ispc"}},
39+
{"Java", {".java"}},
40+
{"OBJC", {".m"}},
41+
{"OBJCXX", {".M", ".m", ".mm"}},
42+
{"RC", {".rc", ".RC"}},
43+
{"Swift", {".swift"}},
2244
};
2345

2446
static std::string format(const char *format, tsl::ordered_map<std::string, std::string> variables) {
@@ -520,7 +542,11 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
520542

521543
for (auto const &lang : project.project_languages) {
522544
if (known_languages.find(lang) == known_languages.end()) {
523-
throw std::runtime_error("Unknown language specified: " + lang);
545+
if (project.project_allow_unknown_languages) {
546+
printf("Unknown language '%s' specified\n", lang.c_str());
547+
} else {
548+
throw std::runtime_error("Unknown language '" + lang + "' specified");
549+
}
524550
}
525551
}
526552

@@ -851,6 +877,31 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
851877
gen.conditional_cmake(subdir.cmake_after);
852878
}
853879

880+
// The implicit default is ["C", "CXX"], so make sure this list isn't
881+
// empty or projects without languages explicitly defined will error.
882+
auto project_languages = project.project_languages;
883+
if (project_languages.empty())
884+
project_languages = {"C", "CXX"};
885+
886+
// All acceptable extensions based off our given languages.
887+
tsl::ordered_set<std::string> project_extensions;
888+
for (const auto &language : project_languages) {
889+
auto itr = known_languages.find(language);
890+
if (itr != known_languages.end()) {
891+
project_extensions.insert(itr->second.begin(), itr->second.end());
892+
}
893+
}
894+
895+
auto contains_language_source = [&project_extensions](const std::vector<std::string>& sources) {
896+
for (const auto &source : sources) {
897+
auto extension = fs::path(source).extension().string();
898+
if (project_extensions.count(extension) > 0) {
899+
return true;
900+
}
901+
}
902+
return false;
903+
};
904+
854905
if (!project.targets.empty()) {
855906
auto project_root = project.root();
856907
for (size_t i = 0; i < project.targets.size(); i++) {
@@ -961,57 +1012,19 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
9611012
throw std::runtime_error(target.name + " " + source_key + " wildcard found 0 files");
9621013
}
9631014

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) {
1015+
// Make sure there are source files for the languages used by the project
1016+
switch (target.type) {
1017+
case parser::target_executable:
1018+
case parser::target_library:
1019+
case parser::target_shared:
1020+
case parser::target_static:
1021+
case parser::target_object:
1022+
if (!contains_language_source(sources)) {
10131023
throw std::runtime_error("There were no source files linked within the target " + target.name);
10141024
}
1025+
break;
1026+
default:
1027+
break;
10151028
}
10161029

10171030
if (sources_with_set) {

src/project_parser.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
288288
project.optional("version", project_version);
289289
project.optional("description", project_description);
290290
project.optional("languages", project_languages);
291+
project.optional("allow-unknown-languages", project_allow_unknown_languages);
291292
project.optional("cmake-before", cmake_before);
292293
project.optional("cmake-after", cmake_after);
293294
project.optional("include-before", include_before);

0 commit comments

Comments
 (0)