update 0.1.1

self-hosting v0.1.1
Mohammed Alyousef 4 years ago
parent 18034af6ce
commit 4e55489845

3
.gitignore vendored

@ -3,4 +3,5 @@ bin2
compile_commands.json compile_commands.json
.clangd .clangd
temp.* temp.*
.vs .vs
.cache

@ -1,9 +1,11 @@
# CHANGELOG # CHANGELOG
## 0.1.0 - Unreleased ## 0.1.1 - 2020-11-19
- Add support for globbing. - Add support for globbing.
- Add support for find_package components. - Add support for find_package components.
- Add options. - Add options.
- Add installs.
- Support aliases. - Support aliases.
- Support interface libs (header-only libs). - Support interface libs (header-only libs).
- Support testing. - Support testing.
- Require cmake >= 3.15.

@ -1,10 +1,10 @@
# This file was generated automatically by cmkr. # 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) set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
project(cmkr VERSION 0.1.0) project(cmkr VERSION 0.1.1)
include(FetchContent) include(FetchContent)
@ -49,5 +49,10 @@ target_link_libraries(cmkr PUBLIC
cmkrlib cmkrlib
) )
install(
TARGETS cmkr
DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
)

@ -4,7 +4,7 @@ cmkr, pronounced "cmaker", is A CMakeLists.txt generator from TOML.
## Building ## 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 git clone https://github.com/moalyousef/cmkr
cd 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: 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 ```toml
[cmake] [cmake]
minimum = "3.14" minimum = "3.15"
[project] [project]
name = "app" name = "app"
@ -31,14 +31,14 @@ sources = ["src/main.cpp"]
This project's cmake.toml: This project's cmake.toml:
```toml ```toml
[cmake] [cmake]
minimum = "3.14" minimum = "3.15"
[project] [project]
name = "cmkr" name = "cmkr"
version = "0.1.0" version = "0.1.0"
[fetch-content] [fetch-content]
toml11 = { GIT_REPOSITORY = "https://github.com/ToruNiina/toml11" } toml11 = { git = "https://github.com/ToruNiina/toml11" }
[[bin]] [[bin]]
name = "cmkrlib" name = "cmkrlib"
@ -53,12 +53,16 @@ name = "cmkr"
type = "exe" type = "exe"
sources = ["src/main.cpp", "src/args.cpp"] sources = ["src/main.cpp", "src/args.cpp"]
link-libs = ["cmkrlib"] link-libs = ["cmkrlib"]
[[install]]
targets = ["cmkr"]
destination = "${CMAKE_INSTALL_PREFIX}/bin"
``` ```
Currently supported fields: Currently supported fields:
```toml ```toml
[cmake] # required for top-level project [cmake] # required for top-level project
minimum = "3.14" # required minimum = "3.15" # required
subdirs = [] # optional subdirs = [] # optional
bin-dir = "bin" # optional bin-dir = "bin" # optional
cpp-flags = [] # optional cpp-flags = [] # optional
@ -76,7 +80,7 @@ Boost = { version = "1.74.0", required = false, components = ["system"] } # opti
spdlog = "*" spdlog = "*"
[fetch-content] # optional, runs fetchContent [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 [options] # optional
APP_BUILD_STUFF = false # optional APP_BUILD_STUFF = false # optional
@ -92,10 +96,17 @@ features = [] # optional
defines = [] # optional defines = [] # optional
link-libs = [] # optional link-libs = [] # optional
[[test]] # optional [[test]] # optional, can define several
name = "test1" # required name = "test1" # required
command = "app" # required command = "app" # required
arguments = ["arg1", "arg2"] # optional 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: 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. init [exe|lib|shared|static|interface] Starts a new project in the same directory.
gen Generates CMakeLists.txt file. gen Generates CMakeLists.txt file.
build <extra cmake args> Run cmake and build. build <extra cmake args> Run cmake and build.
install Run cmake --install. Needs admin privileges.
clean Clean the build directory. clean Clean the build directory.
help Show help. help Show help.
version Current cmkr version. version Current cmkr version.

@ -1,12 +1,12 @@
[cmake] [cmake]
minimum = "3.14" minimum = "3.15"
[project] [project]
name = "cmkr" name = "cmkr"
version = "0.1.0" version = "0.1.1"
[fetch-content] [fetch-content]
toml11 = { GIT_REPOSITORY = "https://github.com/ToruNiina/toml11" } toml11 = { git = "https://github.com/ToruNiina/toml11" }
[[bin]] [[bin]]
name = "cmkrlib" name = "cmkrlib"
@ -22,3 +22,6 @@ type = "exe"
sources = ["src/main.cpp", "src/args.cpp"] sources = ["src/main.cpp", "src/args.cpp"]
link-libs = ["cmkrlib"] link-libs = ["cmkrlib"]
[[install]]
targets = ["cmkr"]
destination = "${CMAKE_INSTALL_PREFIX}/bin"

@ -8,6 +8,8 @@ int run(int argc, char **argv);
int clean(); int clean();
int install();
} // namespace cmkr::build } // namespace cmkr::build
extern "C" { extern "C" {
#endif #endif
@ -16,6 +18,8 @@ int cmkr_build_run(int argc, char **argv);
int cmkr_build_clean(void); int cmkr_build_clean(void);
int cmkr_build_install(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

@ -10,6 +10,8 @@ struct Status {
InitError, InitError,
GenerationError, GenerationError,
BuildError, BuildError,
CleanError,
InstallError,
}; };
Status(Code ec) noexcept; Status(Code ec) noexcept;
operator int() const noexcept; operator int() const noexcept;

@ -7,11 +7,12 @@ int %s() {
std::cout << "Hello World!\n"; std::cout << "Hello World!\n";
return 0; return 0;
} }
)lit"; )lit";
const char *cmake_toml = R"lit( const char *cmake_toml = R"lit(
[cmake] [cmake]
minimum = "3.14" minimum = "3.15"
# subdirs = [] # subdirs = []
# bin-dir = "" # bin-dir = ""
# cpp-flags = [] # cpp-flags = []
@ -39,4 +40,9 @@ include-dirs = ["include"]
# features = [] # features = []
# defines = [] # defines = []
# link-libs = [] # link-libs = []
[[install]]
%s = ["%s"]
destination = "${CMAKE_INSTALL_PREFIX}/%s"
)lit"; )lit";

@ -28,9 +28,10 @@ const char *handle_args(int argc, char **argv) {
} else if (main_arg == "version") { } else if (main_arg == "version") {
return cmkr::help::version(); return cmkr::help::version();
} else if (main_arg == "init") { } else if (main_arg == "init") {
if (args.size() < 3) std::string typ = "exe";
return "Please provide a project type!"; if (args.size() > 2)
auto ret = cmkr::gen::generate_project(args[2].c_str()); typ = args[2];
auto ret = cmkr::gen::generate_project(typ.c_str());
if (ret) if (ret)
return "Initialization failure!"; return "Initialization failure!";
return "Directory initialized!"; return "Directory initialized!";
@ -39,6 +40,11 @@ const char *handle_args(int argc, char **argv) {
if (ret) if (ret)
return "CMake build error!"; return "CMake build error!";
return "CMake run completed!"; 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") { } else if (main_arg == "clean") {
auto ret = build::clean(); auto ret = build::clean();
if (ret) if (ret)

@ -57,6 +57,12 @@ int clean() {
return !ret; return !ret;
} }
int install() {
cmake::CMake cmake(".", false);
auto cmd = "cmake --install " + cmake.bin_dir;
return ::system(cmd.c_str());
}
} // namespace cmkr::build } // namespace cmkr::build
int cmkr_build_run(int argc, char **argv) { int cmkr_build_run(int argc, char **argv) {
@ -75,6 +81,16 @@ int cmkr_build_clean(void) {
} catch (const std::system_error &e) { } catch (const std::system_error &e) {
return e.code().value(); return e.code().value();
} catch (...) { } 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);
} }
} }

@ -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.sources = detail::to_string_vec(toml::find(bin, "sources").as_array());
b.alias = toml::find(bin, "alias").as_string();
if (bin.contains("include-dirs")) { if (bin.contains("include-dirs")) {
b.include_dirs = b.include_dirs =
detail::to_string_vec(toml::find(bin, "include-dirs").as_array()); 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")) { if (bin.contains("defines")) {
b.defines = detail::to_string_vec(toml::find(bin, "defines").as_array()); 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); binaries.push_back(b);
} }
} }
@ -165,6 +168,27 @@ CMake::CMake(const std::string &path, bool build) {
tests.push_back(test); 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 } // namespace cmkr::cmake

@ -36,8 +36,16 @@ struct Test {
std::vector<std::string> args; std::vector<std::string> args;
}; };
struct Install {
std::vector<std::string> targets;
std::vector<std::string> files;
std::vector<std::string> dirs;
std::vector<std::string> configs;
std::string destination;
};
struct CMake { struct CMake {
std::string cmake_version = "3.14"; std::string cmake_version = "3.15";
std::string bin_dir = "bin"; std::string bin_dir = "bin";
std::string generator; std::string generator;
std::vector<std::string> subdirs; std::vector<std::string> subdirs;
@ -53,6 +61,7 @@ struct CMake {
std::map<std::string, std::map<std::string, std::string>> contents; std::map<std::string, std::map<std::string, std::string>> contents;
std::vector<Bin> binaries; std::vector<Bin> binaries;
std::vector<Test> tests; std::vector<Test> tests;
std::vector<Install> installs;
CMake(const std::string &path, bool build); CMake(const std::string &path, bool build);
}; };

@ -39,6 +39,21 @@ std::string format(const char *fmt, Args... args) {
return temp; return temp;
} }
std::vector<fs::path> expand_path(const fs::path &p) {
std::vector<fs::path> 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 } // namespace detail
int generate_project(const char *str) { int generate_project(const char *str) {
@ -46,19 +61,31 @@ int generate_project(const char *str) {
fs::create_directory("include"); fs::create_directory("include");
const auto dir_name = fs::current_path().stem().string(); const auto dir_name = fs::current_path().stem().string();
std::string mainbuf; std::string mainbuf;
const auto tomlbuf = std::string installed;
detail::format(cmake_toml, dir_name.c_str(), dir_name.c_str(), str); std::string target;
std::string dest;
if (!strcmp(str, "exe")) { if (!strcmp(str, "exe")) {
mainbuf = detail::format(hello_world, "main"); mainbuf = detail::format(hello_world, "main");
installed = "targets";
target = dir_name;
dest = "bin";
} else if (!strcmp(str, "static") || !strcmp(str, "shared") || !strcmp(str, "lib")) { } else if (!strcmp(str, "static") || !strcmp(str, "shared") || !strcmp(str, "lib")) {
mainbuf = detail::format(hello_world, "test"); mainbuf = detail::format(hello_world, "test");
installed = "targets";
target = dir_name;
dest = "lib";
} else if (!strcmp(str, "interface")) { } else if (!strcmp(str, "interface")) {
// Nothing special! installed = "files";
target = "include/*.h";
dest = "include/" + dir_name;
} else { } else {
throw std::runtime_error( throw std::runtime_error(
"Unknown project type. Types are exe, lib, shared, static, interface!"); "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")) { if (strcmp(str, "interface")) {
std::ofstream ofs("src/main.cpp"); std::ofstream ofs("src/main.cpp");
if (ofs.is_open()) { if (ofs.is_open()) {
@ -149,7 +176,23 @@ int generate_cmake(const char *path) {
for (const auto &dep : cmake.contents) { for (const auto &dep : cmake.contents) {
ss << "FetchContent_Declare(\n\t" << dep.first << "\n"; ss << "FetchContent_Declare(\n\t" << dep.first << "\n";
for (const auto &arg : dep.second) { 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" ss << "\t)\n\n"
<< "FetchContent_MakeAvailable(" << dep.first << ")\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"; ss << "set(" << detail::to_upper(bin.name) << "_SOURCES\n";
for (const auto &src : bin.sources) { for (const auto &src : bin.sources) {
auto path = fs::path(src); auto path = fs::path(src);
if (path.filename().stem().string() == "*") { auto expanded = detail::expand_path(path);
auto ext = path.extension(); for (const auto &f : expanded) {
for (const auto &f : fs::directory_iterator(path.parent_path())) { ss << "\t" << f << "\n";
if (f.path().extension() == ext) {
ss << "\t" << f.path() << "\n";
}
}
} else {
ss << "\t" << path << "\n";
} }
} }
ss << "\t)\n\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"; ss << "\n\n";
// printf("%s\n", ss.str().c_str()); // printf("%s\n", ss.str().c_str());

@ -11,6 +11,7 @@ arguments:
init [exe|lib|shared|static|interface] Starts a new project in the same directory. init [exe|lib|shared|static|interface] Starts a new project in the same directory.
gen Generates CMakeLists.txt file. gen Generates CMakeLists.txt file.
build <extra cmake args> Run cmake and build. build <extra cmake args> Run cmake and build.
install Run cmake --install. Needs admin privileges.
clean Clean the build directory. clean Clean the build directory.
help Show help. help Show help.
version Current cmkr version. version Current cmkr version.

Loading…
Cancel
Save