Link with prebuilt OpenBLAS and fix shared libs build on Windows (#3036)

This commit is contained in:
Cheng
2026-01-23 11:17:26 +09:00
committed by GitHub
parent becc769012
commit 1650c4905a
6 changed files with 33 additions and 52 deletions
+1 -1
View File
@@ -9,5 +9,5 @@ runs:
DEVICE: cpu
run: |
echo "::group::CPP tests - CPU"
./build/tests/tests -tce="*gguf*,test random uniform"
./build/tests.exe -tce="*gguf*,test random uniform"
echo "::endgroup::"
+31 -18
View File
@@ -40,7 +40,6 @@ option(MLX_METAL_DEBUG "Enhance metal debug workflow" OFF)
option(MLX_ENABLE_X64_MAC "Enable building for x64 macOS" OFF)
option(MLX_BUILD_GGUF "Include support for GGUF format" ON)
option(MLX_BUILD_SAFETENSORS "Include support for safetensors format" ON)
option(MLX_BUILD_BLAS_FROM_SOURCE "Build OpenBLAS from source code" OFF)
option(MLX_BUILD_PYTHON_STUBS "Build stub files for python bindings" ON)
option(MLX_METAL_JIT "Use JIT compilation for Metal kernels" OFF)
option(MLX_USE_CCACHE "Use CCache for compilation cache when available" ON)
@@ -219,14 +218,17 @@ if(WIN32)
if(MSVC)
# GGUF does not build with MSVC.
set(MLX_BUILD_GGUF OFF)
# There is no prebuilt OpenBLAS distribution for MSVC.
set(MLX_BUILD_BLAS_FROM_SOURCE ON)
endif()
# Generate DLL and EXE in the same dir, otherwise EXE will not be able to run.
# This is only done when MLX is built as the top project.
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
endif()
# Windows implementation of dlfcn.h APIs.
FetchContent_Declare(
dlfcn-win32
GIT_REPOSITORY https://github.com/dlfcn-win32/dlfcn-win32.git
GIT_TAG v1.4.1
GIT_TAG v1.4.2
EXCLUDE_FROM_ALL)
block()
set(BUILD_SHARED_LIBS OFF)
@@ -250,23 +252,25 @@ if(MLX_BUILD_CPU)
target_link_libraries(mlx PUBLIC ${ACCELERATE_LIBRARY})
add_compile_definitions(MLX_USE_ACCELERATE)
add_compile_definitions(ACCELERATE_NEW_LAPACK)
elseif(MLX_BUILD_BLAS_FROM_SOURCE)
# Download and build OpenBLAS from source code.
elseif(WIN32)
# Download and link prebuilt binaries of OpenBLAS. Note that we can only
# link with the dynamic library, the prebuilt binaries were built with MinGW
# so static-linking would require linking with MinGW's runtime.
FetchContent_Declare(
openblas
GIT_REPOSITORY https://github.com/OpenMathLib/OpenBLAS.git
GIT_TAG v0.3.28
EXCLUDE_FROM_ALL)
block(PROPAGATE openblas_SOURCE_DIR)
set(BUILD_SHARED_LIBS OFF) # link statically
set(BUILD_STATIC_LIBS ON)
set(NOFORTRAN ON) # msvc has no fortran compiler
URL "https://github.com/OpenMathLib/OpenBLAS/releases/download/v0.3.31/OpenBLAS-0.3.31-x64.zip"
)
FetchContent_MakeAvailable(openblas)
endblock()
target_link_libraries(mlx PRIVATE openblas)
target_include_directories(
mlx PRIVATE "${openblas_SOURCE_DIR}/lapack-netlib/LAPACKE/include"
"${CMAKE_BINARY_DIR}/generated" "${CMAKE_BINARY_DIR}")
target_link_libraries(mlx
PRIVATE "${openblas_SOURCE_DIR}/lib/libopenblas.lib")
target_include_directories(mlx PRIVATE "${openblas_SOURCE_DIR}/include")
# Make sure the DLL file is placed in the same dir with executables.
set(OPENBLAS_DLL_FILE "${openblas_SOURCE_DIR}/bin/libopenblas.dll")
add_custom_command(
TARGET mlx
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${OPENBLAS_DLL_FILE}
${CMAKE_BINARY_DIR})
else()
if(${CMAKE_HOST_APPLE})
# The blas shipped in macOS SDK is not supported, search homebrew for
@@ -365,6 +369,15 @@ endif()
# ----------------------------- Installation -----------------------------
include(GNUInstallDirs)
if(WIN32)
# Install DLLs to the same dir with extension file (core.pyd) on Windows.
set(CMAKE_INSTALL_BINDIR ".")
if(MLX_BUILD_CPU)
# Install OpenBLAS.
install(FILES ${OPENBLAS_DLL_FILE} TYPE BIN)
endif()
endif()
# Install library
install(
TARGETS mlx
-8
View File
@@ -3,14 +3,6 @@ function(build_benchmark SRCFILE)
set(target "${src_name}")
add_executable(${target} ${SRCFILE})
target_link_libraries(${target} PRIVATE mlx)
# On Windows, copy the mlx DLL to the executable directory for runtime loading
if(WIN32 AND BUILD_SHARED_LIBS)
add_custom_command(
TARGET ${target}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:mlx>
$<TARGET_FILE_DIR:${target}>)
endif()
endfunction(build_benchmark)
build_benchmark(single_ops.cpp)
-8
View File
@@ -3,14 +3,6 @@ function(build_example SRCFILE)
set(target "${src_name}")
add_executable(${target} ${SRCFILE})
target_link_libraries(${target} PRIVATE mlx)
# On Windows, copy the mlx DLL to the executable directory for runtime loading
if(WIN32 AND BUILD_SHARED_LIBS)
add_custom_command(
TARGET ${target}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:mlx>
$<TARGET_FILE_DIR:${target}>)
endif()
endfunction(build_example)
build_example(tutorial.cpp)
+1 -7
View File
@@ -95,6 +95,7 @@ class CMakeBuild(build_ext):
"-DMLX_BUILD_TESTS=OFF",
"-DMLX_BUILD_BENCHMARKS=OFF",
"-DMLX_BUILD_EXAMPLES=OFF",
"-DBUILD_SHARED_LIBS=ON",
]
if build_stage == 2 and build_cuda:
# Last arch is always real and virtual for forward-compatibility
@@ -125,13 +126,6 @@ class CMakeBuild(build_ext):
archs = re.findall(r"-arch (\S+)", os.environ.get("ARCHFLAGS", ""))
if archs:
cmake_args += ["-DCMAKE_OSX_ARCHITECTURES={}".format(";".join(archs))]
if platform.system() == "Windows":
# On Windows DLLs must be put in the same dir with the extension
# while cmake puts mlx.dll into the "bin" sub-dir. Link with mlx
# statically to work around it.
cmake_args += ["-DBUILD_SHARED_LIBS=OFF"]
else:
cmake_args += ["-DBUILD_SHARED_LIBS=ON"]
# Set CMAKE_BUILD_PARALLEL_LEVEL to control the parallel build level
# across all generators.
-10
View File
@@ -40,15 +40,5 @@ target_link_libraries(tests PRIVATE mlx doctest)
target_compile_options(tests PRIVATE ${SANITIZER_COMPILE_FLAGS})
target_link_options(tests PRIVATE ${SANITIZER_LINK_FLAGS})
# On Windows, copy the mlx DLL to the test executable directory for runtime
# loading
if(WIN32 AND BUILD_SHARED_LIBS)
add_custom_command(
TARGET tests
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:mlx>
$<TARGET_FILE_DIR:tests>)
endif()
doctest_discover_tests(tests)
add_test(NAME tests COMMAND tests)