diff --git a/CMakeLists.txt b/CMakeLists.txt index a2cbfa6..8b9d0a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,31 +5,32 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) project(cmkr VERSION 0.1.0) set(CMKRLIB_SOURCES - "src/args.cpp" - "src/gen.cpp" - "src/help.cpp" - "src/build.cpp" - "src/error.cpp" + src/cmake.cpp + src/gen.cpp + src/help.cpp + src/build.cpp + src/error.cpp ) add_library(cmkrlib STATIC ${CMKRLIB_SOURCES}) target_include_directories(cmkrlib PUBLIC - "vendor" + vendor ) target_compile_features(cmkrlib PUBLIC - "cxx_std_17" + cxx_std_17 ) set(CMKR_SOURCES - "src/main.cpp" + src/main.cpp + src/args.cpp ) add_executable(cmkr ${CMKR_SOURCES}) target_link_libraries(cmkr PUBLIC - "cmkrlib" + cmkrlib ) diff --git a/README.md b/README.md index 23e299f..13193dd 100644 --- a/README.md +++ b/README.md @@ -40,14 +40,14 @@ version = "0.1.0" [[bin]] name = "cmkrlib" type = "static" -sources = ["src/args.cpp", "src/gen.cpp", "src/help.cpp", "src/build.cpp", "error.cpp"] +sources = ["src/cmake.cpp", "src/gen.cpp", "src/help.cpp", "src/build.cpp", "src/error.cpp"] include-dirs = ["vendor"] features = ["cxx_std_17"] [[bin]] name = "cmkr" type = "exe" -sources = ["src/main.cpp"] +sources = ["src/main.cpp", "src/args.cpp"] link-libs = ["cmkrlib"] ``` diff --git a/cmake.toml b/cmake.toml index aaabc42..0602dd5 100644 --- a/cmake.toml +++ b/cmake.toml @@ -8,13 +8,13 @@ version = "0.1.0" [[bin]] name = "cmkrlib" type = "static" -sources = ["src/args.cpp", "src/gen.cpp", "src/help.cpp", "src/build.cpp", "src/error.cpp"] +sources = ["src/cmake.cpp", "src/gen.cpp", "src/help.cpp", "src/build.cpp", "src/error.cpp"] include-dirs = ["vendor"] features = ["cxx_std_17"] [[bin]] name = "cmkr" type = "exe" -sources = ["src/main.cpp"] +sources = ["src/main.cpp", "src/args.cpp"] link-libs = ["cmkrlib"] diff --git a/src/build.cpp b/src/build.cpp index 350ab87..77afcc2 100644 --- a/src/build.cpp +++ b/src/build.cpp @@ -1,4 +1,5 @@ #include "build.h" +#include "cmake.hpp" #include "error.h" #include "gen.h" @@ -7,45 +8,40 @@ #include #include #include -#include #include -#include namespace cmkr::build { int run(int argc, char **argv) { + cmake::CMake cmake(".", true); + if (argc > 2) { + for (size_t i = 2; i < argc; ++i) { + cmake.build_args.push_back(argv[i]); + } + } std::stringstream ss; - std::string bin_dir = "bin"; if (!std::filesystem::exists("CMakeLists.txt")) if (gen::generate_cmake(".")) throw std::runtime_error("CMake generation failure!"); - const auto toml = toml::parse("cmake.toml"); - if (toml.contains("cmake")) { - const auto &cmake = toml::find(toml, "cmake"); - ss << "cmake -S. -B"; - if (cmake.contains("bin-dir")) { - bin_dir = toml::find(cmake, "bin-dir").as_string(); - } - ss << bin_dir << " "; - if (cmake.contains("generator")) { - const auto gen = toml::find(cmake, "generator").as_string(); - ss << "-G " << gen << " "; - } - if (cmake.contains("arguments")) { - const auto args = toml::find(cmake, "arguments").as_array(); - for (const auto &arg : args) { - ss << "-D" << arg << " "; - } + ss << "cmake -S. -B" << cmake.bin_dir << " "; + + if (!cmake.generator.empty()) { + ss << "-G " << cmake.generator << " "; + } + if (!cmake.gen_args.empty()) { + for (const auto &arg : cmake.gen_args) { + ss << "-D" << arg << " "; } - ss << "&& cmake --build " << bin_dir; - if (argc > 2) { - for (size_t i = 2; i < argc; ++i) { - ss << " " << argv[i]; - } + } + ss << "&& cmake --build " << cmake.bin_dir; + if (argc > 2) { + for (const auto &arg : cmake.build_args) { + ss << " " << arg; } } + return ::system(ss.str().c_str()); } diff --git a/src/cmake.cpp b/src/cmake.cpp new file mode 100644 index 0000000..62a4ef9 --- /dev/null +++ b/src/cmake.cpp @@ -0,0 +1,112 @@ +#include "cmake.hpp" + +#include +#include + +namespace fs = std::filesystem; + +namespace cmkr::cmake { + +namespace detail { +std::vector to_string_vec( + const std::vector> + vals) { + std::vector temp; + for (const auto &val : vals) + temp.push_back(val.as_string()); + return temp; +} +} // namespace detail + +CMake::CMake(const std::string &path, bool build) { + if (fs::exists(fs::path(path) / "cmake.toml")) { + if (build) { + const auto toml = toml::parse("cmake.toml"); + if (toml.contains("cmake")) { + const auto &cmake = toml::find(toml, "cmake"); + + if (cmake.contains("bin-dir")) { + bin_dir = toml::find(cmake, "bin-dir").as_string(); + } + + if (cmake.contains("generator")) { + generator = toml::find(cmake, "generator").as_string(); + } + + if (cmake.contains("arguments")) { + gen_args = detail::to_string_vec(toml::find(cmake, "arguments").as_array()); + } + } + } else { + const auto toml = toml::parse((fs::path(path) / "cmake.toml").string()); + if (toml.contains("cmake")) { + const auto &cmake = toml::find(toml, "cmake"); + cmake_version = toml::find(cmake, "minimum").as_string(); + + if (cmake.contains("cpp-flags")) { + cppflags = detail::to_string_vec(toml::find(cmake, "cpp-flags").as_array()); + } + + if (cmake.contains("c-flags")) { + cflags = detail::to_string_vec(toml::find(cmake, "c-flags").as_array()); + } + + if (cmake.contains("link-flags")) { + linkflags = detail::to_string_vec(toml::find(cmake, "link-flags").as_array()); + } + + if (cmake.contains("subdirs")) { + subdirs = detail::to_string_vec(toml::find(cmake, "subdirs").as_array()); + } + } + + if (toml.contains("project")) { + const auto &project = toml::find(toml, "project"); + proj_name = toml::find(project, "name").as_string(); + proj_version = toml::find(project, "version").as_string(); + } + + if (toml.contains("find-package")) { + using pkg_map = std::map; + packages = toml::find(toml, "find-package"); + } + + if (toml.contains("fetch-content")) { + using content_map = std::map>; + contents = toml::find(toml, "fetch-content"); + } + + if (toml.contains("bin")) { + const auto &bins = toml::find(toml, "bin").as_array(); + + for (const auto &bin : bins) { + Bin b; + b.name = toml::find(bin, "name").as_string(); + b.type = toml::find(bin, "type").as_string(); + + b.sources = detail::to_string_vec(toml::find(bin, "sources").as_array()); + + if (bin.contains("include-dirs")) { + b.include_dirs = + detail::to_string_vec(toml::find(bin, "include-dirs").as_array()); + } + + if (bin.contains("link-libs")) { + b.link_libs = + detail::to_string_vec(toml::find(bin, "link-libs").as_array()); + } + + if (bin.contains("features")) { + b.features = detail::to_string_vec(toml::find(bin, "features").as_array()); + } + + if (bin.contains("defines")) { + b.defines = detail::to_string_vec(toml::find(bin, "defines").as_array()); + } + binaries.push_back(b); + } + } + } + } +} +} // namespace cmkr::cmake diff --git a/src/cmake.hpp b/src/cmake.hpp new file mode 100644 index 0000000..04c689a --- /dev/null +++ b/src/cmake.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include + +namespace cmkr::cmake { + +struct Bin { + std::string name; + std::string type; + std::vector sources; + std::vector include_dirs; + std::vector features; + std::vector defines; + std::vector link_libs; +}; + +struct CMake { + std::string cmake_version = "3.14"; + std::string bin_dir = "bin"; + std::string generator; + std::vector subdirs; + std::vector cppflags; + std::vector cflags; + std::vector linkflags; + std::vector gen_args; + std::vector build_args; + std::string proj_name; + std::string proj_version; + std::map packages; + std::map> contents; + std::vector binaries; + CMake(const std::string &path, bool build); +}; + +} // namespace cmkr::cmake \ No newline at end of file diff --git a/src/error.h b/src/error.h index 80c2150..5dedc41 100644 --- a/src/error.h +++ b/src/error.h @@ -24,7 +24,7 @@ struct Status { extern "C" { #endif -const char *cmkr_error_status(int); +const char *cmkr_error_status_string(int); #ifdef __cplusplus } diff --git a/src/gen.cpp b/src/gen.cpp index 4d75fad..54128e6 100644 --- a/src/gen.cpp +++ b/src/gen.cpp @@ -1,18 +1,16 @@ #include "gen.h" +#include "cmake.hpp" #include "error.h" #include "literals.h" #include #include -#include #include #include #include #include #include #include -#include -#include namespace fs = std::filesystem; @@ -75,166 +73,145 @@ int generate_project(const char *str) { } int generate_cmake(const char *path) { - std::stringstream ss; - std::vector subdirs; - - const auto toml = toml::parse((fs::path(path) / "cmake.toml").string()); - if (toml.contains("cmake")) { - const auto &cmake = toml::find(toml, "cmake"); - const std::string cmake_min = toml::find(cmake, "minimum").as_string(); - ss << "cmake_minimum_required(VERSION " << cmake_min << ")\n\n"; - - ss << "set(CMAKE_EXPORT_COMPILE_COMMANDS ON)\n\n"; - - if (cmake.contains("cpp-flags")) { - ss << "set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}\""; - const auto flags = toml::find(cmake, "cpp-flags").as_array(); - for (const auto &flag : flags) { - ss << " " << std::string_view(flag.as_string()); + if (fs::exists(fs::path(path) / "cmake.toml")) { + cmake::CMake cmake(path, false); + std::stringstream ss; + + if (!cmake.cmake_version.empty()) { + ss << "cmake_minimum_required(VERSION " << cmake.cmake_version << ")\n\n"; + + ss << "set(CMAKE_EXPORT_COMPILE_COMMANDS ON)\n\n"; + } + + if (!cmake.cppflags.empty()) { + ss << "set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} \""; + for (const auto &flag : cmake.cppflags) { + ss << flag << " "; } ss << "\")\n\n"; } - if (cmake.contains("c-flags")) { - ss << "set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS}\""; - const auto flags = toml::find(cmake, "c-flags").as_array(); - for (const auto &flag : flags) { - ss << " " << std::string_view(flag.as_string()); + if (!cmake.cflags.empty()) { + ss << "set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} \""; + for (const auto &flag : cmake.cflags) { + ss << flag << " "; } ss << "\")\n\n"; } - if (cmake.contains("link-flags")) { - ss << "set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS}\""; - const auto flags = toml::find(cmake, "link-flags").as_array(); - for (const auto &flag : flags) { - ss << " " << std::string_view(flag.as_string()); + if (!cmake.linkflags.empty()) { + ss << "set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} \""; + for (const auto &flag : cmake.linkflags) { + ss << flag << " "; } ss << "\")\n\n"; } - if (cmake.contains("subdirs")) { - const auto dirs = toml::find(cmake, "subdirs").as_array(); - for (const auto &dir : dirs) { + if (!cmake.subdirs.empty()) { + for (const auto &dir : cmake.subdirs) { ss << "add_subdirectory(" << dir << ")\n"; - subdirs.push_back(dir.as_string()); } ss << "\n\n"; } - } - - if (toml.contains("project")) { - const auto &project = toml::find(toml, "project"); - const std::string proj_name = toml::find(project, "name").as_string(); - const std::string proj_version = toml::find(project, "version").as_string(); - ss << "project(" << proj_name << " VERSION " << proj_version << ")\n\n"; - } + if (!cmake.proj_name.empty() && !cmake.proj_version.empty()) { + ss << "project(" << cmake.proj_name << " VERSION " << cmake.proj_version << ")\n\n"; + } - if (toml.contains("find-package")) { - using pkg_map = std::map; - pkg_map deps = - toml::find(toml, "find-package"); - for (const auto &dep : deps) { - ss << "find_package(" << dep.first; - if (dep.second != "*") { - ss << " " << dep.second << " CONFIG REQUIRED)\n"; - } else { - ss << " CONFIG REQUIRED)\n"; + if (!cmake.packages.empty()) { + for (const auto &dep : cmake.packages) { + ss << "find_package(" << dep.first; + if (dep.second != "*") { + ss << " " << dep.second << " CONFIG REQUIRED)\n"; + } else { + ss << " CONFIG REQUIRED)\n"; + } } } - } - if (toml.contains("fetch-content")) { - using content_map = std::map>; - content_map deps = toml::find(toml, "fetch-content"); - ss << "include(FetchContent)\n\n"; - for (const auto &dep : deps) { - ss << "FetchContent_Declare(\n\t" << dep.first << "\n"; - for (const auto &arg : dep.second) { - ss << "\t" << arg.first << " " << arg.second << "\n"; + if (!cmake.contents.empty()) { + ss << "include(FetchContent)\n\n"; + for (const auto &dep : cmake.contents) { + ss << "FetchContent_Declare(\n\t" << dep.first << "\n"; + for (const auto &arg : dep.second) { + ss << "\t" << arg.first << " " << arg.second << "\n"; + } + ss << "\t)\n\n" + << "FetchContent_MakeAvailable(" << dep.first << ")\n\n"; } - ss << "\t)\n\n" - << "FetchContent_MakeAvailable(" << dep.first << ")\n\n"; } - } - if (toml.contains("bin")) { - const auto &bins = toml::find(toml, "bin").as_array(); - - for (const auto &bin : bins) { - const std::string bin_name = toml::find(bin, "name").as_string(); - const std::string type = toml::find(bin, "type").as_string(); - std::string bin_type; - std::string add_command; - if (type == "exe") { - bin_type = ""; - add_command = "add_executable"; - } else if (type == "shared" || type == "static") { - bin_type = detail::to_upper(type); - add_command = "add_library"; - } else { - throw std::runtime_error( - "Unknown binary type! Supported types are exe, shared and static"); - } + if (!cmake.binaries.empty()) { + for (const auto &bin : cmake.binaries) { + std::string bin_type; + std::string add_command; + if (bin.type == "exe") { + bin_type = ""; + add_command = "add_executable"; + } else if (bin.type == "shared" || bin.type == "static") { + bin_type = detail::to_upper(bin.type); + add_command = "add_library"; + } else { + throw std::runtime_error( + "Unknown binary type! Supported types are exe, shared and static"); + } - const auto srcs = toml::find(bin, "sources").as_array(); - ss << "set(" << detail::to_upper(bin_name) << "_SOURCES\n"; - for (const auto &src : srcs) { - ss << "\t" << src << "\n"; - } - ss << "\t)\n\n" - << add_command << "(" << bin_name << " " << bin_type << " ${" - << detail::to_upper(bin_name) << "_SOURCES})\n\n"; - - if (bin.contains("include-dirs")) { - const auto includes = toml::find(bin, "include-dirs").as_array(); - ss << "target_include_directories(" << bin_name << " PUBLIC\n\t"; - for (const auto &inc : includes) { - ss << inc << "\n\t"; + ss << "set(" << detail::to_upper(bin.name) << "_SOURCES\n"; + for (const auto &src : bin.sources) { + ss << "\t" << src << "\n"; + } + ss << "\t)\n\n" + << add_command << "(" << bin.name << " " << bin_type << " ${" + << detail::to_upper(bin.name) << "_SOURCES})\n\n"; + + if (!bin.include_dirs.empty()) { + ss << "target_include_directories(" << bin.name << " PUBLIC\n\t"; + for (const auto &inc : bin.include_dirs) { + ss << inc << "\n\t"; + } + ss << ")\n\n"; } - ss << ")\n\n"; - } - if (bin.contains("link-libs")) { - const auto libraries = toml::find(bin, "link-libs").as_array(); - ss << "target_link_libraries(" << bin_name << " PUBLIC\n\t"; - for (const auto &l : libraries) { - ss << l << "\n\t"; + if (!bin.link_libs.empty()) { + ss << "target_link_libraries(" << bin.name << " PUBLIC\n\t"; + for (const auto &l : bin.link_libs) { + ss << l << "\n\t"; + } + ss << ")\n\n"; } - ss << ")\n\n"; - } - if (bin.contains("features")) { - const auto feats = toml::find(bin, "features").as_array(); - ss << "target_compile_features(" << bin_name << " PUBLIC\n\t"; - for (const auto &feat : feats) { - ss << feat << "\n\t"; + if (!bin.features.empty()) { + ss << "target_compile_features(" << bin.name << " PUBLIC\n\t"; + for (const auto &feat : bin.features) { + ss << feat << "\n\t"; + } + ss << ")\n\n"; } - ss << ")\n\n"; - } - if (bin.contains("defines")) { - const auto defs = toml::find(bin, "defines").as_array(); - ss << "target_add_definitions(" << bin_name << " PUBLIC\n\t"; - for (const auto &def : defs) { - ss << def << "\n\t"; + if (!bin.defines.empty()) { + ss << "target_add_definitions(" << bin.name << " PUBLIC\n\t"; + for (const auto &def : bin.defines) { + ss << def << "\n\t"; + } + ss << ")\n\n"; } - ss << ")\n\n"; } } - } - ss << "\n\n"; - // printf("%s\n", ss.str().c_str()); - std::ofstream ofs(fs::path(path) / "CMakeLists.txt"); - if (ofs.is_open()) { - ofs << ss.rdbuf(); - } - ofs.flush(); - ofs.close(); - for (const auto &sub : subdirs) { - generate_cmake(sub.c_str()); + ss << "\n\n"; + // printf("%s\n", ss.str().c_str()); + + std::ofstream ofs(fs::path(path) / "CMakeLists.txt"); + if (ofs.is_open()) { + ofs << ss.rdbuf(); + } + ofs.flush(); + ofs.close(); + + for (const auto &sub : cmake.subdirs) { + if (fs::exists(fs::path(sub) / "cmake.toml")) + generate_cmake(sub.c_str()); + } } return 0; }