win32: Add --with-mimalloc

The vcpkg feature `mimalloc` installs the DLL with the other libraries, so that prepare-vcpkg and binary-package pick it up. It is built from an overlay port, the port of vcpkg with MI_WIN_REDIRECT turned off, because mimalloc-redirect.dll would try to redirect malloc of the whole process.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Hiroshi SHIBATA 2026-11-04 06:55:23 +09:00
parent a04c1e136f
commit bd3ea61fdf
Notes: git 2026-11-04 01:29:46 +00:00
12 changed files with 206 additions and 5 deletions

9
LEGAL
View File

@ -462,6 +462,15 @@ mentioned below.
You may distribute under the terms of either the GNU General Public
License or the Artistic License, as specified in the perl README file.
[win32/vcpkg-ports/mimalloc]
This port is adapted from vcpkg, under the following license.
>>>
Copyright (c) Microsoft Corporation
{MIT License}[rdoc-ref:@MIT+License]
[missing/mt19937.c]
This file is under the new-style BSD license.

View File

@ -173,6 +173,17 @@ sh ../../ruby/configure -C --disable-install-doc --with-opt-dir=C:\Users\usernam
"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\setup.exe" modify --installPath "%ProgramFiles(x86)%\Microsoft Visual Studio\18\BuildTools" --add Microsoft.VisualStudio.Component.VC.Llvm.Clang --passive
```
10. If you want the GC to allocate memory with
[mimalloc](https://github.com/microsoft/mimalloc), install it with
the `mimalloc` feature of vcpkg, and specify `--with-mimalloc` of
`win32\configure.bat`. Only `ruby_xmalloc` and its family use
mimalloc, so a C extension that frees their memory with `free`, or
frees memory from `malloc` with `ruby_xfree`, crashes.
```batch
vcpkg --triplet x64-windows install --x-feature=mimalloc
```
### How to compile and install
1. Execute `win32\configure.bat` on your build directory.

View File

@ -7,8 +7,17 @@
"openssl",
"zlib"
],
"features": {
"mimalloc": {
"description": "Allocate memory for the GC with mimalloc",
"dependencies": [
"mimalloc"
]
}
},
"builtin-baseline": "e456309491fd875487bf02b8a0dca76c1b1b00cc",
"vcpkg-configuration": {
"overlay-ports": ["win32/vcpkg-ports"],
"overlay-triplets": [".github/vcpkg-triplets"]
}
}

View File

@ -229,7 +229,7 @@ EXTLIBS ?=
EXTSOLIBS ?=
ifeq ($(origin LIBS),undefined)
LIBS = user32.lib advapi32.lib shell32.lib ws2_32.lib iphlpapi.lib \
$(if $(USE_GMP),gmp.lib) imagehlp.lib shlwapi.lib bcrypt.lib $(EXTLIBS)
$(if $(USE_GMP),gmp.lib)$(if $(filter yes,$(WITH_MIMALLOC)), mimalloc.dll.lib) imagehlp.lib shlwapi.lib bcrypt.lib $(EXTLIBS)
endif
ifeq ($(origin MISSING),undefined)
MISSING = crypt.obj ffs.obj lgamma_r.obj strlcat.obj strlcpy.obj win32/win32.obj win32/file.obj setproctitle.obj \
@ -496,7 +496,7 @@ update-vcpkg::
@cd "$(call win,$(srcdir))" && set LC_TIME=C && vcpkg x-update-baseline $(TRIPLET_OPTION)
install-vcpkg::
@cd "$(call win,$(srcdir))" && set LC_TIME=C && vcpkg install $(TRIPLET_OPTION)
@cd "$(call win,$(srcdir))" && set LC_TIME=C && vcpkg install $(TRIPLET_OPTION)$(if $(filter yes,$(WITH_MIMALLOC)), --x-feature=mimalloc)
# mklink is a cmd builtin that GNU make does not know to pass to cmd.
mklink = cmd /c mklink "$(call win,$(1))" "$(call win,$(2))"$(newline)
@ -729,7 +729,7 @@ $(sharp)define THREAD_IMPL_H "$(THREAD_IMPL_H)"
$(sharp)define THREAD_IMPL_SRC "$(THREAD_IMPL_SRC)"
$(sharp)define LOAD_RELATIVE 1
$(sharp)define DLEXT ".$(DLEXT)"
$(if $(filter-out lib,$(libdir_basename)),$(sharp)define LIBDIR_BASENAME "$(libdir_basename)"$(newline))$(if $(filter static,$(EXTSTATIC)),$(sharp)define EXTSTATIC 1$(newline))$(if $(USE_GMP),$(sharp)define USE_GMP 1$(newline))$(if $(filter yes,$(YJIT_SUPPORT)),$(sharp)define USE_YJIT 1$(newline))$(sharp)define EXECUTABLE_EXTS $(EXECUTABLE_EXTS)
$(if $(filter-out lib,$(libdir_basename)),$(sharp)define LIBDIR_BASENAME "$(libdir_basename)"$(newline))$(if $(filter static,$(EXTSTATIC)),$(sharp)define EXTSTATIC 1$(newline))$(if $(USE_GMP),$(sharp)define USE_GMP 1$(newline))$(if $(filter yes,$(WITH_MIMALLOC)),$(sharp)define USE_MIMALLOC 1$(newline))$(if $(filter yes,$(YJIT_SUPPORT)),$(sharp)define USE_YJIT 1$(newline))$(sharp)define EXECUTABLE_EXTS $(EXECUTABLE_EXTS)
$(sharp)define RUBY_COREDLL "$(RT)"
$(sharp)define RUBY_PLATFORM "$(arch)"
$(sharp)define RUBY_SITEARCH "$(sitearch)"

View File

@ -332,6 +332,9 @@ LIBS = $(LIBS) iphlpapi.lib
!if defined(USE_GMP)
LIBS = $(LIBS) gmp.lib
!endif
!if "$(WITH_MIMALLOC)" == "yes"
LIBS = $(LIBS) mimalloc.dll.lib
!endif
LIBS = $(LIBS) imagehlp.lib shlwapi.lib bcrypt.lib $(EXTLIBS)
!endif
!if !defined(MISSING)
@ -675,12 +678,15 @@ update-src::
VCPKG_DEFAULT_TRIPLET = $(MACHINE)-windows
!endif
TRIPLET_OPTION = --triplet $(VCPKG_DEFAULT_TRIPLET)
!if "$(WITH_MIMALLOC)" == "yes"
FEATURE_OPTION = --x-feature=mimalloc
!endif
update-vcpkg::
@cd "$(srcdir:/=\)" && set LC_TIME=C && vcpkg x-update-baseline $(TRIPLET_OPTION)
install-vcpkg::
@cd "$(srcdir:/=\)" && set LC_TIME=C && vcpkg install $(TRIPLET_OPTION)
@cd "$(srcdir:/=\)" && set LC_TIME=C && vcpkg install $(TRIPLET_OPTION) $(FEATURE_OPTION)
prepare-vcpkg::
@del /a:l *.dll 2> nul
@ -990,6 +996,9 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
!if "$(USE_GMP)" != ""
#define USE_GMP 1
!endif
!if "$(WITH_MIMALLOC)" == "yes"
#define USE_MIMALLOC 1
!endif
!if "$(YJIT_SUPPORT)" == "yes"
#define USE_YJIT 1
!endif

View File

@ -176,12 +176,14 @@ goto :loopend ;
::- them here too would duplicate them at each reconfiguration.
if "%opt%" == "--without-ext" goto :witharg
if "%opt%" == "--without-extensions" goto :witharg
if "%opt%" == "--without-mimalloc" echo>> %config_make% WITH_MIMALLOC = no
echo>>%confargs% "%opt%" \
if "%opt%" == "--without-baseruby" goto :nobaseruby
if "%opt%" == "--without-git" goto :nogit
goto :loop ;
:witharg
if "%opt%" == "--with-static-linked-ext" goto :extstatic
if "%opt%" == "--with-mimalloc" goto :mimalloc
if "%eq%" == "" call :take_arg
if not "%arg%" == "" (
echo>>%confargs% "%opt%=%arg:$=$$%" \
@ -246,6 +248,10 @@ goto :loop ;
:gmp
echo>> %config_make% WITH_GMP = yes
goto :loop ;
:mimalloc
if "%eq%" == "" (set "arg=yes")
echo>> %config_make% WITH_MIMALLOC = %arg%
goto :loopend ;
:destdir
echo>> %config_make% DESTDIR = %arg%
goto :loop ;
@ -286,6 +292,7 @@ goto :loop ;
echo --with-ext="a,b,..." use extensions a, b, ...
echo --without-ext="a,b,..." ignore extensions a, b, ...
echo --with-opt-dir="DIR-LIST" add optional headers and libraries directories separated by ';'
echo --with-mimalloc allocate memory for the GC with mimalloc
echo --disable-install-doc do not install rdoc indexes during install
echo --enable-yjit enable in-process JIT compiler that requires rustc (x64 only)
echo --with-ntver=0xXXXX target NT version (shouldn't use with old SDK)

View File

@ -47,7 +47,7 @@ i686-mswin32: -prologue- -i686- -epilogue-
x64-mswin64: -prologue- -x64- -epilogue-
arm64-mswin64: -prologue- -arm64- -epilogue-
-prologue-: -basic-vars- -baseruby- -dependencies- -gmp-
-prologue-: -basic-vars- -baseruby- -dependencies- -gmp- -mimalloc-
-generic-: -osname-
-basic-vars-: nul
@ -88,6 +88,15 @@ int main(void) {mpz_init(x); return 0;}
@$(WIN32DIR:/=\)\rm.bat conftest.*
!endif
-mimalloc-:
!if "$(WITH_MIMALLOC)" == "yes"
@$(CC) $(XINCFLAGS) <<conftest.c -link $(XLDFLAGS) mimalloc.dll.lib > nul || ($(WIN32DIR:/=\)\rm.bat conftest.* & echo mimalloc requested but not found 1>&2 & exit /b 1)
#include <mimalloc.h>
int main(void) {mi_free(mi_malloc(1)); return 0;}
<<
@$(WIN32DIR:/=\)\rm.bat conftest.*
!endif
-osname-section-:
@$(APPEND)
@echo # TARGET>>$(MAKEFILE)

View File

@ -0,0 +1,19 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5cc7ec5..578d235 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -680,8 +680,13 @@ endif()
# pkg-config file support
+set(mi_cxx_libraries "")
+if(MI_USE_CXX)
+ set(mi_cxx_libraries ${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES})
+ list(REMOVE_ITEM mi_cxx_libraries ${CMAKE_C_IMPLICIT_LINK_LIBRARIES})
+endif()
set(mi_pc_libraries "")
-foreach(item IN LISTS mi_libraries)
+foreach(item IN LISTS mi_libraries mi_cxx_libraries)
if(item MATCHES " *[-].*")
set(mi_pc_libraries "${mi_pc_libraries} ${item}")
else()

View File

@ -0,0 +1,71 @@
vcpkg_from_github(
OUT_SOURCE_PATH SOURCE_PATH
REPO microsoft/mimalloc
REF "v${VERSION}"
SHA512 ef24d926153eb81c95e6c79c335eed12c6e14523a2dd817faddc3f666909a244eab5f4be43cc01a6d8c8d62b5695d29fb535b3762128cdef50a7ee55302b2886
HEAD_REF dev3
PATCHES
pkgconfig-cxx.diff
)
vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS
FEATURES
override MI_OVERRIDE
secure MI_SECURE
)
string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "static" MI_BUILD_STATIC)
string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "dynamic" MI_BUILD_SHARED)
vcpkg_cmake_configure(
SOURCE_PATH "${SOURCE_PATH}"
OPTIONS
${FEATURE_OPTIONS}
# The only change from the port of vcpkg. Ruby allocates only the
# memory of its GC with mimalloc, and mimalloc-redirect.dll would try
# to redirect malloc of the whole process.
-DMI_WIN_REDIRECT=OFF
-DMI_USE_CXX=ON
-DMI_BUILD_OBJECT=OFF
-DMI_BUILD_TESTS=OFF
-DMI_BUILD_STATIC=${MI_BUILD_STATIC}
-DMI_BUILD_SHARED=${MI_BUILD_SHARED}
-DMI_INSTALL_TOPLEVEL=ON
OPTIONS_DEBUG
-DMI_DEBUG_FULL=ON
OPTIONS_RELEASE
-DMI_DEBUG_FULL=OFF
)
vcpkg_cmake_install()
vcpkg_copy_pdbs()
file(COPY
"${CMAKE_CURRENT_LIST_DIR}/vcpkg-cmake-wrapper.cmake"
"${CMAKE_CURRENT_LIST_DIR}/usage"
DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}"
)
vcpkg_cmake_config_fixup(CONFIG_PATH lib/cmake/mimalloc)
if(VCPKG_TARGET_IS_WINDOWS)
file(INSTALL
"${SOURCE_PATH}/bin/minject.exe"
"${SOURCE_PATH}/bin/minject32.exe"
"${SOURCE_PATH}/bin/minject-arm64.exe"
DESTINATION "${CURRENT_PACKAGES_DIR}/tools/${PORT}/"
)
endif()
if(VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic")
vcpkg_replace_string(
"${CURRENT_PACKAGES_DIR}/include/mimalloc.h"
"!defined(MI_SHARED_LIB)"
"0 // !defined(MI_SHARED_LIB)"
)
endif()
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include")
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/share")
vcpkg_fixup_pkgconfig()
vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE")

View File

@ -0,0 +1,9 @@
mimalloc provides CMake targets:
find_package(mimalloc CONFIG REQUIRED)
target_link_libraries(main PRIVATE $<IF:$<TARGET_EXISTS:mimalloc-static>,mimalloc-static,mimalloc>)
To ensure the mimalloc-override.dll is loaded at runtime on Windows with
dynamic linkage, it is suggested to insert some call to the mimalloc API
in the main function, eg. `mi_version()`. Cf.
https://github.com/microsoft/mimalloc/blob/dev/readme.md#dynamic-override-on-windows

View File

@ -0,0 +1,21 @@
_find_package(${ARGS})
if(CMAKE_CURRENT_LIST_DIR STREQUAL "${MIMALLOC_CMAKE_DIR}/${MIMALLOC_VERSION_DIR}")
set(MIMALLOC_INCLUDE_DIR "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include")
# As in vcpkg.cmake
if(NOT DEFINED CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE MATCHES "^[Dd][Ee][Bb][Uu][Gg]$")
set(MIMALLOC_LIBRARY_DIR "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug/lib")
else()
set(MIMALLOC_LIBRARY_DIR "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib")
endif()
set(MIMALLOC_OBJECT_DIR "MIMALLOC_OBJECT_DIR-NOTFOUND") # not installed
set(MIMALLOC_TARGET_DIR "${MIMALLOC_LIBRARY_DIR}")
endif()
if(TARGET mimalloc AND NOT TARGET mimalloc-static)
add_library(mimalloc-static INTERFACE IMPORTED)
set_target_properties(mimalloc-static PROPERTIES INTERFACE_LINK_LIBRARIES mimalloc)
elseif(TARGET mimalloc-static AND NOT TARGET mimalloc)
add_library(mimalloc INTERFACE IMPORTED)
set_target_properties(mimalloc PROPERTIES INTERFACE_LINK_LIBRARIES mimalloc-static)
endif()

View File

@ -0,0 +1,27 @@
{
"name": "mimalloc",
"version": "3.5.3",
"description": "Compact general purpose allocator with excellent performance",
"homepage": "https://github.com/microsoft/mimalloc",
"license": "MIT",
"supports": "!uwp",
"dependencies": [
{
"name": "vcpkg-cmake",
"host": true
},
{
"name": "vcpkg-cmake-config",
"host": true
}
],
"features": {
"override": {
"description": "Override the standard malloc interface (i.e. define entry points for 'malloc', 'free', etc)",
"supports": "!windows | !static"
},
"secure": {
"description": "Use full security mitigations (like guard pages, allocation randomization, double-free mitigation, and free-list corruption detection)"
}
}
}