Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 8 additions & 0 deletions .github/scripts/build-linux-cuda-cmake.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ rm -rf build
mkdir -p build
pushd build
cmake -DMLX_BUILD_METAL=OFF -DMLX_BUILD_CUDA=ON -DMLX_C_BUILD_EXAMPLES=OFF .. -G Ninja

# Verify the local mlx patch is actually in place: without it the examples below
# crash on exit, which is easy to misread as an unrelated CUDA failure.
git -C _deps/mlx-src apply --reverse --check "$PWD/../cmake/mlx.patch" || {
echo "error: cmake/mlx.patch is not applied to _deps/mlx-src"
exit 1
}

ninja
./example1 --device gpu
./tutorial --device gpu
Expand Down
16 changes: 14 additions & 2 deletions .github/scripts/setup+build-linux-container-cmake.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
set -ex

# [Setup] Install dependencies inside the container.
# Note: mlx-c requires a C++20 toolchain with <format> support:
# - libstdc++ >= 13 (Ubuntu noble, Fedora 39+)
# - or libc++ >= 17
# Debian bookworm (libstdc++ 12) is *not* sufficient.
if command -v apt-get >/dev/null 2>&1; then
apt-get update -y
apt-get install -y \
Expand All @@ -12,6 +16,9 @@ if command -v apt-get >/dev/null 2>&1; then
liblapacke-dev \
libopenblas-dev

export CC=/usr/bin/gcc
export CXX=/usr/bin/g++

elif command -v dnf >/dev/null 2>&1; then
dnf update -y
dnf install -y \
Expand All @@ -23,6 +30,11 @@ elif command -v dnf >/dev/null 2>&1; then
clang \
ninja-build

# Fedora's default gcc (13+) has <format>; keep it as the compiler so this
# build keeps matching what has been passing in CI.
export CC=/usr/bin/gcc
export CXX=/usr/bin/g++

else
echo "No supported package manager found (apt-get, dnf)"
exit 1
Expand All @@ -31,8 +43,8 @@ fi
# [CMake] CI Build Sanity Check: Verifies code compilation, not for release.
export CMAKE_ARGS="-DCMAKE_COMPILE_WARNING_AS_ERROR=ON"
export DEBUG=1
export CMAKE_C_COMPILER=/usr/bin/clang
export CMAKE_CXX_COMPILER=/usr/bin/clang++

"$CXX" --version

rm -rf build
mkdir -p build
Expand Down
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[submodule "submodules/mlx"]
path = Source/Cmlx/mlx
url = https://github.com/ml-explore/mlx
[submodule "submodules/mlx-c"]
path = Source/Cmlx/mlx-c
url = https://github.com/ml-explore/mlx-c
75 changes: 68 additions & 7 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# ----------------------------- Configuration -----------------------------
# note: mirrors a subset of MLX options exactly (1:1 mapping)

option(MLX_BUILD_EXAMPLES "Build examples for mlx" ON)
# note: MLX_BUILD_EXAMPLES is owned by mlx itself (see below), so the Swift
# examples use their own option name to avoid colliding with mlx's C++ examples
option(MLX_SWIFT_BUILD_EXAMPLES "Build Swift examples for mlx-swift" ON)
option(MLX_BUILD_METAL "Build metal backend" ON)
option(MLX_BUILD_CUDA "Build cuda backend" OFF)

Expand All @@ -26,21 +28,61 @@ if(POLICY CMP0135)
cmake_policy(SET CMP0135 NEW)
endif()

# mlx

# note: patches are applied via cmake/apply-patch.cmake so that they are
# idempotent (the patch step re-runs on every update step) while still failing
# the build loudly if a patch does not apply -- a silently unpatched dependency
# is very hard to diagnose (it typically shows up as a runtime failure).
set(apply_patch ${CMAKE_COMMAND} -DREPO=<SOURCE_DIR>)
set(apply_patch_script -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/apply-patch.cmake)

# two local patches for CUDA:
#
# * https://github.com/ml-explore/mlx/pull/4480: leak the global command encoder
# map rather than synchronizing on process shutdown
# * make ~CudaHandle non-throwing: cu::Worker is detached and holds the last
# reference to itself, so ~Worker -> ~CudaEvent -> cudaEventDestroy runs on
# the worker thread at an arbitrary point during exit, racing the CUDA
# runtime's own teardown. A failing destroy there terminated the process.
set(mlx_patch
${apply_patch} -DPATCH=${CMAKE_CURRENT_SOURCE_DIR}/cmake/mlx.patch
${apply_patch_script})

