mirror of
https://github.com/build-cpp/cmkr
synced 2026-06-08 13:22:55 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 00121c261f | |||
| df41d3eaff | |||
| e29c408854 | |||
| 8d0c8678c4 | |||
| 369ef8f68d | |||
| 861bd59676 | |||
| 1d1ea3fdfd | |||
| f8ab24e0a2 | |||
| 16e68d7542 | |||
| 5dc71f9ba1 | |||
| ba2c52dd39 | |||
| 41b00b4f98 | |||
| b016d7139c | |||
| 473926bcfd | |||
| f29f9fa365 | |||
| 4c59ca75da | |||
| 1114aaca94 | |||
| 887f9e4ece | |||
| fa510bb00e | |||
| 31bf4e3e96 |
@@ -11,9 +11,9 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows-latest, macos-10.15]
|
||||
os: [windows-latest, macos-10.15, ubuntu-18.04]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: cmake -S. -Bbin && cmake --build bin --config $BUILD_TYPE
|
||||
run: cmake -S. -Bbin -DCMAKE_BUILD_TYPE=$BUILD_TYPE && cmake --build bin --parallel --config $BUILD_TYPE
|
||||
|
||||
+2
-1
@@ -4,4 +4,5 @@ compile_commands.json
|
||||
.clangd
|
||||
temp.*
|
||||
.vs
|
||||
.cache
|
||||
.cache
|
||||
build*/
|
||||
+19
-3
@@ -1,11 +1,27 @@
|
||||
# CHANGELOG
|
||||
|
||||
## 0.1.4 - 2021-04-11
|
||||
- Use `GIT_SHALLOW ON` by default when getting git dependencies.
|
||||
- Add cmake.description field.
|
||||
- Change bin.defines to bin.definitions.
|
||||
|
||||
## 0.1.3 - 2020-11-27
|
||||
- Support building with C++11.
|
||||
- @mrexodia implemented CMake integration and bootstrapping.
|
||||
- Add dependency on ghc_filesystem and mpark_variant which are fetched automatically using FetchContent.
|
||||
|
||||
## 0.1.2 - 2020-11-20
|
||||
- Add support for target properties.
|
||||
- Add installs.
|
||||
- Require cmake >= 3.15.
|
||||
- Support settings and caching settings.
|
||||
- Support config when running cmkr build.
|
||||
- Add prompt prior to CMakeLists.txt generation if already existent in the current dir.
|
||||
|
||||
## 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.
|
||||
- Require cmake >= 3.15.
|
||||
- Support testing.
|
||||
+40
-11
@@ -1,46 +1,74 @@
|
||||
# This file was generated automatically by cmkr.
|
||||
|
||||
# Regenerate CMakeLists.txt file when necessary
|
||||
include(cmkr.cmake OPTIONAL RESULT_VARIABLE CMKR_INCLUDE_RESULT)
|
||||
|
||||
if(CMKR_INCLUDE_RESULT)
|
||||
cmkr()
|
||||
endif()
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
project(cmkr VERSION 0.1.1)
|
||||
project(cmkr
|
||||
VERSION 0.1.4
|
||||
LANGUAGES C CXX
|
||||
DESCRIPTION "CMakeLists generator from TOML"
|
||||
)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
filesystem
|
||||
GIT_REPOSITORY https://github.com/gulrak/filesystem
|
||||
GIT_SHALLOW ON
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(filesystem)
|
||||
|
||||
FetchContent_Declare(
|
||||
mpark_variant
|
||||
URL https://github.com/mpark/variant/archive/v1.4.0.tar.gz
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(mpark_variant)
|
||||
|
||||
FetchContent_Declare(
|
||||
toml11
|
||||
GIT_REPOSITORY https://github.com/ToruNiina/toml11
|
||||
GIT_SHALLOW ON
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(toml11)
|
||||
|
||||
|
||||
set(CMKRLIB_SOURCES
|
||||
"src/cmake.cpp"
|
||||
"src/gen.cpp"
|
||||
"src/help.cpp"
|
||||
"src/build.cpp"
|
||||
"src/error.cpp"
|
||||
src/cmake.cpp
|
||||
src/gen.cpp
|
||||
src/help.cpp
|
||||
src/build.cpp
|
||||
src/error.cpp
|
||||
)
|
||||
|
||||
add_library(cmkrlib STATIC ${CMKRLIB_SOURCES})
|
||||
|
||||
target_include_directories(cmkrlib PUBLIC
|
||||
"include"
|
||||
include
|
||||
)
|
||||
|
||||
target_link_libraries(cmkrlib PUBLIC
|
||||
toml11::toml11
|
||||
ghc_filesystem
|
||||
mpark_variant
|
||||
)
|
||||
|
||||
target_compile_features(cmkrlib PUBLIC
|
||||
cxx_std_17
|
||||
cxx_std_11
|
||||
)
|
||||
|
||||
set(CMKR_SOURCES
|
||||
"src/main.cpp"
|
||||
"src/args.cpp"
|
||||
src/main.cpp
|
||||
src/args.cpp
|
||||
)
|
||||
|
||||
add_executable(cmkr ${CMKR_SOURCES})
|
||||
@@ -52,6 +80,7 @@ target_link_libraries(cmkr PUBLIC
|
||||
install(
|
||||
TARGETS cmkr
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
|
||||
COMPONENT cmkr
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@ cmkr, pronounced "cmaker", is A CMakeLists.txt generator from TOML.
|
||||
|
||||
|
||||
## Building
|
||||
cmkr requires a C++17 compiler, cmake >= 3.15.
|
||||
cmkr requires a C++11 compiler, cmake >= 3.15.
|
||||
```
|
||||
git clone https://github.com/moalyousef/cmkr
|
||||
cd cmkr
|
||||
cmake -Bbin
|
||||
cmake --build bin
|
||||
cmake --build bin --parallel
|
||||
```
|
||||
|
||||
## Usage
|
||||
@@ -35,18 +35,21 @@ minimum = "3.15"
|
||||
|
||||
[project]
|
||||
name = "cmkr"
|
||||
version = "0.1.0"
|
||||
version = "0.1.4"
|
||||
description = "CMakeLists generator from TOML"
|
||||
|
||||
[fetch-content]
|
||||
toml11 = { git = "https://github.com/ToruNiina/toml11" }
|
||||
filesystem = { git = "https://github.com/gulrak/filesystem" }
|
||||
mpark_variant = { url = "https://github.com/mpark/variant/archive/v1.4.0.tar.gz" }
|
||||
|
||||
[[bin]]
|
||||
name = "cmkrlib"
|
||||
type = "static"
|
||||
sources = ["src/cmake.cpp", "src/gen.cpp", "src/help.cpp", "src/build.cpp", "src/error.cpp"]
|
||||
include-dirs = ["include"]
|
||||
features = ["cxx_std_17"]
|
||||
link-libs = ["toml11::toml11"]
|
||||
features = ["cxx_std_11"]
|
||||
link-libs = ["toml11::toml11", "ghc_filesystem"]
|
||||
|
||||
[[bin]]
|
||||
name = "cmkr"
|
||||
@@ -63,13 +66,21 @@ Currently supported fields:
|
||||
```toml
|
||||
[cmake] # required for top-level project
|
||||
minimum = "3.15" # required
|
||||
description = "" # optional
|
||||
subdirs = [] # optional
|
||||
bin-dir = "bin" # optional
|
||||
cpp-flags = [] # optional
|
||||
c-flags = [] # optional
|
||||
link-flags = [] # optional
|
||||
generator = "Ninja" # optional
|
||||
arguments = ["CMAKE_TOOLCHAIN_FILE=/path/to/toolchain"] # optional
|
||||
generator = "Ninja" # optional, only valid when run using: cmkr build
|
||||
config = "Release" # optional, only valid when run using: cmkr build
|
||||
arguments = ["CMAKE_TOOLCHAIN_FILE=/path/to/toolchain"] # optional, valid when run using: cmkr build
|
||||
|
||||
[settings] # optional
|
||||
CMAKE_BUILD_TYPE = "Release"
|
||||
TOML_BUILD_TESTS = false # optional
|
||||
TOML_BUILD_DOCS = { value = false, comment = "builds dependency docs", cache = true, force = true } # optional
|
||||
OLD_VERSION = "0.1.1" # optional
|
||||
|
||||
[project] # required per project
|
||||
name = "app" # required
|
||||
@@ -93,8 +104,9 @@ sources = ["src/*.cpp"] # required, supports globbing
|
||||
include-dirs = ["include"] # optional
|
||||
alias = "" # optional
|
||||
features = [] # optional
|
||||
defines = [] # optional
|
||||
definitions = [] # optional
|
||||
link-libs = [] # optional
|
||||
properties = { PROPERTY1 = "property1", ... } # optional
|
||||
|
||||
[[test]] # optional, can define several
|
||||
name = "test1" # required
|
||||
|
||||
+6
-3
@@ -1,20 +1,23 @@
|
||||
[cmake]
|
||||
minimum = "3.15"
|
||||
description = "CMakeLists generator from TOML"
|
||||
|
||||
[project]
|
||||
name = "cmkr"
|
||||
version = "0.1.1"
|
||||
version = "0.1.4"
|
||||
|
||||
[fetch-content]
|
||||
toml11 = { git = "https://github.com/ToruNiina/toml11" }
|
||||
filesystem = { git = "https://github.com/gulrak/filesystem" }
|
||||
mpark_variant = { url = "https://github.com/mpark/variant/archive/v1.4.0.tar.gz" }
|
||||
|
||||
[[bin]]
|
||||
name = "cmkrlib"
|
||||
type = "static"
|
||||
sources = ["src/cmake.cpp", "src/gen.cpp", "src/help.cpp", "src/build.cpp", "src/error.cpp"]
|
||||
include-dirs = ["include"]
|
||||
features = ["cxx_std_17"]
|
||||
link-libs = ["toml11::toml11"]
|
||||
features = ["cxx_std_11"]
|
||||
link-libs = ["toml11::toml11", "ghc_filesystem", "mpark_variant"]
|
||||
|
||||
[[bin]]
|
||||
name = "cmkr"
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# This file was generated automatically by cmkr.
|
||||
|
||||
# Regenerate CMakeLists.txt file when necessary
|
||||
include(cmkr.cmake OPTIONAL RESULT_VARIABLE CMKR_INCLUDE_RESULT)
|
||||
|
||||
if(CMKR_INCLUDE_RESULT)
|
||||
cmkr()
|
||||
endif()
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
set(example_PROJECT_VERSION 0.1.0)
|
||||
project(example VERSION ${example_PROJECT_VERSION})
|
||||
|
||||
set(EXAMPLE_SOURCES
|
||||
src/example.cpp
|
||||
)
|
||||
|
||||
add_executable(example ${EXAMPLE_SOURCES})
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# This is a minimal example project used for testing the cmkr bootstrapping process
|
||||
|
||||
[cmake]
|
||||
minimum = "3.15"
|
||||
|
||||
[project]
|
||||
name = "example"
|
||||
version = "0.1.0"
|
||||
|
||||
[[bin]]
|
||||
name = "example"
|
||||
type = "exe"
|
||||
sources = ["src/example.cpp"]
|
||||
@@ -0,0 +1,112 @@
|
||||
include_guard()
|
||||
|
||||
# Disable cmkr if no cmake.toml file is found
|
||||
if(NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/cmake.toml)
|
||||
message(STATUS "[cmkr] Not found: ${CMAKE_CURRENT_LIST_DIR}/cmake.toml")
|
||||
macro(cmkr)
|
||||
endmacro()
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Add a build-time dependency on the contents of cmake.toml to regenerate the CMakeLists.txt when modified
|
||||
configure_file(${CMAKE_CURRENT_LIST_DIR}/cmake.toml ${CMAKE_CURRENT_BINARY_DIR}/cmake.toml COPYONLY)
|
||||
|
||||
# Helper macro to execute a process (COMMAND_ERROR_IS_FATAL ANY is 3.19 and higher)
|
||||
macro(cmkr_exec)
|
||||
execute_process(COMMAND ${ARGV} RESULT_VARIABLE CMKR_EXEC_RESULT)
|
||||
if(NOT CMKR_EXEC_RESULT EQUAL 0)
|
||||
message(FATAL_ERROR "cmkr_exec(${ARGV}) failed (exit code ${CMKR_EXEC_RESULT})")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Windows-specific hack (CMAKE_EXECUTABLE_PREFIX is not set at the moment)
|
||||
if(WIN32)
|
||||
set(CMKR_EXECUTABLE_NAME "cmkr.exe")
|
||||
else()
|
||||
set(CMKR_EXECUTABLE_NAME "cmkr")
|
||||
endif()
|
||||
|
||||
# Use cached cmkr if found
|
||||
if(DEFINED CACHE{CMKR_EXECUTABLE} AND EXISTS ${CMKR_EXECUTABLE})
|
||||
message(VERBOSE "[cmkr] Found cmkr: '${CMKR_EXECUTABLE}'")
|
||||
else()
|
||||
if(DEFINED CACHE{CMKR_EXECUTABLE})
|
||||
message(VERBOSE "[cmkr] '${CMKR_EXECUTABLE}' not found")
|
||||
endif()
|
||||
set(CMKR_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/_cmkr)
|
||||
set(CMKR_EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/_cmkr/bin/${CMKR_EXECUTABLE_NAME} CACHE INTERNAL "Full path to cmkr executable")
|
||||
if(NOT EXISTS ${CMKR_EXECUTABLE})
|
||||
message(VERBOSE "[cmkr] Bootstrapping '${CMKR_EXECUTABLE}'")
|
||||
message(STATUS "[cmkr] Fetching cmkr...")
|
||||
if(EXISTS ${CMKR_DIRECTORY})
|
||||
cmkr_exec(${CMAKE_COMMAND} -E rm -rf ${CMKR_DIRECTORY})
|
||||
endif()
|
||||
find_package(Git QUIET REQUIRED)
|
||||
set(CMKR_REPO "https://github.com/moalyousef/cmkr")
|
||||
cmkr_exec(${GIT_EXECUTABLE} clone ${CMKR_REPO} ${CMKR_DIRECTORY})
|
||||
cmkr_exec(${CMAKE_COMMAND} ${CMKR_DIRECTORY} -B${CMKR_DIRECTORY}/build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=${CMKR_DIRECTORY})
|
||||
cmkr_exec(${CMAKE_COMMAND} --build ${CMKR_DIRECTORY}/build --parallel --config Release)
|
||||
cmkr_exec(${CMAKE_COMMAND} --install ${CMKR_DIRECTORY}/build --config Release --prefix ${CMKR_DIRECTORY} --component cmkr)
|
||||
if(NOT EXISTS ${CMKR_EXECUTABLE})
|
||||
message(FATAL_ERROR "[cmkr] Failed to bootstrap '${CMKR_EXECUTABLE}'")
|
||||
endif()
|
||||
cmkr_exec(${CMKR_EXECUTABLE} version OUTPUT_VARIABLE CMKR_VERSION)
|
||||
string(STRIP ${CMKR_VERSION} CMKR_VERSION)
|
||||
message(STATUS "[cmkr] Bootstrapped ${CMKR_EXECUTABLE}")
|
||||
else()
|
||||
message(VERBOSE "[cmkr] Found cmkr: '${CMKR_EXECUTABLE}'")
|
||||
endif()
|
||||
endif()
|
||||
execute_process(COMMAND ${CMKR_EXECUTABLE} version
|
||||
OUTPUT_VARIABLE CMKR_VERSION
|
||||
RESULT_VARIABLE CMKR_EXEC_RESULT
|
||||
)
|
||||
if(NOT CMKR_EXEC_RESULT EQUAL 0)
|
||||
unset(CMKR_EXECUTABLE CACHE)
|
||||
message(FATAL_ERROR "[cmkr] Failed to get version, try clearing the cache and rebuilding")
|
||||
endif()
|
||||
string(STRIP ${CMKR_VERSION} CMKR_VERSION)
|
||||
message(STATUS "[cmkr] Using ${CMKR_VERSION}")
|
||||
|
||||
# This is the macro that contains black magic
|
||||
macro(cmkr)
|
||||
# When this macro is called from the generated file, fake some internal CMake variables
|
||||
get_source_file_property(CMKR_CURRENT_LIST_FILE ${CMAKE_CURRENT_LIST_FILE} CMKR_CURRENT_LIST_FILE)
|
||||
if(CMKR_CURRENT_LIST_FILE)
|
||||
set(CMAKE_CURRENT_LIST_FILE ${CMKR_CURRENT_LIST_FILE})
|
||||
get_filename_component(CMAKE_CURRENT_LIST_DIR ${CMAKE_CURRENT_LIST_FILE} DIRECTORY)
|
||||
endif()
|
||||
|
||||
# File-based include guard (include_guard is not documented to work)
|
||||
get_source_file_property(CMKR_INCLUDE_GUARD ${CMAKE_CURRENT_LIST_FILE} CMKR_INCLUDE_GUARD)
|
||||
if(NOT CMKR_INCLUDE_GUARD)
|
||||
set_source_files_properties(${CMAKE_CURRENT_LIST_FILE} PROPERTIES CMKR_INCLUDE_GUARD TRUE)
|
||||
|
||||
# Generate CMakeLists.txt
|
||||
cmkr_exec(${CMKR_EXECUTABLE} gen -y
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
|
||||
OUTPUT_VARIABLE CMKR_GEN_OUTPUT
|
||||
)
|
||||
string(STRIP ${CMKR_GEN_OUTPUT} CMKR_GEN_OUTPUT)
|
||||
message(STATUS "[cmkr] ${CMKR_GEN_OUTPUT}")
|
||||
|
||||
# Copy the now-generated CMakeLists.txt to CMakerLists.txt
|
||||
# This is done because you cannot include() a file you are currently in
|
||||
set(CMKR_TEMP_FILE ${CMAKE_CURRENT_LIST_DIR}/CMakerLists.txt)
|
||||
configure_file(CMakeLists.txt ${CMKR_TEMP_FILE} COPYONLY)
|
||||
|
||||
# Add the macro required for the hack at the start of the cmkr macro
|
||||
set_source_files_properties(${CMKR_TEMP_FILE} PROPERTIES
|
||||
CMKR_CURRENT_LIST_FILE ${CMAKE_CURRENT_LIST_FILE}
|
||||
)
|
||||
|
||||
# 'Execute' the newly-generated CMakeLists.txt
|
||||
include(${CMKR_TEMP_FILE})
|
||||
|
||||
# Delete the generated file
|
||||
file(REMOVE ${CMKR_TEMP_FILE})
|
||||
|
||||
# Do not execute the rest of the original CMakeLists.txt
|
||||
return()
|
||||
endif()
|
||||
endmacro()
|
||||
@@ -0,0 +1,6 @@
|
||||
#include <cstdio>
|
||||
|
||||
int main()
|
||||
{
|
||||
puts("Hello from cmkr!");
|
||||
}
|
||||
+5
-2
@@ -1,10 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace cmkr::args {
|
||||
namespace cmkr {
|
||||
namespace args {
|
||||
|
||||
const char *handle_args(int argc, char **argv);
|
||||
}
|
||||
|
||||
} // namespace args
|
||||
} // namespace cmkr
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
+4
-2
@@ -2,7 +2,8 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace cmkr::build {
|
||||
namespace cmkr {
|
||||
namespace build {
|
||||
|
||||
int run(int argc, char **argv);
|
||||
|
||||
@@ -10,7 +11,8 @@ int clean();
|
||||
|
||||
int install();
|
||||
|
||||
} // namespace cmkr::build
|
||||
} // namespace build
|
||||
} // namespace cmkr
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
+4
-2
@@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace cmkr::error {
|
||||
namespace cmkr {
|
||||
namespace error {
|
||||
|
||||
struct Status {
|
||||
enum class Code {
|
||||
@@ -21,7 +22,8 @@ struct Status {
|
||||
Code ec_ = Code::Success;
|
||||
};
|
||||
|
||||
} // namespace cmkr::error
|
||||
} // namespace error
|
||||
} // namespace cmkr
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
+4
-2
@@ -1,13 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace cmkr::gen {
|
||||
namespace cmkr {
|
||||
namespace gen {
|
||||
|
||||
int generate_project(const char *typ);
|
||||
|
||||
int generate_cmake(const char *path);
|
||||
|
||||
} // namespace cmkr::gen
|
||||
} // namespace gen
|
||||
} // namespace cmkr
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
+4
-2
@@ -1,13 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace cmkr::help {
|
||||
namespace cmkr {
|
||||
namespace help {
|
||||
|
||||
const char *version() noexcept;
|
||||
|
||||
const char *message() noexcept;
|
||||
|
||||
} // namespace cmkr::help
|
||||
} // namespace help
|
||||
} // namespace cmkr
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ sources = ["src/*.cpp"]
|
||||
include-dirs = ["include"]
|
||||
# alias = ""
|
||||
# features = []
|
||||
# defines = []
|
||||
# definitions = []
|
||||
# link-libs = []
|
||||
|
||||
[[install]]
|
||||
|
||||
+21
-4
@@ -3,13 +3,15 @@
|
||||
#include "gen.h"
|
||||
#include "help.h"
|
||||
|
||||
#include "fs.hpp"
|
||||
#include <exception>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace cmkr::args {
|
||||
namespace cmkr {
|
||||
namespace args {
|
||||
const char *handle_args(int argc, char **argv) {
|
||||
std::vector<std::string> args;
|
||||
for (int i = 0; i < argc; ++i)
|
||||
@@ -19,7 +21,21 @@ const char *handle_args(int argc, char **argv) {
|
||||
return "Please provide command line arguments!";
|
||||
std::string main_arg = args[1];
|
||||
if (main_arg == "gen") {
|
||||
auto ret = cmkr::gen::generate_cmake(std::filesystem::current_path().string().c_str());
|
||||
bool cont = false;
|
||||
if (args.size() > 2 && args[2] == "-y")
|
||||
cont = true;
|
||||
auto current_path = fs::current_path();
|
||||
if (fs::exists(current_path / "CMakeLists.txt") && cont == false) {
|
||||
std::cout
|
||||
<< "A CMakeLists.txt file already exists in the current directory.\nWould you "
|
||||
"like to overwrite it?[y/n]"
|
||||
<< std::endl;
|
||||
std::string resp;
|
||||
std::cin >> resp;
|
||||
if (resp != "y")
|
||||
return "CMake generation aborted!";
|
||||
}
|
||||
auto ret = cmkr::gen::generate_cmake(current_path.string().c_str());
|
||||
if (ret)
|
||||
return "CMake generation error!";
|
||||
return "CMake generation successful!";
|
||||
@@ -54,7 +70,8 @@ const char *handle_args(int argc, char **argv) {
|
||||
return "Unknown argument!";
|
||||
}
|
||||
}
|
||||
} // namespace cmkr::args
|
||||
} // namespace args
|
||||
} // namespace cmkr
|
||||
|
||||
const char *cmkr_args_handle_args(int argc, char **argv) {
|
||||
try {
|
||||
|
||||
+10
-8
@@ -3,16 +3,15 @@
|
||||
#include "error.h"
|
||||
#include "gen.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include "fs.hpp"
|
||||
#include <sstream>
|
||||
#include <stddef.h>
|
||||
#include <stdexcept>
|
||||
#include <stdlib.h>
|
||||
#include <system_error>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace cmkr::build {
|
||||
namespace cmkr {
|
||||
namespace build {
|
||||
|
||||
int run(int argc, char **argv) {
|
||||
cmake::CMake cmake(".", true);
|
||||
@@ -25,19 +24,22 @@ int run(int argc, char **argv) {
|
||||
|
||||
if (!fs::exists("CMakeLists.txt"))
|
||||
if (gen::generate_cmake("."))
|
||||
throw std::runtime_error("CMake generation failure!");
|
||||
throw std::runtime_error("[cmkr] error: CMake generation failure!");
|
||||
|
||||
ss << "cmake -S. -B" << cmake.bin_dir << " ";
|
||||
|
||||
if (!cmake.generator.empty()) {
|
||||
ss << "-G \"" << cmake.generator << "\" ";
|
||||
}
|
||||
if (!cmake.config.empty()) {
|
||||
ss << "-DCMAKE_BUILD_TYPE=" << cmake.config << " ";
|
||||
}
|
||||
if (!cmake.gen_args.empty()) {
|
||||
for (const auto &arg : cmake.gen_args) {
|
||||
ss << "-D" << arg << " ";
|
||||
}
|
||||
}
|
||||
ss << "&& cmake --build " << cmake.bin_dir;
|
||||
ss << "&& cmake --build " << cmake.bin_dir << " --parallel";
|
||||
if (argc > 2) {
|
||||
for (const auto &arg : cmake.build_args) {
|
||||
ss << " " << arg;
|
||||
@@ -62,8 +64,8 @@ int install() {
|
||||
auto cmd = "cmake --install " + cmake.bin_dir;
|
||||
return ::system(cmd.c_str());
|
||||
}
|
||||
|
||||
} // namespace cmkr::build
|
||||
} // namespace build
|
||||
} // namespace cmkr
|
||||
|
||||
int cmkr_build_run(int argc, char **argv) {
|
||||
try {
|
||||
|
||||
+56
-8
@@ -1,12 +1,11 @@
|
||||
#include "cmake.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include "fs.hpp"
|
||||
#include <stdexcept>
|
||||
#include <toml.hpp>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace cmkr::cmake {
|
||||
namespace cmkr {
|
||||
namespace cmake {
|
||||
|
||||
namespace detail {
|
||||
std::vector<std::string> to_string_vec(
|
||||
@@ -21,7 +20,7 @@ std::vector<std::string> to_string_vec(
|
||||
|
||||
CMake::CMake(const std::string &path, bool build) {
|
||||
if (!fs::exists(fs::path(path) / "cmake.toml")) {
|
||||
throw std::runtime_error("No cmake.toml was found!");
|
||||
throw std::runtime_error("[cmkr] error: No cmake.toml was found!");
|
||||
}
|
||||
const auto toml = toml::parse((fs::path(path) / "cmake.toml").string());
|
||||
if (build) {
|
||||
@@ -36,6 +35,10 @@ CMake::CMake(const std::string &path, bool build) {
|
||||
generator = toml::find(cmake, "generator").as_string();
|
||||
}
|
||||
|
||||
if (cmake.contains("config")) {
|
||||
config = toml::find(cmake, "config").as_string();
|
||||
}
|
||||
|
||||
if (cmake.contains("arguments")) {
|
||||
gen_args = detail::to_string_vec(toml::find(cmake, "arguments").as_array());
|
||||
}
|
||||
@@ -45,6 +48,10 @@ CMake::CMake(const std::string &path, bool build) {
|
||||
const auto &cmake = toml::find(toml, "cmake");
|
||||
cmake_version = toml::find(cmake, "minimum").as_string();
|
||||
|
||||
if (cmake.contains("description")) {
|
||||
desc = toml::find(cmake, "description").as_string();
|
||||
}
|
||||
|
||||
if (cmake.contains("cpp-flags")) {
|
||||
cppflags = detail::to_string_vec(toml::find(cmake, "cpp-flags").as_array());
|
||||
}
|
||||
@@ -68,6 +75,41 @@ CMake::CMake(const std::string &path, bool build) {
|
||||
proj_version = toml::find(project, "version").as_string();
|
||||
}
|
||||
|
||||
if (toml.contains("settings")) {
|
||||
using set_map =
|
||||
std::map<std::string, toml::basic_value<toml::discard_comments, std::unordered_map,
|
||||
std::vector>>;
|
||||
const auto &sets = toml::find<set_map>(toml, "settings");
|
||||
for (const auto set : sets) {
|
||||
Setting s;
|
||||
s.name = set.first;
|
||||
if (set.second.is_boolean()) {
|
||||
s.val = set.second.as_boolean();
|
||||
} else if (set.second.is_string()) {
|
||||
s.val = set.second.as_string();
|
||||
} else {
|
||||
if (set.second.contains("comment")) {
|
||||
s.comment = toml::find(set.second, "comment").as_string();
|
||||
}
|
||||
if (set.second.contains("value")) {
|
||||
auto v = toml::find(set.second, "value");
|
||||
if (v.is_boolean()) {
|
||||
s.val = v.as_boolean();
|
||||
} else {
|
||||
s.val = v.as_string();
|
||||
}
|
||||
}
|
||||
if (set.second.contains("cache")) {
|
||||
s.cache = toml::find(set.second, "cache").as_boolean();
|
||||
}
|
||||
if (set.second.contains("force")) {
|
||||
s.force = toml::find(set.second, "force").as_boolean();
|
||||
}
|
||||
}
|
||||
settings.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
if (toml.contains("options")) {
|
||||
using opts_map =
|
||||
std::map<std::string, toml::basic_value<toml::discard_comments, std::unordered_map,
|
||||
@@ -144,14 +186,19 @@ CMake::CMake(const std::string &path, bool build) {
|
||||
b.features = detail::to_string_vec(toml::find(bin, "features").as_array());
|
||||
}
|
||||
|
||||
if (bin.contains("defines")) {
|
||||
b.defines = detail::to_string_vec(toml::find(bin, "defines").as_array());
|
||||
if (bin.contains("definitions")) {
|
||||
b.defines = detail::to_string_vec(toml::find(bin, "definitions").as_array());
|
||||
}
|
||||
|
||||
if (bin.contains("alias")) {
|
||||
b.alias = toml::find(bin, "alias").as_string();
|
||||
}
|
||||
|
||||
if (bin.contains("properties")) {
|
||||
using prop_map = std::map<std::string, std::string>;
|
||||
b.properties = toml::find<prop_map>(bin, "properties");
|
||||
}
|
||||
|
||||
binaries.push_back(b);
|
||||
}
|
||||
}
|
||||
@@ -191,4 +238,5 @@ CMake::CMake(const std::string &path, bool build) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace cmkr::cmake
|
||||
} // namespace cmake
|
||||
} // namespace cmkr
|
||||
|
||||
+18
-2
@@ -1,10 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <mpark/variant.hpp>
|
||||
|
||||
namespace cmkr::cmake {
|
||||
namespace cmkr {
|
||||
namespace cmake {
|
||||
|
||||
struct Setting {
|
||||
std::string name;
|
||||
std::string comment;
|
||||
mpark::variant<bool, std::string> val;
|
||||
bool cache = false;
|
||||
bool force = false;
|
||||
};
|
||||
|
||||
struct Option {
|
||||
std::string name;
|
||||
@@ -28,6 +39,7 @@ struct Bin {
|
||||
std::vector<std::string> defines;
|
||||
std::vector<std::string> link_libs;
|
||||
std::string alias;
|
||||
std::map<std::string, std::string> properties;
|
||||
};
|
||||
|
||||
struct Test {
|
||||
@@ -46,8 +58,10 @@ struct Install {
|
||||
|
||||
struct CMake {
|
||||
std::string cmake_version = "3.15";
|
||||
std::string desc;
|
||||
std::string bin_dir = "bin";
|
||||
std::string generator;
|
||||
std::string config;
|
||||
std::vector<std::string> subdirs;
|
||||
std::vector<std::string> cppflags;
|
||||
std::vector<std::string> cflags;
|
||||
@@ -56,6 +70,7 @@ struct CMake {
|
||||
std::vector<std::string> build_args;
|
||||
std::string proj_name;
|
||||
std::string proj_version;
|
||||
std::vector<Setting> settings;
|
||||
std::vector<Option> options;
|
||||
std::vector<Package> packages;
|
||||
std::map<std::string, std::map<std::string, std::string>> contents;
|
||||
@@ -65,4 +80,5 @@ struct CMake {
|
||||
CMake(const std::string &path, bool build);
|
||||
};
|
||||
|
||||
} // namespace cmkr::cmake
|
||||
} // namespace cmake
|
||||
} // namespace cmkr
|
||||
+4
-2
@@ -2,7 +2,8 @@
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
namespace cmkr::error {
|
||||
namespace cmkr {
|
||||
namespace error {
|
||||
|
||||
Status::Status(Code ec) noexcept : ec_(ec) {}
|
||||
|
||||
@@ -10,7 +11,8 @@ Status::operator int() const noexcept { return static_cast<int>(ec_); }
|
||||
|
||||
Status::Code Status::code() const noexcept { return ec_; }
|
||||
|
||||
} // namespace cmkr::error
|
||||
} // namespace error
|
||||
} // namespace cmkr
|
||||
|
||||
const char *err_string[] = {
|
||||
"Success", "Runtime error", "Initialization error", "CMake generation error", "Build error",
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || \
|
||||
(defined(__cplusplus) && __cplusplus >= 201703L)) && \
|
||||
defined(__has_include)
|
||||
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
|
||||
#define GHC_USE_STD_FS
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
#endif
|
||||
#endif
|
||||
#ifndef GHC_USE_STD_FS
|
||||
#include <ghc/filesystem.hpp>
|
||||
namespace fs = ghc::filesystem;
|
||||
#endif
|
||||
+82
-24
@@ -3,7 +3,7 @@
|
||||
#include "error.h"
|
||||
#include "literals.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include "fs.hpp"
|
||||
#include <fstream>
|
||||
#include <new>
|
||||
#include <sstream>
|
||||
@@ -12,9 +12,8 @@
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace cmkr::gen {
|
||||
namespace cmkr {
|
||||
namespace gen {
|
||||
|
||||
namespace detail {
|
||||
|
||||
@@ -33,23 +32,27 @@ std::string format(const char *fmt, Args... args) {
|
||||
char *buf = new char[sz];
|
||||
int ret = snprintf(buf, sz, fmt, args...);
|
||||
if (ret != sz - 1)
|
||||
throw std::runtime_error("Error formatting string!");
|
||||
throw std::runtime_error("[cmkr] error: Error formatting string!");
|
||||
std::string temp(buf, buf + sz - 1);
|
||||
delete[] buf;
|
||||
return temp;
|
||||
}
|
||||
|
||||
std::vector<fs::path> expand_path(const fs::path &p) {
|
||||
std::vector<fs::path> temp;
|
||||
static std::vector<std::string> expand_cmake_path(const fs::path &p) {
|
||||
std::vector<std::string> 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());
|
||||
temp.push_back(f.path().string());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
temp.push_back(p);
|
||||
temp.push_back(p.string());
|
||||
}
|
||||
// Normalize all paths to work with CMake (it needs a / on Windows as well)
|
||||
for (auto &path : temp) {
|
||||
std::replace(path.begin(), path.end(), '\\', '/');
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
@@ -80,7 +83,7 @@ int generate_project(const char *str) {
|
||||
dest = "include/" + dir_name;
|
||||
} else {
|
||||
throw std::runtime_error(
|
||||
"Unknown project type. Types are exe, lib, shared, static, interface!");
|
||||
"[cmkr] 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,
|
||||
@@ -109,7 +112,15 @@ int generate_cmake(const char *path) {
|
||||
if (fs::exists(fs::path(path) / "cmake.toml")) {
|
||||
cmake::CMake cmake(path, false);
|
||||
std::stringstream ss;
|
||||
ss << "# This file was generated automatically by cmkr.\n\n";
|
||||
ss << "# This file was generated automatically by cmkr.\n";
|
||||
ss << "\n";
|
||||
|
||||
ss << "# Regenerate CMakeLists.txt file when necessary\n";
|
||||
ss << "include(cmkr.cmake OPTIONAL RESULT_VARIABLE CMKR_INCLUDE_RESULT)\n\n";
|
||||
ss << "if(CMKR_INCLUDE_RESULT)\n";
|
||||
ss << "\tcmkr()\n";
|
||||
ss << "endif()\n";
|
||||
ss << "\n";
|
||||
|
||||
if (!cmake.cmake_version.empty()) {
|
||||
ss << "cmake_minimum_required(VERSION " << cmake.cmake_version << ")\n\n";
|
||||
@@ -148,8 +159,13 @@ int generate_cmake(const char *path) {
|
||||
ss << "\n\n";
|
||||
}
|
||||
|
||||
std::string desc = "";
|
||||
if (!cmake.desc.empty())
|
||||
desc = "\n\tLANGUAGES C CXX\n\tDESCRIPTION \"" + cmake.desc + "\"";
|
||||
|
||||
if (!cmake.proj_name.empty() && !cmake.proj_version.empty()) {
|
||||
ss << "project(" << cmake.proj_name << " VERSION " << cmake.proj_version << ")\n\n";
|
||||
ss << "project(" << cmake.proj_name << "\n\tVERSION " << cmake.proj_version << desc
|
||||
<< "\n\t)\n\n";
|
||||
}
|
||||
|
||||
if (!cmake.packages.empty()) {
|
||||
@@ -182,9 +198,9 @@ int generate_cmake(const char *path) {
|
||||
} else if (first_arg == "tag") {
|
||||
first_arg = "GIT_TAG";
|
||||
} else if (first_arg == "svn") {
|
||||
first_arg == "SVN_REPOSITORY";
|
||||
first_arg = "SVN_REPOSITORY";
|
||||
} else if (first_arg == "rev") {
|
||||
first_arg == "SVN_REVISION";
|
||||
first_arg = "SVN_REVISION";
|
||||
} else if (first_arg == "url") {
|
||||
first_arg = "URL";
|
||||
} else if (first_arg == "hash") {
|
||||
@@ -192,7 +208,12 @@ int generate_cmake(const char *path) {
|
||||
} else {
|
||||
// don't change arg
|
||||
}
|
||||
ss << "\t" << first_arg << " " << arg.second << "\n";
|
||||
if (first_arg != "GIT_REPOSITORY")
|
||||
ss << "\t" << first_arg << " " << arg.second << "\n";
|
||||
else
|
||||
ss << "\t" << first_arg << " " << arg.second << "\n\t"
|
||||
<< "GIT_SHALLOW "
|
||||
<< "ON\n";
|
||||
}
|
||||
ss << "\t)\n\n"
|
||||
<< "FetchContent_MakeAvailable(" << dep.first << ")\n\n";
|
||||
@@ -202,11 +223,33 @@ int generate_cmake(const char *path) {
|
||||
if (!cmake.options.empty()) {
|
||||
for (const auto &opt : cmake.options) {
|
||||
ss << "option(" << opt.name << " \"" << opt.comment << "\" "
|
||||
<< (opt.val ? "ON" : "OFF") << ")\n";
|
||||
<< (opt.val ? "ON" : "OFF") << ")\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
ss << "\n";
|
||||
if (!cmake.settings.empty()) {
|
||||
for (const auto &set : cmake.settings) {
|
||||
std::string set_val;
|
||||
if (set.val.index() == 1) {
|
||||
set_val = mpark::get<1>(set.val);
|
||||
} else {
|
||||
set_val = mpark::get<0>(set.val) ? "ON" : "OFF";
|
||||
}
|
||||
ss << "set(" << set.name << " " << set_val;
|
||||
;
|
||||
if (set.cache) {
|
||||
std::string typ;
|
||||
if (set.val.index() == 1)
|
||||
typ = "STRING";
|
||||
else
|
||||
typ = "BOOL";
|
||||
ss << " CACHE " << typ << " \"" << set.comment << "\"";
|
||||
if (set.force)
|
||||
ss << " FORCE";
|
||||
}
|
||||
ss << ")\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (!cmake.binaries.empty()) {
|
||||
for (const auto &bin : cmake.binaries) {
|
||||
@@ -223,15 +266,15 @@ int generate_cmake(const char *path) {
|
||||
bin_type = "";
|
||||
add_command = "add_library";
|
||||
} else {
|
||||
throw std::runtime_error(
|
||||
"Unknown binary type! Supported types are exe, shared and static");
|
||||
throw std::runtime_error("[cmkr] error: Unknown binary type! Supported types "
|
||||
"are exe, lib, shared, static, interface");
|
||||
}
|
||||
|
||||
if (!bin.sources.empty()) {
|
||||
ss << "set(" << detail::to_upper(bin.name) << "_SOURCES\n";
|
||||
for (const auto &src : bin.sources) {
|
||||
auto path = fs::path(src);
|
||||
auto expanded = detail::expand_path(path);
|
||||
auto expanded = detail::expand_cmake_path(path);
|
||||
for (const auto &f : expanded) {
|
||||
ss << "\t" << f << "\n";
|
||||
}
|
||||
@@ -254,7 +297,7 @@ int generate_cmake(const char *path) {
|
||||
if (!bin.include_dirs.empty()) {
|
||||
ss << "target_include_directories(" << bin.name << " PUBLIC\n\t";
|
||||
for (const auto &inc : bin.include_dirs) {
|
||||
ss << fs::path(inc) << "\n\t";
|
||||
ss << fs::path(inc).string() << "\n\t";
|
||||
}
|
||||
ss << ")\n\n";
|
||||
}
|
||||
@@ -282,6 +325,14 @@ int generate_cmake(const char *path) {
|
||||
}
|
||||
ss << ")\n\n";
|
||||
}
|
||||
|
||||
if (!bin.properties.empty()) {
|
||||
ss << "set_target_properties(" << bin.name << " PROPERTIES\n";
|
||||
for (const auto &prop : bin.properties) {
|
||||
ss << "\t" << prop.first << " " << prop.second << "\n";
|
||||
}
|
||||
ss << "\t)\n\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,7 +368,7 @@ int generate_cmake(const char *path) {
|
||||
if (!inst.files.empty()) {
|
||||
ss << "\tFILES ";
|
||||
for (const auto &file : inst.files) {
|
||||
auto path = detail::expand_path(fs::path(file));
|
||||
auto path = detail::expand_cmake_path(fs::path(file));
|
||||
for (const auto &f : path)
|
||||
ss << f << " ";
|
||||
}
|
||||
@@ -328,7 +379,11 @@ int generate_cmake(const char *path) {
|
||||
ss << conf << " ";
|
||||
}
|
||||
}
|
||||
ss << "\n\tDESTINATION " << inst.destination << "\n\t)\n\n";
|
||||
ss << "\n\tDESTINATION " << inst.destination << "\n\t";
|
||||
if (!inst.targets.empty())
|
||||
ss << "COMPONENT " << inst.targets[0] << "\n\t)\n\n";
|
||||
else
|
||||
ss << "\n\t)\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,10 +401,13 @@ int generate_cmake(const char *path) {
|
||||
if (fs::exists(fs::path(sub) / "cmake.toml"))
|
||||
generate_cmake(sub.c_str());
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error("[cmkr] error: No cmake.toml found!");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} // namespace cmkr::gen
|
||||
} // namespace gen
|
||||
} // namespace cmkr
|
||||
|
||||
int cmkr_gen_generate_project(const char *typ) {
|
||||
try {
|
||||
|
||||
+5
-3
@@ -1,8 +1,9 @@
|
||||
#include "help.h"
|
||||
|
||||
namespace cmkr::help {
|
||||
namespace cmkr {
|
||||
namespace help {
|
||||
|
||||
const char *version() noexcept { return "cmkr version 0.1.0"; }
|
||||
const char *version() noexcept { return "cmkr version 0.1.3"; }
|
||||
|
||||
const char *message() noexcept {
|
||||
return R"lit(
|
||||
@@ -17,7 +18,8 @@ arguments:
|
||||
version Current cmkr version.
|
||||
)lit";
|
||||
}
|
||||
} // namespace cmkr::help
|
||||
} // namespace help
|
||||
} // namespace cmkr
|
||||
|
||||
const char *cmkr_help_version(void) { return cmkr::help::version(); }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user