diff --git a/Package.swift b/Package.swift index d88d9e45..191d5942 100644 --- a/Package.swift +++ b/Package.swift @@ -1,9 +1,12 @@ -// swift-tools-version: 5.12 +// swift-tools-version: 6.2 // The swift-tools-version declares the minimum version of Swift required to build this package. // Copyright © 2024 Apple Inc. +import Foundation import PackageDescription +let inXcode = ProcessInfo.processInfo.environment["XCODE_VERSION_ACTUAL"] != nil + let package = Package( name: "mlx-swift", @@ -26,7 +29,8 @@ let package = Package( ], dependencies: [ // for Complex type - .package(url: "https://github.com/apple/swift-numerics", from: "1.0.0") + .package(url: "https://github.com/apple/swift-numerics", from: "1.0.0"), + .package(url: "https://github.com/schwa/MetalCompilerPlugin", branch: "main"), ], targets: [ .target( @@ -155,7 +159,14 @@ let package = Package( .linkedFramework("Foundation"), .linkedFramework("Metal"), .linkedFramework("Accelerate"), - ] + ], + + plugins: + // Optional: Use plugin for custom Metal compilation + // needed for swift build. Xcode does it automatically + inXcode ? [] : [ + .plugin(name: "MetalCompilerPlugin", package: "MetalCompilerPlugin") + ], ), .testTarget( name: "CmlxTests", diff --git a/README.md b/README.md index 598b8c44..6097a4ef 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,6 @@ MLX is an array framework for machine learning on Apple silicon. MLX Swift expands MLX to the Swift language, making research and experimentation easier on Apple silicon. -## Language Models - -LLM and VLM implementations are available in [mlx-swift-lm](https://github.com/ml-explore/mlx-swift-lm). - ## Examples MLX Swift has [many @@ -42,7 +38,7 @@ from MLX Python. ## Installation -The ``MLX`` Swift package can be built and run from Xcode or SwiftPM. A CMake installation is also provided, featuring a native Linux build option. +The ``MLX`` Swift package can be built and run from Xcode or SwiftPM. A CMake install is also provided. More details are in the [documentation](https://swiftpackageindex.com/ml-explore/mlx-swift/main/documentation/mlx/install). @@ -72,6 +68,8 @@ dependencies: [.product(name: "MLX", package: "mlx-swift"), > [!Note] > SwiftPM (command line) cannot build the Metal shaders so the ultimate build has to be done > via Xcode. +> +>Update: Using [Metal Compiler Plugin](https://github.com/schwa/MetalCompilerPlugin), the library will be compiled and stored as default.metallib inside the Clmx-bundle. It is not in the Resources of the main bundle! With [patch](https://github.com/ml-explore/mlx/pull/2885) mlx is able to load default.metallib from any bundle root. What is left to the application/bundle to ensure, the bundle is loaded. Check the `setUp()` function in ArrayAtTests.swift as an example for manual loading. ### xcodebuild @@ -99,7 +97,7 @@ brew install ninja With CMake: ```shell -mkdir -p build +mkdir build cd build cmake .. -G Ninja ninja @@ -107,49 +105,6 @@ ninja ./tutorial ``` -
- Expand Native Linux Build Instructions - - #### (1) Install Dependencies - - RHEL/Fedora: - ```shell - sudo dnf install -y blas-devel lapack-devel openblas-devel clang llvm cmake make ninja - # Then install Swift by following the instructions at https://swift.org - ``` - - Ubuntu/Debian: - ```shell - sudo apt update; - sudo apt install -y libblas-dev liblapack-dev libopenblas-dev clang llvm cmake make ninja; - # Then install Swift by following the instructions at https://swift.org - ``` - - Refer to [swift.org](https://www.swift.org/install/linux/) for installation options and instructions specific to your Linux distribution. - - - #### (2) Build + Run Examples - - On Linux, the examples use the CPU backend by default. - - Note: GPU+CUDA support is a work in progress for `mlx-swift` on Linux, but is available in the Python-based MLX. - - Note: SwiftPM builds are not currently supported for native Linux targets. - - ```shell - mkdir -p build - cd build - cmake -DMLX_BUILD_METAL=OFF .. -G Ninja - ninja - ./example1 - ./tutorial - ``` - - -
- -
- ## Contributing Check out the [contribution guidelines](CONTRIBUTING.md) for more information diff --git a/Source/Cmlx/.metal-compiler-plugin.json b/Source/Cmlx/.metal-compiler-plugin.json new file mode 100644 index 00000000..3f386021 --- /dev/null +++ b/Source/Cmlx/.metal-compiler-plugin.json @@ -0,0 +1,23 @@ +{ + "xcrun": true, + "find-inputs": false, + "include-dependencies": false, + "dependency-path-suffix": "include", + "include-paths": ["mlx-generated"], + "inputs": [ + "Source/Cmlx/mlx-generated/metal/steel/attn/kernels/steel_attention.metal", + "Source/Cmlx/mlx-generated/metal/arg_reduce.metal", + "Source/Cmlx/mlx-generated/metal/conv.metal", + "Source/Cmlx/mlx-generated/metal/rms_norm.metal", + "Source/Cmlx/mlx-generated/metal/random.metal", + "Source/Cmlx/mlx-generated/metal/scaled_dot_product_attention.metal", + "Source/Cmlx/mlx-generated/metal/gemv.metal", + "Source/Cmlx/mlx-generated/metal/layer_norm.metal", + "Source/Cmlx/mlx-generated/metal/rope.metal"], + "output": "default.metallib", + "flags": ["-gline-tables-only", "-frecord-sources", "-Wno-c++20-extensions", "-std=metal4.0"], + "plugin-logging": true, + "verbose-logging": false, + "metal-enable-logging": false, + "logging-prefix": "[Metal]" +} diff --git a/Tests/MLXTests/ArrayAtTests.swift b/Tests/MLXTests/ArrayAtTests.swift index 67e6d9ee..48cba99d 100644 --- a/Tests/MLXTests/ArrayAtTests.swift +++ b/Tests/MLXTests/ArrayAtTests.swift @@ -3,8 +3,33 @@ import Foundation import MLX import XCTest +import Cmlx class ArrayAtTests: XCTestCase { + override class func setUp() { + super.setUp() + + // Cmlx is not an automatically loaded bundle. + // Let's load Cmlx manually, so that the mlx-lib can find the default.metallib. + // This requires patch #2885 in ml-explore/mlx be applied. + + // Find the test bundle (.xctest) + let testBundle = Bundle(for: self) + + // Go to its parent directory: …/debug + let buildDir = testBundle.bundleURL.deletingLastPathComponent() + + // Append the actual SwiftPM bundle name for Cmlx + let cmlxURL = buildDir.appendingPathComponent("mlx-swift_Cmlx.bundle") + + if let cmlxBundle = Bundle(url: cmlxURL) { + print("Loaded Cmlx bundle at:", cmlxURL.path) + _ = cmlxBundle.load() // registers it globally + } else { + print("Failed to load Cmlx bundle at:", cmlxURL.path) + } + + } func testArrayAt() { // from example at https://ml-explore.github.io/mlx/build/html/python/_autosummary/mlx.core.array.at.html#mlx.core.array.at