# note: this must be declared (and named `mlx`) before mlx-c is made available
# so that our pinned/patched version wins over the one mlx-c declares. Because
# we now pull mlx in first, we are also responsible for the option defaults that
# mlx-c would normally set for us.
set(MLX_BUILD_TESTS OFF)
set(MLX_BUILD_EXAMPLES OFF)
set(MLX_BUILD_BENCHMARKS OFF)
set(MLX_BUILD_PYTHON_BINDINGS OFF)

FetchContent_Declare(
mlx
GIT_REPOSITORY "https://github.com/ml-explore/mlx.git"
GIT_TAG "v0.32.2"
PATCH_COMMAND ${mlx_patch})
FetchContent_MakeAvailable(mlx)

# mlx-c
set(MLX_C_BUILD_EXAMPLES OFF)
FetchContent_Declare(
mlx-c
GIT_REPOSITORY "https://github.com/ml-explore/mlx-c.git"
GIT_TAG "v0.6.0")
GIT_TAG "ebc88f10caa1b625e6b581437a8dea6df8a70085")
FetchContent_MakeAvailable(mlx-c)

# swift-numerics
set(swift_numerics_patch git apply
${CMAKE_CURRENT_SOURCE_DIR}/cmake/swift-numerics.patch)
set(swift_numerics_patch
${apply_patch}
-DPATCH=${CMAKE_CURRENT_SOURCE_DIR}/cmake/swift-numerics.patch
${apply_patch_script})
FetchContent_Declare(
swift-numerics
GIT_REPOSITORY "https://github.com/apple/swift-numerics.git"
GIT_TAG "1.0.2"
PATCH_COMMAND ${swift_numerics_patch} || true)
PATCH_COMMAND ${swift_numerics_patch})
FetchContent_MakeAvailable(swift-numerics)

# MLX package
Expand All @@ -57,18 +99,37 @@ if(MLX_BUILD_CUDA)
CUDNN::cudnn_all # Promoted from PRIVATE, required by mlx
)
endif()

# cLogSupport package small C shim that exposes os_log_type_enabled() to Swift
# (see #491)
set(cLogSupport_include ${CMAKE_CURRENT_LIST_DIR}/Source/cLogSupport/include)
set(cLogSupport_module_dir ${CMAKE_CURRENT_BINARY_DIR}/cLogSupport-module)
file(
WRITE ${cLogSupport_module_dir}/module.modulemap
"module cLogSupport {\n header \"${cLogSupport_include}/cLogSupport.h\"\n export *\n}\n"
)

add_library(cLogSupport STATIC
${CMAKE_CURRENT_LIST_DIR}/Source/cLogSupport/cLogSupport.c)
target_include_directories(cLogSupport PUBLIC ${cLogSupport_include}
${cLogSupport_module_dir})

file(GLOB MLX-src ${CMAKE_CURRENT_LIST_DIR}/Source/MLX/*.swift)

if(NOT MLX_BUILD_METAL)
list(REMOVE_ITEM MLX-src ${CMAKE_CURRENT_LIST_DIR}/Source/MLX/GPU+Metal.swift
${CMAKE_CURRENT_LIST_DIR}/Source/MLX/MLXArray+Metal.swift)
endif()

if(NOT MLX_BUILD_CUDA)
list(REMOVE_ITEM MLX-src ${CMAKE_CURRENT_LIST_DIR}/Source/MLX/GPU+CUDA.swift)
endif()

add_library(MLX STATIC ${MLX-src})
target_include_directories(MLX
PUBLIC ${CMAKE_CURRENT_LIST_DIR}/Source/Cmlx/include)
# Note: mlxc is target name exported by mlx-c
target_link_libraries(MLX PUBLIC mlxc Numerics)
target_link_libraries(MLX PUBLIC mlxc Numerics cLogSupport)
target_compile_options(MLX PRIVATE -package-name MLX)

# MLXRandom package
Expand Down Expand Up @@ -103,7 +164,7 @@ add_library(MLXLinalg STATIC ${MLXLinalg-src})
target_link_libraries(MLXLinalg PRIVATE MLX)

# Examples
if(MLX_BUILD_EXAMPLES)
if(MLX_SWIFT_BUILD_EXAMPLES)
add_executable(example1
${CMAKE_CURRENT_LIST_DIR}/Source/Examples/Example1.swift)
target_link_libraries(example1 PRIVATE MLX)
Expand Down
7 changes: 1 addition & 6 deletions MAINTENANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,7 @@ dependencies: [.product(name: "MLX", package: "mlx-swift"),
.product(name: "MLXOptimizers", package: "mlx-swift")]
```

10. Update `tools/generate_integration_tests.py` as needed

```
import MLXNN
@testable import MLXOptimizers
```
10. Update `tools/integration_tests/cases.py` as needed, regenerate tests if needed

11. Update tests as needed

Expand Down
Loading