From 4e55489845d5dbbaa154b51daba7763f4b20b1ba Mon Sep 17 00:00:00 2001 From: Mohammed Alyousef Date: Thu, 19 Nov 2020 01:11:33 +0300 Subject: [PATCH] update 0.1.1 --- .gitignore | 3 +- CHANGELOG.md | 6 ++- CMakeLists.txt | 9 ++++- README.md | 26 +++++++++---- cmake.toml | 9 +++-- include/build.h | 4 ++ include/error.h | 2 + include/literals.h | 8 +++- src/args.cpp | 12 ++++-- src/build.cpp | 18 ++++++++- src/cmake.cpp | 28 +++++++++++++- src/cmake.hpp | 11 +++++- src/gen.cpp | 96 +++++++++++++++++++++++++++++++++++++++------- src/help.cpp | 1 + 14 files changed, 197 insertions(+), 36 deletions(-) diff --git a/.gitignore b/.gitignore index 352b28a..9ec48ce 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ bin2 compile_commands.json .clangd temp.* -.vs \ No newline at end of file +.vs +.cache \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 6572203..e3c8a18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,11 @@ # CHANGELOG -## 0.1.0 - Unreleased +## 0.1.1 - 2020-11-19 - Add support for globbing. - Add support for find_package components. - Add options. +- Add installs. - Support aliases. - Support interface libs (header-only libs). -- Support testing. \ No newline at end of file +- Support testing. +- Require cmake >= 3.15. \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index d481646..26a2cf9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,10 @@ # This file was generated automatically by cmkr. -cmake_minimum_required(VERSION 3.14) +cmake_minimum_required(VERSION 3.15) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -project(cmkr VERSION 0.1.0) +project(cmkr VERSION 0.1.1) include(FetchContent) @@ -49,5 +49,10 @@ target_link_libraries(cmkr PUBLIC cmkrlib ) +install( + TARGETS cmkr + DESTINATION ${CMAKE_INSTALL_PREFIX}/bin + ) + diff --git a/README.md b/README.md index 522e61b..3bc483e 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ cmkr, pronounced "cmaker", is A CMakeLists.txt generator from TOML. ## Building -cmkr requires a C++17 compiler, cmake >= 3.14. +cmkr requires a C++17 compiler, cmake >= 3.15. ``` git clone https://github.com/moalyousef/cmkr cd cmkr @@ -16,7 +16,7 @@ cmake --build bin cmkr parses cmake.toml files (using toml11 by Toru Niina) at the project directory. A basic hello world format with the minimum required fields: ```toml [cmake] -minimum = "3.14" +minimum = "3.15" [project] name = "app" @@ -31,14 +31,14 @@ sources = ["src/main.cpp"] This project's cmake.toml: ```toml [cmake] -minimum = "3.14" +minimum = "3.15" [project] name = "cmkr" version = "0.1.0" [fetch-content] -toml11 = { GIT_REPOSITORY = "https://github.com/ToruNiina/toml11" } +toml11 = { git = "https://github.com/ToruNiina/toml11" } [[bin]] name = "cmkrlib" @@ -53,12 +53,16 @@ name = "cmkr" type = "exe" sources = ["src/main.cpp", "src/args.cpp"] link-libs = ["cmkrlib"] + +[[install]] +targets = ["cmkr"] +destination = "${CMAKE_INSTALL_PREFIX}/bin" ``` Currently supported fields: ```toml [cmake] # required for top-level project -minimum = "3.14" # required +minimum = "3.15" # required subdirs = [] # optional bin-dir = "bin" # optional cpp-flags = [] # optional @@ -76,7 +80,7 @@ Boost = { version = "1.74.0", required = false, components = ["system"] } # opti spdlog = "*" [fetch-content] # optional, runs fetchContent -toml11 = { GIT_REPOSITORY = "https://github.com/ToruNiina/toml11", GIT_TAG = "v3.5.0" } # optional +toml11 = { git = "https://github.com/ToruNiina/toml11", tag = "v3.5.0" } # optional [options] # optional APP_BUILD_STUFF = false # optional @@ -92,10 +96,17 @@ features = [] # optional defines = [] # optional link-libs = [] # optional -[[test]] # optional +[[test]] # optional, can define several name = "test1" # required command = "app" # required arguments = ["arg1", "arg2"] # optional + +[[install]] # optional, can define several +targets = ["app"] # optional +files = ["include/*.h"] # optional +dirs = [] # optional +configs = [] # optional (Release|Debug...etc) +destination = "${CMAKE_INSTALL_PREFIX}/bin" # required ``` The cmkr executable can be run from the command-line: @@ -105,6 +116,7 @@ arguments: init [exe|lib|shared|static|interface] Starts a new project in the same directory. gen Generates CMakeLists.txt file. build Run cmake and build. + install Run cmake --install. Needs admin privileges. clean Clean the build directory. help Show help. version Current cmkr version. diff --git a/cmake.toml b/cmake.toml index 690f4b2..f909195 100644 --- a/cmake.toml +++ b/cmake.toml @@ -1,12 +1,12 @@ [cmake] -minimum = "3.14" +minimum = "3.15" [project] name = "cmkr" -version = "0.1.0" +version = "0.1.1" [fetch-content] -toml11 = { GIT_REPOSITORY = "https://github.com/ToruNiina/toml11" } +toml11 = { git = "https://github.com/ToruNiina/toml11" } [[bin]] name = "cmkrlib" @@ -22,3 +22,6 @@ type = "exe" sources = ["src/main.cpp", "src/args.cpp"] link-libs = ["cmkrlib"] +[[install]] +targets = ["cmkr"] +destination = "${CMAKE_INSTALL_PREFIX}/bin" diff --git a/include/build.h b/include/build.h index 40787b9..46dfdba 100644 --- a/include/build.h +++ b/include/build.h @@ -8,6 +8,8 @@ int run(int argc, char **argv); int clean(); +int install(); + } // namespace cmkr::build extern "C" { #endif @@ -16,6 +18,8 @@ int cmkr_build_run(int argc, char **argv); int cmkr_build_clean(void); +int cmkr_build_install(void); + #ifdef __cplusplus } #endif diff --git a/include/error.h b/include/error.h index 5dedc41..7d18305 100644 --- a/include/error.h +++ b/include/error.h @@ -10,6 +10,8 @@ struct Status { InitError, GenerationError, BuildError, + CleanError, + InstallError, }; Status(Code ec) noexcept; operator int() const noexcept; diff --git a/include/literals.h b/include/literals.h index 8f2f85d..9af61d0 100644 --- a/include/literals.h +++ b/include/literals.h @@ -7,11 +7,12 @@ int %s() { std::cout << "Hello World!\n"; return 0; } + )lit"; const char *cmake_toml = R"lit( [cmake] -minimum = "3.14" +minimum = "3.15" # subdirs = [] # bin-dir = "" # cpp-flags = [] @@ -39,4 +40,9 @@ include-dirs = ["include"] # features = [] # defines = [] # link-libs = [] + +[[install]] +%s = ["%s"] +destination = "${CMAKE_INSTALL_PREFIX}/%s" + )lit"; diff --git a/src/args.cpp b/src/args.cpp index e317fd5..fb2727f 100644 --- a/src/args.cpp +++ b/src/args.cpp @@ -28,9 +28,10 @@ const char *handle_args(int argc, char **argv) { } else if (main_arg == "version") { return cmkr::help::version(); } else if (main_arg == "init") { - if (args.size() < 3) - return "Please provide a project type!"; - auto ret = cmkr::gen::generate_project(args[2].c_str()); + std::string typ = "exe"; + if (args.size() > 2) + typ = args[2]; + auto ret = cmkr::gen::generate_project(typ.c_str()); if (ret) return "Initialization failure!"; return "Directory initialized!"; @@ -39,6 +40,11 @@ const char *handle_args(int argc, char **argv) { if (ret) return "CMake build error!"; return "CMake run completed!"; + } else if (main_arg == "install") { + auto ret = build::install(); + if (ret) + return "CMake install error!"; + return "CMake install completed!"; } else if (main_arg == "clean") { auto ret = build::clean(); if (ret) diff --git a/src/build.cpp b/src/build.cpp index 011d236..11619b7 100644 --- a/src/build.cpp +++ b/src/build.cpp @@ -57,6 +57,12 @@ int clean() { return !ret; } +int install() { + cmake::CMake cmake(".", false); + auto cmd = "cmake --install " + cmake.bin_dir; + return ::system(cmd.c_str()); +} + } // namespace cmkr::build int cmkr_build_run(int argc, char **argv) { @@ -75,6 +81,16 @@ int cmkr_build_clean(void) { } catch (const std::system_error &e) { return e.code().value(); } catch (...) { - return cmkr::error::Status(cmkr::error::Status::Code::BuildError); + return cmkr::error::Status(cmkr::error::Status::Code::CleanError); + } +} + +int cmkr_build_install(void) { + try { + return cmkr::build::install(); + } catch (const std::system_error &e) { + return e.code().value(); + } catch (...) { + return cmkr::error::Status(cmkr::error::Status::Code::InstallError); } } \ No newline at end of file diff --git a/src/cmake.cpp b/src/cmake.cpp index 397f1e9..fc51f45 100644 --- a/src/cmake.cpp +++ b/src/cmake.cpp @@ -131,8 +131,6 @@ CMake::CMake(const std::string &path, bool build) { b.sources = detail::to_string_vec(toml::find(bin, "sources").as_array()); - b.alias = toml::find(bin, "alias").as_string(); - if (bin.contains("include-dirs")) { b.include_dirs = detail::to_string_vec(toml::find(bin, "include-dirs").as_array()); @@ -149,6 +147,11 @@ CMake::CMake(const std::string &path, bool build) { if (bin.contains("defines")) { b.defines = detail::to_string_vec(toml::find(bin, "defines").as_array()); } + + if (bin.contains("alias")) { + b.alias = toml::find(bin, "alias").as_string(); + } + binaries.push_back(b); } } @@ -165,6 +168,27 @@ CMake::CMake(const std::string &path, bool build) { tests.push_back(test); } } + + if (toml.contains("install")) { + const auto &ts = toml::find(toml, "install").as_array(); + for (const auto &t : ts) { + Install inst; + if (t.contains("targets")) { + inst.targets = detail::to_string_vec(toml::find(t, "targets").as_array()); + } + if (t.contains("files")) { + inst.files = detail::to_string_vec(toml::find(t, "files").as_array()); + } + if (t.contains("dirs")) { + inst.dirs = detail::to_string_vec(toml::find(t, "dirs").as_array()); + } + if (t.contains("configs")) { + inst.configs = detail::to_string_vec(toml::find(t, "configs").as_array()); + } + inst.destination = toml::find(t, "destination").as_string(); + installs.push_back(inst); + } + } } } } // namespace cmkr::cmake diff --git a/src/cmake.hpp b/src/cmake.hpp index 3a705b7..e9939bf 100644 --- a/src/cmake.hpp +++ b/src/cmake.hpp @@ -36,8 +36,16 @@ struct Test { std::vector args; }; +struct Install { + std::vector targets; + std::vector files; + std::vector dirs; + std::vector configs; + std::string destination; +}; + struct CMake { - std::string cmake_version = "3.14"; + std::string cmake_version = "3.15"; std::string bin_dir = "bin"; std::string generator; std::vector subdirs; @@ -53,6 +61,7 @@ struct CMake { std::map> contents; std::vector binaries; std::vector tests; + std::vector installs; CMake(const std::string &path, bool build); }; diff --git a/src/gen.cpp b/src/gen.cpp index f7dc7f3..15a2ba0 100644 --- a/src/gen.cpp +++ b/src/gen.cpp @@ -39,6 +39,21 @@ std::string format(const char *fmt, Args... args) { return temp; } +std::vector expand_path(const fs::path &p) { + std::vector temp; + if (p.filename().stem().string() == "*") { + auto ext = p.extension(); + for (const auto &f : fs::directory_iterator(p.parent_path())) { + if (f.path().extension() == ext) { + temp.push_back(f.path()); + } + } + } else { + temp.push_back(p); + } + return temp; +} + } // namespace detail int generate_project(const char *str) { @@ -46,19 +61,31 @@ int generate_project(const char *str) { fs::create_directory("include"); const auto dir_name = fs::current_path().stem().string(); std::string mainbuf; - const auto tomlbuf = - detail::format(cmake_toml, dir_name.c_str(), dir_name.c_str(), str); + std::string installed; + std::string target; + std::string dest; if (!strcmp(str, "exe")) { mainbuf = detail::format(hello_world, "main"); + installed = "targets"; + target = dir_name; + dest = "bin"; } else if (!strcmp(str, "static") || !strcmp(str, "shared") || !strcmp(str, "lib")) { mainbuf = detail::format(hello_world, "test"); + installed = "targets"; + target = dir_name; + dest = "lib"; } else if (!strcmp(str, "interface")) { - // Nothing special! + installed = "files"; + target = "include/*.h"; + dest = "include/" + dir_name; } else { throw std::runtime_error( "Unknown project type. Types are exe, lib, shared, static, interface!"); } + const auto tomlbuf = detail::format(cmake_toml, dir_name.c_str(), dir_name.c_str(), str, + installed.c_str(), target.c_str(), dest.c_str()); + if (strcmp(str, "interface")) { std::ofstream ofs("src/main.cpp"); if (ofs.is_open()) { @@ -149,7 +176,23 @@ int generate_cmake(const char *path) { 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"; + std::string first_arg = arg.first; + if (first_arg == "git") { + first_arg = "GIT_REPOSITORY"; + } else if (first_arg == "tag") { + first_arg = "GIT_TAG"; + } else if (first_arg == "svn") { + first_arg == "SVN_REPOSITORY"; + } else if (first_arg == "rev") { + first_arg == "SVN_REVISION"; + } else if (first_arg == "url") { + first_arg = "URL"; + } else if (first_arg == "hash") { + first_arg = "URL_HASH"; + } else { + // don't change arg + } + ss << "\t" << first_arg << " " << arg.second << "\n"; } ss << "\t)\n\n" << "FetchContent_MakeAvailable(" << dep.first << ")\n\n"; @@ -188,15 +231,9 @@ int generate_cmake(const char *path) { ss << "set(" << detail::to_upper(bin.name) << "_SOURCES\n"; for (const auto &src : bin.sources) { auto path = fs::path(src); - if (path.filename().stem().string() == "*") { - auto ext = path.extension(); - for (const auto &f : fs::directory_iterator(path.parent_path())) { - if (f.path().extension() == ext) { - ss << "\t" << f.path() << "\n"; - } - } - } else { - ss << "\t" << path << "\n"; + auto expanded = detail::expand_path(path); + for (const auto &f : expanded) { + ss << "\t" << f << "\n"; } } ss << "\t)\n\n"; @@ -262,6 +299,39 @@ int generate_cmake(const char *path) { } } + if (!cmake.installs.empty()) { + for (const auto &inst : cmake.installs) { + ss << "install(\n"; + if (!inst.targets.empty()) { + ss << "\tTARGETS "; + for (const auto &target : inst.targets) { + ss << target << " "; + } + } + if (!inst.dirs.empty()) { + ss << "\tDIRS "; + for (const auto &dir : inst.dirs) { + ss << dir << " "; + } + } + if (!inst.files.empty()) { + ss << "\tFILES "; + for (const auto &file : inst.files) { + auto path = detail::expand_path(fs::path(file)); + for (const auto &f : path) + ss << f << " "; + } + } + if (!inst.configs.empty()) { + ss << "\tCONFIGURATIONS"; + for (const auto &conf : inst.configs) { + ss << conf << " "; + } + } + ss << "\n\tDESTINATION " << inst.destination << "\n\t)\n\n"; + } + } + ss << "\n\n"; // printf("%s\n", ss.str().c_str()); diff --git a/src/help.cpp b/src/help.cpp index 9104d5b..7976fe6 100644 --- a/src/help.cpp +++ b/src/help.cpp @@ -11,6 +11,7 @@ arguments: init [exe|lib|shared|static|interface] Starts a new project in the same directory. gen Generates CMakeLists.txt file. build Run cmake and build. + install Run cmake --install. Needs admin privileges. clean Clean the build directory. help Show help. version Current cmkr version.