Skip to content

Commit 6a825e1

Browse files
committed
Slightly improve cmkr init #24
1 parent cc2b984 commit 6a825e1

File tree

5 files changed

+143
-138
lines changed

5 files changed

+143
-138
lines changed

include/cmake_generator.hpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,9 @@
55
namespace cmkr {
66
namespace gen {
77

8-
int generate_project(const char *typ);
8+
void generate_project(const std::string &type);
99

10-
int generate_cmake(const char *path, const parser::Project *parent_project = nullptr);
10+
void generate_cmake(const char *path, const parser::Project *parent_project = nullptr);
1111

1212
} // namespace gen
1313
} // namespace cmkr
14-
15-
int cmkr_gen_generate_project(const char *typ);
16-
17-
int cmkr_gen_generate_cmake(const char *path);

include/literals.hpp

Lines changed: 85 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,100 @@
11
#pragma once
22

3-
static const char *hello_world = &R"lit(
3+
static const char *cpp_executable = &R"lit(
44
#include <iostream>
5+
#include <cstdlib>
56
6-
int %s() {
7-
std::cout << "Hello World!\n";
8-
return 0;
7+
int main() {
8+
std::cout << "Hello from cmkr!\n";
9+
return EXIT_SUCCESS;
910
}
1011
)lit"[1]; // skip initial newline
1112

12-
static const char *cmake_toml = &R"lit(
13-
[cmake]
14-
version = "3.15"
15-
# subdirs = []
16-
# build-dir = ""
17-
# cpp-flags = []
18-
# c-flags = []
19-
# link-flags = []
20-
# generator = ""
21-
# arguments = []
13+
static const char *cpp_library = &R"lit(
14+
#include <@name/@name.hpp>
2215
16+
#include <iostream>
17+
18+
namespace @name {
19+
20+
void hello() {
21+
std::cout << "Hello from cmkr!\n";
22+
}
23+
24+
} // namespace @name
25+
)lit"[1]; // skip initial newline
26+
27+
static const char *hpp_library = &R"lit(
28+
#pragma once
29+
30+
namespace @name {
31+
32+
void hello();
33+
34+
} // namespace @name
35+
)lit"[1]; // skip initial newline
36+
37+
static const char *hpp_interface = &R"lit(
38+
#pragma once
39+
40+
#include <iostream>
41+
42+
namespace @name {
43+
44+
inline void hello() {
45+
std::cout << "Hello from cmkr!\n";
46+
}
47+
48+
} // namespace @name
49+
)lit"[1]; // skip initial newline
50+
51+
static const char *toml_executable = &R"lit(
52+
# Reference: https://build-cpp.github.io/cmkr/cmake-toml
2353
[project]
24-
name = "%s"
25-
version = "0.1.0"
54+
name = "@name"
55+
56+
[target.@name]
57+
type = "executable"
58+
sources = ["src/@name/main.cpp"]
59+
compile-features = ["cxx_std_11"]
60+
)lit"[1]; // skip initial newline
2661

27-
# [find-package]
62+
static const char *toml_library = &R"lit(
63+
# Reference: https://build-cpp.github.io/cmkr/cmake-toml
64+
[project]
65+
name = "@name"
2866
29-
# [fetch-content]
67+
[target.@name]
68+
type = "@type"
69+
sources = [
70+
"src/@name/@name.cpp",
71+
"include/@name/@name.hpp"
72+
]
73+
include-directories = ["include"]
74+
compile-features = ["cxx_std_11"]
75+
)lit"[1]; // skip initial newline
3076

31-
# [options]
77+
static const char *toml_interface = &R"lit(
78+
# Reference: https://build-cpp.github.io/cmkr/cmake-toml
79+
[project]
80+
name = "@name"
3281
33-
[target.%s]
34-
type = "%s"
35-
sources = ["src/*.cpp"]
82+
[target.@name]
83+
type = "interface"
3684
include-directories = ["include"]
37-
# alias = ""
38-
# compile-features = []
39-
# compile-definitions = []
40-
# link-libraries = []
41-
42-
[[install]]
43-
%s = ["%s"]
44-
destination = "${CMAKE_INSTALL_PREFIX}/%s"
85+
compile-features = ["cxx_std_11"]
86+
)lit"[1]; // skip initial newline
87+
88+
static const char *toml_migration = &R"lit(
89+
# Reference: https://build-cpp.github.io/cmkr/cmake-toml
90+
[project]
91+
name = "@name"
92+
93+
# TODO: define a target for each of your executables/libraries like this:
94+
#[target.@name]
95+
#type = "executable"
96+
#sources = ["src/@name/*.cpp", "include/@name/*.hpp"]
97+
#include-directories = ["include"]
98+
#compile-features = ["cxx_std_11"]
99+
#link-libraries = ["other-targets"]
45100
)lit"[1]; // skip initial newline

