diff --git a/.ci/ci.yaml b/.ci/ci.yaml deleted file mode 100644 index ab57443861..0000000000 --- a/.ci/ci.yaml +++ /dev/null @@ -1,81 +0,0 @@ -trigger: - branches: - include: - - '*' -pr: - branches: - include: - - '*' - -jobs: -- job: Linux - timeoutInMinutes: 360 - pool: - vmImage: ubuntu-latest - strategy: - matrix: - Plain: - # Precompiled headers with debug symbols can cause too much disk space / - # RAM usage. - CMakeArgs: '-DDEBUG=ON -DPROFILE=OFF -DBUILD_TESTS=ON -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=OFF -DBUILD_GO_BINDINGS=OFF -DBUILD_R_BINDINGS=OFF -DUSE_PRECOMPILED_HEADERS=OFF' - Python: - CMakeArgs: '-DDEBUG=OFF -DPROFILE=OFF -DBUILD_TESTS=ON -DBUILD_PYTHON_BINDINGS=ON -DPYTHON_EXECUTABLE=/usr/bin/python3 -DBUILD_GO_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=OFF -DBUILD_R_BINDINGS=OFF' - binding: 'python' - python.version: '3.7' - Julia: - CMakeArgs: '-DDEBUG=OFF -DPROFILE=OFF -DBUILD_TESTS=ON -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=ON -DBUILD_GO_BINDINGS=OFF -DJULIA_EXECUTABLE=/opt/julia-1.10.4/bin/julia -DBUILD_R_BINDINGS=OFF' - binding: 'julia' - Go: - CMakeArgs: '-DDEBUG=OFF -DPROFILE=OFF -DBUILD_TESTS=ON -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=OFF -DBUILD_GO_BINDINGS=ON -DBUILD_R_BINDINGS=OFF' - binding: 'go' - Markdown: - CMakeArgs: '-DDEBUG=OFF -DPROFILE=OFF -DBUILD_TESTS=ON -DBUILD_MARKDOWN_BINDINGS=ON -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_GO_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=OFF -DBUILD_R_BINDINGS=OFF' - - steps: - - template: linux-steps.yaml - -- job: macOS - timeoutInMinutes: 360 - pool: - vmImage: macOS-latest - strategy: - matrix: - # clang on OS X segfaults when using precompiled headers, so we disable - # them. - Plain: - python.version: '3.8' - CMakeArgs: '-DDEBUG=ON -DPROFILE=OFF -DBUILD_TESTS=ON -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=OFF -DBUILD_GO_BINDINGS=OFF -DBUILD_R_BINDINGS=OFF -DUSE_PRECOMPILED_HEADERS=OFF' - Python: - python.version: '3.8' - binding: 'python' - CMakeArgs: '-DDEBUG=ON -DPROFILE=OFF -DBUILD_TESTS=ON -DBUILD_PYTHON_BINDINGS=ON -DBUILD_JULIA_BINDINGS=OFF -DBUILD_GO_BINDINGS=OFF -DBUILD_R_BINDINGS=OFF -DUSE_PRECOMPILED_HEADERS=OFF' - Julia: - python.version: '3.8' - binding: 'julia' - CMakeArgs: '-DDEBUG=ON -DPROFILE=OFF -DBUILD_TESTS=ON -DBUILD_JULIA_BINDINGS=ON -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_GO_BINDINGS=OFF -DBUILD_R_BINDINGS=OFF -DUSE_PRECOMPILED_HEADERS=OFF' - Go: - python.version: '3.8' - binding: 'go' - CMakeArgs: '-DDEBUG=ON -DPROFILE=OFF -DBUILD_TESTS=ON -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=OFF -DBUILD_GO_BINDINGS=ON -DBUILD_R_BINDINGS=OFF -DUSE_PRECOMPILED_HEADERS=OFF' - - steps: - - template: macos-steps.yaml - -- job: WindowsVS17 - timeoutInMinutes: 360 - displayName: Windows VS17 - pool: - vmImage: windows-2022 - strategy: - matrix: - Plain: - CMakeArgs: '-DDEBUG=ON -DPROFILE=OFF -DBUILD_TESTS=ON -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_GO_BINDINGS=OFF -DBUILD_R_BINDINGS=OFF' - python.version: '2.7' - CMakeGenerator: '-G "Visual Studio 17 2022"' - MSBuildVersion: '17.0' - ArchiveNoLibs: 'mlpack-windows-vs17-no-libs.zip' - ArchiveLibs: 'mlpack-windows-vs17.zip' - ArchiveTests: 'mlpack_test-vs17.xml' - - steps: - - template: windows-steps.yaml diff --git a/.ci/linux-steps.yaml b/.ci/linux-steps.yaml deleted file mode 100644 index 42e06068ac..0000000000 --- a/.ci/linux-steps.yaml +++ /dev/null @@ -1,93 +0,0 @@ -steps: -# Checkout repository -- checkout: self - clean: true - fetchDepth: 1 - -# Set python version -- task: UsePythonVersion@0 - inputs: - versionSpec: '$(python.version)' - condition: ne(variables['python.version'], '') - -# Install build dependencies. -- script: | - # Workaround to avoid a build failure, because we run out of memory. - free -h - df -h - sudo dd if=/dev/zero of=/usr/swapfile.img bs=1024 count=12M - sudo mkswap /usr/swapfile.img - sudo swapon /usr/swapfile.img - free -h - df -h - - git clone --depth 1 https://github.com/mlpack/jenkins-conf.git conf - - sudo apt-get install --yes --allow-unauthenticated \ - libopenblas-dev libstb-dev libcereal-dev xz-utils ccache - - if [ "$BINDING" = "python" ]; then - python -m pip install --upgrade pip - python -m pip install --upgrade --ignore-installed setuptools cython pandas wheel - fi - - if [ "$BINDING" = "julia" ]; then - wget https://julialang-s3.julialang.org/bin/linux/x64/1.10/julia-1.10.4-linux-x86_64.tar.gz - sudo tar -C /opt/ -xvpf julia-1.10.4-linux-x86_64.tar.gz - fi - - ## Show the ccache config settings, and zero the statistics counter - ccache --show-config - ccache --zero-stats - - # Install armadillo. - curl -k -L https://sourceforge.net/projects/arma/files/armadillo-10.8.2.tar.xz | tar -xvJ && \ - cd armadillo* && \ - cmake . && \ - make && \ - sudo make install && \ - cd .. - - # Install ensmallen. - wget https://ensmallen.org/files/ensmallen-latest.tar.gz - tar -xvzpf ensmallen-latest.tar.gz # Unpack into ensmallen-*/. - cd ensmallen-*/ && \ - sudo cp -vr include/* /usr/include/ && \ - cd .. - - displayName: 'Install Build Dependencies' - -# Configure mlpack (CMake) -- script: | - mkdir build && cd build - cmake $CMAKEARGS -DPYTHON_EXECUTABLE=`which python` -DCEREAL_INCLUDE_DIR=/usr/include/ .. - displayName: 'CMake' - -# Build mlpack -- script: cd build && make -j2 - displayName: 'Build' - -# Run tests via ctest. -# The OMP_NUM_THREADS is to prevent thrashing on older versions of OpenBLAS -# (0.3.26 and older) where OpenMP and pthreads aren't playing together well. -- script: cd build && OMP_NUM_THREADS=1 CTEST_OUTPUT_ON_FAILURE=1 ctest -T Test . - displayName: 'Run tests via ctest' - -# Ccache stats (two verbosity levels supported) -- script: ccache --show-stats --verbose --verbose - displayName: 'Show ccache stats' - -# Publish test results to Azure Pipelines -- task: PublishTestResults@2 - inputs: - testResultsFormat: cTest - testResultsFiles: build/Testing/*/Test.xml - failTaskOnFailedTests: true - displayName: 'Publish tests' - -# Publish build artifacts to Azure Pipelines -- task: PublishBuildArtifacts@1 - inputs: - pathtoPublish: 'build/Testing/' - artifactName: 'Tests' - displayName: 'Publish artifacts test results' diff --git a/.ci/macos-steps.yaml b/.ci/macos-steps.yaml deleted file mode 100644 index 0de6bc5183..0000000000 --- a/.ci/macos-steps.yaml +++ /dev/null @@ -1,83 +0,0 @@ -steps: -# Checkout repository -- checkout: self - clean: true - fetchDepth: 1 - -# Set python version. -- task: UsePythonVersion@0 - inputs: - versionSpec: '$(python.version)' - -# Install Build Dependencies -- script: | - set -e - sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer - brew install libomp openblas armadillo cereal ensmallen ccache - - if [ "$BINDING" = "python" ]; then - pip install --upgrade pip - pip install cython numpy pandas zipp configparser wheel - fi - - if [ "$BINDING" = "julia" ]; then - brew install --cask julia - fi - - if [ "$BINDING" = "go" ]; then - brew install go - fi - - if [ "$BINDING" = "R" ]; then - # R needs to be told about ccache as it is not invoked directly by cmake - # - # ccache also needs two configuration settings due to where/how it constructs directories - # - # Note that every developer who would like to take advantage for ccache - # for R builds has to run this as well locally (once as it persists locally) - mkdir -p ~/.R - cp ${Build.SourcesDirectory}/.github/etc/R_Makevars_clang ~/.R/Makevars - ccache --set-config "sloppiness=include_file_ctime" - ccache --set-config "hash_dir=false" - ccache --show-config - ccache --zero-stats - fi - - displayName: 'Install Build Dependencies' - -# Configure mlpack (CMake) -- script: | - mkdir build && cd build - if [ "$BINDING" = "python" ]; then - cmake $CMAKEARGS -DPYTHON_EXECUTABLE=$(which python) .. - else - cmake $CMAKEARGS .. - fi - displayName: 'CMake' - -# Build mlpack -- script: cd build && make -j2 - displayName: 'Build' - -# Run tests via ctest. -- script: cd build && CTEST_OUTPUT_ON_FAILURE=1 ctest -T Test . - displayName: 'Run tests via ctest' - -# Ccache stats (two verbosity levels supported -- script: ccache --show-stats --verbose --verbose - displayName: 'Show ccache stats' - -# Publish test results to Azure Pipelines -- task: PublishTestResults@2 - inputs: - testResultsFormat: cTest - testResultsFiles: build/Testing/*/Test.xml - failTaskOnFailedTests: true - displayName: 'Publish tests' - -# Publish build artifacts to Azure Pipelines -- task: PublishBuildArtifacts@1 - inputs: - pathtoPublish: 'build/Testing/' - artifactName: 'Tests' - displayName: 'Publish artifacts test results' diff --git a/.ci/windows-steps.yaml b/.ci/windows-steps.yaml deleted file mode 100644 index 2f6eb90b93..0000000000 --- a/.ci/windows-steps.yaml +++ /dev/null @@ -1,214 +0,0 @@ -steps: -- checkout: self - clean: true - fetchDepth: 1 -- task: NuGetToolInstaller@0 - inputs: - versionSpec: '5.3.0' - -# Fetch build dependencies -- powershell: | - nuget install OpenBLAS -o $(Agent.ToolsDirectory) - nuget install ensmallen -o $(Agent.ToolsDirectory) -Version 2.17.0 - ## Delete all ensmallen dependencies including armadillo headers, we do not need them here - Remove-Item $(Agent.ToolsDirectory)\ensmallen.2.17.0\installed\x64-linux\share -Force -Recurse - Remove-Item $(Agent.ToolsDirectory)\ensmallen.2.17.0\installed\x64-linux\include\armadillo_bits -Force -Recurse - Remove-Item $(Agent.ToolsDirectory)\ensmallen.2.17.0\installed\x64-linux\include\armadillo -Force - - displayName: 'Fetch build dependencies' - -# Get cereal -- bash: | - curl -L https://github.com/USCiLab/cereal/archive/refs/tags/v1.3.2.tar.gz -o cereal-1.3.2.tar.gz - tar -xvzf cereal-1.3.2.tar.gz - displayName: 'Download cereal' - -# Configure armadillo -- bash: | - git clone --depth 1 https://github.com/mlpack/jenkins-conf.git conf - - curl -O -L https://sourceforge.net/projects/arma/files/armadillo-10.8.2.tar.xz -o armadillo-10.8.2.tar.xz - tar -xvf armadillo-10.8.2.tar.xz - - cd armadillo-10.8.2/ && cmake $(CMakeGenerator) \ - -DBLAS_LIBRARY:FILEPATH=$(Agent.ToolsDirectory)/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a \ - -DLAPACK_LIBRARY:FILEPATH=$(Agent.ToolsDirectory)/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a \ - -DCMAKE_PREFIX:FILEPATH=../../armadillo \ - -DBUILD_SHARED_LIBS=OFF \ - -DCMAKE_BUILD_TYPE=Release . - displayName: 'Configure armadillo' - -# Build armadillo -- task: MSBuild@1 - inputs: - solution: 'armadillo-10.8.2/*.sln' - msbuildLocationMethod: 'location' - msbuildVersion: $(MSBuildVersion) - configuration: 'Release' - msbuildArchitecture: 'x64' - msbuildArguments: /m /p:BuildInParallel=true - clean: false - maximumCpuCount: false - displayName: 'Build armadillo' - -# Configure mlpack -- powershell: | - mkdir build - cd build - - cmake $(CMakeGenerator) ` - $(CMakeArgs) ` - -DBLAS_LIBRARIES:FILEPATH=$(Agent.ToolsDirectory)\OpenBLAS.0.2.14.1\lib\native\lib\x64\libopenblas.dll.a ` - -DLAPACK_LIBRARIES:FILEPATH=$(Agent.ToolsDirectory)\OpenBLAS.0.2.14.1\lib\native\lib\x64\libopenblas.dll.a ` - -DARMADILLO_INCLUDE_DIR="..\armadillo-10.8.2\tmp\include" ` - -DARMADILLO_LIBRARY="..\armadillo-10.8.2\Release\armadillo.lib" ` - -DCEREAL_INCLUDE_DIR="..\cereal-1.3.2\include" ` - -DENSMALLEN_INCLUDE_DIR=$(Agent.ToolsDirectory)\ensmallen.2.17.0\installed\x64-linux\include ` - -DBUILD_JULIA_BINDINGS=OFF ` - -DCMAKE_BUILD_TYPE=Release .. - displayName: 'Configure mlpack' - -# Build mlpack -- task: MSBuild@1 - inputs: - solution: 'build/*.sln' - msbuildLocationMethod: 'location' - msbuildVersion: $(MSBuildVersion) - configuration: 'Release' - msbuildArchitecture: 'x64' - maximumCpuCount: false - clean: false - displayName: 'Build mlpack' - -# Build documentation. This involves setting up Ruby so that kramdown is -# available. -- task: UseRubyVersion@0 - inputs: - versionSpec: '>= 2.5' - addToPath: true - displayName: 'Set up Ruby' - -- bash: | - gem install kramdown - DISABLE_HTML_CHECKS=1 ./scripts/build-docs.sh - displayName: 'Build mlpack documentation' - -# Configure mlpack -- powershell: | - # The .dlls are stored in the bin/ directory, and those are the ones we need - # to run with. - cp $(Agent.ToolsDirectory)\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.* build\Release\ - cp $(Agent.ToolsDirectory)\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.* build\ - displayName: 'Copy DLLs to run tests' - -# Run tests via ctest. -- bash: | - cd build - cmake --build . --target mlpack_test --config Release - CTEST_OUTPUT_ON_FAILURE=1 ctest -T Test -C Release . -j1 - displayName: 'Run tests via ctest' - -# Copy artifacts -- powershell: | - mkdir exe-archive - cp build\Release\*.exe exe-archive\ - displayName: 'Copy artifacts' - -# Build artifacts archive -- task: ArchiveFiles@2 - inputs: - rootFolderOrFile: 'exe-archive\' - includeRootFolder: false - archiveType: 'zip' - archiveFile: $(ArchiveNoLibs) - replaceExistingArchive: true - displayName: 'Build artifacts' - -- task: ArchiveFiles@2 - inputs: - rootFolderOrFile: 'build\Release\' - includeRootFolder: false - archiveType: 'zip' - archiveFile: $(ArchiveLibs) - replaceExistingArchive: true - displayName: 'Build artifacts' - -# Build MSI installer. -- powershell: | - # Preparing installer staging. - mkdir dist\win-installer\mlpack-win-installer\Sources\lib - cp build\Release\*.lib dist\win-installer\mlpack-win-installer\Sources\lib\ - cp build\Release\*.exp dist\win-installer\mlpack-win-installer\Sources\lib\ - cp build\Release\*.dll dist\win-installer\mlpack-win-installer\Sources\ - cp build\Release\*.exe dist\win-installer\mlpack-win-installer\Sources\ - cp $(Agent.ToolsDirectory)\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.dll dist\win-installer\mlpack-win-installer\Sources\ - - # Copy documentation. - mkdir dist\win-installer\mlpack-win-installer\Sources\doc - cp doc\html dist\win-installer\mlpack-win-installer\Sources\doc -recurse - - # Copy sources. - mkdir dist\win-installer\mlpack-win-installer\Sources\include\mlpack - cp src\mlpack.hpp dist\win-installer\mlpack-win-installer\Sources\include - cp src\mlpack\*.hpp dist\win-installer\mlpack-win-installer\Sources\include\mlpack - cp src\mlpack\core dist\win-installer\mlpack-win-installer\Sources\include\mlpack -recurse - cp src\mlpack\methods dist\win-installer\mlpack-win-installer\Sources\include\mlpack -recurse - - # Copy examples. - cp doc\examples dist\win-installer\mlpack-win-installer\Sources\ -recurse - cp src\mlpack\tests\data\german.csv dist\win-installer\mlpack-win-installer\Sources\examples\sample-ml-app\sample-ml-app\data\ - - # Check current git version or mlpack version. - $ver = (Get-Content "src\mlpack\core\util\version.hpp" | where {$_ -like "*MLPACK_VERSION*"}); - $env:MLPACK_VERSION += $ver[0].substring($ver[0].length - 1, 1) + '.'; - $env:MLPACK_VERSION += $ver[1].substring($ver[1].length - 1, 1) + '.'; - $env:MLPACK_VERSION += $ver[2].substring($ver[2].length - 1, 1); - - if (Test-Path "src/mlpack/core/util/gitversion.hpp") - { - $ver = (Get-Content "src/mlpack/core/util/gitversion.hpp"); - $env:INSTALL_VERSION = $ver.Split('"')[1].Split(' ')[1]; - } - else - { - $env:INSTALL_VERSION = $env:MLPACK_VERSION; - } - - # Build the MSI installer. - cd dist\win-installer\mlpack-win-installer - & 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\MSBuild.exe' ` - -t:rebuild ` - -p:Configuration=Release ` - -p:TreatWarningsAsErrors=True ` - mlpack-win-installer.wixproj - displayName: 'Build MSI Windows installer' - -# Publish artifacts to Azure Pipelines -- task: PublishBuildArtifacts@1 - inputs: - pathtoPublish: $(ArchiveNoLibs) - artifactName: $(ArchiveNoLibs) - displayName: 'Publish artifacts no-libs' -- task: PublishBuildArtifacts@1 - inputs: - pathtoPublish: $(ArchiveLibs) - artifactName: $(ArchiveLibs) - displayName: 'Publish artifacts complete' -- task: PublishBuildArtifacts@1 - inputs: - pathtoPublish: 'build/Testing/' - artifactName: 'Tests' - displayName: 'Publish artifacts test results' -- task: PublishBuildArtifacts@1 - inputs: - pathtoPublish: 'dist\win-installer\mlpack-win-installer\bin\Release\mlpack-windows.msi' - artifactName: mlpack-windows-installer - displayName: 'Publish Windows MSI installer' - -# Publish test results to Azure Pipelines -- task: PublishTestResults@2 - inputs: - testResultsFormat: cTest - testResultsFiles: build/Testing/*/Test.xml - failTaskOnFailedTests: true - displayName: 'Publish tests' diff --git a/.github/actions/binding_run_tests/action.yml b/.github/actions/binding_run_tests/action.yml new file mode 100644 index 0000000000..87718ce29f --- /dev/null +++ b/.github/actions/binding_run_tests/action.yml @@ -0,0 +1,100 @@ +# This action sets up any language-specific environment for any of mlpack's +# bindings. +name: "Run binding tests" +description: "Run tests for mlpack's bindings to other languages and gather results in junit format." +inputs: + lang: + required: true + description: "The language to run binding tests for." + +runs: + using: "composite" + steps: + # + # Python bindings. + # + - name: "Run Python binding tests" + if: inputs.lang == 'Python' + shell: bash + run: | + # Run manually instead of through CTest so we can get XML output. + ROOTDIR=`pwd`; + cd build/src/mlpack/bindings/python/ + python3 -m pytest tests/ --junit-xml="$ROOTDIR/build/python_bindings.junit.xml" + + # + # Julia bindings. + # + - name: "Run Julia binding tests" + if: inputs.lang == 'Julia' + shell: bash + run: | + # Run manually instead of through CTest so we can get XML output. + # We use the TestReports.jl package for getting output in the right + # format. + ROOTDIR=`pwd`; + cd build/src/mlpack/bindings/julia/mlpack/ + JULIA_PROJECT=$PWD $JULIA_EXECUTABLE -e \ + "using Pkg; Pkg.add(\"TestReports\"); using TestReports; TestReports.test(\"mlpack\")" + mv testlog.xml $ROOTDIR/build/julia_bindings.junit.xml + + # + # R bindings. + # + - name: "Run R binding tests" + if: inputs.lang == 'R' + shell: bash + run: | + ROOTDIR=`pwd`; + cd build/src/mlpack/bindings/R/mlpack/ + Rscript -e "library(pkgload); load_all('.'); library(testthat); options(testthat.output_file='r_bindings.junit.xml'); test_file('tests/testthat/test-R_binding.R', reporter = 'junit')" + mv tests/testthat/r_bindings.junit.xml $ROOTDIR/build/r_bindings.junit.xml + + - name: "Upload R package artifact" + if: inputs.lang == 'R' && runner.os == 'Linux' # Only upload one tarball. + uses: actions/upload-artifact@v4.4.0 + with: + name: mlpack_r_tarball + path: build/src/mlpack/bindings/R/${{ env.MLPACK_R_PACKAGE }} + + - name: "Install R CMD check dependencies" + if: inputs.lang == 'R' + shell: Rscript {0} + run: | + install.packages(c('remotes', 'rcmdcheck', 'curl')) + remotes::install_deps('build/src/mlpack/bindings/R/${{ env.MLPACK_R_PACKAGE }}', dependencies = TRUE) + + - name: "Run R CMD check" + if: inputs.lang == 'R' + shell: bash + # TODO: revert to error_on = 'warning' + run: Rscript -e "rcmdcheck::rcmdcheck('build/src/mlpack/bindings/R/${{ env.MLPACK_R_PACKAGE }}', args = c('--no-manual', '--as-cran'), error_on = 'error', check_dir = 'check')" + + # TODO: upload check results on failure + + # + # Go bindings. + # + - name: "Run Go binding tests (Linux)" + if: inputs.lang == 'Go' && runner.os == 'Linux' + shell: bash + run: | + # Run manually instead of through CTest so we can get XML output (via + # an extra tool). + go install github.com/jstemmer/go-junit-report/v2@latest + ROOTDIR=`pwd`; + cd build/src/mlpack/bindings/go/src/mlpack.org/v1/mlpack/ + go test -v $ROOTDIR/src/mlpack/bindings/go/tests/go_binding_test.go 2>&1 |\ + $HOME/go/bin/go-junit-report | tee $ROOTDIR/build/go_bindings.junit.xml; + + - name: "Run Go binding tests (macOS)" + if: inputs.lang == 'Go' && runner.os == 'macOS' + shell: bash + run: | + # Run manually instead of through CTest so we can get XML output (via + # an extra tool). + go install github.com/jstemmer/go-junit-report/v2@latest + ROOTDIR=`pwd`; + cd build/src/mlpack/bindings/go/src/mlpack.org/v1/mlpack/ + CGO_LDFLAGS="-Wl,-no_warn_duplicate_libraries" go test -v $ROOTDIR/src/mlpack/bindings/go/tests/go_binding_test.go 2>&1 |\ + $HOME/go/bin/go-junit-report | tee $ROOTDIR/build/go_bindings.junit.xml; diff --git a/.github/actions/binding_setup/action.yml b/.github/actions/binding_setup/action.yml new file mode 100644 index 0000000000..9bbdddcf5a --- /dev/null +++ b/.github/actions/binding_setup/action.yml @@ -0,0 +1,126 @@ +# This action sets up any language-specific environment for any of mlpack's +# bindings. +name: "Set up binding environments" +description: "Install build and runtime dependencies for mlpack's bindings to other languages." +inputs: + lang: + required: true + description: "The language to set up bindings for." + +runs: + using: "composite" + steps: + # + # Python bindings. + # + - name: "Set up Python (Linux)" + if: inputs.lang == 'Python' && runner.os == 'Linux' + shell: bash + run: | + python3 -m pip install --upgrade pip + python3 -m pip install --upgrade --ignore-installed setuptools cython \ + pandas wheel pytest + echo "CMAKE_BINDING_ARGS=-DPYTHON_EXECUTABLE=`which python3`" >> $GITHUB_ENV + + - name: "Set up Python (macOS)" + if: inputs.lang == 'Python' && runner.os == 'macOS' + shell: bash + run: | + /opt/homebrew/bin/python3 -m pip install --break-system-packages --upgrade pip + /opt/homebrew/bin/python3 -m pip install --break-system-packages setuptools cython pandas zipp configparser wheel pytest + echo "CMAKE_BINDING_ARGS=-DPYTHON_EXECUTABLE=/opt/homebrew/bin/python3" >> $GITHUB_ENV + + # + # Julia bindings. + # + - name: "Set up Julia on Linux" + if: inputs.lang == 'Julia' && runner.os == 'Linux' + shell: bash + run: | + wget https://julialang-s3.julialang.org/bin/linux/x64/1.10/julia-1.10.4-linux-x86_64.tar.gz + sudo tar -C /opt/ -xvpf julia-1.10.4-linux-x86_64.tar.gz + echo "CMAKE_BINDING_ARGS=-DJULIA_EXECUTABLE=/opt/julia-1.10.4/bin/julia" >> $GITHUB_ENV + echo "JULIA_EXECUTABLE=/opt/julia-1.10.4/bin/julia" >> $GITHUB_ENV + + - name: "Set up Julia on macOS" + if: inputs.lang == 'Julia' && runner.os == 'macOS' + shell: bash + run: | + brew install --cask julia + echo "CMAKE_BINDING_ARGS=-DJULIA_EXECUTABLE=/opt/homebrew/bin/julia" >> $GITHUB_ENV + echo "JULIA_EXECUTABLE=/opt/homebrew/bin/julia" >> $GITHUB_ENV + + # + # R bindings. + # + - name: Extract mlpack version for R bindings + if: inputs.lang == 'R' + shell: bash + run: | + MLPACK_VERSION_MAJOR=$(grep -i ".*#define MLPACK_VERSION_MAJOR.*" src/mlpack/core/util/version.hpp | grep -o "[0-9]*") + MLPACK_VERSION_MINOR=$(grep -i ".*#define MLPACK_VERSION_MINOR.*" src/mlpack/core/util/version.hpp | grep -o "[0-9]*") + MLPACK_VERSION_PATCH=$(grep -i ".*#define MLPACK_VERSION_PATCH.*" src/mlpack/core/util/version.hpp | grep -o "[0-9]*") + MLPACK_VERSION_VALUE=${MLPACK_VERSION_MAJOR}.${MLPACK_VERSION_MINOR}.${MLPACK_VERSION_PATCH} + echo "MLPACK_R_PACKAGE=$(echo mlpack_"$MLPACK_VERSION_VALUE".tar.gz)" >> $GITHUB_ENV + + - name: "Setup pandoc for R" + if: inputs.lang == 'R' + uses: r-lib/actions/setup-pandoc@v2 + + # Setup r2u (linux) + - name: Setup r2u + if: inputs.lang == 'R' && runner.os == 'Linux' + uses: eddelbuettel/github-actions/r2u-setup@master + + - name: Setup p3m.dev (macOS / Windows) + uses: r-lib/actions/setup-r@v2 + if: inputs.lang == 'R' && (runner.os == 'Windows' || runner.os == 'macOS') + with: + r-version: "release" + use-public-rspm: true + + - name: "Configure ccache for R" + if: inputs.lang == 'R' + shell: bash + run: | + ccache --set-config "sloppiness=include_file_ctime" + ccache --set-config "hash_dir=false" + ccache --zero-stats + + - name: "Query R dependencies" + if: inputs.lang == 'R' + shell: bash + run: | + cp src/mlpack/bindings/R/mlpack/DESCRIPTION.in DESCRIPTION + Rscript -e 'install.packages(c("remotes", "roxygen2", "pkgbuild"))' + Rscript -e 'remotes::install_deps(".", dependencies=TRUE)' + + - name: Install cereal manually for R + if: inputs.lang == 'R' + shell: bash + run: | + # We don't install cereal via apt, because the Debian packagers + # split the rapidjson dependency into a separate package. We will + # bundle the cereal sources with the R package, so we want them to + # be exactly the upstream sources (with rapidjson included). + wget https://github.com/USCiLab/cereal/archive/refs/tags/v1.3.2.tar.gz + tar -xvzpf v1.3.2.tar.gz + # + # These directives cause warnings on CRAN: + # https://github.com/USCiLab/cereal/blob/master/include/cereal/external/base64.hpp#L28-L31 + # The command below comments them out. + sed 's|#pragma|// #pragma|' cereal-1.3.2/include/cereal/external/base64.hpp > cereal-1.3.2/include/cereal/external/base64.hpp.tmp + mv cereal-1.3.2/include/cereal/external/base64.hpp.tmp cereal-1.3.2/include/cereal/external/base64.hpp + # + # Fix cereal compilation on clang 19+; see + # https://github.com/USCiLab/cereal/pull/835 + sed 's|::template apply|::apply|' cereal-1.3.2/include/cereal/types/tuple.hpp > cereal-1.3.2/include/cereal/types/tuple.hpp.tmp + mv cereal-1.3.2/include/cereal/types/tuple.hpp.tmp cereal-1.3.2/include/cereal/types/tuple.hpp + + # + # Go bindings. + # + - name: "Set up Go on macOS" + if: inputs.lang == 'Go' && runner.os == 'macOS' + shell: bash + run: brew install go diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..a14a7c63a8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,279 @@ +# ci.yml: defines all the CI jobs run for each commit and pull request. For +# Linux and macOS, we run a matrix job that tests all the bindings. For +# Windows, we just run one build (see the later part of the file). + +on: + workflow_dispatch: + push: + branches: + - master + - main + pull_request: + branches: + - master + - main + release: + types: [published, created, edited] +permissions: + contents: read +name: mlpack.mlpack + +jobs: + ### + ### Linux and macOS test matrix for all binding types. + ### + ci_matrix: + strategy: + fail-fast: false # Run all configurations even if one fails. + matrix: + config: [ + { + runner: ubuntu-latest, + os: 'Linux', + name: 'Debug', + # Disable [DEBUG] output from the tests because it's WAY too verbose. + cmakeVars: '-DCMAKE_BUILD_TYPE=Debug -DBUILD_CLI_EXECUTABLES=OFF -DCMAKE_CXX_FLAGS="-DMLPACK_NO_PRINT_DEBUG"' + }, + { + runner: ubuntu-latest, + os: 'Linux', + name: 'CLI', + cmakeVars: '-DBUILD_CLI_EXECUTABLES=ON' + }, + { + runner: ubuntu-latest, + os: 'Linux', + name: 'Python', + cmakeVars: '-DBUILD_CLI_EXECUTABLES=OFF -DBUILD_PYTHON_BINDINGS=ON' + }, + { + runner: ubuntu-latest, + os: 'Linux', + name: 'Julia', + cmakeVars: '-DBUILD_CLI_EXECUTABLES=OFF -DBUILD_JULIA_BINDINGS=ON' + }, + { + runner: ubuntu-latest, + os: 'Linux', + name: 'R', + cmakeVars: '-DBUILD_CLI_EXECUTABLES=OFF -DBUILD_R_BINDINGS=ON -DCEREAL_INCLUDE_DIR=../cereal-1.3.2/include/' + }, + { + runner: ubuntu-latest, + os: 'Linux', + name: 'Go', + cmakeVars: '-DBUILD_CLI_EXECUTABLES=OFF -DBUILD_GO_BINDINGS=ON' + }, + { + runner: ubuntu-latest, + os: 'Linux', + name: 'Markdown', + cmakeVars: '-DBUILD_CLI_EXECUTABLES=OFF -DBUILD_MARKDOWN_BINDINGS=ON' + }, + { + runner: macOS-latest, + os: 'macOS', + name: 'CLI', + cmakeVars: '-DBUILD_CLI_EXECUTABLES=ON' + }, + { + runner: macOS-latest, + os: 'macOS', + name: 'Python', + cmakeVars: '-DBUILD_CLI_EXECUTABLES=OFF -DBUILD_PYTHON_BINDINGS=ON' + } + ] + + name: '${{ matrix.config.os }} (${{ matrix.config.name }})' + if: ${{ github.repository == 'mlpack/mlpack' }} + runs-on: ${{ matrix.config.runner }} + + steps: + - uses: actions/checkout@v3 + + # Set up ccache. + - name: Get ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: ${{ matrix.config.os }}-${{ matrix.config.name }} + variant: ccache + max-size: 1G + + # Set up the build environment for any bindings, if needed. + - name: Set up binding dependencies + uses: ./.github/actions/binding_setup + with: + lang: ${{ matrix.config.name }} + + # Install build dependencies. + - name: Install build dependencies (Linux) + if: matrix.config.os == 'Linux' + run: | + git clone --depth 1 https://github.com/mlpack/jenkins-conf.git conf + sudo apt-get update + sudo apt-get install --yes --allow-unauthenticated \ + libopenblas-dev libstb-dev libcereal-dev xz-utils + # Install the oldest Armadillo version that we support. + curl -k -L https://sourceforge.net/projects/arma/files/armadillo-10.8.2.tar.xz | tar -xvJ && \ + cd armadillo* && \ + cmake . && \ + make && \ + sudo make install && \ + cd .. + # Install the latest ensmallen version. + wget https://ensmallen.org/files/ensmallen-latest.tar.gz + tar -xvzpf ensmallen-latest.tar.gz # Unpack into ensmallen-*/. + cd ensmallen-*/ && \ + sudo cp -vr include/* /usr/include/ && \ + cd .. + + - name: Install build dependencies (macOS) + if: matrix.config.os == 'macOS' + run: | + sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer + brew install libomp openblas armadillo cereal ensmallen ccache + + # Because mlpack's precompiled headers basically include everything + # (mlpack.hpp, core.hpp, etc.), changes to a single file will invalidate + # the ccache entry---so it is better to leave it turned off, so that + # ccache entries will be at a more granular level and are more likely to + # be reused across runs. + - name: Configure mlpack with CMake + run: | + mkdir build && cd build + cmake ${{ matrix.config.cmakeVars }} $CMAKE_BINDING_ARGS -DUSE_PRECOMPILED_HEADERS=OFF -DBUILD_TESTS=ON ../ + + - name: Build mlpack + run: cd build && make -j4 + + # Run the tests manually so that we can get JUnit output. + - name: Run mlpack_test + run: | + cd build + # The use of only one thread is to prevent thrashing on older versions + # of OpenBLAS (0.3.26 and older) where OpenMP and pthreads aren't + # playing together well. + OMP_NUM_THREADS=1 bin/mlpack_test -r junit | tee /dev/stderr > mlpack_test.junit.xml + # Remove version numbers and other non-xml from the output. + cat mlpack_test.junit.xml | sed '/ mlpack_test.junit.xml.tmp + mv mlpack_test.junit.xml.tmp mlpack_test.junit.xml + + # Run binding tests for each binding type. + - name: Run binding tests + uses: ./.github/actions/binding_run_tests + with: + lang: ${{ matrix.config.name }} + + - name: Parse test output + uses: rcurtin/test-summary-action@dist + if: success() || failure() + with: + paths: "build/*.junit.xml" + show: "fail, skip" + fail_job: true + print_output: true + + ### + ### Windows CI testing. + ### + + ci_windows: + name: 'Windows build: VS2022' + if: ${{ github.repository == 'mlpack/mlpack' }} + runs-on: windows-2022 + + steps: + - uses: actions/checkout@v3 + + # Set up ccache. + - name: Get ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: ${{ runner.os }} + variant: ccache + max-size: 5G + + # Set up Visual Studio. + - name: Set up Visual Studio + uses: microsoft/setup-msbuild@v2 + + # Install build dependencies. + - name: Install build dependencies (Windows) + shell: powershell + run: | + nuget install OpenBLAS -o deps + nuget install ensmallen -o deps -Version 2.17.0 + # Delete all ensmallen dependencies including armadillo headers, we do not need them here. + Remove-Item deps\ensmallen.2.17.0\installed\x64-linux\share -Force -Recurse + Remove-Item deps\ensmallen.2.17.0\installed\x64-linux\include\armadillo_bits -Force -Recurse + Remove-Item deps\ensmallen.2.17.0\installed\x64-linux\include\armadillo -Force + + # Install the oldest supported version of Armadillo and install cereal. + - name: Install some dependencies manually + shell: bash + run: | + cd deps/ + curl -L https://sourceforge.net/projects/arma/files/armadillo-10.8.2.tar.xz -o armadillo-10.8.2.tar.xz + tar -xf armadillo-10.8.2.tar.xz + cd armadillo-10.8.2/ + cmake -G "Visual Studio 17 2022" \ + -DBLAS_LIBRARY:FILEPATH=${{ github.workspace }}/deps/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a \ + -DLAPACK_LIBRARY:FILEPATH=${{ github.workspace }}/deps/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a \ + -DBUILD_SHARED_LIBS=OFF . + # Disable the wrapper because transitive linking doesn't work on + # Windows anyway. + cp tmp/include/armadillo_bits/config.hpp tmp/include/armadillo_bits/config.hpp.tmp + cat tmp/include/armadillo_bits/config.hpp.tmp | sed 's|#define ARMA_USE_WRAPPER|// #define ARMA_USE_WRAPPER|' \ + > tmp/include/armadillo_bits/config.hpp + # Now download and unpack cereal. + cd ../ + curl -L https://github.com/USCiLab/cereal/archive/refs/tags/v1.3.2.tar.gz -o cereal-1.3.2.tar.gz + tar -xzf cereal-1.3.2.tar.gz + # Download and unpack STB. + curl -O https://www.mlpack.org/files/stb.tar.gz + tar -xzf stb.tar.gz + + # Because mlpack's precompiled headers basically include everything + # (mlpack.hpp, core.hpp, etc.), changes to a single file will invalidate + # the ccache entry---so it is better to leave it turned off, so that + # ccache entries will be at a more granular level and are more likely to + # be reused across runs. + - name: Configure mlpack with CMake + shell: bash + run: | + mkdir build && cd build + cmake -DUSE_PRECOMPILED_HEADERS=OFF -DBUILD_TESTS=ON \ + -DARMADILLO_INCLUDE_DIR=../deps/armadillo-10.8.2/tmp/include/ \ + -DBLAS_LIBRARIES='${{ github.workspace }}'/deps/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a \ + -DLAPACK_LIBRARIES='${{ github.workspace }}'/deps/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a \ + -DENSMALLEN_INCLUDE_DIR=../deps/ensmallen.2.17.0/installed/x64-linux/include/ \ + -DCEREAL_INCLUDE_DIR=../deps/cereal-1.3.2/include/ \ + -DSTB_IMAGE_INCLUDE_DIR='${{ github.workspace }}'/deps/stb/include/ \ + -DCMAKE_HAS_WORKING_STATIC_STB=1 \ + ../ + + - name: Build mlpack + run: cd build && cmake --build . --config Release + + # Run the tests manually so that we can get JUnit output. + - name: Run mlpack_test + shell: bash + run: | + # The .dlls are stored in the bin/ directory, and those are the ones + # we need to run with. + cp -v '${{ github.workspace }}'/deps/OpenBLAS.0.2.14.1/lib/native/bin/x64/* build/Release + cd build/ + ./Release/mlpack_test.exe -r junit > mlpack_test.junit.xml + # Remove version numbers and other non-xml from the output. + cat mlpack_test.junit.xml | sed '/ mlpack_test.junit.xml.tmp + rm mlpack_test.junit.xml + mv mlpack_test.junit.xml.tmp mlpack_test.junit.xml + + - name: Parse test output + uses: rcurtin/test-summary-action@dist + if: success() || failure() + with: + paths: "build/*.junit.xml" + show: "fail, skip" + fail_job: true + print_output: true diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 0c4527e0b1..0000000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,181 +0,0 @@ -on: - workflow_dispatch: - push: - branches: - - master - - main - pull_request: - branches: - - master - - main - release: - types: [published, created, edited] -permissions: - contents: read -name: mlpack.mlpack - -jobs: - jobR: - name: mlpack R tarball - if: ${{ github.repository == 'mlpack/mlpack' }} - runs-on: ubuntu-latest - - outputs: - r_bindings: ${{ steps.mlpack_version.outputs.mlpack_r_package }} - - steps: - - uses: actions/checkout@v3 - - - name: Extract mlpack version - id: mlpack_version - run: | - MLPACK_VERSION_MAJOR=$(grep -i ".*#define MLPACK_VERSION_MAJOR.*" src/mlpack/core/util/version.hpp | grep -o "[0-9]*") - MLPACK_VERSION_MINOR=$(grep -i ".*#define MLPACK_VERSION_MINOR.*" src/mlpack/core/util/version.hpp | grep -o "[0-9]*") - MLPACK_VERSION_PATCH=$(grep -i ".*#define MLPACK_VERSION_PATCH.*" src/mlpack/core/util/version.hpp | grep -o "[0-9]*") - MLPACK_VERSION_VALUE=${MLPACK_VERSION_MAJOR}.${MLPACK_VERSION_MINOR}.${MLPACK_VERSION_PATCH} - echo "mlpack_r_package=$(echo mlpack_"$MLPACK_VERSION_VALUE".tar.gz)" >> $GITHUB_OUTPUT - - # Setup Pandoc - - name: Setup pandoc - uses: r-lib/actions/setup-pandoc@v2 - - # Setup r2u (linux) - - name: Setup r2u - uses: eddelbuettel/github-actions/r2u-setup@master - - # Get and set up ccache - - name: Get CCache - uses: hendrikmuhs/ccache-action@v1.2 - with: - # can also be eg ${{ matrix.os }} but just ubuntu-latest here - key: ${{ runner.os }} - # this is the default but 'sccache' can be selected here - variant: ccache - - - name: Prepare R for Ccache - run: | - mkdir -p ~/.R - cp -vax .github/etc/R_Makevars_${{ runner.os }} ~/.R/Makevars - - - name: Configure Ccache for R - run: | - ccache --set-config "sloppiness=include_file_ctime" - ccache --set-config "hash_dir=false" - ccache --show-config - ccache --zero-stats - - - name: Query dependencies - run: | - cp src/mlpack/bindings/R/mlpack/DESCRIPTION.in DESCRIPTION - Rscript -e 'install.packages(c("remotes", "roxygen2", "pkgbuild"))' - Rscript -e 'remotes::install_deps(".", dependencies=TRUE)' - - - name: Install Additional Build Dependencies - run: | - sudo apt-get update - # We don't install cereal via apt, because the Debian packagers - # split the rapidjson dependency into a separate package. We will - # bundle the cereal sources with the R package, so we want them to - # be exactly the upstream sources (with rapidjson included). - sudo apt-get install -y --allow-unauthenticated libopenblas-dev liblapack-dev g++ libensmallen-dev libhdf5-dev libarmadillo-dev libcurl4-openssl-dev - wget https://github.com/USCiLab/cereal/archive/refs/tags/v1.3.2.tar.gz - tar -xvzpf v1.3.2.tar.gz - # - # These directives cause warnings on CRAN: - # https://github.com/USCiLab/cereal/blob/master/include/cereal/external/base64.hpp#L28-L31 - # The command below comments them out. - sed -i 's|#pragma|// #pragma|' cereal-1.3.2/include/cereal/external/base64.hpp - # - # Fix cereal compilation on clang 19+; see - # https://github.com/USCiLab/cereal/pull/835 - sed -i 's|::template apply|::apply|' cereal-1.3.2/include/cereal/types/tuple.hpp - - - name: CMake - run: | - mkdir build - cd build && cmake -DDEBUG=OFF -DPROFILE=OFF -DBUILD_CLI_EXECUTABLES=OFF -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=OFF -DBUILD_GO_BINDINGS=OFF -DBUILD_R_BINDINGS=ON -DDOWNLOAD_DEPENDENCIES=ON -DBUILD_TESTS=ON -DCEREAL_INCLUDE_DIR=../cereal-1.3.2/include/ .. - - - name: Build - run: | - cd build && make -j4 - - - name: Run tests via ctest - run: | - # The OMP_NUM_THREADS is to prevent thrashing on older versions of - # OpenBLAS (0.3.26 and older) where OpenMP and pthreads aren't playing - # together well. - cd build && OMP_NUM_THREADS=2 CTEST_OUTPUT_ON_FAILURE=1 ctest -T Test . - - - name: Upload R packages - uses: actions/upload-artifact@v4.4.0 - with: - name: mlpack_r_tarball - path: build/src/mlpack/bindings/R/${{ steps.mlpack_version.outputs.mlpack_r_package }} - - R-CMD-check: - needs: jobR - runs-on: ${{ matrix.config.os }} - - name: ${{ matrix.config.name }} - if: ${{ github.repository == 'mlpack/mlpack' }} - - strategy: - fail-fast: false - matrix: - config: - #- { os: windows-latest, r: "release", name: "Windows R" } - - { os: macOS-latest, r: "release", name: "macOS R" } - - { os: ubuntu-latest, r: "release", name: "Linux R" } - - env: - MAKEFLAGS: "-j 4" - R_BUILD_ARGS: "--no-build-vignettes" - R_CHECK_ARGS: "--no-build-vignettes" - _R_CHECK_FORCE_SUGGESTS: 0 - R_REMOTES_NO_ERRORS_FROM_WARNINGS: true - GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - R_KEEP_PKG_SOURCE: yes - - steps: - - uses: actions/download-artifact@v4.1.8 - with: - name: mlpack_r_tarball - - - name: Setup pandoc - uses: r-lib/actions/setup-pandoc@v2 - - - name: Setup p3m.dev (macos) - uses: r-lib/actions/setup-r@v2 - if: runner.os == 'Windows' || runner.os == 'macOS' - with: - r-version: ${{ matrix.config.r }} - use-public-rspm: true - - - name: Setup r2u (linux) - if: runner.os != 'Windows' && runner.os != 'macOS' - uses: eddelbuettel/github-actions/r2u-setup@master - - - name: Add system packages (linux) - if: runner.os != 'Windows' && runner.os != 'macOS' - run: | - sudo apt update -qq - sudo apt install -y --allow-unauthenticated libopenblas-dev liblapack-dev libensmallen-dev libarmadillo-dev - - - name: Install dependencies - run: | - Rscript -e "install.packages(c('remotes', 'rcmdcheck'))" - Rscript -e "remotes::install_deps('${{ needs.jobR.outputs.r_bindings }}', dependencies=TRUE)" - - - name: Run the package check - # TODO: revert to error_on = 'warning' - run: | - Rscript -e "rcmdcheck::rcmdcheck('${{ needs.jobR.outputs.r_bindings }}', args = c('--no-manual','--as-cran'), error_on = 'error', check_dir = 'check')" - - - name: Upload check results - if: failure() - uses: actions/upload-artifact@v4.4.0 - with: - name: ${{ runner.os }}-r${{ matrix.config.r }}-results - path: | - check/mlpack.Rcheck/00check.log - check/mlpack.Rcheck/00install.out diff --git a/CMake/TestStaticSTB.cmake b/CMake/TestStaticSTB.cmake index 91a114d665..5eb17b255e 100644 --- a/CMake/TestStaticSTB.cmake +++ b/CMake/TestStaticSTB.cmake @@ -32,6 +32,9 @@ if(NOT DEFINED CMAKE_HAS_WORKING_STATIC_STB) if (CMAKE_HAS_WORKING_STATIC_STB) message(STATUS "Check that STB static implementation mode links " "correctly... success") + message(STATUS + "Determining if STB's static implementation can link correctly passed " + "with the following output:\n${out}\n\n") set(CMAKE_HAS_WORKING_STATIC_STB 1 CACHE INTERNAL "Does STB static implementation mode link correctly") file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log @@ -40,6 +43,9 @@ if(NOT DEFINED CMAKE_HAS_WORKING_STATIC_STB) else () message(STATUS "Check that STB static implementation mode links " "correctly... fail") + message(STATUS + "Determining if STB's static implementation can link correctly failed " + "with the following output:\n${out}\n\n") set(CMAKE_HAS_WORKING_STATIC_STB 0 CACHE INTERNAL "Does STB static implementation mode link correctly") file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log diff --git a/CMakeLists.txt b/CMakeLists.txt index ebf4c5164f..4a6627d039 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -314,6 +314,7 @@ endif() # Include directories for the previous dependencies. set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${ARMADILLO_INCLUDE_DIRS}) set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${ARMADILLO_LIBRARIES}) +message(STATUS "Armadillo libraries: ${ARMADILLO_LIBRARIES}") if (USE_SYSTEM_STB) find_package(StbImage REQUIRED) diff --git a/doc/developer/ci.md b/doc/developer/ci.md index ef72515092..b516442e93 100644 --- a/doc/developer/ci.md +++ b/doc/developer/ci.md @@ -9,7 +9,6 @@ complex project, there are occasionally spurious failures or other unrelated problems. * [Basic compilation and test jobs](#basic-compilation-and-test-jobs) - * [R build](#r-build) * [Documentation build and test](#documentation-build-and-test) * [Style checks](#style-checks) * [Cross-compilation checks](#cross-compilation-checks) @@ -19,25 +18,29 @@ Also you can see the [list of CI infrastructure](#list-of-ci-infrastructure). ## Basic compilation and test jobs -Basic compilation and testing is done on Azure Pipelines. -We use Azure Pipelines primarily because of the large number of resources that +Basic compilation and testing is done on Github Actions. +We use Github Actions primarily because of the large number of resources that an mlpack build takes; our own [internal resources](#list-of-ci-infrastructure) are thus preserved for more specific usage. -Link: [***mlpack on Azure Pipelines***](https://dev.azure.com/mlpack/mlpack/_build/) +Link: [***mlpack on Github Actions***](https://github.com/mlpack/mlpack/actions) - * Builds and tests mlpack for Linux, OS X, and Windows. + * Builds and tests mlpack for Linux, macOS, and Windows. - * Also builds and tests bindings on Linux and OS X. + * Also builds and tests all bindings on Linux, and Python bindings on macOS. + + * Builds the R tarball that can be submitted to CRAN and publishes it as an + artifact. * Configurations for these jobs can be found in the mlpack repository under the - `.ci/` directory. + `.github/` directory. + - The main file for the build pipeline is `.github/workflows/ci.yml`. * *These jobs are most of what's shown in the jobs in a PR.* -***If your build is failing on Azure Pipelines:*** +***If your build is failing on Github Actions:*** - * Take a look at the build log to identify the issue. + * Take a look at the build summary and build logs to identify the issue. * If the failure is during `mlpack_test`, look through the test output to find where the actual failed test is. @@ -49,22 +52,20 @@ Link: [***mlpack on Azure Pipelines***](https://dev.azure.com/mlpack/mlpack/_bui - If the test seems like a random failure, try different random seeds: `bin/mlpack_test --rng-seed=X NameOfTest`. -## R build +## Binding tests -The R build uses Github Actions (not for any particular reason). +Inside of `.github/workflows/ci.yml`, the bindings are configured and built +(depending on the parameters of the matrix build) using a local Github action. +Similarly, the binding tests are also run using a local Github action. -Link: [***mlpack R build actions***](https://github.com/mlpack/mlpack/actions/workflows/main.yml) + * `.github/actions/binding_setup/main.yml` defines the steps required to set up + the environment for building each type of binding. Sometimes the steps are + specific to an OS (e.g. Linux/macOS/Windows). - * Job configuration is found in `.github/workflows/main.yml` - - * The job produces 1 artifact, which is the tarball that can be uploaded to - [CRAN](https://cran.r-project.org/). - - * When this job fails, it is usually because of: - - An intermittent problem downloading dependencies or setting up the - environment. - - A test failure which can probably be more easily debugged or reproduced via - the main [Azure Pipelines build jobs](#basic-compilation-and-test-jobs). + * `.github/actions/binding_run_tests/main.yml` defines the steps to run tests + for each binding type. Note that because we want output as junit XML so we + can parse it, sometimes we have to do strange things for some languages, and + we can't use CTest directly. ## Documentation build and test diff --git a/src/mlpack/bindings/R/mlpack/tests/testthat/test-R_binding.R b/src/mlpack/bindings/R/mlpack/tests/testthat/test-R_binding.R index 726f053706..923ccf7e43 100644 --- a/src/mlpack/bindings/R/mlpack/tests/testthat/test-R_binding.R +++ b/src/mlpack/bindings/R/mlpack/tests/testthat/test-R_binding.R @@ -325,6 +325,8 @@ test_that("TestVerbose", { # Test that we get no output when verbose output is disabled. test_that("TestNotVerbose", { + # Make sure that global verbosity is turned off. + options(mlpack.verbose = FALSE) expect_silent(test_r_binding(4.0, 12, "hello", build_model=TRUE)) }) diff --git a/src/mlpack/bindings/go/mlpack/arma_util.go b/src/mlpack/bindings/go/mlpack/arma_util.go index b107117353..02c1f31e40 100644 --- a/src/mlpack/bindings/go/mlpack/arma_util.go +++ b/src/mlpack/bindings/go/mlpack/arma_util.go @@ -1,7 +1,7 @@ package mlpack /* -#cgo CFLAGS: -I. -I/capi -g -Wall -Wno-unused-variable +#cgo CFLAGS: -I. -I/capi #cgo LDFLAGS: -L. -lmlpack_go_util #include #include diff --git a/src/mlpack/bindings/go/mlpack/io_util.go b/src/mlpack/bindings/go/mlpack/io_util.go index 226ff87ca0..ad50a2102c 100644 --- a/src/mlpack/bindings/go/mlpack/io_util.go +++ b/src/mlpack/bindings/go/mlpack/io_util.go @@ -1,7 +1,7 @@ package mlpack /* -#cgo CFLAGS: -I. -I/capi -g -Wall +#cgo CFLAGS: -I. -I/capi #cgo LDFLAGS: -L${SRCDIR} -Wl,-rpath,${SRCDIR} -lmlpack_go_util #include */ diff --git a/src/mlpack/bindings/go/print_go.cpp b/src/mlpack/bindings/go/print_go.cpp index 19d4ee33a1..f13fc9b632 100644 --- a/src/mlpack/bindings/go/print_go.cpp +++ b/src/mlpack/bindings/go/print_go.cpp @@ -78,7 +78,7 @@ void PrintGo(util::Params& params, // Now we must print the cgo's import libraries and files. cout << "/*" << endl; - cout << "#cgo CFLAGS: -I./capi -Wall" << endl; + cout << "#cgo CFLAGS: -I./capi" << endl; cout << "#cgo LDFLAGS: -L. -lmlpack_go_" << functionName << endl; cout << "#include " << endl; cout << "#include " << endl; diff --git a/src/mlpack/bindings/julia/tests/CMakeLists.txt b/src/mlpack/bindings/julia/tests/CMakeLists.txt index da99511949..9c3ec5832a 100644 --- a/src/mlpack/bindings/julia/tests/CMakeLists.txt +++ b/src/mlpack/bindings/julia/tests/CMakeLists.txt @@ -1,6 +1,9 @@ # Add the Julia binding test. add_julia_binding("" test_julia_binding) +# Julia expects the runtests.jl file to be in test/, not tests/. +file(COPY runtests.jl DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/../mlpack/test/) + add_test(NAME julia_binding_test - COMMAND ${JULIA_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/runtests.jl + COMMAND ${JULIA_EXECUTABLE} test/runtests.jl WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/) diff --git a/src/mlpack/bindings/julia/tests/runtests.jl b/src/mlpack/bindings/julia/tests/runtests.jl index 49517782c2..380a85e678 100644 --- a/src/mlpack/bindings/julia/tests/runtests.jl +++ b/src/mlpack/bindings/julia/tests/runtests.jl @@ -8,8 +8,6 @@ # 3-clause BSD license along with mlpack. If not, see # http://www.opensource.org/licenses/BSD-3-Clause for more information. -using Pkg -Pkg.activate(".") using Test using mlpack: test_julia_binding, GaussianKernel, serialize_bin, deserialize_bin using Serialization diff --git a/src/mlpack/bindings/python/CMakeLists.txt b/src/mlpack/bindings/python/CMakeLists.txt index 2668c6422d..f49827ab5c 100644 --- a/src/mlpack/bindings/python/CMakeLists.txt +++ b/src/mlpack/bindings/python/CMakeLists.txt @@ -113,7 +113,7 @@ set(CYTHON_SOURCES ) set(TEST_SOURCES - tests/dataset_info_test.py + tests/test_dataset_info.py tests/test_python_binding.py ) @@ -366,11 +366,8 @@ endmacro () if (BUILD_PYTHON_BINDINGS) if (BUILD_TESTS) add_test(NAME python_bindings_test - COMMAND ${PYTHON_EXECUTABLE} - ${CMAKE_BINARY_DIR}/src/mlpack/bindings/python/setup.py test + COMMAND ${PYTHON_EXECUTABLE} -m pytest tests/ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src/mlpack/bindings/python/) - set_tests_properties(python_bindings_test - PROPERTIES ENVIRONMENT "NO_BUILD=1;LD_LIBRARY_PATH=$ENV{LD_LIBRARY_PATH}:${CMAKE_BINARY_DIR}/lib/") endif () endif () diff --git a/src/mlpack/bindings/python/tests/dataset_info_test.py b/src/mlpack/bindings/python/tests/test_dataset_info.py similarity index 97% rename from src/mlpack/bindings/python/tests/dataset_info_test.py rename to src/mlpack/bindings/python/tests/test_dataset_info.py index 660558fcdc..7e39752548 100644 --- a/src/mlpack/bindings/python/tests/dataset_info_test.py +++ b/src/mlpack/bindings/python/tests/test_dataset_info.py @@ -306,15 +306,5 @@ class TestToMatrixWithInfo(unittest.TestCase): self.assertTrue(m[1] != m[2]) self.assertTrue(m[0] != m[2]) -def test_suite(): - """ - Run all tests. - """ - loader = unittest.TestLoader() - suite = unittest.TestSuite() - suite.addTest(loader.loadTestsFromTestCase(TestToMatrix)) - suite.addTest(loader.loadTestsFromTestCase(TestToMatrixWithInfo)) - return suite - if __name__ == '__main__': unittest.main() diff --git a/src/mlpack/core/util/log.hpp b/src/mlpack/core/util/log.hpp index 5b9478925d..b6dcd681b4 100644 --- a/src/mlpack/core/util/log.hpp +++ b/src/mlpack/core/util/log.hpp @@ -98,7 +98,8 @@ void Assert(bool condition, #define BASH_CLEAR "" #endif -#if defined(DEBUG) || defined(MLPACK_PRINT_DEBUG) +#if (defined(DEBUG) || defined(MLPACK_PRINT_DEBUG)) && \ + !defined(MLPACK_NO_PRINT_DEBUG) static util::PrefixedOutStream Debug = util::PrefixedOutStream(MLPACK_COUT_STREAM, BASH_CYAN "[DEBUG] " BASH_CLEAR); diff --git a/src/mlpack/tests/ann/layer/parametric_relu.cpp b/src/mlpack/tests/ann/layer/parametric_relu.cpp index 56113fe73e..e96d3a3686 100644 --- a/src/mlpack/tests/ann/layer/parametric_relu.cpp +++ b/src/mlpack/tests/ann/layer/parametric_relu.cpp @@ -20,9 +20,9 @@ using namespace mlpack; /** - * PReLU FORWARD Test. + * PReLU forward pass test. */ -TEST_CASE("PReLUFORWARDTest", "[ANNLayerTest]") +TEST_CASE("PReLUForwardTest", "[ANNLayerTest]") { arma::mat input = {{0.5, 1.2, 3.1}, {-2.2, -1.5, 0.8}, @@ -43,9 +43,9 @@ TEST_CASE("PReLUFORWARDTest", "[ANNLayerTest]") } /** - * PReLU BACKWARD Test. + * PReLU backward pass Test. */ -TEST_CASE("PReLUBACKWARDTest", "[ANNLayerTest]") +TEST_CASE("PReLUBackwardTest", "[ANNLayerTest]") { arma::mat input = {{0.5, 1.2, 3.1}, {-2.2, -1.5, 0.8}, @@ -73,9 +73,9 @@ TEST_CASE("PReLUBACKWARDTest", "[ANNLayerTest]") } /** - * PReLU GRADIENT Test. + * PReLU gradient pass test. */ -TEST_CASE("PReLUGRADIENTTest", "[ANNLayerTest]") +TEST_CASE("PReLUGradientTest", "[ANNLayerTest]") { arma::mat input = {{0.5, 1.2, 3.1}, {-2.2, -1.5, 0.8}, @@ -104,26 +104,27 @@ double ComputeMSRE(arma::mat input, arma::mat target) TEST_CASE("PReLUIntegrationTest", "[ANNLayerTest]") { arma::mat data; - data::Load("boston_housing_price.csv", data); + data::Load("boston_housing_price.csv", data, true /* fatal */); arma::mat labels; - data::Load("boston_housing_price_responses.csv", labels); - - arma::mat trainData, testData, trainLabels, testLabels; - data::Split(data, labels, trainData, testData, trainLabels, testLabels, 0.2); - - FFN model; - model.Add(10); - model.Add(0.01); - model.Add(3); - model.Add(0.01); - model.Add(1); + data::Load("boston_housing_price_responses.csv", labels, true /* fatal */); // Sometimes the model may not optimize correctly, so we allow a few trials. bool success = false; - for (size_t trial = 0; trial < 3; ++trial) + for (size_t trial = 0; trial < 5; ++trial) { - const size_t epochs = 250; - ens::RMSProp optimizer(0.003, 8, 0.99, 1e-8, epochs * trainData.n_cols); + arma::mat trainData, testData, trainLabels, testLabels; + data::Split(data, labels, trainData, testData, trainLabels, testLabels, + 0.2); + + FFN model; + model.Add(10); + model.Add(0.01); + model.Add(3); + model.Add(0.01); + model.Add(1); + + const size_t epochs = 500; + ens::RMSProp optimizer(0.0025, 8, 0.99, 1e-8, epochs * trainData.n_cols); model.Reset(data.n_rows); model.Train(trainData, trainLabels, optimizer); diff --git a/src/mlpack/tests/split_data_test.cpp b/src/mlpack/tests/split_data_test.cpp index 626ea15925..04e50bb47b 100644 --- a/src/mlpack/tests/split_data_test.cpp +++ b/src/mlpack/tests/split_data_test.cpp @@ -841,7 +841,7 @@ TEST_CASE("SplitCubeDataShuffleWithLabelsAndWeights", "[SplitDataTest]") TEST_CASE("SplitMatDataShuffleWithLabelsAndWeights", "[SplitDataTest]") { mat input(10, 30, fill::randu); - Row labels = randi>(30, distr_param(0, 100000)); + Row labels = linspace>(10, 39, 30); frowvec weights(30, fill::randu); mat trainInput, testInput;