diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e49eb5e5..f31e4829 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,12 @@ on: branches: - master tags: '*' + +# avoid wasted runs +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: test-unix: runs-on: ${{ matrix.os }} @@ -17,11 +23,28 @@ jobs: - ubuntu-latest - macos-latest steps: - - uses: actions/checkout@v6 - - run: make - - run: make test + - &git-checkout + name: Checkout Openlibm + uses: actions/checkout@v6 + - &count-cpu + name: Count CPU cores + uses: ./.github/workflows/composite-nproc + - &make-build + name: Build with GNU Make + run: make -j${CMAKE_BUILD_PARALLEL_LEVEL} + - &make-test + name: Test with GNU Make + run: make test -j${CTEST_PARALLEL_LEVEL} + - &cmake-build + name: Build with CMake + run: cmake -Bbuild && cmake --build build + - &ctest + name: Test with CTest + run: ctest --test-dir build --output-on-failure windows: runs-on: windows-latest + env: + CMAKE_GENERATOR: "MinGW Makefiles" strategy: fail-fast: false matrix: @@ -34,18 +57,21 @@ jobs: run: shell: msys2 {0} steps: - - uses: actions/checkout@v6 + - *git-checkout + - *count-cpu - name: Set up the desired MSYS2 environment uses: msys2/setup-msys2@v2 with: msystem: ${{matrix.sys}} - install: base-devel mingw-w64-${{matrix.env}}-toolchain - - run: make - - run: make test + install: base-devel mingw-w64-${{ matrix.env }}-cmake mingw-w64-${{ matrix.env }}-make mingw-w64-${{matrix.env}}-toolchain + - *make-build + - *make-test + - *cmake-build + - *ctest code-coverage-old: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - *git-checkout - name: Setup LCOV uses: hrishikesh-kadam/setup-lcov@v1 - name: Build and Run tests @@ -62,8 +88,7 @@ jobs: code-coverage: runs-on: ubuntu-latest steps: - - name: Checkout Openlibm - uses: actions/checkout@v6 + - *git-checkout - name: Checkout Openlibm-test uses: actions/checkout@v6 with: @@ -71,11 +96,12 @@ jobs: path: 'openlibm-test' - name: Setup LCOV uses: hrishikesh-kadam/setup-lcov@v1 + - *count-cpu - name: Build Openlibm - run: make -j`nproc` CODE_COVERAGE=1 + run: make -j${CMAKE_BUILD_PARALLEL_LEVEL} CODE_COVERAGE=1 - name: Run Test run: | - make -j`nproc` -C openlibm-test \ + make -j${CTEST_PARALLEL_LEVEL} -C openlibm-test \ USE_OPENLIBM=1 OPENLIBM_HOME="$(pwd)" \ SKIP_FP_EXCEPT_TEST=1 \ - name: Show Test Result diff --git a/.github/workflows/composite-nproc/action.yml b/.github/workflows/composite-nproc/action.yml new file mode 100644 index 00000000..8496f861 --- /dev/null +++ b/.github/workflows/composite-nproc/action.yml @@ -0,0 +1,24 @@ +name: Detect CPU core count +description: Set CPU core count as environment variables for parallel builds and tests + +runs: + + using: composite + + steps: + - name: Detect CPU cores + shell: bash + id: cores + run: | + if [[ "$RUNNER_OS" == "Linux" ]]; then + CORES=$(nproc) + elif [[ "$RUNNER_OS" == "macOS" ]]; then + CORES=$(sysctl -n hw.ncpu) + elif [[ "$RUNNER_OS" == "Windows" ]]; then + CORES=$NUMBER_OF_PROCESSORS + else + CORES=2 + fi + echo "CMAKE_BUILD_PARALLEL_LEVEL=$CORES" >> $GITHUB_ENV + echo "CTEST_PARALLEL_LEVEL=$CORES" >> $GITHUB_ENV + echo "Detected $CORES cores" diff --git a/.github/workflows/cross-loongarch64.yml b/.github/workflows/cross-loongarch64.yml index a2e48123..f3cd4f54 100644 --- a/.github/workflows/cross-loongarch64.yml +++ b/.github/workflows/cross-loongarch64.yml @@ -1,6 +1,6 @@ # merge this file into cross.yml # when we can `sudo apt install gcc-loongarch64-linux-gnu` on ubuntu -name: Cross +name: Cross-LoongArch64 on: pull_request: @@ -11,6 +11,11 @@ on: - master tags: '*' +# avoid wasted runs +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build-cross-qemu: # TODO: We need Ubuntu 24.04 to use newer version of qemu, @@ -27,6 +32,8 @@ jobs: TRIPLE: ${{ matrix.config.triple }} steps: - uses: actions/checkout@v6 + - name: Count CPU cores + uses: ./.github/workflows/composite-nproc - name: Install qemu run: | sudo apt update @@ -37,12 +44,12 @@ jobs: run: sudo apt install -y gcc-14-loongarch64-linux-gnu - name: Build with ${{ matrix.config.triple }}-gcc run: | - make ARCH=$ARCH TOOLPREFIX=$TRIPLE- \ + make -j${CMAKE_BUILD_PARALLEL_LEVEL} ARCH=$ARCH TOOLPREFIX=$TRIPLE- \ CC='loongarch64-linux-gnu-gcc-14' \ AR='loongarch64-linux-gnu-gcc-ar-14' \ - name: Build tests run: | - make -C test ARCH=$ARCH TOOLPREFIX=$TRIPLE- \ + make -C test -j${CTEST_PARALLEL_LEVEL} ARCH=$ARCH TOOLPREFIX=$TRIPLE- \ CC='loongarch64-linux-gnu-gcc-14' \ AR='loongarch64-linux-gnu-gcc-ar-14' \ - name: Run Tests diff --git a/.github/workflows/cross.yml b/.github/workflows/cross.yml index 004cfa7a..023edd83 100644 --- a/.github/workflows/cross.yml +++ b/.github/workflows/cross.yml @@ -9,6 +9,11 @@ on: - master tags: '*' +# avoid wasted runs +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build-cross-qemu: # TODO: We need Ubuntu 24.04 to use newer version of qemu, @@ -36,14 +41,16 @@ jobs: TRIPLE: ${{ matrix.config.triple }} steps: - uses: actions/checkout@v6 + - name: Count CPU cores + uses: ./.github/workflows/composite-nproc - name: Install qemu and toolchain gcc-${{ matrix.config.triple }} run: | sudo apt update sudo apt install qemu-user qemu-user-binfmt gcc-$TRIPLE -y - name: Build with ${{ matrix.config.triple }}-gcc - run: make ARCH=$ARCH TOOLPREFIX=$TRIPLE- + run: make -j${CMAKE_BUILD_PARALLEL_LEVEL} ARCH=$ARCH TOOLPREFIX=$TRIPLE- - name: Build tests - run: make -C test ARCH=$ARCH TOOLPREFIX=$TRIPLE- + run: make -C test -j${CTEST_PARALLEL_LEVEL} ARCH=$ARCH TOOLPREFIX=$TRIPLE- - name: Run Tests env: QEMU_EXEC: qemu-${{ matrix.config.arch }} diff --git a/CMakeLists.txt b/CMakeLists.txt index f46f0371..9a7a53ad 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ project(openlibm LANGUAGES C ASM) option(BUILD_SHARED_LIBS "Build using shared libraries" ON) +option(openlibm_PIC "Build openlibm with position independent code" ON) add_library("${PROJECT_NAME}") @@ -16,17 +17,24 @@ add_library("${PROJECT_NAME}") set(OPENLIBM_ARCH_FOLDER ${CMAKE_SYSTEM_PROCESSOR}) string(TOLOWER "${OPENLIBM_ARCH_FOLDER}" OPENLIBM_ARCH_FOLDER) -if(${OPENLIBM_ARCH_FOLDER} STREQUAL "amd64" OR ${OPENLIBM_ARCH_FOLDER} STREQUAL "x86_64") - set(OPENLIBM_ARCH_FOLDER "amd64") -elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "arm64" OR ${OPENLIBM_ARCH_FOLDER} STREQUAL "aarch64") +# CMAKE_SYSTEM_PROCESSOR reflects the host instead of the selected MinGW target. +# Use pointer size to disambiguate x86/x64. +if(OPENLIBM_ARCH_FOLDER STREQUAL "x86_64" OR OPENLIBM_ARCH_FOLDER STREQUAL "amd64" OR + OPENLIBM_ARCH_FOLDER STREQUAL "x86" OR OPENLIBM_ARCH_FOLDER STREQUAL "i686") + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(OPENLIBM_ARCH_FOLDER "amd64") + elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) + set(OPENLIBM_ARCH_FOLDER "i387") + else() + message(FATAL_ERROR "Unsupported pointer size: ${CMAKE_SIZEOF_VOID_P}") + endif() +elseif(OPENLIBM_ARCH_FOLDER STREQUAL "arm64" OR OPENLIBM_ARCH_FOLDER STREQUAL "aarch64") set(OPENLIBM_ARCH_FOLDER "aarch64") -elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "armv7-a") +elseif(OPENLIBM_ARCH_FOLDER STREQUAL "armv7-a") set(OPENLIBM_ARCH_FOLDER "arm") -elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "x86" OR ${OPENLIBM_ARCH_FOLDER} STREQUAL "i686") - set(OPENLIBM_ARCH_FOLDER "i387") -elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "powerpc") +elseif(OPENLIBM_ARCH_FOLDER STREQUAL "powerpc") set(OPENLIBM_ARCH_FOLDER "powerpc") -elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "riscv64") +elseif(OPENLIBM_ARCH_FOLDER STREQUAL "riscv64") set(OPENLIBM_ARCH_FOLDER "riscv64") else() message(FATAL_ERROR "${PROJECT_NAME} not set up for detected architecture: ${OPENLIBM_ARCH_FOLDER}") @@ -35,23 +43,23 @@ endif() # Compile flags list(APPEND C_ASM_COMPILE_FLAGS "-ffp-contract=off" "-fno-fast-math" "-fno-rounding-math" "-fno-math-errno") -list(APPEND C_ASM_COMPILE_FLAGS "-fPIC" "-std=c99" "-fno-builtin") +list(APPEND C_ASM_COMPILE_FLAGS "-fno-builtin") list(APPEND C_ASM_COMPILE_FLAGS "-Wall" "-Wno-implicit-function-declaration") list(APPEND C_ASM_COMPILE_FLAGS "-DASSEMBLER" "-D__BSD_VISIBLE" "-O3") # Compiler-specific compile flags -if("${CMAKE_C_COMPILER_ID}" MATCHES "Clang") +if(CMAKE_C_COMPILER_ID MATCHES "Clang") list(APPEND C_ASM_COMPILE_FLAGS "-fno-strict-aliasing" "-ffp-exception-behavior=strict") -elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") +elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU") list(APPEND C_ASM_COMPILE_FLAGS "-fno-gnu89-inline") else() message(FATAL_ERROR "${PROJECT_NAME} not set up to be compiled with ${CMAKE_C_COMPILER_ID}") endif() # Architecture-specific compile flags - take advantage of sse on x86 -if(${OPENLIBM_ARCH_FOLDER} STREQUAL "i387") +if(OPENLIBM_ARCH_FOLDER STREQUAL "i387") list(APPEND C_ASM_COMPILE_FLAGS "-march=i686" "-m32" "-msse2" "-mfpmath=sse") -elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "amd64") +elseif(OPENLIBM_ARCH_FOLDER STREQUAL "amd64") list(APPEND C_ASM_COMPILE_FLAGS "-m64" "-msse2" "-mfpmath=sse") endif() @@ -249,15 +257,15 @@ list(APPEND OPENLIBM_C_SOURCE "${PROJECT_SRC}/bsdsrc/b_tgamma.c" ) -if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows") +if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") list(APPEND OPENLIBM_C_SOURCE "${PROJECT_SRC}/src/s_nan.c" ) endif() # Determine if long double and double are the same size -include(CheckCSourceCompiles) -check_c_source_compiles(" +include(CheckSourceCompiles) +check_source_compiles(C " #include #if (LDBL_MANT_DIG == DBL_MANT_DIG) #error \"long double and double are the same size\" @@ -332,7 +340,7 @@ if(LONG_DOUBLE_NOT_DOUBLE) endif() if (LONG_DOUBLE_NOT_DOUBLE) - if (${OPENLIBM_ARCH_FOLDER} STREQUAL "i387" OR ${OPENLIBM_ARCH_FOLDER} STREQUAL "amd64") + if (OPENLIBM_ARCH_FOLDER STREQUAL "i387" OR OPENLIBM_ARCH_FOLDER STREQUAL "amd64") list(APPEND OPENLIBM_C_SOURCE # ld80 "${PROJECT_SRC}/ld80/invtrig.c" @@ -358,13 +366,13 @@ if (LONG_DOUBLE_NOT_DOUBLE) "${PROJECT_SRC}/ld80/s_erfl.c" ) - if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") list(APPEND OPENLIBM_C_SOURCE "${PROJECT_SRC}/ld80/s_nanl.c" ) endif() else() - if(${OPENLIBM_ARCH_FOLDER} STREQUAL "aarch64") + if(OPENLIBM_ARCH_FOLDER STREQUAL "aarch64") list(APPEND OPENLIBM_C_SOURCE # ld128 "${PROJECT_SRC}/ld128/invtrig.c" @@ -390,7 +398,7 @@ if (LONG_DOUBLE_NOT_DOUBLE) "${PROJECT_SRC}/ld128/s_erfl.c" ) - if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") list(APPEND OPENLIBM_C_SOURCE "${PROJECT_SRC}/ld128/s_nanl.c" ) @@ -400,7 +408,7 @@ if (LONG_DOUBLE_NOT_DOUBLE) endif() # Architecture-specific sources -if (${OPENLIBM_ARCH_FOLDER} STREQUAL "amd64") +if (OPENLIBM_ARCH_FOLDER STREQUAL "amd64") list(APPEND OPENLIBM_C_SOURCE "${PROJECT_SRC}/amd64/fenv.c" ) @@ -431,17 +439,17 @@ if (${OPENLIBM_ARCH_FOLDER} STREQUAL "amd64") "${PROJECT_SRC}/amd64/e_fmodl.S" ) -elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "aarch64") +elseif(OPENLIBM_ARCH_FOLDER STREQUAL "aarch64") list(APPEND OPENLIBM_C_SOURCE "${PROJECT_SRC}/aarch64/fenv.c" ) -elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "arm") +elseif(OPENLIBM_ARCH_FOLDER STREQUAL "arm") list(APPEND OPENLIBM_C_SOURCE "${PROJECT_SRC}/${OPENLIBM_ARCH_FOLDER}/fenv.c" ) -elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "i387") +elseif(OPENLIBM_ARCH_FOLDER STREQUAL "i387") list(APPEND OPENLIBM_C_SOURCE "${PROJECT_SRC}/i387/fenv.c" ) @@ -493,7 +501,7 @@ elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "i387") "${PROJECT_SRC}/i387/s_truncl.S" ) - if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") list(APPEND OPENLIBM_ASM_SOURCE "${PROJECT_SRC}/i387/s_scalbn.S" "${PROJECT_SRC}/i387/s_scalbnf.S" @@ -501,11 +509,11 @@ elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "i387") ) endif() -elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "powerpc") +elseif(OPENLIBM_ARCH_FOLDER STREQUAL "powerpc") list(APPEND OPENLIBM_C_SOURCE "${PROJECT_SRC}/powerpc/fenv.c" ) -elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "riscv64") +elseif(OPENLIBM_ARCH_FOLDER STREQUAL "riscv64") list(APPEND OPENLIBM_C_SOURCE "${PROJECT_SRC}/riscv64/fenv.c") else() @@ -514,18 +522,18 @@ endif() # Filter out C implementation from compilation list if a native implementation exists -foreach(FILE_TO_REMOVE ${OPENLIBM_ASM_SOURCE}) +foreach(FILE_TO_REMOVE IN LISTS OPENLIBM_ASM_SOURCE) # Get filename and strip out extension cmake_path(GET FILE_TO_REMOVE FILENAME FILENAME_TO_REMOVE) - cmake_path(REMOVE_EXTENSION FILENAME_TO_REMOVE OUTPUT_VARIABLE FILENAME_TO_REMOVE) + cmake_path(REMOVE_EXTENSION FILENAME_TO_REMOVE) message(DEBUG "Filename to remove: ${FILENAME_TO_REMOVE}") # Go through files and remove one with the same name - foreach(CUR_FILE ${OPENLIBM_C_SOURCE}) + foreach(CUR_FILE IN LISTS OPENLIBM_C_SOURCE) cmake_path(GET CUR_FILE FILENAME CUR_FILENAME) - cmake_path(REMOVE_EXTENSION CUR_FILENAME OUTPUT_VARIABLE CUR_FILENAME) + cmake_path(REMOVE_EXTENSION CUR_FILENAME) - if(${CUR_FILENAME} STREQUAL ${FILENAME_TO_REMOVE}) + if(CUR_FILENAME STREQUAL ${FILENAME_TO_REMOVE}) list(REMOVE_ITEM OPENLIBM_C_SOURCE ${CUR_FILE}) message(DEBUG "Removed source file from compilation list: ${CUR_FILE}") break() @@ -539,6 +547,18 @@ target_sources("${PROJECT_NAME}" PRIVATE ${OPENLIBM_C_SOURCE} ${OPENLIBM_ASM_SOURCE} ) +if(openlibm_PIC) + include(CheckPIESupported) + check_pie_supported() +endif() + +set_target_properties("${PROJECT_NAME}" PROPERTIES + C_STANDARD 99 + C_STANDARD_REQUIRED ON + C_EXTENSIONS OFF + POSITION_INDEPENDENT_CODE ${openlibm_PIC} +) + # Include directories list(APPEND OPENLIBM_INCLUDE_DIRS @@ -548,10 +568,10 @@ list(APPEND OPENLIBM_INCLUDE_DIRS "${PROJECT_SRC}/src" ) -if(${OPENLIBM_ARCH_FOLDER} STREQUAL "i387" OR ${OPENLIBM_ARCH_FOLDER} STREQUAL "amd64" OR ${OPENLIBM_ARCH_FOLDER} STREQUAL "powerpc") +if(OPENLIBM_ARCH_FOLDER STREQUAL "i387" OR OPENLIBM_ARCH_FOLDER STREQUAL "amd64" OR OPENLIBM_ARCH_FOLDER STREQUAL "powerpc") list(APPEND OPENLIBM_INCLUDE_DIRS "${PROJECT_SRC}/ld80") else() - if(${OPENLIBM_ARCH_FOLDER} STREQUAL "aarch64" OR ${OPENLIBM_ARCH_FOLDER} STREQUAL "riscv64") + if(OPENLIBM_ARCH_FOLDER STREQUAL "aarch64" OR OPENLIBM_ARCH_FOLDER STREQUAL "riscv64") list(APPEND OPENLIBM_INCLUDE_DIRS "${PROJECT_SRC}/ld128") endif() endif()