diff --git a/.gitignore b/.gitignore index 9287d31..352b28a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ bin +bin2 compile_commands.json .clangd temp.* diff --git a/CMakeLists.txt b/CMakeLists.txt index e68f9ae..cb7f206 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,24 +1,35 @@ cmake_minimum_required(VERSION 3.0) -project(cmkr VERSION 0.1.0) - set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +project(cmkr VERSION 0.1.0) -set(CMKR_SOURCES - "src/main.cpp" +set(CMKRLIB_SOURCES "src/args.cpp" "src/gen.cpp" + "src/help.cpp" ) -add_executable(cmkr ${CMKR_SOURCES}) +add_library(cmkrlib STATIC ${CMKRLIB_SOURCES}) -target_include_directories(cmkr PUBLIC +target_include_directories(cmkrlib PUBLIC "vendor" ) -target_compile_features(cmkr PUBLIC +target_compile_features(cmkrlib PUBLIC "cxx_std_17" ) +set(CMKR_SOURCES + "src/main.cpp" + ) + +add_executable(cmkr ${CMKR_SOURCES}) + +target_link_libraries(cmkr PUBLIC + "cmkrlib" + ) + + + diff --git a/README.md b/README.md index f7709a6..cd979e7 100644 --- a/README.md +++ b/README.md @@ -18,40 +18,63 @@ cmkr parses cmake.toml files (using toml11) at the project directory. A basic he [cmake] minimum_required = "3.0" +[project] +name = "app" +version = "0.1.0" + +[[bin]] +name = "app" +type = "exe" +sources = ["src/main.cpp"] +``` + +This project's cmake.toml: +```toml +[cmake] +minimum_required = "3.0" + [project] name = "cmkr" version = "0.1.0" +[[bin]] +name = "cmkrlib" +type = "static" +sources = ["src/args.cpp", "src/gen.cpp", "src/help.cpp"] +include_dirs = ["vendor"] +features = ["cxx_std_17"] + [[bin]] name = "cmkr" type = "exe" sources = ["src/main.cpp"] +link_libs = ["cmkrlib"] ``` Currently supported fields: ```toml -[cmake] # required +[cmake] # required for top-level project minimum_required = "3.0" # required -# cpp_flags = [] # optional -# c_flags = [] # optional -# linker_flags = [] # optional -# subdirs = [] # optional +cpp_flags = [] # optional +c_flags = [] # optional +link_flags = [] # optional +subdirs = [] # optional -[project] # required -name = "cmkr" # required +[project] # required per project +name = "app" # required version = "0.1.0" # required [dependencies] # optional, runs find_package, use "*" to ignore version boost = "1.74.0" # optional [[bin]] # required, can define several binaries -name = "cmkr" # required +name = "app" # required type = "exe" # required (exe || shared || static) -sources = ["src/main.cpp", "src/args.cpp", "src/gen.cpp"] # required -include_directories = ["vendor"] # optional -compile_features = ["cxx_std_17"] # optional -# definitions = [] # optional -# link_libraries = [] # optional +sources = ["src/main.cpp"] # required +include_dirs = ["vendor"] # optional +features = ["cxx_std_17"] # optional +defines = [] # optional +link_libs = [] # optional ``` The cmkr executable can be run from the command-line: @@ -60,7 +83,7 @@ Usage: cmkr [arguments] arguments: init [exe|shared|static] Starts a new project in the same directory. gen Generates CMakeLists.txt file. - build [extra cmake args] Run cmake and build. + build Run cmake and build. help Show help. version Current cmkr version. ``` diff --git a/cmake.toml b/cmake.toml index 7c06070..54035dc 100644 --- a/cmake.toml +++ b/cmake.toml @@ -1,23 +1,20 @@ -[cmake] # required -minimum_required = "3.0" # required -# cpp_flags = [] # optional -# c_flags = [] # optional -# linker_flags = [] # optional -# subdirs = [] # optional +[cmake] +minimum_required = "3.0" -[project] # required -name = "cmkr" # required -version = "0.1.0" # required +[project] +name = "cmkr" +version = "0.1.0" -# [dependencies] # optional, runs find_package, use "*" to ignore version -# boost = "1.74.0" +[[bin]] +name = "cmkrlib" +type = "static" +sources = ["src/args.cpp", "src/gen.cpp", "src/help.cpp"] +include_dirs = ["vendor"] +features = ["cxx_std_17"] -[[bin]] # required -name = "cmkr" # required -type = "exe" # required (exe || shared || static) -sources = ["src/main.cpp", "src/args.cpp", "src/gen.cpp"] # required -include_directories = ["vendor"] # optional -compile_features = ["cxx_std_17"] # optional -# definitions = [] # optional -# link_libraries = [] # optional +[[bin]] +name = "cmkr" +type = "exe" +sources = ["src/main.cpp"] +link_libs = ["cmkrlib"] diff --git a/src/args.cpp b/src/args.cpp index 630325c..56ea515 100644 --- a/src/args.cpp +++ b/src/args.cpp @@ -1,26 +1,34 @@ -#include "args.hpp" -#include "gen.hpp" -#include "help.hpp" -#include -#include +#include "args.h" +#include "gen.h" +#include "help.h" + +#include +#include #include +#include +#include +#include namespace cmkr::args { -std::string handle_args(std::vector &args) { +const char *handle_args(int argc, char **argv) { + std::vector args; + for (int i = 0; i < argc; ++i) + args.push_back(argv[i]); + 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(); + cmkr::gen::generate_cmake(std::filesystem::current_path().string().c_str()); return "Generation successful!"; } else if (main_arg == "help") { - return cmkr::help::help_msg; + return cmkr::help::message(); } else if (main_arg == "version") { - return cmkr::help::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]); + cmkr::gen::generate_project(args[2].c_str()); return "Directory initialized!"; } else if (main_arg == "build") { std::string command = "cmake -S. -Bbin "; @@ -38,4 +46,8 @@ std::string handle_args(std::vector &args) { return "Unknown argument!"; } } -} // namespace cmkr::args \ No newline at end of file +} // namespace cmkr::args + +const char *cmkr_args_handle_args(int argc, char **argv) { + return cmkr::args::handle_args(argc, argv); +} diff --git a/src/args.h b/src/args.h new file mode 100644 index 0000000..3dfa47e --- /dev/null +++ b/src/args.h @@ -0,0 +1,16 @@ +#pragma once + +#ifdef __cplusplus +namespace cmkr::args { + +const char *handle_args(int argc, char **argv); +} + +extern "C" { +#endif + +const char *cmkr_args_handle_args(int, char **); + +#ifdef __cplusplus +} +#endif diff --git a/src/args.hpp b/src/args.hpp deleted file mode 100644 index e022c9e..0000000 --- a/src/args.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#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 index 3572acc..c442fd8 100644 --- a/src/gen.cpp +++ b/src/gen.cpp @@ -1,4 +1,5 @@ -#include "gen.hpp" +#include "gen.h" + #include #include #include @@ -9,7 +10,9 @@ 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()); @@ -18,14 +21,13 @@ inline std::string to_upper(const std::string &str) { } return temp; } -void handle_bins(std::stringstream &s, const std::string &bin_type) { -} + } // namespace detail -void generate_project(const std::string &str) { +void generate_project(const char *str) { fs::create_directory("src"); auto dir_name = fs::current_path().stem(); - if (str == "exe") { + if (!strcmp(str, "exe")) { std::ofstream ofs("src/main.cpp"); if (ofs.is_open()) { ofs << "#include \n\nint main() {\n\tstd::cout << \"Hello world!\" << " @@ -44,7 +46,7 @@ void generate_project(const std::string &str) { } ofs2.flush(); ofs2.close(); - } else if (str == "static" || str == "shared") { + } else if (!strcmp(str, "static") || !strcmp(str, "shared")) { std::ofstream ofs("src/lib.cpp"); if (ofs.is_open()) { ofs << "int dll_main() {\n\treturn 0;\n}"; @@ -58,7 +60,8 @@ void generate_project(const std::string &str) { << dir_name.string() << "\"\nversion = " "\"0.1.0\"\n\n[[lib]]\nname = \"" - << dir_name.string() << "\"\nsources = [\"src/lib.cpp\"]\ntype = \"" << str << "\"\n"; + << dir_name.string() << "\"\nsources = [\"src/lib.cpp\"]\ntype = \"" << str + << "\"\n"; } ofs2.flush(); ofs2.close(); @@ -67,53 +70,60 @@ void generate_project(const std::string &str) { } } -void generate_cmake() { +void generate_cmake(const char *path) { std::stringstream ss; + std::vector subdirs; + + const auto toml = toml::parse(fs::path(path) / "cmake.toml"); + if (toml.contains("cmake")) { + const auto &cmake = toml::find(toml, "cmake"); + const std::string cmake_min = toml::find(cmake, "minimum_required").as_string(); + ss << "cmake_minimum_required(VERSION " << cmake_min << ")\n\n" + << "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 << " " << flag; + } + ss << ")\n\n"; + } - 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" - << "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 << " " << flag; + 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 << " " << flag; + } + ss << ")\n\n"; } - 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 << " " << flag; + 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 << " " << flag; + } + ss << ")\n\n"; } - ss << ")\n\n"; - } - if (cmake.contains("linker_flags")) { - ss << "set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS}"; - const auto flags = toml::find(cmake, "linker_flags").as_array(); - for (const auto &flag : flags) { - ss << " " << flag; + if (cmake.contains("subdirs")) { + const auto dirs = toml::find(cmake, "subdirs").as_array(); + for (const auto &dir : dirs) { + ss << "add_subdirectory(" << dir << ")\n"; + subdirs.push_back(dir.as_string()); + } + ss << "\n\n"; } - ss << ")\n\n"; } - if (cmake.contains("subdirs")) { - const auto dirs = toml::find(cmake, "subdirs").as_array(); - for (const auto &dir : dirs) { - ss << "add_subdirectory(" << dir << ")\n"; - } - 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 (toml.contains("dependencies")) { @@ -159,8 +169,8 @@ void generate_cmake() { << add_command << "(" << bin_name << " " << bin_type << " ${" << detail::to_upper(bin_name) << "_SOURCES})\n\n"; - if (bin.contains("include_directories")) { - const auto includes = toml::find(bin, "include_directories").as_array(); + 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"; @@ -168,8 +178,8 @@ void generate_cmake() { ss << ")\n\n"; } - if (bin.contains("link_libraries")) { - const auto libraries = toml::find(bin, "link_libraries").as_array(); + 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"; @@ -177,8 +187,8 @@ void generate_cmake() { ss << ")\n\n"; } - if (bin.contains("compile_features")) { - const auto feats = toml::find(bin, "compile_features").as_array(); + 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"; @@ -186,8 +196,8 @@ void generate_cmake() { ss << ")\n\n"; } - if (bin.contains("definitions")) { - const auto defs = toml::find(bin, "definitions").as_array(); + 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"; @@ -198,12 +208,23 @@ void generate_cmake() { } ss << "\n\n"; - - std::ofstream ofs("CMakeLists.txt"); + // 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()); + } +} +} // namespace cmkr::gen + +void cmkr_gen_generate_project(const char *typ) { + cmkr::gen::generate_project(typ); +} + +void cmkr_gen_generate_cmake(const char *path) { + cmkr::gen::generate_cmake(path); } -} // namespace cmkr::gen \ No newline at end of file diff --git a/src/gen.h b/src/gen.h new file mode 100644 index 0000000..0ef6bc2 --- /dev/null +++ b/src/gen.h @@ -0,0 +1,21 @@ +#pragma once + +#ifdef __cplusplus +namespace cmkr::gen { + +void generate_project(const char *typ); + +void generate_cmake(const char *path); + +} // namespace cmkr::gen + +extern "C" { +#endif + +void cmkr_gen_generate_project(const char *typ); + +void cmkr_gen_generate_cmake(const char *path); + +#ifdef __cplusplus +} +#endif diff --git a/src/gen.hpp b/src/gen.hpp deleted file mode 100644 index e828803..0000000 --- a/src/gen.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#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.cpp b/src/help.cpp new file mode 100644 index 0000000..445b677 --- /dev/null +++ b/src/help.cpp @@ -0,0 +1,28 @@ +#include "help.h" + +namespace cmkr::help { + +const char *version() { + return "cmkr version 0.1.0"; +} + +const char *message() { + return R"lit( +Usage: cmkr [arguments] +arguments: + init [exe|shared|static] Starts a new project in the same directory. + gen Generates CMakeLists.txt file. + build Run cmake and build. + help Show help. + version Current cmkr version. + )lit"; +} +} // namespace cmkr::help + +const char *cmkr_help_version(void) { + return cmkr::help::version(); +} + +const char *cmkr_help_message(void) { + return cmkr::help::message(); +} \ No newline at end of file diff --git a/src/help.h b/src/help.h new file mode 100644 index 0000000..4cece36 --- /dev/null +++ b/src/help.h @@ -0,0 +1,21 @@ +#pragma once + +#ifdef __cplusplus +namespace cmkr::help { + +const char *version(); + +const char *message(); + +} // namespace cmkr::help + +extern "C" { +#endif + +const char *cmkr_help_version(void); + +const char *cmkr_help_message(void); + +#ifdef __cplusplus +} +#endif diff --git a/src/help.hpp b/src/help.hpp deleted file mode 100644 index f3390c6..0000000 --- a/src/help.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -namespace cmkr::help { - -const char *version = "cmkr version 0.1.0"; - -const char *help_msg = R"lit( -Usage: cmkr [arguments] -arguments: - init [exe|shared|static] Starts a new project in the same directory. - gen Generates CMakeLists.txt file. - build [cmake args...] Run cmake and build. - help Show help. - version Current cmkr version. - )lit"; - -} // namespace cmkr::help diff --git a/src/main.cpp b/src/main.cpp index a973ddb..6faac06 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,16 +1,12 @@ -#include "args.hpp" -#include -#include -#include +#include "args.h" -int main(int argc, char **argv) try { - std::vector args; - for (int i = 0; i < argc; ++i) - args.push_back(argv[i]); +#include +#include +#include - auto output = cmkr::args::handle_args(args); - std::cout << output << std::endl; - return 0; +int main(int argc, char **argv) try { + auto output = cmkr::args::handle_args(argc, argv); + return fprintf(stdout, "%s\n", output) < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } catch (const std::exception &e) { - std::cerr << e.what() << std::endl; + fprintf(stderr, "%s\n", e.what()); } \ No newline at end of file