Skip to content

Commit fc674b4

Browse files
authored
Merge pull request #195 from build-cpp/conditional-languages
Add support for conditional [project].languages
2 parents fb4931d + 433dbb0 commit fc674b4

9 files changed

Lines changed: 129 additions & 36 deletions

File tree

docs/examples/objective-c.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
# Automatically generated from tests/objective-c/cmake.toml - DO NOT EDIT
3+
layout: default
4+
title: Objective-C
5+
permalink: /examples/objective-c
6+
parent: Examples
7+
nav_order: 11
8+
---
9+
10+
# Objective-C
11+
12+
Add Objective-C sources on Apple platforms:
13+
14+
```toml
15+
[project]
16+
name = "objective-c"
17+
description = "Objective-C"
18+
languages = ["C"]
19+
apple.languages = ["OBJC"]
20+
21+
[target.hello]
22+
type = "executable"
23+
sources = ["src/main.c"]
24+
apple.sources = ["src/apple.m"]
25+
apple.link-libraries = ["$<LINK_LIBRARY:FRAMEWORK,Foundation>"]
26+
```
27+
28+
29+
30+
<sup><sub>This page was automatically generated from [tests/objective-c/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/objective-c/cmake.toml).</sub></sup>

include/project_parser.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ struct Project {
194194
std::string project_name;
195195
std::string project_version;
196196
std::string project_description;
197-
std::vector<std::string> project_languages;
197+
ConditionVector project_languages;
198198
bool project_allow_unknown_languages = false;
199199
MsvcRuntimeType project_msvc_runtime = msvc_last;
200200
Condition<std::string> cmake_before;

src/cmake_generator.cpp

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -725,16 +725,41 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
725725

726726
parser::Project project(parent_project, path, false);
727727

728-
for (const auto &lang : project.project_languages) {
729-
if (known_languages.find(lang) == known_languages.end()) {
728+
tsl::ordered_set<std::string> flat_project_languages;
729+
for (const auto &itr : project.project_languages) {
730+
for (const auto &language : itr.second) {
731+
flat_project_languages.insert(language);
732+
}
733+
}
734+
735+
// Reference: https://gitlab.kitware.com/cmake/cmake/-/issues/24340#note_1304703
736+
flat_project_languages.insert("RC");
737+
738+
// All acceptable extensions based off our given languages.
739+
tsl::ordered_set<std::string> project_extensions;
740+
for (const auto &language : flat_project_languages) {
741+
auto itr = known_languages.find(language);
742+
if (itr == known_languages.end()) {
730743
if (project.project_allow_unknown_languages) {
731-
printf("[warning] Unknown language '%s' specified\n", lang.c_str());
744+
printf("[warning] Unknown language '%s' specified\n", language.c_str());
732745
} else {
733-
throw std::runtime_error("Unknown language '" + lang + "' specified");
746+
throw std::runtime_error("Unknown language '" + language + "' specified");
734747
}
748+
} else {
749+
project_extensions.insert(itr->second.begin(), itr->second.end());
735750
}
736751
}
737752

753+
auto contains_language_source = [&project_extensions](const std::vector<std::string> &sources) {
754+
for (const auto &source : sources) {
755+
auto extension = fs::path(source).extension().string();
756+
if (project_extensions.count(extension) > 0) {
757+
return true;
758+
}
759+
}
760+
return false;
761+
};
762+
738763
Generator gen(project, path);
739764

740765
// Helper lambdas for more convenient CMake generation
@@ -912,17 +937,29 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
912937
gen.conditional_cmake(project.cmake_before);
913938

914939
if (!project.project_name.empty()) {
915-
auto languages = std::make_pair("LANGUAGES", project.project_languages);
940+
auto languages = std::make_pair("LANGUAGES", project.project_languages[""]);
916941
auto version = std::make_pair("VERSION", project.project_version);
917942
auto description = std::make_pair("DESCRIPTION", project.project_description);
918-
cmd("project")(project.project_name, languages, version, description).endl();
943+
cmd("project")(project.project_name, languages, version, description);
919944

920-
for (const auto &language : project.project_languages) {
945+
for (const auto &language : project.project_languages[""]) {
921946
if (language == "CSharp") {
922947
cmd("include")("CSharpUtilities").endl();
923948
break;
924949
}
925950
}
951+
952+
gen.handle_condition(project.project_languages, [&cmd](const std::string &condition, const std::vector<std::string> &languages) {
953+
if (!condition.empty()) {
954+
cmd("enable_language")(languages).endl();
955+
for (const auto &language : languages) {
956+
if (language == "CSharp") {
957+
cmd("include")("CSharpUtilities").endl();
958+
break;
959+
}
960+
}
961+
}
962+
});
926963
}
927964

928965
gen.conditional_includes(project.include_after);
@@ -1138,34 +1175,6 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
11381175
gen.conditional_cmake(subdir.cmake_after);
11391176
}
11401177

1141-
// The implicit default is ["C", "CXX"], so make sure this list isn't
1142-
// empty or projects without languages explicitly defined will error.
1143-
auto project_languages = project.project_languages;
1144-
if (project_languages.empty())
1145-
project_languages = {"C", "CXX"};
1146-
1147-
// Reference: https://gitlab.kitware.com/cmake/cmake/-/issues/24340#note_1304703
1148-
project_languages.push_back("RC");
1149-
1150-
// All acceptable extensions based off our given languages.
1151-
tsl::ordered_set<std::string> project_extensions;
1152-
for (const auto &language : project_languages) {
1153-
auto itr = known_languages.find(language);
1154-
if (itr != known_languages.end()) {
1155-
project_extensions.insert(itr->second.begin(), itr->second.end());
1156-
}
1157-
}
1158-
1159-
auto contains_language_source = [&project_extensions](const std::vector<std::string> &sources) {
1160-
for (const auto &source : sources) {
1161-
auto extension = fs::path(source).extension().string();
1162-
if (project_extensions.count(extension) > 0) {
1163-
return true;
1164-
}
1165-
}
1166-
return false;
1167-
};
1168-
11691178
if (!project.targets.empty()) {
11701179
auto project_root = project.root();
11711180
for (size_t i = 0; i < project.targets.size(); i++) {

src/project_parser.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,11 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
301301
project.required("name", project_name);
302302
project.optional("version", project_version);
303303
project.optional("description", project_description);
304+
305+
// The implicit default is ["C", "CXX"], so make sure this list isn't
306+
// empty or projects without languages explicitly defined will error.
307+
project_languages[""] = {"C", "CXX"};
308+
304309
project.optional("languages", project_languages);
305310
project.optional("allow-unknown-languages", project_allow_unknown_languages);
306311
project.optional("cmake-before", cmake_before);

tests/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/cmake.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,9 @@ name = "relative-paths"
6565
working-directory = "relative-paths"
6666
command = "$<TARGET_FILE:cmkr>"
6767
arguments = ["build"]
68+
69+
[[test]]
70+
name = "objective-c"
71+
working-directory = "objective-c"
72+
command = "$<TARGET_FILE:cmkr>"
73+
arguments = ["build"]

tests/objective-c/cmake.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Add Objective-C sources on Apple platforms:
2+
3+
[project]
4+
name = "objective-c"
5+
description = "Objective-C"
6+
languages = ["C"]
7+
apple.languages = ["OBJC"]
8+
9+
[target.hello]
10+
type = "executable"
11+
sources = ["src/main.c"]
12+
apple.sources = ["src/apple.m"]
13+
apple.link-libraries = ["$<LINK_LIBRARY:FRAMEWORK,Foundation>"]

tests/objective-c/src/apple.m

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#import <Foundation/Foundation.h>
2+
3+
void platform_specific() {
4+
NSFileHandle *stdout = [NSFileHandle fileHandleWithStandardOutput];
5+
NSString *message = @"Hello from Objective-C!\n";
6+
[stdout writeData:[message dataUsingEncoding:NSUTF8StringEncoding] error:nil];
7+
}

tests/objective-c/src/main.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#include <stdio.h>
2+
3+
#ifdef __APPLE__
4+
void platform_specific();
5+
#else
6+
void platform_specific() {
7+
puts("This is not an Apple platform.");
8+
}
9+
#endif
10+
11+
int main() {
12+
platform_specific();
13+
return 0;
14+
}

0 commit comments

Comments
 (0)