self-hosting
MoAlyousef 4 years ago
parent 4db372900d
commit e382482021

1
.gitignore vendored

@ -1,4 +1,5 @@
bin
bin2
compile_commands.json
.clangd
temp.*

@ -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"
)

@ -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 <extra cmake args> Run cmake and build.
help Show help.
version Current cmkr version.
```

@ -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"]

@ -1,26 +1,34 @@
#include "args.hpp"
#include "gen.hpp"
#include "help.hpp"
#include <cstddef>
#include <cstdlib>
#include "args.h"
#include "gen.h"
#include "help.h"
#include <filesystem>
#include <stddef.h>
#include <stdexcept>
#include <stdlib.h>
#include <string>
#include <vector>
namespace cmkr::args {
std::string handle_args(std::vector<std::string> &args) {
const char *handle_args(int argc, char **argv) {
std::vector<std::string> 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<std::string> &args) {
return "Unknown argument!";
}
}
} // namespace cmkr::args
} // namespace cmkr::args
const char *cmkr_args_handle_args(int argc, char **argv) {
return cmkr::args::handle_args(argc, argv);
}

@ -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

@ -1,8 +0,0 @@
#pragma once
#include <string>
#include <vector>
namespace cmkr::args {
std::string handle_args(std::vector<std::string> &args);
}

@ -1,4 +1,5 @@
#include "gen.hpp"
#include "gen.h"
#include <filesystem>
#include <fstream>
#include <map>
@ -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 <iostream>\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<std::string> 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

@ -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

@ -1,9 +0,0 @@
#pragma once
#include <string>
namespace cmkr::gen {
void generate_project(const std::string &str);
void generate_cmake();
} // namespace cmkr::gen

@ -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 <extra cmake args> 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();
}

@ -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

@ -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

@ -1,16 +1,12 @@
#include "args.hpp"
#include <iostream>
#include <string>
#include <vector>
#include "args.h"
int main(int argc, char **argv) try {
std::vector<std::string> args;
for (int i = 0; i < argc; ++i)
args.push_back(argv[i]);
#include <stdexcept>
#include <stdio.h>
#include <stdlib.h>
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());
}
Loading…
Cancel
Save