diff --git a/.github/workflows/conda-package-cf.yml b/.github/workflows/conda-package-cf.yml new file mode 100644 index 00000000..229994da --- /dev/null +++ b/.github/workflows/conda-package-cf.yml @@ -0,0 +1,397 @@ +name: Conda package with conda-forge + +on: + push: + branches: + - master + pull_request: + +permissions: read-all + +env: + PACKAGE_NAME: mkl_umath + MODULE_NAME: mkl_umath + TEST_ENV_NAME: test_mkl_umath + VER_SCRIPT1: "import json; f = open('ver.json', 'r'); j = json.load(f); f.close(); d = j['mkl_umath'][0];" + VER_SCRIPT2: "print('='.join((d[s] for s in ('version', 'build'))))" + CONDA_BUILD_VERSION: 26.3.0 + +jobs: + build_linux: + runs-on: ubuntu-latest + strategy: + matrix: + include: + - python: "3.10" + numpy: "2.2" + - python: "3.11" + numpy: "2.3" + - python: "3.12" + numpy: "2.3" + - python: "3.13" + numpy: "2.3" + - python: "3.14" + numpy: "2.3" + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@d07a454dad7609a92316b57b23c9ccfd4f59af66 # 0.13.1 + with: + access_token: ${{ github.token }} + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + + - name: Set pkgs_dirs + run: | + echo "pkgs_dirs: [~/.conda/pkgs]" >> ~/.condarc + + - name: Cache conda packages + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + env: + CACHE_NUMBER: 0 # Increase to reset cache + with: + path: ~/.conda/pkgs + key: + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-${{hashFiles('**/meta.yaml') }} + restore-keys: | + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}- + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- + + - name: Add conda to system path + run: echo "$CONDA/bin" >> "$GITHUB_PATH" + + - name: Update conda + run: | + conda update -n base --all + + - name: Install conda-build + run: conda install -n base conda-build=${{ env.CONDA_BUILD_VERSION }} -c conda-forge --override-channels + + - name: Show Conda info + run: | + conda info --all + + - name: List base environment packages + run: | + conda list -n base + + - name: Build conda package + run: | + CHANNELS=(-c "conda-forge" --override-channels) + VERSIONS=(--python "${{ matrix.python }}" --numpy "${{ matrix.numpy }}") + TEST=(--no-test) + echo "CONDA_BLD=${CONDA}/conda-bld/linux-64" >> "$GITHUB_ENV" + + conda build \ + "${TEST[@]}" \ + "${VERSIONS[@]}" \ + "${CHANNELS[@]}" \ + conda-recipe-cf + + - name: Upload artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} + path: ${{ env.CONDA_BLD }}/${{ env.PACKAGE_NAME }}-*.conda + + test_linux: + needs: build_linux + runs-on: ${{ matrix.runner }} + + strategy: + matrix: + python: ["3.10", "3.11", "3.12", "3.13", "3.14"] + numpy: ['numpy">=2"'] + experimental: [false] + runner: [ubuntu-latest] + continue-on-error: ${{ matrix.experimental }} + env: + CHANNELS: -c conda-forge --override-channels + + steps: + - name: Download artifact + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} + - name: Update conda + run: | + conda update -n base --all + - name: Install conda-index + run: | + conda install -n base conda-index -c conda-forge --override-channels + - name: Show Conda info + run: | + conda info --all + - name: List base environment packages + run: | + conda list -n base + - name: Add conda to system path + run: echo "$CONDA/bin" >> "$GITHUB_PATH" + - name: Create conda channel + run: | + mkdir -p "$GITHUB_WORKSPACE/channel/linux-64" + mv "${PACKAGE_NAME}"-*.conda "$GITHUB_WORKSPACE/channel/linux-64" + conda index "$GITHUB_WORKSPACE/channel" + # Test channel + conda search "$PACKAGE_NAME" -c "$GITHUB_WORKSPACE/channel" --override-channels + - name: Test conda channel + run: | + conda search "$PACKAGE_NAME" -c "$GITHUB_WORKSPACE"/channel --override-channels --info --json > "$GITHUB_WORKSPACE"/ver.json + cat "$GITHUB_WORKSPACE"/ver.json + - name: Collect dependencies + run: | + CHANNELS=(-c "$GITHUB_WORKSPACE/channel" -c "conda-forge" --override-channels) + PACKAGE_VERSION="$(python -c "${VER_SCRIPT1} ${VER_SCRIPT2}")" + conda create -n "${{ env.TEST_ENV_NAME }}" "${PACKAGE_NAME}=${PACKAGE_VERSION}" "python=${{ matrix.python }}" ${{ matrix.numpy }} "${CHANNELS[@]}" --only-deps --dry-run > lockfile + - name: Display lockfile + run: cat lockfile + + - name: Set pkgs_dirs + run: | + echo "pkgs_dirs: [~/.conda/pkgs]" >> ~/.condarc + + - name: Cache conda packages + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + env: + CACHE_NUMBER: 0 # Increase to reset cache + with: + path: ~/.conda/pkgs + key: + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-${{hashFiles('lockfile') }} + restore-keys: | + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}- + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- + + - name: Install mkl_umath + run: | + CHANNELS=(-c "$GITHUB_WORKSPACE/channel" -c "conda-forge" --override-channels) + PACKAGE_VERSION="$(python -c "${VER_SCRIPT1} ${VER_SCRIPT2}")" + conda create -n "${{ env.TEST_ENV_NAME }}" "python=${{ matrix.python }}" ${{ matrix.numpy }} "$PACKAGE_NAME=${PACKAGE_VERSION}" pytest "${CHANNELS[@]}" + # Test installed packages + conda list -n "${{ env.TEST_ENV_NAME }}" + + - name: Smoke test + run: | + source "$CONDA/etc/profile.d/conda.sh" + conda activate "${{ env.TEST_ENV_NAME }}" + python -c "import mkl_umath, numpy as np; mkl_umath.patch_numpy_umath(); np.sin(np.linspace(0, 1, num=10**6));" + + - name: Run tests + run: | + source "$CONDA/etc/profile.d/conda.sh" + conda activate "${{ env.TEST_ENV_NAME }}" + pytest -v --pyargs ${{ env.MODULE_NAME }} + + build_windows: + runs-on: windows-latest + + strategy: + matrix: + include: + - python: "3.10" + numpy: "2.2" + - python: "3.11" + numpy: "2.4.4" + - python: "3.12" + numpy: "2.4.4" + - python: "3.13" + numpy: "2.4.4" + - python: "3.14" + numpy: "2.4.4" + env: + conda-bld: C:\Miniconda\conda-bld\win-64\ + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@d07a454dad7609a92316b57b23c9ccfd4f59af66 # 0.13.1 + with: + access_token: ${{ github.token }} + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + + - uses: conda-incubator/setup-miniconda@8ee1f361103df19b6f8c8655fd3967a8ecb162d5 # v4.0.1 + with: + auto-update-conda: true + miniforge-version: latest + activate-environment: build + channels: conda-forge + python-version: ${{ matrix.python }} + conda-build-version: ${{ env.CONDA_BUILD_VERSION }} + + - name: Cache conda packages + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + env: + CACHE_NUMBER: 3 # Increase to reset cache + with: + path: /home/runner/conda_pkgs_dir + key: + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-${{hashFiles('**/meta.yaml') }} + restore-keys: | + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}- + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- + + - name: Store conda paths as envs + shell: bash -l {0} + run: | + echo "CONDA_BLD=$CONDA/conda-bld/win-64/" | tr "\\\\" '/' >> "$GITHUB_ENV" + + - name: Install conda build + run: | + conda activate + conda install -y conda-build + conda list -n base + + - name: Build conda package + run: | + conda activate + conda build --no-test --python ${{ matrix.python }} --numpy ${{ matrix.numpy }} -c conda-forge --override-channels conda-recipe-cf + + - name: Upload artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} + path: ${{ env.CONDA_BLD }}${{ env.PACKAGE_NAME }}-*.conda + + test_windows: + needs: build_windows + runs-on: ${{ matrix.runner }} + defaults: + run: + shell: cmd /C CALL {0} + strategy: + matrix: + python: ["3.10", "3.11", "3.12", "3.13", "3.14"] + numpy: ['numpy">=2"'] + experimental: [false] + runner: [windows-latest] + continue-on-error: ${{ matrix.experimental }} + env: + workdir: '${{ github.workspace }}' + CHANNELS: -c conda-forge --override-channels + + steps: + - name: Download artifact + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} + + - uses: conda-incubator/setup-miniconda@8ee1f361103df19b6f8c8655fd3967a8ecb162d5 # v4.0.1 + with: + auto-update-conda: true + miniforge-version: latest + activate-environment: ${{ env.TEST_ENV_NAME }} + channels: conda-forge + conda-remove-defaults: "true" + python-version: ${{ matrix.python }} + + - name: Install conda-index + run: | + conda install -n base conda-index + + - name: Show Conda info + run: | + conda info --all + + - name: List base environment packages + run: | + conda list -n base + + - name: Create conda channel with the artifact bit + shell: cmd /C CALL {0} + run: | + echo ${{ env.workdir }} + mkdir ${{ env.workdir }}\channel + mkdir ${{ env.workdir }}\channel\win-64 + move ${{ env.PACKAGE_NAME }}-*.conda ${{ env.workdir }}\channel\win-64 + dir ${{ env.workdir }}\channel\win-64 + + - name: Index the channel + shell: cmd /C CALL {0} + run: | + conda index ${{ env.workdir }}\channel + + - name: Dump mkl_umath version info from created channel to STDOUT + shell: cmd /C CALL {0} + run: | + conda search ${{ env.PACKAGE_NAME }} -c ${{ env.workdir }}/channel --override-channels --info --json + + - name: Dump mkl_umath version info from created channel into ver.json + shell: cmd /C CALL {0} + run: | + conda search ${{ env.PACKAGE_NAME }} -c ${{ env.workdir }}/channel --override-channels --info --json > ${{ env.workdir }}\ver.json + + - name: Output content of workdir + shell: pwsh + run: Get-ChildItem -Path ${{ env.workdir }} + + - name: Output content of produced ver.json + shell: pwsh + run: Get-Content -Path ${{ env.workdir }}\ver.json + + - name: Collect dependencies + shell: cmd /C CALL {0} + run: | + @ECHO ON + IF NOT EXIST ver.json ( + copy /Y ${{ env.workdir }}\ver.json . + ) + SET "SCRIPT=%VER_SCRIPT1% %VER_SCRIPT2%" + FOR /F "tokens=* USEBACKQ" %%F IN (`python -c "%SCRIPT%"`) DO ( + SET PACKAGE_VERSION=%%F + ) + conda install -n ${{ env.TEST_ENV_NAME }} ${{ env.PACKAGE_NAME }}=%PACKAGE_VERSION% python=${{ matrix.python }} ${{ matrix.numpy }} -c ${{ env.workdir }}/channel ${{ env.CHANNELS }} --only-deps --dry-run > lockfile + + - name: Display lockfile content + shell: pwsh + run: Get-Content -Path .\lockfile + + - name: Cache conda packages + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + env: + CACHE_NUMBER: 0 # Increase to reset cache + with: + path: /home/runner/conda_pkgs_dir + key: + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-${{hashFiles('lockfile') }} + restore-keys: | + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}- + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- + + # add intel-openmp as an explicit dependency + # to avoid it being missed when package version is specified exactly + - name: Install mkl_umath + shell: cmd /C CALL {0} + run: | + @ECHO ON + IF NOT EXIST ver.json ( + copy /Y ${{ env.workdir }}\ver.json . + ) + set "SCRIPT=%VER_SCRIPT1% %VER_SCRIPT2%" + FOR /F "tokens=* USEBACKQ" %%F IN (`python -c "%SCRIPT%"`) DO ( + SET PACKAGE_VERSION=%%F + ) + SET "TEST_DEPENDENCIES=pytest pytest-cov" + SET "WORKAROUND_DEPENDENCIES=intel-openmp" + SET "DEPENDENCIES=%TEST_DEPENDENCIES% %WORKAROUND_DEPENDENCIES%" + conda install -n ${{ env.TEST_ENV_NAME }} ${{ env.PACKAGE_NAME }}=%PACKAGE_VERSION% %DEPENDENCIES% python=${{ matrix.python }} ${{ matrix.numpy }} -c ${{ env.workdir }}/channel ${{ env.CHANNELS }} + + - name: Report content of test environment + shell: cmd /C CALL {0} + run: | + conda activate + echo "Value of CONDA environment variable was: " %CONDA% + echo "Value of CONDA_PREFIX environment variable was: " %CONDA_PREFIX% + conda info && conda list -n ${{ env.TEST_ENV_NAME }} + + - name: Smoke test + shell: cmd /C CALL {0} + run: | + @ECHO ON + conda activate ${{ env.TEST_ENV_NAME }} + python -c "import mkl_umath, numpy as np; mkl_umath.patch_numpy_umath(); np.sin(np.linspace(0, 1, num=10**6));" + + - name: Run tests + shell: cmd /C CALL {0} + run: | + conda activate ${{ env.TEST_ENV_NAME }} + python -m pytest -v -s --pyargs ${{ env.MODULE_NAME }} diff --git a/conda-recipe-cf/bld.bat b/conda-recipe-cf/bld.bat index e27318da..edbb0d1e 100644 --- a/conda-recipe-cf/bld.bat +++ b/conda-recipe-cf/bld.bat @@ -2,24 +2,8 @@ REM A workaround for activate-dpcpp.bat issue to be addressed in 2021.4 set "LIB=%BUILD_PREFIX%\Library\lib;%BUILD_PREFIX%\compiler\lib;%LIB%" set "INCLUDE=%BUILD_PREFIX%\include;%INCLUDE%" -"%PYTHON%" setup.py clean --all -set "SKBUILD_ARGS=-G Ninja -- -DCMAKE_C_COMPILER:PATH=icx -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON" +set "CMAKE_GENERATOR=Ninja" +set "CMAKE_ARGS=-DCMAKE_C_COMPILER:PATH=icx -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON" -FOR %%V IN (14.0.0 14 15.0.0 15 16.0.0 16 17.0.0 17) DO @( - REM set DIR_HINT if directory exists - IF EXIST "%BUILD_PREFIX%\Library\lib\clang\%%V\" ( - SET "SYCL_INCLUDE_DIR_HINT=%BUILD_PREFIX%\Library\lib\clang\%%V" - ) -) - -if NOT "%WHEELS_OUTPUT_FOLDER%"=="" ( - rem Install and assemble wheel package from the build bits - "%PYTHON%" setup.py install bdist_wheel %SKBUILD_ARGS% - if errorlevel 1 exit 1 - copy dist\mkl_umath*.whl %WHEELS_OUTPUT_FOLDER% - if errorlevel 1 exit 1 -) ELSE ( - rem Only install - "%PYTHON%" setup.py install %SKBUILD_ARGS% - if errorlevel 1 exit 1 -) +%PYTHON% -m pip install --no-build-isolation --no-deps . --verbose +if errorlevel 1 exit 1 diff --git a/conda-recipe-cf/build.sh b/conda-recipe-cf/build.sh index 00414a1c..f8993d68 100644 --- a/conda-recipe-cf/build.sh +++ b/conda-recipe-cf/build.sh @@ -1,31 +1,3 @@ -#!/bin/bash +#!/bin/bash -x -# This is necessary to help DPC++ find Intel libraries such as SVML, IRNG, etc in build prefix -export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${BUILD_PREFIX}/lib" - -# Intel LLVM must cooperate with compiler and sysroot from conda -echo "--gcc-toolchain=${BUILD_PREFIX} --sysroot=${BUILD_PREFIX}/${HOST}/sysroot -target ${HOST}" > icx_for_conda.cfg -ICXCFG="$(pwd)/icx_for_conda.cfg" -export ICXCFG - -read -r GLIBC_MAJOR GLIBC_MINOR <<< "$(conda list '^sysroot_linux-64$' \ - | tail -n 1 | awk '{print $2}' | grep -oP '\d+' | head -n 2 | tr '\n' ' ')" - -export CMAKE_GENERATOR="Ninja" -SKBUILD_ARGS=( - "--" - "-DCMAKE_C_COMPILER:PATH=icx" - "-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON" -) - -if [ -n "${WHEELS_OUTPUT_FOLDER}" ]; then - # Install packages and assemble wheel package from built bits - WHEELS_BUILD_ARGS=( - "-p" "manylinux_${GLIBC_MAJOR}_${GLIBC_MINOR}_x86_64" - ) - ${PYTHON} setup.py install bdist_wheel "${WHEELS_BUILD_ARGS[@]}" "${SKBUILD_ARGS[@]}" - cp dist/mkl_umath*.whl "${WHEELS_OUTPUT_FOLDER}" -else - # Perform regular install - ${PYTHON} setup.py install "${SKBUILD_ARGS[@]}" -fi +CC=icx CXX=icpx $PYTHON -m pip install --no-build-isolation --no-deps . diff --git a/conda-recipe-cf/conda_build_config.yaml b/conda-recipe-cf/conda_build_config.yaml new file mode 100644 index 00000000..6f302ab0 --- /dev/null +++ b/conda-recipe-cf/conda_build_config.yaml @@ -0,0 +1,24 @@ +numpy: + - '1.26.4' +c_compiler: # [linux] + - gcc # [linux] +cxx_compiler: # [linux] + - gxx # [linux] +cxx_compiler_version: # [linux] + - '14' # [linux] +c_stdlib: # [linux] + - sysroot # [linux] +c_stdlib_version: # [linux] + - '2.28' # [linux] +c_stdlib: # [win] + - vs # [win] +cxx_compiler: # [win] + - vs2022 # [win] +c_compiler: # [win] + - vs2022 # [win] +CFLAGS: + - -fno-fast-math # [linux] +CXXFLAGS: + - -fno-fast-math # [linux] +CL: + - /fp:precise # [win] diff --git a/conda-recipe-cf/meta.yaml b/conda-recipe-cf/meta.yaml index 2657c2d7..ce83093f 100644 --- a/conda-recipe-cf/meta.yaml +++ b/conda-recipe-cf/meta.yaml @@ -17,8 +17,8 @@ requirements: build: - {{ compiler('c') }} - {{ compiler('cxx') }} + - {{ stdlib('c') }} - {{ compiler('dpcpp') }} >=2024.2 # [not osx] - - sysroot_linux-64 >=2.28 # [linux] host: - setuptools >=77 - cmake