diff --git a/.gitignore b/.gitignore index 2af4ba0..a0d3cab 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ bin compile_commands.json +.clangd +temp.* \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index e2f450b..41d9798 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,12 +1,18 @@ cmake_minimum_required(VERSION 3.0) -project(cmk) +project(cmkr) + +project(cmkr VERSION 0.1.0 LANGUAGES CXX) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -set(CMK_SRCS +set(cmkr_SOURCES src/main.cpp + src/args.cpp + src/gen.cpp ) -add_executable(cmk ${CMK_SRCS}) -target_compile_features(cmk PRIVATE cxx_std_17) -target_include_directories(cmk PRIVATE ${CMAKE_CURRENT_LIST_DIR}/vendor) \ No newline at end of file +add_executable(cmkr ${cmkr_SOURCES}) + +target_compile_features(cmkr PRIVATE cxx_std_17) + +target_include_directories(cmkr PRIVATE ${CMAKE_CURRENT_LIST_DIR}/vendor) diff --git a/cmake.toml b/cmake.toml index f574dd9..7bf9f3f 100644 --- a/cmake.toml +++ b/cmake.toml @@ -1,13 +1,28 @@ -[cmake] -minimum_required = "3.0" +[cmake] # required +minimum_required = "3.0" # required +arguments = [""] # optional +cpp_flags = [""] # optional +c_flags = [""] # optional +link_flags = [""] # optional +prefix_path = [""] # optional +export_compile_commands = true # optional -[project] -name = "cmk" -version = "0.1.0" -authors = ["MoAlyousef "] +[project] # required +name = "cmkr" # required +version = "0.1.0" # required +languages = [""] # optional (C, CXX, OBJC, OBJCXX) -[[executable]] -name = "cmk" -sources = ["src/main.cpp"] -include_directories = ["vendor"] -compile_features = ["cxx_std_17"] +[[app]] # optional +name = "cmkr" # required +sources = ["src/main.cpp", "src/args.cpp", "src/gen.cpp", "src/help.cpp"] # required +headers = [""] # optional +include_directories = ["vendor"] # optional +compile_features = ["cxx_std_17"] # optional + +# [[lib]] # optional +# name = "cmkr" # required +# sources = ["src/args.cpp", "src/gen.cpp", "src/help.cpp"] # required +# type = "shared" # required +# headers = [""] # optional +# include_directories = ["vendor"] # optional +# compile_features = ["cxx_std_17"] # optional \ No newline at end of file diff --git a/src/args.cpp b/src/args.cpp new file mode 100644 index 0000000..40a1a59 --- /dev/null +++ b/src/args.cpp @@ -0,0 +1,38 @@ +#include "args.hpp" +#include "gen.hpp" +#include "help.hpp" +#include +#include + +namespace cmkr::args { +std::string handle_args(std::vector args) { + if (args.size() < 2) + throw std::runtime_error("Please provide command line arguments!"); + std::string main_arg = args[1]; + if (main_arg == "gen") { + cmkr::gen::generate_cmake(); + return "Generation successful!"; + } else if (main_arg == "help") { + return cmkr::help::help_msg; + } else if (main_arg == "version") { + return cmkr::help::version; + } else if (main_arg == "init") { + if (args.size() < 3) + throw std::runtime_error("Please provide a project type!"); + cmkr::gen::generate_project(args[2]); + return "Directory initialized!"; + } else if (main_arg == "run") { + std::string command = "cmake -S. -Bbin "; + if (args.size() > 2) { + for (int i = 2; i < args.size(); ++i) { + command += args[i] + " "; + } + } + command += "&& cmake --build bin"; + system(command.c_str()); + return "Run completed!"; + } else { + return "Unknown argument!"; + } +} +} // namespace cmkr::args \ No newline at end of file diff --git a/src/args.hpp b/src/args.hpp new file mode 100644 index 0000000..6bd4bc0 --- /dev/null +++ b/src/args.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include +#include + +namespace cmkr::args { +std::string handle_args(std::vector args); +} \ No newline at end of file diff --git a/src/gen.cpp b/src/gen.cpp new file mode 100644 index 0000000..e04cc70 --- /dev/null +++ b/src/gen.cpp @@ -0,0 +1,129 @@ +#include "gen.hpp" +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; + +namespace cmkr::gen { +namespace detail { +inline std::string to_upper(const std::string &str) { + std::string temp; + temp.reserve(str.size()); + for (auto c : str) { + temp.push_back(toupper(c)); + } + return temp; +} +} // namespace detail + +void generate_project(const std::string &str) { + fs::create_directory("src"); + auto dir_name = fs::current_path().stem(); + if (str == "app") { + std::ofstream ofs("src/main.cpp"); + if (ofs.is_open()) { + ofs << "#include \n\nint main() {\n\tstd::cout << \"Hello world!\" << " + "std::endl;\n}"; + } + ofs.flush(); + ofs.close(); + + std::ofstream ofs2("cmake.toml"); + if (ofs2.is_open()) { + ofs2 << "[cmake]\nminimum_required = \"3.0\"\n\n[project]\nname = \"" + << dir_name.string() + << "\"\nversion = " + "\"0.1.0\"\n\n[[app]]\nname = \"" + << dir_name.string() << "\"\nsources = [\"src/main.cpp\"]\n"; + } + ofs2.flush(); + ofs2.close(); + } else if (str == "static") { + std::ofstream ofs2("cmake.toml"); + if (ofs2.is_open()) { + ofs2 << "[cmake]\nminimum_required = \"3.0\"\n\n[project]\nname = \"" + << dir_name.string() + << "\"\nversion = " + "\"0.1.0\"\n\n[[lib]]\nname = \"" + << dir_name.string() << "\"\nsources = [\"src/main.cpp\"]\ntype = \"static\"\n"; + } + ofs2.flush(); + ofs2.close(); + } else if (str == "shared") { + std::ofstream ofs2("cmake.toml"); + if (ofs2.is_open()) { + ofs2 << "[cmake]\nminimum_required = \"3.0\"\n\n[project]\nname = \"" + << dir_name.string() + << "\"\nversion = " + "\"0.1.0\"\n\n[[lib]]\nname = \"" + << dir_name.string() << "\"\nsources = [\"src/main.cpp\"]\ntype = \"shared\"\n"; + } + ofs2.flush(); + ofs2.close(); + } else { + throw std::runtime_error("Unknown project type. Types are app, shared, static!"); + } +} + +void generate_cmake() { + std::stringstream ss; + + const auto toml = toml::parse("cmake.toml"); + const auto &cmake = toml::find(toml, "cmake"); + const std::string cmake_min = toml::find(cmake, "minimum_required").as_string(); + 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 << "cmake_minimum_required(VERSION " << cmake_min << ")\n\n" + << "project(" << proj_name << " VERSION " << proj_version << ")\n\n"; + + if (toml.contains("app")) { + const auto &bins = toml::find(toml, "app"); + + for (auto i = 0; i < bins.size(); ++i) { + const auto bin = toml::find(bins, i); + const std::string bin_name = toml::find(bin, "name").as_string(); + + const auto srcs = toml::find(bin, "sources"); + ss << "set(" << detail::to_upper(bin_name) << "_SOURCES\n"; + for (auto j = 0; j < srcs.size(); ++j) { + const std::string source = toml::find(srcs, i).as_string(); + ss << "\t" << source << "\n"; + } + ss << "\t)\n\n" + << "add_executable(" << bin_name << " ${" << detail::to_upper(bin_name) + << "_SOURCES})\n\n"; + } + } + + if (toml.contains("lib")) { + const auto &libs = toml::find(toml, "lib"); + + for (auto i = 0; i < libs.size(); ++i) { + const auto lib = toml::find(libs, i); + const std::string lib_name = toml::find(lib, "name").as_string(); + const std::string type = toml::find(lib, "type").as_string(); + + const auto srcs = toml::find(lib, "sources"); + ss << "set(" << detail::to_upper(lib_name) << "_SOURCES\n"; + for (auto j = 0; j < srcs.size(); ++j) { + const std::string source = toml::find(srcs, i).as_string(); + ss << "\t" << source << "\n"; + } + ss << "\t)\n\n" + << "add_library(" << lib_name << " " << detail::to_upper(type) << " ${" + << detail::to_upper(lib_name) << "_SOURCES})\n\n"; + } + } + std::ofstream ofs("CMakeLists.txt"); + if (ofs.is_open()) { + ofs << ss.rdbuf(); + } + ofs.flush(); + ofs.close(); +} +} // namespace cmkr::gen \ No newline at end of file diff --git a/src/gen.hpp b/src/gen.hpp new file mode 100644 index 0000000..e828803 --- /dev/null +++ b/src/gen.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include + +namespace cmkr::gen { +void generate_project(const std::string &str); + +void generate_cmake(); +} // namespace cmkr::gen \ No newline at end of file diff --git a/src/help.hpp b/src/help.hpp new file mode 100644 index 0000000..df9990d --- /dev/null +++ b/src/help.hpp @@ -0,0 +1,17 @@ +#pragma once + +namespace cmkr::help { + +const char *version = "cmkr version 0.1.0"; + +const char *help_msg = R"lit( +Usage: cmk [argument] +arguments: + init [app|shared|static] Starts a new project in the same directory. + gen Generates CMakeLists.txt file. + run Run cmake. + help Show help. + version Current cmkr version. + )lit"; + +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index bcd9a47..9100236 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,26 +1,20 @@ +#include "args.hpp" #include #include -#include #include int main(int argc, char **argv) try { + std::vector args; + for (int i = 0; i < argc; ++i) args.push_back(argv[i]); - const auto data = toml::parse("../cmake.toml"); - const auto &cmake = toml::find(data, "cmake"); - const auto cmake_min = toml::find(cmake, "minimum_required"); - const auto &project = toml::find(data, "project"); - const auto name = toml::find(project, "name"); - const auto version = toml::find(project, "version"); - const auto &bin = toml::find(data, "executable"); - const auto bin1 = toml::find(bin, 0); - const auto bin1_name = toml::find(bin1, "name"); - std::cout << cmake_min << std::endl; - std::cout << name << std::endl; - std::cout << version << std::endl; - std::cout << bin.size() << std::endl; - std::cout << bin1_name << std::endl; + + auto output = cmkr::args::handle_args(args); + + std::cout << output << std::endl; + + return 0; } catch (const std::exception &e) { std::cerr << e.what() << std::endl; } \ No newline at end of file