diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c8b7c0e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,72 @@ +--- +name: CI + +on: + push: + branches: [main, dev, '**'] + pull_request: + branches: [main, dev] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: Build (${{ matrix.os }}, ${{ matrix.compiler }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + compiler: [clang] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Set compiler (Linux) + if: matrix.os == 'ubuntu-latest' + run: | + if [ "${{ matrix.compiler }}" = "gcc" ]; then + echo "CXX=g++" >> $GITHUB_ENV + else + echo "CXX=clang++" >> $GITHUB_ENV + fi + + - name: Set compiler (macOS) + if: matrix.os == 'macos-latest' + run: echo "CXX=clang++" >> $GITHUB_ENV + + - name: Set compiler (Windows) + if: matrix.os == 'windows-latest' + run: echo "CXX=clang++" >> $GITHUB_ENV + + - name: Configure CMake + run: cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLES=ON -DBUILD_TESTING=ON + + - name: Build + run: cmake --build build --parallel + + - name: Run tests + run: ctest --test-dir build --output-on-failure + + - name: Build and Run examples (Linux/macOS) + if: matrix.os != 'windows-latest' + run: | + if [ -d "build/examples" ]; then + for exe in build/examples/*_example; do + if [ -f "$exe" ]; then + "$exe" + fi + done + fi + + - name: Build and Run examples (Windows) + if: matrix.os == 'windows-latest' + run: | + if (Test-Path build/examples) { + Get-ChildItem -Path build/examples -Filter "*.exe" | ForEach-Object { & $_.FullName } + } diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml new file mode 100644 index 0000000..42359dc --- /dev/null +++ b/.github/workflows/code-quality.yml @@ -0,0 +1,42 @@ +--- +name: Code Quality + +on: + push: + branches: [main, dev, '**'] + pull_request: + branches: [main, dev] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + clang-format: + name: Clang Format Check + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Check formatting + run: | + # Install clang-format if not available + if ! command -v clang-format &> /dev/null; then + sudo apt-get update + sudo apt-get install -y clang-format + fi + + # Find all C++ source files + FAILED=0 + for file in $(find . -name '*.hpp' -o -name '*.cc'); do + if ! clang-format --style=file --dry-run "$file" 2>/dev/null; then + echo "Formatting issues found in: $file" + FAILED=1 + fi + done + + if [ $FAILED -eq 1 ]; then + echo "Some files have formatting issues. Run 'cmake --build . --target format' to fix." + fi diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..4f12f54 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,133 @@ +name: Release + +on: + push: + tags: + - 'v*' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: Build (${{ matrix.os }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Get version from tag + id: version + run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT + + - name: Setup CMake and Ninja + if: runner.os != 'Windows' + run: | + if [ "$RUNNER_OS" = "Linux" ]; then + sudo apt-get update && sudo apt-get install -y cmake ninja-build + elif [ "$RUNNER_OS" = "macOS" ]; then + brew install cmake ninja + fi + + - name: Configure CMake + run: | + cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLES=ON -DBUILD_TESTING=ON + + - name: Build + run: | + cmake --build build --parallel + + - name: Run tests + run: ctest --test-dir build --output-on-failure + + - name: Run examples (Linux/macOS) + if: runner.os != 'Windows' + run: | + if [ -d "build/examples" ]; then + for exe in build/examples/*_example; do + if [ -f "$exe" ] || [ -f "$exe.exe" ]; then + "$exe" || exit 1 + fi + done + fi + + - name: Run examples (Windows) + if: runner.os == 'Windows' + run: | + if (Test-Path build/examples) { + Get-ChildItem -Path build/examples -Filter "*.exe" | ForEach-Object { & $_.FullName } + } + + - name: Package (Linux/macOS) + if: runner.os != 'Windows' + run: | + cmake -B release -G Ninja -DCMAKE_BUILD_TYPE=Release \ + -DXCMATH_BUILD_EXAMPLES=ON \ + -DCMAKE_INSTALL_PREFIX=install \ + -DBUILD_TESTING=OFF + cmake --build release --target install + + # Create archive + cd install + tar -czvf ../xcmath-${{ steps.version.outputs.VERSION }}-${{ matrix.os }}.tar.gz * + + - name: Package (Windows) + if: runner.os == 'Windows' + run: | + cmake -B release -G Ninja -DCMAKE_BUILD_TYPE=Release -DXCMATH_BUILD_EXAMPLES=ON -DCMAKE_INSTALL_PREFIX=install -DBUILD_TESTING=OFF + cmake --build release --target install + + # Create archive + Compress-Archive -Path 'install/*' -DestinationPath 'xcmath-${{ steps.version.outputs.VERSION }}-${{ matrix.os }}.zip' + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: xcmath-${{ matrix.os }} + path: xcmath-${{ steps.version.outputs.VERSION }}-${{ matrix.os }}.* + retention-days: 5 + + release: + name: Create Release + needs: build + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Get version from tag + id: version + run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT + + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: Create Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ github.ref_name }} + name: xcmath v${{ steps.version.outputs.VERSION }} + draft: false + prerelease: ${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') }} + generate_release_notes: true + files: | + artifacts/xcmath-ubuntu-latest/* + artifacts/xcmath-macos-latest/* + artifacts/xcmath-windows-latest/* + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index b54c9c3..81633d1 100644 --- a/.gitignore +++ b/.gitignore @@ -8,13 +8,13 @@ !/README-zh.md !/LICENSE !/.clang-format -!resources/ -!vcpkg.json -!CMakePresets.json -!Doxyfile -!xmake.lua -!examples/ -!TODO -!cmake +!/resources/ +!/CMakePresets.json +!/Doxyfile +!/xmake.lua +!/examples/ +!/TODO +!/cmake !/third_party/ -docs/doxygen +!/docs/doxygen +!/.github/ diff --git a/cmake/get_version.cmake b/cmake/get_version.cmake new file mode 100644 index 0000000..6eb37cc --- /dev/null +++ b/cmake/get_version.cmake @@ -0,0 +1,62 @@ +# Version Management via Git Tags +# +# This module provides functions to extract project version from git tags. +# Version format: vX.Y.Z (e.g., v1.0.0) +# +# Usage: +# include(cmake/get_version.cmake) +# xc_get_project_version(PROJECT_VERSION) +# +# Public API: +# xc_get_last_git_tag(TAG_VAR DEFAULT_VALUE) - Get the most recent git tag +# xc_get_project_version(VERSION_VAR) - Get version from latest tag + +find_program(GIT_EXE NAMES git) + +# xc_get_last_git_tag(TAG_VAR DEFAULT_VALUE) +# Get the most recent git tag +# +# Args: +# TAG_VAR - Variable to store the tag +# DEFAULT_VALUE - Default value if no tag found +# +# Examples: +# xc_get_last_git_tag(TAG "v0.0.0") +function(xc_get_last_git_tag TAG_VAR DEFAULT_VALUE) + if(NOT GIT_EXE) + message(FATAL_ERROR "git not found") + endif() + + set(${TAG_VAR} ${DEFAULT_VALUE} PARENT_SCOPE) + + execute_process( + COMMAND ${GIT_EXE} describe --abbrev=0 --tags + OUTPUT_VARIABLE GIT_TAG + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + if(GIT_TAG) + message(STATUS "GIT_TAG: ${GIT_TAG}") + set(${TAG_VAR} ${GIT_TAG} PARENT_SCOPE) + endif() +endfunction(xc_get_last_git_tag) + +# xc_get_project_version(VERSION_VAR) +# Get project version from latest git tag +# +# Extracts version in format X.Y.Z from tag (e.g., v1.2.3 -> 1.2.3) +# Defaults to 0.0.0 if no valid tag found +# +# Args: +# VERSION_VAR - Variable to store the version +# +# Examples: +# xc_get_project_version(PROJECT_VERSION) +function(xc_get_project_version VERSION_VAR) + xc_get_last_git_tag(GIT_TAG "v0.0.0") + string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" VERSION ${GIT_TAG}) + if(NOT VERSION) + message(FATAL_ERROR "git tag ${GIT_TAG} not match version format") + endif() + set(${VERSION_VAR} ${VERSION} PARENT_SCOPE) +endfunction(xc_get_project_version) diff --git a/cmake/install.cmake b/cmake/install.cmake new file mode 100644 index 0000000..c04924f --- /dev/null +++ b/cmake/install.cmake @@ -0,0 +1,58 @@ +# Installation configuration for xcmath +# +# This file handles the installation of xcmath library targets and headers. + +include(CMakePackageConfigHelpers) + +# Set uppercase project name +set(UP_XCMATH "XCMATH") + +# Define install directory for CMake config +set(UP_XCMATH_CMAKE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/cmake/xcmath") + +# Install export set +install( + TARGETS xcmath + EXPORT xcmath + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) + +# Install headers +install( + DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/xcmath/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/xcmath/ + FILES_MATCHING + PATTERN "*.hpp" + PATTERN "*.h" +) + +# Generate and install CMake config files +configure_package_config_file( + ${CMAKE_SOURCE_DIR}/cmake/xcmathConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/xcmathConfig.cmake + INSTALL_DESTINATION ${UP_XCMATH_CMAKE_INSTALL_DIR} +) + +write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/xcmathConfigVersion.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion +) + +install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/xcmathConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/xcmathConfigVersion.cmake + DESTINATION ${UP_XCMATH_CMAKE_INSTALL_DIR} +) + +# Install export +install( + EXPORT xcmath + NAMESPACE xcmath:: + FILE xcmathConfig.cmake + DESTINATION ${UP_XCMATH_CMAKE_INSTALL_DIR} +) diff --git a/cmake/install_deps.cmake b/cmake/install_deps.cmake new file mode 100644 index 0000000..9355a6c --- /dev/null +++ b/cmake/install_deps.cmake @@ -0,0 +1,10 @@ +# Dependency installation for xcmath +# +# This file is intentionally empty as xcmath is a header-only library +# with no external dependencies. +# +# If dependencies are added in the future, add them here using +# find_package() or FetchContent_Declare()/FetchContent_MakeAvailable() + +# Example: +# find_package(OpenGL QUIET) diff --git a/cmake/install_test_deps.cmake b/cmake/install_test_deps.cmake new file mode 100644 index 0000000..2e4405b --- /dev/null +++ b/cmake/install_test_deps.cmake @@ -0,0 +1,21 @@ +# Test dependency installation for xcmath +# +# This file handles the installation of test dependencies (Google Test). + +include(FetchContent) + +# Google Test +if(NOT gtest_PRESENT) + message(STATUS "Fetching Google Test...") + FetchContent_Declare( + gtest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG v1.14.0 + ) + # For Windows: prevent GDTHREAD local conflict + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + FetchContent_MakeAvailable(gtest) +endif() + +# Set test support libraries +set(TEST_SUPPORT_LIBRARIES gtest gtest_main) diff --git a/cmake/xc_utils.cmake b/cmake/xc_utils.cmake new file mode 100644 index 0000000..a095848 --- /dev/null +++ b/cmake/xc_utils.cmake @@ -0,0 +1,390 @@ +# CMake Utilities for xcmath +# +# This CMake file provides utility functions for library creation. + +# Configuration Variables: +# DEFAULT_NAMESPACE - Default namespace for libraries (default: CMAKE_PROJECT_NAME) +# TEST_PREFIX - Prefix for test executables (default: "test_") +# TEST_SUFFIX - Suffix for test executables (default: "") +# BUILD_SHARED - Build shared libraries instead of static (default: OFF) +# ${PROJECT_NAME}_BUILD_SHARED - Override BUILD_SHARED per project +# ${PROJECT_NAME}_MODIFY_OUTPUT_PREFIX - Add namespace prefix to output name (default: ON) +# +# Internal Functions (prefixed with __xc_): +# __xc_link_include - Add link libraries and include directories +# __xc_get_namespace - Get namespace +# __xc_set_output - Set output name with prefix +# +# Public API: +# xc_install - Install target and headers +# xc_add_alias - Add namespace alias +# xc_target_source - Add source files +# xc_add_header_library - Create header-only library +# xc_add_static_library - Create static library +# xc_add_shared_library - Create shared library +# xc_add_library - Create static or shared library +# xc_add_test - Create unit test + +if(NOT DEFINED DEFAULT_NAMESPACE) + set(DEFAULT_NAMESPACE ${CMAKE_PROJECT_NAME}) +endif() + +if(NOT DEFINED TEST_PREFIX) + set(TEST_PREFIX "test_") +endif() + +if(NOT DEFINED TEST_SUFFIX) + set(TEST_SUFFIX "") +endif() + +set(BUILD_SHARED OFF) + +if(DEFINED ${CMAKE_PROJECT_NAME}_BUILD_SHARED) + set(BUILD_SHARED ${${CMAKE_PROJECT_NAME}_BUILD_SHARED}) +endif() + +if(NOT DEFINED ${CMAKE_PROJECT_NAME}_MODIFY_OUTPUT_PREFIX) + set(${CMAKE_PROJECT_NAME}_MODIFY_OUTPUT_PREFIX ON) +endif() + +include(GNUInstallDirs) +string(TOUPPER ${CMAKE_PROJECT_NAME} UPPER_PROJECT_NAME) +set(${UPPER_PROJECT_NAME}_CMAKE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/cmake/${CMAKE_PROJECT_NAME}") + +# __xc_link_include(TARGET) +# Add link libraries and include directories to target +# +# Options: +# PUBLIC_LINK lib - Public link library +# PRIVATE_LINK lib - Private link library +# INTERFACE_LINK lib - Interface link library +# PUBLIC_INCLUDE path - Public include directory +# PRIVATE_INCLUDE path - Private include directory +# INTERFACE_INCLUDE path - Interface include directory +# +# Examples: +# __xc_link_include(my_target PUBLIC_LINK lib1 PRIVATE_LINK lib2) +# __xc_link_include(my_target PUBLIC_INCLUDE /path/to/include) +# __xc_link_include(my_target INTERFACE_LINK some_target INTERFACE_INCLUDE /path) +function(__xc_link_include TARGET) + cmake_parse_arguments( + ARG + "" + "" + "PUBLIC_LINK;PRIVATE_LINK;INTERFACE_LINK;PUBLIC_INCLUDE;PRIVATE_INCLUDE;INTERFACE_INCLUDE" + "${ARGN}" + ) + + if(DEFINED ARG_PUBLIC_LINK) + target_link_libraries(${TARGET} PUBLIC ${ARG_PUBLIC_LINK}) + endif() + + if(DEFINED ARG_PRIVATE_LINK) + target_link_libraries(${TARGET} PRIVATE ${ARG_PRIVATE_LINK}) + endif() + + if(DEFINED ARG_INTERFACE_LINK) + target_link_libraries(${TARGET} INTERFACE ${ARG_INTERFACE_LINK}) + endif() + + if(DEFINED ARG_PUBLIC_INCLUDE) + target_include_directories(${TARGET} PUBLIC ${ARG_PUBLIC_INCLUDE}) + endif() + + if(DEFINED ARG_PRIVATE_INCLUDE) + target_include_directories(${TARGET} PRIVATE ${ARG_PRIVATE_INCLUDE}) + endif() + + if(DEFINED ARG_INTERFACE_INCLUDE) + target_include_directories(${TARGET} INTERFACE ${ARG_INTERFACE_INCLUDE}) + endif() +endfunction(__xc_link_include) + +# __xc_get_namespace(OUT_VAR) +# Get namespace, defaults to DEFAULT_NAMESPACE +# +# Options: +# NAMESPACE name - Override namespace +# +# Examples: +# __xc_get_namespace(NS) +# __xc_get_namespace(NS NAMESPACE custom) +function(__xc_get_namespace OUT_VAR) + cmake_parse_arguments( + ARG + "" + "NAMESPACE" + "" + "${ARGN}" + ) + set(${OUT_VAR} ${DEFAULT_NAMESPACE} PARENT_SCOPE) + + if(DEFINED ARG_NAMESPACE) + set(${OUT_VAR} ${ARG_NAMESPACE} PARENT_SCOPE) + endif() +endfunction(__xc_get_namespace) + +# xc_install(TARGET DIR NAMESPACE) +# Install target library and header files +# +# Examples: +# xc_install(myhello hello myproject) +function(xc_install TARGET DIR NAMESPACE) + install( + TARGETS ${TARGET} + EXPORT ${NAMESPACE} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + install( + DIRECTORY ${DIR} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${NAMESPACE}/ + FILES_MATCHING + PATTERN "*.hpp" + PATTERN "*.h" + PATTERN "*.hh" + ) +endfunction(xc_install) + +# xc_add_alias(TARGET NAMESPACE) +# Add namespace alias for target (e.g., myproject::hello) +# +# Examples: +# xc_add_alias(hello myproject) +function(xc_add_alias TARGET NAMESPACE) + set(ALIAS_NAME "${NAMESPACE}::${TARGET}") + + if("${TARGET}" MATCHES "^${NAMESPACE}_.*") + string(REPLACE "${NAMESPACE}_" "${NAMESPACE}::" ALIAS_NAME ${TARGET}) + endif() + + add_library("${ALIAS_NAME}" ALIAS ${TARGET}) + message(STATUS "add alias ${ALIAS_NAME} to ${TARGET}") +endfunction(xc_add_alias) + +# __xc_set_output(TARGET NAMESPACE) +# Set target output name (e.g., myproject_hello) +# +# Examples: +# __xc_set_output(hello myproject) +function(__xc_set_output TARGET NAMESPACE) + if("${TARGET}" MATCHES "^${NAMESPACE}_.*") + set_target_properties( + ${TARGET} + PROPERTIES OUTPUT_NAME "${TARGET}" + ) + else() + set_target_properties( + ${TARGET} + PROPERTIES OUTPUT_NAME "${NAMESPACE}_${TARGET}" + ) + endif() +endfunction(__xc_set_output TARGET NAMESPACE) + +# xc_target_source(TARGET DIR) +# Add source files to target with recursive/non-recursive support +# +# Options: +# NORECURSIVE - Non-recursive search (default: recursive) +# EXCLUDE_PATH path - Exclude files matching path +# EXTSRC file - Add extra source files +# +# Examples: +# xc_target_source(my_target src) +# xc_target_source(my_target src NORECURSIVE) +# xc_target_source(my_target src EXCLUDE_PATH "test" EXCLUDE_PATH "mock") +# xc_target_source(my_target src EXTSRC extra.cpp) +function(xc_target_source TARGET DIR) + cmake_parse_arguments( + ARG + "NORECURSIVE" + "" + "EXCLUDE_PATH;EXTSRC" + ${ARGN} + ) + set(SOURCE_PATTERNS "${DIR}/*.cc" "${DIR}/*.cpp" "${DIR}/*.c") + + if(ARG_NORECURSIVE) + file(GLOB SRC_FILES ${SOURCE_PATTERNS}) + else() + file(GLOB_RECURSE SRC_FILES ${SOURCE_PATTERNS}) + endif() + + if(DEFINED ARG_EXCLUDE_PATH) + foreach(EXCLUDE ${ARG_EXCLUDE_PATH}) + list(FILTER SRC_FILES EXCLUDE REGEX ".*${EXCLUDE}.*") + endforeach() + endif() + + if(DEFINED ARG_EXTSRC) + list(APPEND SRC_FILES ${ARG_EXTSRC}) + endif() + + target_sources(${TARGET} PRIVATE ${SRC_FILES}) +endfunction(xc_target_source) + +# Internal macro: common library setup +macro(__xc_setup_lib TARGET SRCDIR) + __xc_get_namespace(NAMESPACE ${ARGN}) + xc_add_alias(${TARGET} ${NAMESPACE}) + + if(${CMAKE_PROJECT_NAME}_MODIFY_OUTPUT_PREFIX) + __xc_set_output(${TARGET} ${NAMESPACE}) + endif() + + target_include_directories(${TARGET} INTERFACE + $ + $ + ) + xc_target_source(${TARGET} ${SRCDIR} ${ARGN}) + __xc_link_include(${TARGET} ${ARGN}) + xc_install(${TARGET} ${SRCDIR} ${NAMESPACE}) +endmacro(__xc_setup_lib) + +# xc_add_header_library(TARGET INCDIR) +# Create a header-only library +# +# Options: +# NAMESPACE name - Specify namespace (default: CMAKE_PROJECT_NAME) +# PUBLIC_LINK lib - Public link library +# PRIVATE_LINK lib - Private link library +# INTERFACE_LINK lib - Interface link library +# PUBLIC_INCLUDE path - Public include directory +# PRIVATE_INCLUDE path - Private include directory +# INTERFACE_INCLUDE path - Interface include directory +# +# Examples: +# xc_add_header_library(mylib include) +# xc_add_header_library(mylib include NAMESPACE myproject) +# xc_add_header_library(mylib include PUBLIC_INCLUDE /path/to/include PRIVATE_LINK some_lib) +function(xc_add_header_library TARGET INCDIR) + add_library(${TARGET} INTERFACE) + __xc_get_namespace(NAMESPACE ${ARGN}) + xc_add_alias(${TARGET} ${NAMESPACE}) + target_include_directories(${TARGET} INTERFACE + $ + $ + ) + __xc_link_include(${TARGET} ${ARGN}) + xc_install(${TARGET} ${INCDIR} ${NAMESPACE}) +endfunction(xc_add_header_library) + +# xc_add_static_library(TARGET SRCDIR) +# Create a static library +# +# Options: +# NAMESPACE name - Specify namespace (default: CMAKE_PROJECT_NAME) +# PUBLIC_LINK lib - Public link library +# PRIVATE_LINK lib - Private link library +# INTERFACE_LINK lib - Interface link library +# PUBLIC_INCLUDE path - Public include directory +# PRIVATE_INCLUDE path - Private include directory +# INTERFACE_INCLUDE path - Interface include directory +# +# Examples: +# xc_add_static_library(hello hello) +# xc_add_static_library(hello hello NAMESPACE myproject) +# xc_add_static_library(hello hello PUBLIC_LINK otherlib PRIVATE_INCLUDE /path/to/include) +function(xc_add_static_library TARGET SRCDIR) + add_library(${TARGET} STATIC) + __xc_setup_lib(${TARGET} ${SRCDIR} ${ARGN}) +endfunction(xc_add_static_library) + +# xc_add_shared_library(TARGET SRCDIR) +# Create a shared library +# +# Options: +# NAMESPACE name - Specify namespace (default: CMAKE_PROJECT_NAME) +# PUBLIC_LINK lib - Public link library +# PRIVATE_LINK lib - Private link library +# INTERFACE_LINK lib - Interface link library +# PUBLIC_INCLUDE path - Public include directory +# PRIVATE_INCLUDE path - Private include directory +# INTERFACE_INCLUDE path - Interface include directory +# +# Examples: +# xc_add_shared_library(hello hello) +# xc_add_shared_library(hello hello NAMESPACE myproject) +# xc_add_shared_library(hello hello PUBLIC_LINK otherlib PRIVATE_INCLUDE /path/to/include) +function(xc_add_shared_library TARGET SRCDIR) + add_library(${TARGET} SHARED) + __xc_setup_lib(${TARGET} ${SRCDIR} ${ARGN}) + target_compile_definitions(${TARGET} PRIVATE ${CMAKE_PROJECT_NAME}_BUILD_SHARED) +endfunction(xc_add_shared_library) + +# xc_add_library(TARGET SRCDIR) +# Create static or shared library based on BUILD_SHARED variable +# +# Options: +# NAMESPACE name - Specify namespace (default: CMAKE_PROJECT_NAME) +# PUBLIC_LINK lib - Public link library +# PRIVATE_LINK lib - Private link library +# INTERFACE_LINK lib - Interface link library +# PUBLIC_INCLUDE path - Public include directory +# PRIVATE_INCLUDE path - Private include directory +# INTERFACE_INCLUDE path - Interface include directory +# +# Examples: +# xc_add_library(hello hello) +# xc_add_library(hello hello NAMESPACE myproject) +# xc_add_library(hello hello PUBLIC_LINK otherlib PRIVATE_INCLUDE /path/to/include) +function(xc_add_library TARGET SRCDIR) + if(${BUILD_SHARED}) + xc_add_shared_library(${TARGET} ${SRCDIR} ${ARGN}) + else() + xc_add_static_library(${TARGET} ${SRCDIR} ${ARGN}) + endif() +endfunction(xc_add_library) + +# xc_add_test(NAME SOURCES) +# Create a unit test +# +# Options: +# TARGET_OUTPUT outvar - Output variable to receive test executable name +# PUBLIC_LINK lib - Public link library +# PRIVATE_LINK lib - Private link library +# INTERFACE_LINK lib - Interface link library +# PUBLIC_INCLUDE path - Public include directory +# PRIVATE_INCLUDE path - Private include directory +# INTERFACE_INCLUDE path - Interface include directory +# +# Examples: +# xc_add_test(mytest test.cc) +# xc_add_test(mytest test.cc PUBLIC_INCLUDE /path/to/include) +# xc_add_test(mytest test.cc PRIVATE_LINK mylib PUBLIC_INCLUDE /path/to/include) +# xc_add_test(mytest test.cc TARGET_OUTPUT test_exe) +function(xc_add_test NAME SOURCES) + cmake_parse_arguments( + ARG + "" + "TARGET_OUTPUT" + "" + ${ARGN} + ) + set(TEST_NAME "${TEST_PREFIX}${NAME}${TEST_SUFFIX}") + add_executable(${TEST_NAME} ${SOURCES}) + target_link_libraries(${TEST_NAME} PRIVATE ${TEST_SUPPORT_LIBRARIES}) + add_test(NAME ${NAME} COMMAND ${TEST_NAME}) + __xc_link_include(${TEST_NAME} ${ARGN}) + + if(NOT ARG_TARGET_OUTPUT) + set(${ARG_TARGET_OUTPUT} ${TEST_NAME} PARENT_SCOPE) + endif() +endfunction(xc_add_test SOURCES) + +# xc_add_format_dir(DIR) +# Add directory to the list of directories to be formatted +# +# The format target will search recursively for source files +# (.hpp, .h, .hh, .c, .cc, .cpp) in all added directories +# +# Args: +# DIR - Directory to add for formatting +# +# Examples: +# xc_add_format_dir(${CMAKE_SOURCE_DIR}/src) +# xc_add_format_dir(${CMAKE_SOURCE_DIR}/include) +macro(xc_add_format_dir DIR) + get_filename_component(ABSOLUTE_DIR ${DIR} ABSOLUTE) + list(APPEND ${CMAKE_PROJECT_NAME}_FORMAT_DIRS ${ABSOLUTE_DIR}) + message(STATUS "Add format directory: ${ABSOLUTE_DIR}") +endmacro(xc_add_format_dir) diff --git a/cmake/xcmathConfig.cmake.in b/cmake/xcmathConfig.cmake.in new file mode 100644 index 0000000..69e39ce --- /dev/null +++ b/cmake/xcmathConfig.cmake.in @@ -0,0 +1,5 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/xcmathTargets.cmake") + +check_required_components(xcmath)