src/arguments.cpp

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ const char *handle_args(int argc, char **argv) {
2121
throw std::runtime_error(cmkr::help::message());
2222
std::string main_arg = args[1];
2323
if (main_arg == "gen") {
24-
auto ret = cmkr::gen::generate_cmake(fs::current_path().string().c_str());
25-
if (ret)
26-
return "CMake generation error!";
24+
cmkr::gen::generate_cmake(fs::current_path().string().c_str());
2725
return "CMake generation successful!";
2826
} else if (main_arg == "help") {
2927
return cmkr::help::message();
@@ -33,18 +31,14 @@ const char *handle_args(int argc, char **argv) {
3331
std::string type = "executable";
3432
if (args.size() > 2)
3533
type = args[2];
36-
auto ret = cmkr::gen::generate_project(type.c_str());
37-
if (ret)
38-
return "Initialization failure!";
39-
ret = cmkr::gen::generate_cmake(fs::current_path().string().c_str());
40-
if (ret)
41-
return "CMake generation error!";
34+
cmkr::gen::generate_project(type.c_str());
35+
cmkr::gen::generate_cmake(fs::current_path().string().c_str());
4236
return "Directory initialized!";
4337
} else if (main_arg == "build") {
4438
auto ret = build::run(argc, argv);
4539
if (ret)
4640
return "CMake build error!";
47-
return "CMake run completed!";
41+
return "CMake build completed!";
4842
} else if (main_arg == "install") {
4943
auto ret = build::install();
5044
if (ret)

src/build.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,9 @@ int run(int argc, char **argv) {
2222
}
2323
std::stringstream ss;
2424

25-
if (gen::generate_cmake(fs::current_path().string().c_str()))
26-
throw std::runtime_error("CMake generation failure!");
25+
gen::generate_cmake(fs::current_path().string().c_str());
2726

28-
ss << "cmake -S. -DCMKR_BUILD_SKIP_GENERATION=ON -B" << project.build_dir << " ";
27+
ss << "cmake -DCMKR_BUILD_SKIP_GENERATION=ON -B" << project.build_dir << " ";
2928

3029
if (!project.generator.empty()) {
3130
ss << "-G \"" << project.generator << "\" ";

src/cmake_generator.cpp

Lines changed: 50 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
namespace cmkr {
2020
namespace gen {
2121

22-
inline std::string to_upper(const std::string &str) {
22+
static std::string to_upper(const std::string &str) {
2323
std::string temp;
2424
temp.reserve(str.size());
2525
for (auto c : str) {
@@ -28,16 +28,16 @@ inline std::string to_upper(const std::string &str) {
2828
return temp;
2929
}
3030

31-
template <typename... Args>
32-
std::string format(const char *fmt, Args... args) {
33-
auto sz = snprintf(nullptr, 0, fmt, args...) + 1;
34-
char *buf = new char[sz];
35-
int ret = snprintf(buf, sz, fmt, args...);
36-
if (ret != sz - 1)
37-
throw std::runtime_error("Error formatting string!");
38-
std::string temp(buf, buf + sz - 1);
39-
delete[] buf;
40-
return temp;
31+
static std::string format(const char *format, tsl::ordered_map<std::string, std::string> variables) {
32+
std::string s = format;
33+
for (const auto &itr : variables) {
34+
size_t start_pos = 0;
35+
while ((start_pos = s.find(itr.first, start_pos)) != std::string::npos) {
36+
s.replace(start_pos, itr.first.length(), itr.second);
37+
start_pos += itr.second.length();
38+
}
39+
}
40+
return s;
4141
}
4242

4343
static std::vector<std::string> expand_cmake_path(const fs::path &name, const fs::path &toml_dir) {
@@ -89,52 +89,47 @@ static std::vector<std::string> expand_cmake_paths(const std::vector<std::string
8989
return result;
9090
}
9191

92-
int generate_project(const char *str) {
93-
fs::create_directory("src");
94-
fs::create_directory("include");
95-
const auto dir_name = fs::current_path().stem().string();
96-
std::string mainbuf;
97-
std::string installed;
98-
std::string target;
99-
std::string dest;
100-
if (!strcmp(str, "executable")) {
101-
mainbuf = format(hello_world, "main");
102-
installed = "targets";
103-
target = dir_name;
104-
dest = "bin";
105-
} else if (!strcmp(str, "static") || !strcmp(str, "shared") || !strcmp(str, "library")) {
106-
mainbuf = format(hello_world, "test");
107-
installed = "targets";
108-
target = dir_name;
109-
dest = "lib";
110-
} else if (!strcmp(str, "interface")) {
111-
installed = "files";
112-
target = "include/*.h";
113-
dest = "include/" + dir_name;
114-
} else {
115-
throw std::runtime_error("Unknown project type " + std::string(str) +
116-
"! Supported types are: executable, library, shared, static, interface");
92+
static void create_file(const fs::path &path, const std::string &contents) {
93+
if (!path.parent_path().empty()) {
94+
fs::create_directories(path.parent_path());
11795
}
118-
119-
const auto tomlbuf = format(cmake_toml, dir_name.c_str(), dir_name.c_str(), str, installed.c_str(), target.c_str(), dest.c_str());
120-
121-
if (strcmp(str, "interface")) {
122-
std::ofstream ofs("src/main.cpp", std::ios::binary);
123-
if (ofs.is_open()) {
124-
ofs << mainbuf;
125-
}
126-
ofs.flush();
127-
ofs.close();
96+
std::ofstream ofs(path, std::ios::binary);
97+
if (!ofs) {
98+
throw std::runtime_error("Failed to create " + path.string());
12899
}
100+
ofs << contents;
101+
}
129102

130-
std::ofstream ofs2("cmake.toml", std::ios::binary);
131-
if (ofs2.is_open()) {
132-
ofs2 << tomlbuf;
103+
void generate_project(const std::string &type) {
104+
const auto name = fs::current_path().stem().string();
105+
if (fs::exists(fs::current_path() / "cmake.toml")) {
106+
throw std::runtime_error("Cannot initialize a project when cmake.toml already exists!");
133107
}
134-
ofs2.flush();
135-
ofs2.close();
136108

137-
return 0;
109+
tsl::ordered_map<std::string, std::string> variables = {
110+
{"@name", name},
111+
{"@type", type},
112+
};
113+
114+
if (!fs::is_empty(fs::current_path())) {
115+
create_file("cmake.toml", format(toml_migration, variables));
116+
puts("Generated migration cmake.toml in existing project directory...");
117+
return;
118+
}
119+
120+
if (type == "executable") {
121+
create_file("cmake.toml", format(toml_executable, variables));
122+
create_file("src/" + name + "/main.cpp", format(cpp_executable, variables));
123+
} else if (type == "static" || type == "shared" || type == "library") {
124+
create_file("cmake.toml", format(toml_library, variables));
125+
create_file("src/" + name + "/" + name + ".cpp", format(cpp_library, variables));
126+
create_file("include/" + name + "/" + name + ".hpp", format(hpp_library, variables));
127+
} else if (type == "interface") {
128+
create_file("cmake.toml", format(toml_interface, variables));
129+
create_file("include/" + name + "/" + name + ".hpp", format(hpp_interface, variables));
130+
} else {
131+
throw std::runtime_error("Unknown project type " + type + "! Supported types are: executable, library, shared, static, interface");
132+
}
138133
}
139134

140135
struct CommandEndl {
@@ -440,7 +435,7 @@ static std::string vcpkg_escape_identifier(const std::string &name) {
440435
return escaped;
441436
}
442437

443-
int generate_cmake(const char *path, const parser::Project *parent_project) {
438+
void generate_cmake(const char *path, const parser::Project *parent_project) {
444439
if (!fs::exists(fs::path(path) / "cmake.toml")) {
445440
throw std::runtime_error("No cmake.toml found!");
446441
}
@@ -494,14 +489,7 @@ int generate_cmake(const char *path, const parser::Project *parent_project) {
494489

495490
fs::path cmkr_include(project.cmkr_include);
496491
if (!project.cmkr_include.empty() && !fs::exists(cmkr_include) && cmkr_include.is_relative()) {
497-
if (!cmkr_include.parent_path().empty()) {
498-
fs::create_directories(cmkr_include.parent_path());
499-
}
500-
std::ofstream ofs(cmkr_include.string(), std::ios::binary);
501-
if (!ofs) {
502-
throw std::runtime_error("Failed to create " + project.cmkr_include);
503-
}
504-
ofs.write(resources::cmkr, strlen(resources::cmkr));
492+
create_file(cmkr_include, resources::cmkr);
505493
}
506494
}
507495

@@ -910,12 +898,7 @@ int generate_cmake(const char *path, const parser::Project *parent_project) {
910898
}();
911899

912900
if (should_regenerate) {
913-
std::ofstream ofs(list_path, std::ios::binary);
914-
if (ofs.is_open()) {
915-
ofs << ss.str();
916-
} else {
917-
throw std::runtime_error("Failed to write " + list_path.string());
918-
}
901+
create_file(list_path, ss.str());
919902
}
920903

921904
auto generate_subdir = [path, &project](const fs::path &sub) {
@@ -941,28 +924,6 @@ int generate_cmake(const char *path, const parser::Project *parent_project) {
941924
for (const auto &subdir : project.subdirs) {
942925
generate_subdir(subdir.name);
943926
}
944-
945-
return 0;
946927
}
947928
} // namespace gen
948929
} // namespace cmkr
949-
950-
int cmkr_gen_generate_project(const char *typ) {
951-
try {
952-
return cmkr::gen::generate_project(typ);
953-
} catch (const std::system_error &e) {
954-
return e.code().value();
955-
} catch (...) {
956-
return cmkr::error::Status(cmkr::error::Status::Code::InitError);
957-
}
958-
}
959-
960-
int cmkr_gen_generate_cmake(const char *path) {
961-
try {
962-
return cmkr::gen::generate_cmake(path);
963-
} catch (const std::system_error &e) {
964-
return e.code().value();
965-
} catch (...) {
966-
return cmkr::error::Status(cmkr::error::Status::Code::GenerationError);
967-
}
968-
}

0 commit comments

Comments
 (0)