diff --git a/cmake/local.cmake b/cmake/local.cmake index 5eb7a066a9a..1df5d89e12f 100644 --- a/cmake/local.cmake +++ b/cmake/local.cmake @@ -5,6 +5,7 @@ # llama/server CMake project and building the Go binary into a matching layout. include(ExternalProject) +include(${CMAKE_CURRENT_LIST_DIR}/mlx-backend-order.cmake) set(OLLAMA_LLAMA_BACKENDS "" CACHE STRING "Semicolon-separated llama-server GPU backends to build: cuda_v12;cuda_v13;rocm_v7_1;rocm_v7_2;vulkan;cuda_jetpack5;cuda_jetpack6") @@ -855,6 +856,8 @@ foreach(_backend IN LISTS OLLAMA_MLX_BACKENDS) endif() endforeach() +ollama_order_mlx_metal_builds() + if(_mlx_targets) add_custom_target(ollama-mlx-backends ALL DEPENDS ${_mlx_targets} diff --git a/cmake/mlx-backend-order.cmake b/cmake/mlx-backend-order.cmake new file mode 100644 index 00000000000..74e619a7d11 --- /dev/null +++ b/cmake/mlx-backend-order.cmake @@ -0,0 +1,7 @@ +function(ollama_order_mlx_metal_builds) + if(TARGET ollama-mlx-metal_v3 AND TARGET ollama-mlx-metal_v4) + # Both external projects install shared notices and licenses into the + # same payload root. Keep their complete install phases from racing. + add_dependencies(ollama-mlx-metal_v4 ollama-mlx-metal_v3) + endif() +endfunction() diff --git a/cmake/tests/mlx-backend-order/CMakeLists.txt b/cmake/tests/mlx-backend-order/CMakeLists.txt new file mode 100644 index 00000000000..aba3039278a --- /dev/null +++ b/cmake/tests/mlx-backend-order/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 3.24) + +project(OllamaMLXBackendOrderTest NONE) + +if(NOT DEFINED TEST_SCENARIO) + message(FATAL_ERROR "TEST_SCENARIO is required") +endif() + +include(${CMAKE_CURRENT_LIST_DIR}/../../mlx-backend-order.cmake) + +if(TEST_SCENARIO STREQUAL "both_reversed") + # Define v4 first to prove the ordering does not depend on list order. + add_custom_target(ollama-mlx-metal_v4) + add_custom_target(ollama-mlx-metal_v3) +elseif(TEST_SCENARIO STREQUAL "metal_v3_only") + add_custom_target(ollama-mlx-metal_v3) +elseif(TEST_SCENARIO STREQUAL "metal_v4_only") + add_custom_target(ollama-mlx-metal_v4) +else() + message(FATAL_ERROR "unknown TEST_SCENARIO: ${TEST_SCENARIO}") +endif() + +ollama_order_mlx_metal_builds() + +if(TEST_SCENARIO STREQUAL "both_reversed") + get_property(_dependencies + TARGET ollama-mlx-metal_v4 + PROPERTY MANUALLY_ADDED_DEPENDENCIES) + if(NOT "ollama-mlx-metal_v3" IN_LIST _dependencies) + message(FATAL_ERROR + "metal_v4 does not depend on metal_v3: ${_dependencies}") + endif() +elseif(TARGET ollama-mlx-metal_v3) + get_property(_dependencies + TARGET ollama-mlx-metal_v3 + PROPERTY MANUALLY_ADDED_DEPENDENCIES) + if(_dependencies) + message(FATAL_ERROR + "single metal_v3 target has unexpected dependencies: ${_dependencies}") + endif() +elseif(TARGET ollama-mlx-metal_v4) + get_property(_dependencies + TARGET ollama-mlx-metal_v4 + PROPERTY MANUALLY_ADDED_DEPENDENCIES) + if(_dependencies) + message(FATAL_ERROR + "single metal_v4 target has unexpected dependencies: ${_dependencies}") + endif() +endif()