From f6bb7b386e2ace2e185e5e361ed0173f38e7268b Mon Sep 17 00:00:00 2001 From: Paulden Date: Sun, 17 Mar 2024 21:37:57 +0800 Subject: [PATCH] feat(add): support FetchContent for cmake (#22) * add package target * add release workflows * refactor CMakeLists; enhance usability * add alias for library name --- .github/workflows/release.yml | 23 +++++++++++++ CMakeLists.txt | 61 +++++++++++++++++++++++------------ examples/overflowing-sub.cc | 28 ++++++++++++++++ src/CMakeLists.txt | 7 ++-- src/include/integer.hh | 28 ++++++++++++++-- src/include/uinteger.hh | 22 +++++++++++++ src/numbers/CMakeLists.txt | 10 +++--- tests/integer/CMakeLists.txt | 22 ++++++------- tests/uinteger/CMakeLists.txt | 22 ++++++------- tests/utils/CMakeLists.txt | 12 +++---- 10 files changed, 176 insertions(+), 59 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 examples/overflowing-sub.cc diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..369ad48 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,23 @@ +name: Release + +on: + release: + types: [published] + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Create build environment + run: cmake -B build-release + - name: Package source code + working-directory: build-release/ + run: cmake --build . --target package + - name: Add packaged source code to release + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: build-release/numbers-src.zip + tag: ${{ github.ref }} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index a33c0e5..0e4a60d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,22 +1,28 @@ cmake_minimum_required(VERSION 3.10) -set(BUILD_SHARED_LIBS OFF) -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(version 0.0.3) -string(COMPARE EQUAL ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} PROJECT_IS_TOP_LEVEL) +project(numbers VERSION ${version} LANGUAGES CXX) -if (PROJECT_IS_TOP_LEVEL) - message(STATUS "Project is top level") -endif() +set(BUILD_SHARED_LIBS OFF) -option(NUMBERS_TEST "Build and perform numbers tests" ${PROJECT_IS_TOP_LEVEL}) +string(COMPARE EQUAL ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} PROJECT_IS_IN_ROOT) -set(version 0.0.2) +set(CMAKE_EXPORT_COMPILE_COMMANDS ${PROJECT_IS_IN_ROOT}) -project(numbers VERSION ${version} LANGUAGES CXX) +if(PROJECT_IS_IN_ROOT) + set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + message(STATUS "Project ${PROJECT_NAME} is in root") +endif() + +# Check if the compiler supports C++17 +if(NOT CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD LESS 17) + message(FATAL_ERROR "Error: ${PROJECT_NAME} is a library for C++17 and later versions.") +endif() -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +option(NUMBERS_TEST "Build and perform ${PROJECT_NAME} tests" ${PROJECT_IS_IN_ROOT}) +option(NUMBERS_EXAMPLE "Build and perform ${PROJECT_NAME} examples" ${PROJECT_IS_IN_ROOT}) # Includes. set(SRC_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/src/include) @@ -25,14 +31,29 @@ include_directories(${SRC_INCLUDE_DIR}) add_subdirectory(src) -if (NUMBERS_TEST) - message(STATUS "Building and running tests") - set(THIRD_PARTY_INCLUDE_DIR - ${PROJECT_SOURCE_DIR}/third_party - ) - include_directories(${THIRD_PARTY_INCLUDE_DIR}) +if(NUMBERS_EXAMPLE) + add_subdirectory(examples) +endif() - add_subdirectory(examples) - add_subdirectory(third_party) - add_subdirectory(tests) +if(NUMBERS_TEST) + message(STATUS "Building and running tests") + set(THIRD_PARTY_INCLUDE_DIR + ${PROJECT_SOURCE_DIR}/third_party + ) + include_directories(${THIRD_PARTY_INCLUDE_DIR}) + + add_subdirectory(third_party) + add_subdirectory(tests) + + # Provide only the minimum source files needed by downstream users + set(package_files src/ CMakeLists.txt LICENSE.txt) + set(packaged_zip ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-src.zip) + add_custom_command( + OUTPUT ${packaged_zip} + COMMAND ${CMAKE_COMMAND} -E tar c ${packaged_zip} --format=zip -- ${package_files} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "The source files have been packaged into ${packaged_zip}" + DEPENDS ${package_files} + ) + add_custom_target(package DEPENDS ${packaged_zip}) endif() diff --git a/examples/overflowing-sub.cc b/examples/overflowing-sub.cc new file mode 100644 index 0000000..d9e567d --- /dev/null +++ b/examples/overflowing-sub.cc @@ -0,0 +1,28 @@ +#include +#include + +#include "numbers.h" + +void for_error() { + size_t i; + + // error - infinite loop + for (i = 10; i >= 0; i--) { + printf("[ID %u] Hello, World\n", i); + } +} + +void for_correct() { + using namespace numbers; + + u8 i; + bool flag = false; + for (i = 10; !flag && i >= 0; std::tie(i, flag) = i.overflowing_sub(1)) { + printf("[ID %u] Hello, World\n", i); + } +} + +int main(int argc, char const *argv[]) { + for_correct(); + return 0; +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5570d8d..2565205 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,8 @@ add_subdirectory(numbers) -add_library(numbers STATIC ${ALL_OBJECT_FILES}) +add_library(${PROJECT_NAME} STATIC ${ALL_OBJECT_FILES}) +add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) -target_include_directories(numbers PUBLIC $ - $ +target_include_directories(${PROJECT_NAME} PUBLIC $ + $ ) diff --git a/src/include/integer.hh b/src/include/integer.hh index a8a0427..7dc0d0f 100644 --- a/src/include/integer.hh +++ b/src/include/integer.hh @@ -210,9 +210,11 @@ class Integer { return Integer(-num_); } - constexpr bool operator==(const Integer &other) const noexcept { return num_ == other.num_; } - constexpr bool operator<(const Integer &other) const noexcept { return num_ < other.num_; } - constexpr bool operator>(const Integer &other) const noexcept { return num_ > other.num_; } + constexpr bool operator==(Integer other) const noexcept { return num_ == other.num_; } + constexpr bool operator<(Integer other) const noexcept { return num_ < other.num_; } + constexpr bool operator>(Integer other) const noexcept { return num_ > other.num_; } + constexpr bool operator<=(Integer other) const noexcept { return num_ <= other.num_; } + constexpr bool operator>=(Integer other) const noexcept { return num_ >= other.num_; } Integer &operator+=(Integer other) { *this = *this + other; @@ -401,6 +403,26 @@ constexpr bool operator==(U lhs, Integer rhs) noexcept { return Integer(lhs) == rhs; } +template && std::is_convertible_v>> +constexpr bool operator>(U lhs, Integer rhs) noexcept { + return Integer(lhs) > rhs; +} + +template && std::is_convertible_v>> +constexpr bool operator>=(U lhs, Integer rhs) noexcept { + return Integer(lhs) >= rhs; +} + +template && std::is_convertible_v>> +constexpr bool operator<(U lhs, Integer rhs) noexcept { + return Integer(lhs) < rhs; +} + +template && std::is_convertible_v>> +constexpr bool operator<=(U lhs, Integer rhs) noexcept { + return Integer(lhs) <= rhs; +} + using i8 = Integer; using i16 = Integer; using i32 = Integer; diff --git a/src/include/uinteger.hh b/src/include/uinteger.hh index a39bb0f..1cdf2d0 100644 --- a/src/include/uinteger.hh +++ b/src/include/uinteger.hh @@ -169,6 +169,8 @@ class Uinteger { constexpr bool operator==(Uinteger other) const noexcept { return num_ == other.num_; } constexpr bool operator<(Uinteger other) const noexcept { return num_ < other.num_; } constexpr bool operator>(Uinteger other) const noexcept { return num_ > other.num_; } + constexpr bool operator<=(Uinteger other) const noexcept { return num_ <= other.num_; } + constexpr bool operator>=(Uinteger other) const noexcept { return num_ >= other.num_; } Uinteger &operator+=(Uinteger other) { *this = *this + other; @@ -340,6 +342,26 @@ constexpr bool operator==(U lhs, Uinteger rhs) noexcept { return Uinteger(lhs) == rhs; } +template >> +constexpr bool operator>(U lhs, Uinteger rhs) noexcept { + return Uinteger(lhs) > rhs; +} + +template >> +constexpr bool operator>=(U lhs, Uinteger rhs) noexcept { + return Uinteger(lhs) >= rhs; +} + +template >> +constexpr bool operator<(U lhs, Uinteger rhs) noexcept { + return Uinteger(lhs) < rhs; +} + +template >> +constexpr bool operator<=(U lhs, Uinteger rhs) noexcept { + return Uinteger(lhs) <= rhs; +} + using u8 = Uinteger; using u16 = Uinteger; using u32 = Uinteger; diff --git a/src/numbers/CMakeLists.txt b/src/numbers/CMakeLists.txt index bbd2392..49d7422 100644 --- a/src/numbers/CMakeLists.txt +++ b/src/numbers/CMakeLists.txt @@ -1,11 +1,11 @@ file(GLOB obj_files "${CMAKE_CURRENT_SOURCE_DIR}/*.cc") add_library( - numbers_obj - OBJECT - ${obj_files} + numbers_obj + OBJECT + ${obj_files} ) set(ALL_OBJECT_FILES - ${ALL_OBJECT_FILES} $ - PARENT_SCOPE) \ No newline at end of file + ${ALL_OBJECT_FILES} $ + PARENT_SCOPE) \ No newline at end of file diff --git a/tests/integer/CMakeLists.txt b/tests/integer/CMakeLists.txt index f2a6a6c..b691a48 100644 --- a/tests/integer/CMakeLists.txt +++ b/tests/integer/CMakeLists.txt @@ -3,25 +3,25 @@ file(GLOB_RECURSE test_files "${CMAKE_CURRENT_SOURCE_DIR}/*.test.cc") set(PROJECT_NAME integer_test) add_executable( - ${PROJECT_NAME} - EXCLUDE_FROM_ALL - ${test_files} + ${PROJECT_NAME} + EXCLUDE_FROM_ALL + ${test_files} ) target_link_libraries(${PROJECT_NAME} PRIVATE numbers_obj test_utils gtest gmock_main) gtest_discover_tests(${PROJECT_NAME} - EXTRA_ARGS - --gtest_output=xml:${CMAKE_BINARY_DIR}/test/${PROJECT_NAME}.xml - --gtest_catch_exceptions=0 - DISCOVERY_TIMEOUT 120 - PROPERTIES - TIMEOUT 120 + EXTRA_ARGS + --gtest_output=xml:${CMAKE_BINARY_DIR}/test/${PROJECT_NAME}.xml + --gtest_catch_exceptions=0 + DISCOVERY_TIMEOUT 120 + PROPERTIES + TIMEOUT 120 ) set_target_properties(${PROJECT_NAME} - PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/test" + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/test" ) list(APPEND TEST_TARGETS ${PROJECT_NAME} PARENT_SCOPE) diff --git a/tests/uinteger/CMakeLists.txt b/tests/uinteger/CMakeLists.txt index 9393b16..601de01 100644 --- a/tests/uinteger/CMakeLists.txt +++ b/tests/uinteger/CMakeLists.txt @@ -3,25 +3,25 @@ file(GLOB_RECURSE test_files "${CMAKE_CURRENT_SOURCE_DIR}/*.test.cc") set(PROJECT_NAME uinteger_test) add_executable( - ${PROJECT_NAME} - EXCLUDE_FROM_ALL - ${test_files} + ${PROJECT_NAME} + EXCLUDE_FROM_ALL + ${test_files} ) target_link_libraries(${PROJECT_NAME} PRIVATE numbers_obj test_utils gtest gmock_main) gtest_discover_tests(${PROJECT_NAME} - EXTRA_ARGS - --gtest_output=xml:${CMAKE_BINARY_DIR}/test/${PROJECT_NAME}.xml - --gtest_catch_exceptions=0 - DISCOVERY_TIMEOUT 120 - PROPERTIES - TIMEOUT 120 + EXTRA_ARGS + --gtest_output=xml:${CMAKE_BINARY_DIR}/test/${PROJECT_NAME}.xml + --gtest_catch_exceptions=0 + DISCOVERY_TIMEOUT 120 + PROPERTIES + TIMEOUT 120 ) set_target_properties(${PROJECT_NAME} - PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/test" + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/test" ) list(APPEND TEST_TARGETS ${PROJECT_NAME} PARENT_SCOPE) diff --git a/tests/utils/CMakeLists.txt b/tests/utils/CMakeLists.txt index d27b7f5..fdf7004 100644 --- a/tests/utils/CMakeLists.txt +++ b/tests/utils/CMakeLists.txt @@ -1,10 +1,10 @@ add_library( - test_utils - EXCLUDE_FROM_ALL - OBJECT - utils.cc + test_utils + EXCLUDE_FROM_ALL + OBJECT + utils.cc ) set(ALL_OBJECT_FILES - ${ALL_OBJECT_FILES} $ - PARENT_SCOPE) \ No newline at end of file + ${ALL_OBJECT_FILES} $ + PARENT_SCOPE) \ No newline at end of file