diff --git a/include/cmake_generator.hpp b/include/cmake_generator.hpp index 5b34632..3435e90 100644 --- a/include/cmake_generator.hpp +++ b/include/cmake_generator.hpp @@ -5,13 +5,9 @@ namespace cmkr { namespace gen { -int generate_project(const char *typ); +void generate_project(const std::string &type); -int generate_cmake(const char *path, const parser::Project *parent_project = nullptr); +void generate_cmake(const char *path, const parser::Project *parent_project = nullptr); } // namespace gen } // namespace cmkr - -int cmkr_gen_generate_project(const char *typ); - -int cmkr_gen_generate_cmake(const char *path); diff --git a/include/literals.hpp b/include/literals.hpp index 89dfa66..0c742d7 100644 --- a/include/literals.hpp +++ b/include/literals.hpp @@ -1,45 +1,100 @@ #pragma once -static const char *hello_world = &R"lit( +static const char *cpp_executable = &R"lit( #include +#include -int %s() { - std::cout << "Hello World!\n"; - return 0; +int main() { + std::cout << "Hello from cmkr!\n"; + return EXIT_SUCCESS; } )lit"[1]; // skip initial newline -static const char *cmake_toml = &R"lit( -[cmake] -version = "3.15" -# subdirs = [] -# build-dir = "" -# cpp-flags = [] -# c-flags = [] -# link-flags = [] -# generator = "" -# arguments = [] +static const char *cpp_library = &R"lit( +#include <@name/@name.hpp> +#include + +namespace @name { + +void hello() { + std::cout << "Hello from cmkr!\n"; +} + +} // namespace @name +)lit"[1]; // skip initial newline + +static const char *hpp_library = &R"lit( +#pragma once + +namespace @name { + +void hello(); + +} // namespace @name +)lit"[1]; // skip initial newline + +static const char *hpp_interface = &R"lit( +#pragma once + +#include + +namespace @name { + +inline void hello() { + std::cout << "Hello from cmkr!\n"; +} + +} // namespace @name +)lit"[1]; // skip initial newline + +static const char *toml_executable = &R"lit( +# Reference: https://build-cpp.github.io/cmkr/cmake-toml [project] -name = "%s" -version = "0.1.0" +name = "@name" + +[target.@name] +type = "executable" +sources = ["src/@name/main.cpp"] +compile-features = ["cxx_std_11"] +)lit"[1]; // skip initial newline -# [find-package] +static const char *toml_library = &R"lit( +# Reference: https://build-cpp.github.io/cmkr/cmake-toml +[project] +name = "@name" -# [fetch-content] +[target.@name] +type = "@type" +sources = [ + "src/@name/@name.cpp", + "include/@name/@name.hpp" +] +include-directories = ["include"] +compile-features = ["cxx_std_11"] +)lit"[1]; // skip initial newline -# [options] +static const char *toml_interface = &R"lit( +# Reference: https://build-cpp.github.io/cmkr/cmake-toml +[project] +name = "@name" -[target.%s] -type = "%s" -sources = ["src/*.cpp"] +[target.@name] +type = "interface" include-directories = ["include"] -# alias = "" -# compile-features = [] -# compile-definitions = [] -# link-libraries = [] - -[[install]] -%s = ["%s"] -destination = "${CMAKE_INSTALL_PREFIX}/%s" +compile-features = ["cxx_std_11"] +)lit"[1]; // skip initial newline + +static const char *toml_migration = &R"lit( +# Reference: https://build-cpp.github.io/cmkr/cmake-toml +[project] +name = "@name" + +# TODO: define a target for each of your executables/libraries like this: +#[target.@name] +#type = "executable" +#sources = ["src/@name/*.cpp", "include/@name/*.hpp"] +#include-directories = ["include"] +#compile-features = ["cxx_std_11"] +#link-libraries = ["other-targets"] )lit"[1]; // skip initial newline diff --git a/src/arguments.cpp b/src/arguments.cpp index 25507f3..a2796ab 100644 --- a/src/arguments.cpp +++ b/src/arguments.cpp @@ -21,9 +21,7 @@ const char *handle_args(int argc, char **argv) { throw std::runtime_error(cmkr::help::message()); std::string main_arg = args[1]; if (main_arg == "gen") { - auto ret = cmkr::gen::generate_cmake(fs::current_path().string().c_str()); - if (ret) - return "CMake generation error!"; + cmkr::gen::generate_cmake(fs::current_path().string().c_str()); return "CMake generation successful!"; } else if (main_arg == "help") { return cmkr::help::message(); @@ -33,18 +31,14 @@ const char *handle_args(int argc, char **argv) { std::string type = "executable"; if (args.size() > 2) type = args[2]; - auto ret = cmkr::gen::generate_project(type.c_str()); - if (ret) - return "Initialization failure!"; - ret = cmkr::gen::generate_cmake(fs::current_path().string().c_str()); - if (ret) - return "CMake generation error!"; + cmkr::gen::generate_project(type.c_str()); + cmkr::gen::generate_cmake(fs::current_path().string().c_str()); return "Directory initialized!"; } else if (main_arg == "build") { auto ret = build::run(argc, argv); if (ret) return "CMake build error!"; - return "CMake run completed!"; + return "CMake build completed!"; } else if (main_arg == "install") { auto ret = build::install(); if (ret) diff --git a/src/build.cpp b/src/build.cpp index a570721..cd95544 100644 --- a/src/build.cpp +++ b/src/build.cpp @@ -22,10 +22,9 @@ int run(int argc, char **argv) { } std::stringstream ss; - if (gen::generate_cmake(fs::current_path().string().c_str())) - throw std::runtime_error("CMake generation failure!"); + gen::generate_cmake(fs::current_path().string().c_str()); - ss << "cmake -S. -DCMKR_BUILD_SKIP_GENERATION=ON -B" << project.build_dir << " "; + ss << "cmake -DCMKR_BUILD_SKIP_GENERATION=ON -B" << project.build_dir << " "; if (!project.generator.empty()) { ss << "-G \"" << project.generator << "\" "; diff --git a/src/cmake_generator.cpp b/src/cmake_generator.cpp index d9c9cc2..4f55433 100644 --- a/src/cmake_generator.cpp +++ b/src/cmake_generator.cpp @@ -19,7 +19,7 @@ namespace cmkr { namespace gen { -inline std::string to_upper(const std::string &str) { +static std::string to_upper(const std::string &str) { std::string temp; temp.reserve(str.size()); for (auto c : str) { @@ -28,16 +28,16 @@ inline std::string to_upper(const std::string &str) { return temp; } -template -std::string format(const char *fmt, Args... args) { - auto sz = snprintf(nullptr, 0, fmt, args...) + 1; - char *buf = new char[sz]; - int ret = snprintf(buf, sz, fmt, args...); - if (ret != sz - 1) - throw std::runtime_error("Error formatting string!"); - std::string temp(buf, buf + sz - 1); - delete[] buf; - return temp; +static std::string format(const char *format, tsl::ordered_map variables) { + std::string s = format; + for (const auto &itr : variables) { + size_t start_pos = 0; + while ((start_pos = s.find(itr.first, start_pos)) != std::string::npos) { + s.replace(start_pos, itr.first.length(), itr.second); + start_pos += itr.second.length(); + } + } + return s; } static std::vector expand_cmake_path(const fs::path &name, const fs::path &toml_dir) { @@ -89,52 +89,47 @@ static std::vector expand_cmake_paths(const std::vector variables = { + {"@name", name}, + {"@type", type}, + }; + + if (!fs::is_empty(fs::current_path())) { + create_file("cmake.toml", format(toml_migration, variables)); + puts("Generated migration cmake.toml in existing project directory..."); + return; + } + + if (type == "executable") { + create_file("cmake.toml", format(toml_executable, variables)); + create_file("src/" + name + "/main.cpp", format(cpp_executable, variables)); + } else if (type == "static" || type == "shared" || type == "library") { + create_file("cmake.toml", format(toml_library, variables)); + create_file("src/" + name + "/" + name + ".cpp", format(cpp_library, variables)); + create_file("include/" + name + "/" + name + ".hpp", format(hpp_library, variables)); + } else if (type == "interface") { + create_file("cmake.toml", format(toml_interface, variables)); + create_file("include/" + name + "/" + name + ".hpp", format(hpp_interface, variables)); + } else { + throw std::runtime_error("Unknown project type " + type + "! Supported types are: executable, library, shared, static, interface"); + } } struct CommandEndl { @@ -440,7 +435,7 @@ static std::string vcpkg_escape_identifier(const std::string &name) { return escaped; } -int generate_cmake(const char *path, const parser::Project *parent_project) { +void generate_cmake(const char *path, const parser::Project *parent_project) { if (!fs::exists(fs::path(path) / "cmake.toml")) { throw std::runtime_error("No cmake.toml found!"); } @@ -494,14 +489,7 @@ int generate_cmake(const char *path, const parser::Project *parent_project) { fs::path cmkr_include(project.cmkr_include); if (!project.cmkr_include.empty() && !fs::exists(cmkr_include) && cmkr_include.is_relative()) { - if (!cmkr_include.parent_path().empty()) { - fs::create_directories(cmkr_include.parent_path()); - } - std::ofstream ofs(cmkr_include.string(), std::ios::binary); - if (!ofs) { - throw std::runtime_error("Failed to create " + project.cmkr_include); - } - ofs.write(resources::cmkr, strlen(resources::cmkr)); + create_file(cmkr_include, resources::cmkr); } } @@ -910,12 +898,7 @@ int generate_cmake(const char *path, const parser::Project *parent_project) { }(); if (should_regenerate) { - std::ofstream ofs(list_path, std::ios::binary); - if (ofs.is_open()) { - ofs << ss.str(); - } else { - throw std::runtime_error("Failed to write " + list_path.string()); - } + create_file(list_path, ss.str()); } auto generate_subdir = [path, &project](const fs::path &sub) { @@ -941,28 +924,6 @@ int generate_cmake(const char *path, const parser::Project *parent_project) { for (const auto &subdir : project.subdirs) { generate_subdir(subdir.name); } - - return 0; } } // namespace gen } // namespace cmkr - -int cmkr_gen_generate_project(const char *typ) { - try { - return cmkr::gen::generate_project(typ); - } catch (const std::system_error &e) { - return e.code().value(); - } catch (...) { - return cmkr::error::Status(cmkr::error::Status::Code::InitError); - } -} - -int cmkr_gen_generate_cmake(const char *path) { - try { - return cmkr::gen::generate_cmake(path); - } catch (const std::system_error &e) { - return e.code().value(); - } catch (...) { - return cmkr::error::Status(cmkr::error::Status::Code::GenerationError); - } -}