diff --git a/.clang-format b/.clang-format index b89d8a4..f6341fd 100644 --- a/.clang-format +++ b/.clang-format @@ -72,7 +72,7 @@ PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 60 PointerAlignment: Right ReflowComments: true -SortIncludes: true +SortIncludes: false SortUsingDeclarations: true SpaceAfterCStyleCast: false SpaceAfterTemplateKeyword: true diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5af2eb9..29c5e61 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,13 +10,20 @@ jobs: strategy: fail-fast: false matrix: - os: [windows-2019, macos-10.15, ubuntu-20.04] + os: [windows-2022, macos-11, ubuntu-20.04] env: - BUILD_TYPE: Release + BUILD_TYPE: 'Release' + CMAKE_GENERATOR: 'Ninja' steps: - name: Checkout uses: actions/checkout@v3 + - name: Install Ninja + uses: seanmiddleditch/gha-setup-ninja@6263846cf3c17009dfc81604efabae16044fc074 # master + + - name: Visual Studio Development Environment + uses: ilammy/msvc-dev-cmd@cec98b9d092141f74527d0afa6feb2af698cfe89 # v1.12.1 + - name: Tag cmkr.cmake if: ${{ startsWith(github.ref, 'refs/tags/') }} run: cmake -P "cmake/replace_tag.cmake" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..4815039 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,27 @@ +name: lint + +on: [push] + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: clang-format + id: clang-format + uses: DoozyX/clang-format-lint-action@c3b2c943e924028b93a707a5b1b017976ab8d50c # v0.15 + with: + exclude: './third_party' + extensions: 'c,h,cpp,hpp' + clangFormatVersion: 15 + style: file + + - name: clang-format instructions + if: ${{ failure() && steps.clang-format.outcome == 'failure' }} + run: | + # Instructions for fixing the formatting errors + echo -e "\n\033[0;31mTo fix the formatting, run:\nclang-format -style=file -i \$(git ls-files \"*.c\" \"*.h\" \"*.cpp\" \"*.hpp\")\033[0m\n" + exit 1 \ No newline at end of file diff --git a/.gitignore b/.gitignore index a1b9f9c..088450b 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ build*/ .idea/ cmake-build*/ CMakeLists.txt.user -.vscode/ \ No newline at end of file +.vscode/ +.DS_Store \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ad0953..3f15d88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,14 +61,12 @@ set(cmkr_SOURCES "src/arguments.cpp" "src/build.cpp" "src/cmake_generator.cpp" - "src/error.cpp" "src/help.cpp" "src/main.cpp" "src/project_parser.cpp" "include/arguments.hpp" "include/build.hpp" "include/cmake_generator.hpp" - "include/error.hpp" "include/fs.hpp" "include/help.hpp" "include/literals.hpp" diff --git a/include/build.hpp b/include/build.hpp index 068d2b0..5c159e6 100644 --- a/include/build.hpp +++ b/include/build.hpp @@ -11,9 +11,3 @@ int install(); } // namespace build } // namespace cmkr - -int cmkr_build_run(int argc, char **argv); - -int cmkr_build_clean(); - -int cmkr_build_install(); diff --git a/include/error.hpp b/include/error.hpp deleted file mode 100644 index a7b3e3d..0000000 --- a/include/error.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -namespace cmkr { -namespace error { - -struct Status { - enum class Code { - Success = 0, - RuntimeError, - InitError, - GenerationError, - BuildError, - CleanError, - InstallError, - }; - Status(Code ec) noexcept; - operator int() const noexcept; - Code code() const noexcept; - - private: - Code ec_ = Code::Success; -}; - -} // namespace error -} // namespace cmkr - -const char *cmkr_error_status_string(int); diff --git a/include/fs.hpp b/include/fs.hpp index 58f6e92..9b2c3e5 100644 --- a/include/fs.hpp +++ b/include/fs.hpp @@ -1,8 +1,6 @@ #pragma once -#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || \ - (defined(__cplusplus) && __cplusplus >= 201703L)) && \ - defined(__has_include) +#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include) #if __has_include() && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) #define GHC_USE_STD_FS #include diff --git a/include/help.hpp b/include/help.hpp index a2da1b4..e5ac201 100644 --- a/include/help.hpp +++ b/include/help.hpp @@ -9,7 +9,3 @@ const char *message() noexcept; } // namespace help } // namespace cmkr - -const char *cmkr_help_version(void); - -const char *cmkr_help_message(void); diff --git a/include/project_parser.hpp b/include/project_parser.hpp index 0fc5e9f..7b7a855 100644 --- a/include/project_parser.hpp +++ b/include/project_parser.hpp @@ -1,10 +1,11 @@ #pragma once -#include +#include #include + +#include #include #include -#include namespace cmkr { namespace parser { @@ -47,6 +48,10 @@ struct Vcpkg { }; std::vector packages; + + bool enabled() const { + return !packages.empty(); + } }; enum TargetType { diff --git a/src/arguments.cpp b/src/arguments.cpp index 952b28a..96a4520 100644 --- a/src/arguments.cpp +++ b/src/arguments.cpp @@ -2,10 +2,8 @@ #include "build.hpp" #include "cmake_generator.hpp" #include "help.hpp" - #include "fs.hpp" -#include -#include + #include #include #include diff --git a/src/build.cpp b/src/build.cpp index cd95544..fe2a0a6 100644 --- a/src/build.cpp +++ b/src/build.cpp @@ -1,14 +1,10 @@ #include "build.hpp" #include "cmake_generator.hpp" -#include "error.hpp" #include "project_parser.hpp" #include "fs.hpp" -#include #include #include -#include -#include namespace cmkr { namespace build { @@ -17,7 +13,7 @@ int run(int argc, char **argv) { parser::Project project(nullptr, ".", true); if (argc > 2) { for (int i = 2; i < argc; ++i) { - project.build_args.push_back(argv[i]); + project.build_args.emplace_back(argv[i]); } } std::stringstream ss; @@ -48,13 +44,13 @@ int run(int argc, char **argv) { } int clean() { - bool ret = false; + bool success = false; parser::Project project(nullptr, ".", true); if (fs::exists(project.build_dir)) { - ret = fs::remove_all(project.build_dir); + success = fs::remove_all(project.build_dir); fs::create_directory(project.build_dir); } - return !ret; + return success ? EXIT_SUCCESS : EXIT_FAILURE; } int install() { @@ -64,33 +60,3 @@ int install() { } } // namespace build } // namespace cmkr - -int cmkr_build_run(int argc, char **argv) { - try { - return cmkr::build::run(argc, argv); - } catch (const std::system_error &e) { - return e.code().value(); - } catch (...) { - return cmkr::error::Status(cmkr::error::Status::Code::BuildError); - } -} - -int cmkr_build_clean(void) { - try { - return cmkr::build::clean(); - } catch (const std::system_error &e) { - return e.code().value(); - } catch (...) { - 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); - } -} diff --git a/src/cmake_generator.cpp b/src/cmake_generator.cpp index f11d0c2..712a64a 100644 --- a/src/cmake_generator.cpp +++ b/src/cmake_generator.cpp @@ -1,15 +1,14 @@ #include "cmake_generator.hpp" -#include "error.hpp" #include "literals.hpp" #include #include "fs.hpp" #include "project_parser.hpp" #include -#include #include #include #include +#include namespace cmkr { namespace gen { @@ -43,7 +42,7 @@ static tsl::ordered_map> known_languages = {"Swift", {".swift"}}, }; -static std::string format(const char *format, tsl::ordered_map variables) { +static std::string format(const char *format, const tsl::ordered_map &variables) { std::string s = format; for (const auto &itr : variables) { size_t start_pos = 0; @@ -249,7 +248,7 @@ void generate_project(const std::string &type) { struct CommandEndl { std::stringstream &ss; - CommandEndl(std::stringstream &ss) : ss(ss) { + explicit CommandEndl(std::stringstream &ss) : ss(ss) { } void endl() { ss << '\n'; @@ -258,7 +257,7 @@ struct CommandEndl { struct RawArg { RawArg() = default; - RawArg(std::string arg) : arg(std::move(arg)) { + explicit RawArg(std::string arg) : arg(std::move(arg)) { } std::string arg; @@ -293,7 +292,7 @@ struct Command { // https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#unquoted-argument // NOTE: Normally '/' does not require quoting according to the documentation but this has been the case here // previously, so for backwards compatibility its still here. - if (str.find_first_of("()#\"\\'> |/;") == str.npos) + if (str.find_first_of("()#\"\\'> |/;") == std::string::npos) return str; std::string result; result += "\""; @@ -442,10 +441,10 @@ static std::string tolf(const std::string &str) { } } return result; -}; +} struct Generator { - Generator(const parser::Project &project, const fs::path &path) : project(project), path(path) { + Generator(const parser::Project &project, fs::path path) : project(project), path(std::move(path)) { } Generator(const Generator &) = delete; @@ -786,7 +785,11 @@ void generate_cmake(const char *path, const parser::Project *parent_project) { gen.conditional_includes(project.include_after); gen.conditional_cmake(project.cmake_after); - if (!project.vcpkg.packages.empty()) { + if (project.vcpkg.enabled()) { + if (!is_root_project) { + throw std::runtime_error("[vcpkg] is only supported in the root project"); + } + // Allow the user to specify a url or derive it from the version auto url = project.vcpkg.url; auto version_name = url; @@ -799,7 +802,8 @@ void generate_cmake(const char *path, const parser::Project *parent_project) { } // Show a nicer error than vcpkg when specifying an invalid package name - for (const auto &package : project.vcpkg.packages) { + const auto &packages = project.vcpkg.packages; + for (const auto &package : packages) { if (!vcpkg_valid_identifier(package.name)) { throw std::runtime_error("Invalid [vcpkg].packages name '" + package.name + "' (needs to be lowercase alphanumeric)"); } @@ -809,14 +813,20 @@ void generate_cmake(const char *path, const parser::Project *parent_project) { // clang-format off cmd("if")("CMKR_ROOT_PROJECT", "AND", "NOT", "CMKR_DISABLE_VCPKG"); cmd("include")("FetchContent"); - cmd("message")("STATUS", "Fetching vcpkg (" + version_name + ")..."); - cmd("FetchContent_Declare")("vcpkg", "URL", url); - // Not using FetchContent_MakeAvailable here in case vcpkg adds CMakeLists.txt - cmd("FetchContent_GetProperties")("vcpkg"); - cmd("if")("NOT", "vcpkg_POPULATED"); - cmd("FetchContent_Populate")("vcpkg"); - cmd("include")("${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake"); + comment("Fix warnings about DOWNLOAD_EXTRACT_TIMESTAMP"); + // clang-format off + cmd("if")("POLICY", "CMP0135"); + cmd("cmake_policy")("SET", "CMP0135", "NEW"); cmd("endif")(); + // clang-format on + cmd("message")("STATUS", "Fetching vcpkg (" + version_name + ")..."); + cmd("FetchContent_Declare")("vcpkg", "URL", url); + // Not using FetchContent_MakeAvailable here in case vcpkg adds CMakeLists.txt + cmd("FetchContent_GetProperties")("vcpkg"); + cmd("if")("NOT", "vcpkg_POPULATED"); + cmd("FetchContent_Populate")("vcpkg"); + cmd("include")("${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake"); + cmd("endif")(); cmd("endif")(); endl(); // clang-format on @@ -833,7 +843,6 @@ void generate_cmake(const char *path, const parser::Project *parent_project) { "dependencies": [ )"; - const auto &packages = project.vcpkg.packages; for (size_t i = 0; i < packages.size(); i++) { const auto &package = packages[i]; const auto &features = package.features; @@ -887,13 +896,21 @@ void generate_cmake(const char *path, const parser::Project *parent_project) { if (!project.contents.empty()) { cmd("include")("FetchContent").endl(); + if (!project.root()->vcpkg.enabled()) { + comment("Fix warnings about DOWNLOAD_EXTRACT_TIMESTAMP"); + // clang-format off + cmd("if")("POLICY", "CMP0135"); + cmd("cmake_policy")("SET", "CMP0135", "NEW"); + cmd("endif")(); + // clang-format on + } for (const auto &content : project.contents) { ConditionScope cs(gen, content.condition); gen.conditional_includes(content.include_before); gen.conditional_cmake(content.cmake_before); - std::string version_info = ""; + std::string version_info; if (content.arguments.contains("GIT_TAG")) { version_info = " (" + content.arguments.at("GIT_TAG") + ")"; } else if (content.arguments.contains("SVN_REVISION")) { diff --git a/src/error.cpp b/src/error.cpp deleted file mode 100644 index 2fe3081..0000000 --- a/src/error.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "error.hpp" - -#include -#include - -namespace cmkr { -namespace error { - -Status::Status(Code ec) noexcept : ec_(ec) { -} - -Status::operator int() const noexcept { - return static_cast(ec_); -} - -Status::Code Status::code() const noexcept { - return ec_; -} - -} // namespace error -} // namespace cmkr - -// strings for cmkr::error::Status::Code -static const char *err_string[] = { - "Success", "Runtime error", "Initialization error", "CMake generation error", "Build error", "Clean error", "Install error", -}; - -const char *cmkr_error_status(int i) { - assert(i >= 0 && static_cast(i) < (sizeof(err_string) / sizeof(*(err_string)))); - return err_string[i]; -} diff --git a/src/help.cpp b/src/help.cpp index 6e9513f..0a56367 100644 --- a/src/help.cpp +++ b/src/help.cpp @@ -23,11 +23,3 @@ arguments: } } // namespace help } // namespace cmkr - -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/project_parser.cpp b/src/project_parser.cpp index 3e722cb..8c99b40 100644 --- a/src/project_parser.cpp +++ b/src/project_parser.cpp @@ -36,7 +36,7 @@ static std::string format_key_message(const std::string &message, const toml::ke auto loc = value.location(); auto line_number_str = std::to_string(loc.line()); auto line_width = line_number_str.length(); - auto line_str = loc.line_str(); + const auto &line_str = loc.line_str(); std::ostringstream oss; oss << message << "\n"; @@ -73,7 +73,7 @@ class TomlChecker { public: TomlChecker(const TomlBasicValue &v, const toml::key &ky) : m_v(toml::find(v, ky)) { } - TomlChecker(const TomlBasicValue &v) : m_v(v) { + explicit TomlChecker(const TomlBasicValue &v) : m_v(v) { } TomlChecker(const TomlChecker &) = delete; TomlChecker(TomlChecker &&) = delete; @@ -175,7 +175,7 @@ class TomlCheckerRoot { bool m_checked = false; public: - TomlCheckerRoot(const TomlBasicValue &root) : m_root(root) { + explicit TomlCheckerRoot(const TomlBasicValue &root) : m_root(root) { } TomlCheckerRoot(const TomlCheckerRoot &) = delete; TomlCheckerRoot(TomlCheckerRoot &&) = delete; diff --git a/tests/cmake.toml b/tests/cmake.toml index 6935a9a..cddec8f 100644 --- a/tests/cmake.toml +++ b/tests/cmake.toml @@ -51,4 +51,4 @@ condition = "msvc" name = "msvc-runtime" working-directory = "msvc-runtime" command = "$" -arguments = ["build"] \ No newline at end of file +arguments = ["build"] diff --git a/tests/conditions/src/main.cpp b/tests/conditions/src/main.cpp index 41ed330..e1e8e9f 100644 --- a/tests/conditions/src/main.cpp +++ b/tests/conditions/src/main.cpp @@ -1 +1,2 @@ -int main() { } \ No newline at end of file +int main() { +} \ No newline at end of file diff --git a/tests/conditions/src/windows_specific.cpp b/tests/conditions/src/windows_specific.cpp index 84bc4ce..354c05a 100644 --- a/tests/conditions/src/windows_specific.cpp +++ b/tests/conditions/src/windows_specific.cpp @@ -1,3 +1,4 @@ #include -void foo() { } \ No newline at end of file +void foo() { +} \ No newline at end of file diff --git a/tests/cxx-standard/src/main.cpp b/tests/cxx-standard/src/main.cpp index 5d7ecde..29e611f 100644 --- a/tests/cxx-standard/src/main.cpp +++ b/tests/cxx-standard/src/main.cpp @@ -1,8 +1,7 @@ #include #include -int main() -{ +int main() { auto tpl = std::make_tuple(1, 2); printf("Hello from C++11 %d\n", std::get<0>(tpl)); } \ No newline at end of file diff --git a/tests/fetch-content/src/main.cpp b/tests/fetch-content/src/main.cpp index 4a2fe7e..f29bef6 100644 --- a/tests/fetch-content/src/main.cpp +++ b/tests/fetch-content/src/main.cpp @@ -1,6 +1,5 @@ #include -int main() -{ +int main() { fmt::print("Hello, world!\n"); } \ No newline at end of file diff --git a/tests/globbing/mylib/include/mylib/mylib.hpp b/tests/globbing/mylib/include/mylib/mylib.hpp index 1cdf48f..e19482e 100644 --- a/tests/globbing/mylib/include/mylib/mylib.hpp +++ b/tests/globbing/mylib/include/mylib/mylib.hpp @@ -2,7 +2,6 @@ #include -namespace mylib -{ +namespace mylib { std::string message(); } diff --git a/tests/globbing/mylib/src/mylib/mylib.cpp b/tests/globbing/mylib/src/mylib/mylib.cpp index b667ff3..13f192c 100644 --- a/tests/globbing/mylib/src/mylib/mylib.cpp +++ b/tests/globbing/mylib/src/mylib/mylib.cpp @@ -1,6 +1,5 @@ #include -std::string mylib::message() -{ +std::string mylib::message() { return "cmkr is awesome!"; } diff --git a/tests/interface/include/mylib/mylib.hpp b/tests/interface/include/mylib/mylib.hpp index 61325db..2738095 100644 --- a/tests/interface/include/mylib/mylib.hpp +++ b/tests/interface/include/mylib/mylib.hpp @@ -1,4 +1,5 @@ -namespace mylib -{ -static const char* version() { return "v1.0"; } +namespace mylib { +static const char *version() { + return "v1.0"; +} } // namespace mylib \ No newline at end of file diff --git a/tests/interface/src/main.cpp b/tests/interface/src/main.cpp index d181c04..2b4d7ce 100644 --- a/tests/interface/src/main.cpp +++ b/tests/interface/src/main.cpp @@ -2,7 +2,6 @@ #include "mylib/mylib.hpp" -int main() -{ +int main() { printf("mylib version: %s\n", mylib::version()); } diff --git a/tests/vcpkg/src/main.cpp b/tests/vcpkg/src/main.cpp index 4a2fe7e..f29bef6 100644 --- a/tests/vcpkg/src/main.cpp +++ b/tests/vcpkg/src/main.cpp @@ -1,6 +1,5 @@ #include -int main() -{ +int main() { fmt::print("Hello, world!\n"); } \ No newline at end of file diff --git a/third_party/.clang-format b/third_party/.clang-format new file mode 100644 index 0000000..5ffcf50 --- /dev/null +++ b/third_party/.clang-format @@ -0,0 +1,3 @@ +# Disable clang-format in this folder +DisableFormat: true +SortIncludes: Never \ No newline at end of file