version: 2.1 orbs: apple: ml-explore/pr-approval@0.1.0 parameters: nightly_build: type: boolean default: false weekly_build: type: boolean default: false test_release: type: boolean default: false linux_release: type: boolean default: false jobs: build_documentation: parameters: upload-docs: type: boolean default: false macos: xcode: "15.2.0" resource_class: macos.m1.medium.gen1 steps: - checkout - run: name: Install command: | brew install python@3.9 brew install doxygen python3.9 -m venv env source env/bin/activate pip install --upgrade pip pip install --upgrade cmake pip install -r docs/requirements.txt CMAKE_BUILD_PARALLEL_LEVEL=`sysctl -n hw.ncpu` pip install . -v - when: condition: not: << parameters.upload-docs >> steps: - run: name: Build documentation command: | source env/bin/activate cd docs && doxygen && make html O=-W - when: condition: << parameters.upload-docs >> steps: - add_ssh_keys: fingerprints: - "SHA256:OhcVVMovbT0pkgMeiVRyxMnjV9R2t+hKBsNcuxq9h+0" - run: name: Upload documentation command: | source env/bin/activate git config user.email "mlx@group.apple.com" git config user.name "CircleCI Docs" git checkout gh-pages git rebase main cd docs git rm -rf build/html doxygen && make html O=-W git add -f build/html git commit -m "rebase" git push -f origin gh-pages linux_build_and_test: docker: - image: cimg/python:3.9 steps: - checkout - run: name: Run style checks command: | pip install pre-commit pre-commit run --all if ! git diff --quiet; then echo 'Style checks failed, please install pre-commit and run pre-commit run --all and push the change'; exit 1; fi - run: name: Install dependencies command: | pip install --upgrade cmake pip install nanobind==2.4.0 pip install numpy sudo apt-get update sudo apt-get install libblas-dev liblapack-dev liblapacke-dev - run: name: Install Python package command: | CMAKE_ARGS="-DMLX_BUILD_METAL=OFF" \ CMAKE_BUILD_PARALLEL_LEVEL=`nproc` \ python3 setup.py build_ext --inplace CMAKE_ARGS="-DMLX_BUILD_METAL=OFF" \ CMAKE_BUILD_PARALLEL_LEVEL=`nproc` \ python3 setup.py develop - run: name: Generate package stubs command: | echo "stubs" pip install typing_extensions python setup.py generate_stubs - run: name: Run Python tests command: | python3 -m unittest discover python/tests -v - run: name: Build CPP only command: | mkdir -p build && cd build cmake .. -DMLX_BUILD_METAL=OFF -DCMAKE_BUILD_TYPE=DEBUG make -j `nproc` - run: name: Run CPP tests command: ./build/tests/tests mac_build_and_test: parameters: xcode_version: type: string default: "15.2.0" macos: xcode: << parameters.xcode_version >> resource_class: macos.m1.medium.gen1 steps: - checkout - run: name: Install dependencies command: | brew install python@3.9 brew install openmpi python3.9 -m venv env source env/bin/activate pip install --upgrade pip pip install --upgrade cmake pip install nanobind==2.4.0 pip install numpy pip install torch pip install tensorflow pip install unittest-xml-reporting - run: name: Install Python package command: | source env/bin/activate DEBUG=1 CMAKE_BUILD_PARALLEL_LEVEL=`sysctl -n hw.ncpu` pip install -e . -v - run: name: Generate package stubs command: | source env/bin/activate pip install typing_extensions python setup.py generate_stubs - run: name: Run Python tests command: | source env/bin/activate LOW_MEMORY=1 DEVICE=cpu python -m xmlrunner discover -v python/tests -o test-results/cpu LOW_MEMORY=1 DEVICE=gpu METAL_DEVICE_WRAPPER_TYPE=1 METAL_DEBUG_ERROR_MODE=0 python -m xmlrunner discover -v python/tests -o test-results/gpu mpirun --bind-to none -host localhost:8 -np 8 -x DYLD_LIBRARY_PATH=/opt/homebrew/lib/ python python/tests/mpi_test_distributed.py - run: name: Build example extension command: | source env/bin/activate cd examples/extensions pip install -r requirements.txt python setup.py build_ext -j8 - store_test_results: path: test-results - run: name: Build CPP only command: | source env/bin/activate mkdir -p build && cd build && cmake .. && make -j `sysctl -n hw.ncpu` - run: name: Run CPP tests command: | DEVICE=gpu METAL_DEVICE_WRAPPER_TYPE=1 METAL_DEBUG_ERROR_MODE=0 ./build/tests/tests - run: name: Build small binary command: | source env/bin/activate cd build/ cmake .. -DCMAKE_BUILD_TYPE=MinSizeRel \ -DBUILD_SHARED_LIBS=ON \ -DMLX_BUILD_CPU=OFF \ -DMLX_BUILD_SAFETENSORS=OFF \ -DMLX_BUILD_GGUF=OFF \ -DMLX_METAL_JIT=ON make -j `sysctl -n hw.ncpu` - run: name: Run Python tests with JIT command: | source env/bin/activate CMAKE_BUILD_PARALLEL_LEVEL=`sysctl -n hw.ncpu` \ CMAKE_ARGS="-DMLX_METAL_JIT=ON" \ pip install -e . -v LOW_MEMORY=1 DEVICE=gpu METAL_DEVICE_WRAPPER_TYPE=1 \ METAL_DEBUG_ERROR_MODE=0 \ python -m xmlrunner discover -v python/tests -o test-results/gpu_jit build_release: parameters: python_version: type: string default: "3.9" xcode_version: type: string default: "15.2.0" build_env: type: string default: "" macos: xcode: << parameters.xcode_version >> resource_class: macos.m1.medium.gen1 steps: - checkout - run: name: Install dependencies command: | brew install python@<< parameters.python_version >> brew install openmpi python<< parameters.python_version >> -m venv env source env/bin/activate pip install --upgrade pip pip install --upgrade cmake pip install nanobind==2.4.0 pip install --upgrade setuptools pip install numpy pip install twine pip install build - run: name: Install Python package command: | source env/bin/activate DEV_RELEASE=1 \ CMAKE_BUILD_PARALLEL_LEVEL=`sysctl -n hw.ncpu` \ pip install . -v - run: name: Generate package stubs command: | source env/bin/activate pip install typing_extensions python setup.py generate_stubs - run: name: Build Python package command: | source env/bin/activate << parameters.build_env >> \ CMAKE_BUILD_PARALLEL_LEVEL=`sysctl -n hw.ncpu` \ python -m build -w - when: condition: << parameters.build_env >> steps: - run: name: Upload package command: | source env/bin/activate twine upload dist/* - store_artifacts: path: dist/ build_linux_release: parameters: python_version: type: string default: "3.9" extra_env: type: string default: "DEV_RELEASE=1" docker: - image: ubuntu:20.04 steps: - checkout - run: name: Build wheel command: | PYTHON=python<< parameters.python_version >> apt-get update apt-get upgrade -y DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install tzdata apt-get install -y apt-utils apt-get install -y software-properties-common add-apt-repository -y ppa:deadsnakes/ppa apt-get install -y $PYTHON $PYTHON-dev $PYTHON-full apt-get install -y libblas-dev liblapack-dev liblapacke-dev apt-get install -y build-essential git $PYTHON -m venv env source env/bin/activate pip install --upgrade pip pip install --upgrade cmake pip install nanobind==2.4.0 pip install --upgrade setuptools pip install numpy pip install auditwheel pip install patchelf pip install build pip install twine << parameters.extra_env >> \ CMAKE_BUILD_PARALLEL_LEVEL=`nproc` \ pip install . -v pip install typing_extensions python setup.py generate_stubs << parameters.extra_env >> \ CMAKE_BUILD_PARALLEL_LEVEL=`nproc` \ python -m build --wheel auditwheel show dist/* auditwheel repair dist/* --plat manylinux_2_31_x86_64 - run: name: Upload package command: | source env/bin/activate twine upload wheelhouse/* - store_artifacts: path: wheelhouse/ workflows: build_and_test: when: and: - matches: pattern: "^(?!pull/)[-\\w]+$" value: << pipeline.git.branch >> - not: << pipeline.parameters.nightly_build >> - not: << pipeline.parameters.weekly_build >> - not: << pipeline.parameters.test_release >> jobs: - mac_build_and_test: matrix: parameters: xcode_version: ["15.0.0", "15.2.0", "16.0.0"] - linux_build_and_test - build_documentation build_pypi_release: when: and: - not: << pipeline.parameters.nightly_build >> - not: << pipeline.parameters.weekly_build >> - not: << pipeline.parameters.test_release >> jobs: - build_release: filters: tags: only: /^v.*/ branches: ignore: /.*/ matrix: parameters: python_version: ["3.9", "3.10", "3.11", "3.12", "3.13"] xcode_version: ["15.0.0", "15.2.0"] build_env: ["PYPI_RELEASE=1"] - build_documentation: filters: tags: only: /^v.*/ branches: ignore: /.*/ upload-docs: true prb: when: matches: pattern: "^pull/\\d+(/head)?$" value: << pipeline.git.branch >> jobs: - hold: type: approval - apple/authenticate: context: pr-approval - mac_build_and_test: requires: [ hold ] matrix: parameters: xcode_version: ["15.0.0", "15.2.0", "16.0.0"] - linux_build_and_test: requires: [ hold ] nightly_build: when: and: - equal: [ main, << pipeline.git.branch >> ] - << pipeline.parameters.nightly_build >> jobs: - build_release: matrix: parameters: python_version: ["3.9", "3.10", "3.11", "3.12", "3.13"] xcode_version: ["15.0.0", "15.2.0"] weekly_build: when: and: - equal: [ main, << pipeline.git.branch >> ] - << pipeline.parameters.weekly_build >> jobs: - build_release: matrix: parameters: python_version: ["3.9", "3.10", "3.11", "3.12", "3.13"] xcode_version: ["15.0.0", "15.2.0", "16.0.0"] build_env: ["DEV_RELEASE=1"] linux_test_release: when: and: - equal: [ main, << pipeline.git.branch >> ] - << pipeline.parameters.linux_release >> jobs: - build_linux_release: matrix: parameters: python_version: ["3.9", "3.10", "3.11", "3.12", "3.13"] extra_env: ["PYPI_RELEASE=1"]