Skip to content
Merged
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Preserve upstream document bytes and original whitespace on every platform.
upstream/** -text -whitespace
84 changes: 84 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
mcpp:
name: mcpp (${{ matrix.os }}, ${{ matrix.toolchain }})
strategy:
fail-fast: false
matrix:
include:
- { os: ubuntu-24.04, toolchain: 'gcc@16.1.0' }
- { os: ubuntu-24.04, toolchain: 'llvm@23.1.3' }
- { os: macos-15, toolchain: 'llvm@23.1.3' }
- { os: windows-2025, toolchain: 'llvm@23.1.3' }
runs-on: ${{ matrix.os }}
timeout-minutes: 60
defaults:
run:
shell: bash
env:
XLINGS_NON_INTERACTIVE: 1
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Mwrap identity and bilingual README contract
run: python3 tools/check_mwrap_release.py

- name: Install Xlings (Linux/macOS)
if: runner.os != 'Windows'
run: |
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/refs/heads/main/tools/other/quick_install.sh | bash
echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH"

- name: Install Xlings (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
irm https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.ps1 | iex
"$env:USERPROFILE\.xlings\subos\current\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append

- name: Install project tools (.xlings.json)
run: |
for attempt in 1 2 3; do
xlings update > /dev/null 2>&1 || true
if xlings install; then break; fi
[ "$attempt" = 3 ] && exit 1
sleep 30
done
mcpp --version

- name: Select the toolchain
run: |
name="${{ matrix.toolchain }}"
mcpp toolchain install "${name%@*}" "${name#*@}"
mcpp toolchain default "$name"

- name: Build the modules
run: mcpp build

- name: Tests (allocation, heaps, options, the STL allocator, statistics, threads, the constants, header mixing)
run: mcpp test

- name: Export audit (every function, type and enumerator of the three headers, every macro)
run: python3 tools/check_exports.py

- name: Upstream's test-api and test-stress over the same library
run: python3 tools/run_conformance.py --toolchain "${{ matrix.toolchain }}"
49 changes: 49 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Release
on:
push:
tags: ["mwrap-*"]
permissions:
contents: read
jobs:
publish:
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: write
actions: read
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Check tag, upstream version and bilingual entry pages
run: python3 tools/check_mwrap_release.py --tag "$GITHUB_REF_NAME"
- name: Require successful source CI at this exact commit
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
set -euo pipefail
result=$(gh run list --repo "$GITHUB_REPOSITORY" --workflow ci.yml --commit "$GITHUB_SHA" --limit 1 --json status,conclusion --jq '.[0] | .status == "completed" and .conclusion == "success"')
test "$result" = true || { echo 'No successful source CI at the tag commit'; exit 1; }
- name: Build immutable source asset and publish
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
set -euo pipefail
version="${GITHUB_REF_NAME#mwrap-}"
repo="${GITHUB_REPOSITORY#*/}"
asset="${repo}-${version}.tar.gz"
git archive --format=tar.gz --prefix="${repo}-${version}/" "$GITHUB_SHA" > "$RUNNER_TEMP/$asset"
(cd "$RUNNER_TEMP" && sha256sum "$asset" > "$asset.sha256")
if gh release view "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
echo 'Release already exists; refusing to change immutable assets'; exit 1
fi
extra=()
if [[ "$version" == *-rc* ]]; then extra+=(--prerelease); fi
gh release create "$GITHUB_REF_NAME" "$RUNNER_TEMP/$asset" "$RUNNER_TEMP/$asset.sha256" \
--repo "$GITHUB_REPOSITORY" --verify-tag --title "$repo $version" \
--notes "Module wrapper for upstream $version. New mwrap package identities become installable after mcpp-index publication; see the bilingual README for the tested support scope." "${extra[@]}"
28 changes: 28 additions & 0 deletions .github/workflows/templates.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Actual project templates
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
permissions:
contents: read
concurrency:
group: templates-${{ github.ref }}
cancel-in-progress: true
env:
MCPP_VERSION: "2026.11.2.1"
jobs:
templates:
runs-on: ubuntu-24.04
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- name: Install the pinned mcpp
shell: bash
run: |
archive="mcpp-${MCPP_VERSION}-linux-x86_64.tar.gz"
curl -L -fsS -o "$archive" "https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/$archive"
tar -xzf "$archive"
echo "$PWD/mcpp-${MCPP_VERSION}-linux-x86_64/bin" >> "$GITHUB_PATH"
- name: Actual scaffold, strict build and run of the default template
run: python3 tools/test_template.py --toolchain gcc@16.1.0
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
target/
.mcpp/
mcpp.lock
compile_commands.json
__pycache__/
.xlings/
5 changes: 5 additions & 0 deletions .xlings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"workspace": {
"xim:mcpp": "2026.11.2.1"
}
}
13 changes: 13 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
mimalloc-m: C++ module wrapper
Copyright (c) 2026 mcpp-community contributors

The wrapper contributions are licensed under the Apache License, Version 2.0.
Upstream code, copied interfaces and dependencies retain their original
licenses and copyright notices. mimalloc is distributed under the MIT license:

Copyright (c) 2018-2026 Microsoft Corporation, Daan Leijen.

Its original README and license are retained in upstream/mimalloc/. The
library itself is provided by compat.mimalloc from the same release, and the
typed macros of include/mwrap/mimalloc/macros.hpp are upstream's definitions.
Provenance and checksums are recorded in upstream/documents.json.
73 changes: 73 additions & 0 deletions README.zh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# mimalloc

> mimalloc——微软的通用内存分配器,以 C++23 模块提供。

[English](README.md) · **简体中文** · [上游](https://github.com/microsoft/mimalloc) · [发布](https://github.com/mcpplibs/mimalloc-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [索引](https://github.com/mcpplibs/mcpp-index)

[![C++23](https://img.shields.io/badge/C%2B%2B-23-blue.svg)](https://en.cppreference.com/w/cpp/23)
[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
[![mcpp-community](https://img.shields.io/badge/mcpp--community-mwrap-blue)](https://github.com/mcpp-community)
[![CI](https://github.com/mcpplibs/mimalloc-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/mimalloc-m/actions/workflows/ci.yml)

上游 API 不变:`mi_*` 函数、`mi_heap_t`、选项枚举、回调类型与 STL 分配器都是 `<mimalloc.h>` 中的上游实体,位于上游声明它们的
全局命名空间。库本身是 `compat.mimalloc` 3.6.1;值宏映射为常量。每次 CI 都在同一份库上运行上游自己的 `test-api` 与
`test-stress`。

## 模块

- `import mcpplibs.mwrap.mimalloc;`:`<mimalloc.h>` 的函数、堆、arena、子进程、选项与 STL 分配器,并重新导出下面三个模块
- `import mcpplibs.mwrap.mimalloc.stats;`:`mi_stats_get`、`mi_heap_stats_get` 等与 `mi_stats_t`(`<mimalloc-stats.h>`)
- `import mcpplibs.mwrap.mimalloc.profile;`:采样剖析器与 pprof 写出(`<mimalloc-profile.h>`)
- `import mcpplibs.mwrap.mimalloc.macros;`:`MI_MALLOC_VERSION`、`MI_SMALL_SIZE_MAX` 等,位于 `mcpplibs::mwrap::mimalloc::macros`

> 更多模块 API -> [用法与 API](docs/usage.md)

## 快速开始

```sh
mcpp new allocate --template mcpplibs.mwrap.mimalloc@3.6.1
cd allocate
mcpp run
```

默认模板在一个私有堆中分配并一次销毁,分配一个对齐的块,让 vector 的元素由 mimalloc 分配,并打印版本。

```toml
[dependencies]
"mcpplibs.mwrap.mimalloc" = "3.6.1"
```

```cpp
import std;
import mcpplibs.mwrap.mimalloc;

int main() {
mi_heap_t* heap = mi_heap_new();
auto* p = static_cast<char*>(mi_heap_malloc(heap, 64));
std::println("{} usable bytes", mi_usable_size(p));
mi_heap_destroy(heap); // 释放这个堆中的全部块
std::vector<int, mi_stl_allocator<int>> v{1, 2, 3};
}
```

## 配置与宏

mimalloc 在构建 `compat.mimalloc` 时配置;运行时的选项经 `mi_option_set` 或 `MIMALLOC_*` 环境变量设置。带类型参数的分配宏
(`mi_malloc_tp(T)`、`mi_heap_calloc_tp(T, heap, n)` 等)没有调用形式相同的函数可以替代,保留为
`<mwrap/mimalloc/macros.hpp>` 中的宏,在 import 之前包含;其中三个调用上游的 `static inline` 辅助函数,模块无法导出它们,模块以
`mcpplibs::mwrap::mimalloc::mi_malloc_csize` 等同名函数适配。宏在限定名中同样会展开,因此与 `<mimalloc.h>` 同时使用时要换名
读取常量([docs/usage.md](docs/usage.md))。

本包不替换 `malloc`:与 `compat.mimalloc` 相同,构建时不定义 `MI_MALLOC_OVERRIDE`。

## 构建与测试

Linux、macOS 与 Windows 的 CI 构建模块并运行测试:分配、重新分配、清零、对齐、私有堆及其遍历、类型宏、选项、STL 分配器、
统计、四个线程同时分配、常量与头文件混用。CI 还运行导出审计([tools/check_exports.py](tools/check_exports.py):三个头文件的
每个函数与类型都已导出、适配或列出理由),以及在同一份库上构建的上游 `test/test-api.c` 与 `test/test-stress.c`
([tools/run_conformance.py](tools/run_conformance.py))。另有一个作业以已安装包的方式生成默认模板并运行。

## 许可

封装部分为 [Apache-2.0](LICENSE),作者 mcpp-community([NOTICE](NOTICE))。mimalloc 仍为 MIT 许可
([upstream/mimalloc/LICENSE](upstream/mimalloc/LICENSE)、[README](upstream/mimalloc/README.md))。
55 changes: 55 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Usage and API

`mcpplibs.mwrap.mimalloc` 3.6.1 exports mimalloc's public API, upstream's names
unchanged. This page lists what each module holds and the places where a module
and a header differ.

## Modules

| Module | Holds |
|---|---|
| `mcpplibs.mwrap.mimalloc` | the functions of `<mimalloc.h>` (allocation, aligned allocation, heaps, arenas, sub-processes, options, process and thread control, the POSIX and C++ `new` forms); `mi_heap_t`, `mi_heap_area_t`, `mi_theap_t`, `mi_arena_id_t`, `mi_subproc_id_t`, the callback types, `mi_option_t` and its enumerators; `mi_stl_allocator`, `mi_heap_stl_allocator` and `mi_heap_destroy_stl_allocator` with their comparisons; re-exports the three below |
| `mcpplibs.mwrap.mimalloc.stats` | `<mimalloc-stats.h>`: `mi_stats_get`, `mi_heap_stats_get`, `mi_subproc_stats_get` and their JSON and text forms; `mi_stats_t` and its counters; `mi_chunkbin_t` |
| `mcpplibs.mwrap.mimalloc.profile` | `<mimalloc-profile.h>`: `mi_profiler_t` and its callbacks, `mi_heap_profile`, `mi_profile`, `mi_profiler_start` / `stop` / `snapshot`, `mi_pprof_profiler_new` / `delete` |
| `mcpplibs.mwrap.mimalloc.macros` | the value macros as constants in `mcpplibs::mwrap::mimalloc::macros` |

## What a module cannot export, and what stands in for it

- **`static inline` functions.** `<mimalloc.h>` defines nine (`mi_wsize_from_size`,
`mi_malloc_csize`, `mi_zalloc_csize`, `mi_theap_malloc_csize`,
`mi_theap_zalloc_csize`, `mi_free_csize` and its three variants), and
`<mimalloc-stats.h>` two (`mi_stats_header_init`, `mi_stats_init`). A function
with internal linkage belongs to one translation unit, so each is adapted under
its name in `mcpplibs::mwrap::mimalloc` and calls upstream's body.
- **Macros that take a type.** `mi_malloc_tp(T)`, `mi_zalloc_tp(T)`,
`mi_calloc_tp(T, n)`, `mi_mallocn_tp`, `mi_reallocn_tp`, `mi_recalloc_tp`,
`mi_free_tp` and the six `mi_heap_*_tp`, and `mi_stats_t_decl(name)`, stay macros
in `<mwrap/mimalloc/macros.hpp>`. Include it before the imports; the macros
that call an adapted helper name it with its namespace.
- **Value macros.** `MI_MALLOC_VERSION`, `MI_SMALL_WSIZE_MAX`, `MI_SMALL_SIZE_MAX`,
`MI_STAT_VERSION`, `MI_BIN_HUGE`, `MI_PROFILE_SAMPLE_DATA_MAX_SIZE` and
`MI_HAS_HEAP_STL_ALLOCATOR` are `inline constexpr` constants of the same names.

## A header beside the module

`#include <mimalloc.h>` and `import mcpplibs.mwrap.mimalloc;` may appear in one
unit: they declare the same entities. A macro expands even inside a qualified
name, so `mcpplibs::mwrap::mimalloc::macros::MI_MALLOC_VERSION` written after the
header is `...::macros::30601`. Read the header's value under another name and
`#undef` the macro before naming the constant (tests/macros.cpp does this).

## Configuration

The library is `compat.mimalloc` 3.6.1, built by mcpp from the release tarball
without `MI_MALLOC_OVERRIDE`: `malloc` remains the C library's. Options are set at
run time with `mi_option_set` or the `MIMALLOC_*` environment variables
(`MIMALLOC_SHOW_STATS=1`, `MIMALLOC_VERBOSE=1` …), as upstream documents.

## Testing

```sh
mcpp test # the module: API, constants, header mixing
python3 tools/check_exports.py # every entity and macro accounted for
python3 tools/run_conformance.py # upstream's test-api and test-stress
python3 tools/test_template.py # the default template, as installed
```
37 changes: 37 additions & 0 deletions include/mwrap/mimalloc/macros.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// <mwrap/mimalloc/macros.hpp> --- the macros of <mimalloc.h> that take a type
// (`mi_malloc_tp(T)' and its eleven companions), which a named module cannot
// export and no function can replace with the same call syntax. Include it
// before `import mcpplibs.mwrap.mimalloc;'; each expands to the upstream
// functions the module exports, and the three that upstream spells with its
// `static inline' helpers to the module's adaptations of them
// (mcpplibs::mwrap::mimalloc::mi_malloc_csize, mi_zalloc_csize,
// mi_free_csize). The definitions are otherwise upstream's (mimalloc 3.6.1,
// include/mimalloc.h, MIT license, upstream/mimalloc/LICENSE), each defined
// only where <mimalloc.h> has not defined it already.
#ifndef MWRAP_MIMALLOC_MACROS_HPP
#define MWRAP_MIMALLOC_MACROS_HPP

#ifndef mi_malloc_tp
#define mi_malloc_tp(tp) ((tp*)::mcpplibs::mwrap::mimalloc::mi_malloc_csize(sizeof(tp)))
#define mi_zalloc_tp(tp) ((tp*)::mcpplibs::mwrap::mimalloc::mi_zalloc_csize(sizeof(tp)))
#define mi_calloc_tp(tp,n) ((tp*)mi_calloc(n,sizeof(tp)))
#define mi_mallocn_tp(tp,n) ((tp*)mi_mallocn(n,sizeof(tp)))
#define mi_reallocn_tp(tp,p,n) ((tp*)mi_reallocn(p,n,sizeof(tp)))
#define mi_recalloc_tp(tp,p,n) ((tp*)mi_recalloc(p,n,sizeof(tp)))
#define mi_free_tp(tp,p) (::mcpplibs::mwrap::mimalloc::mi_free_csize(p,sizeof(tp)))

#define mi_heap_malloc_tp(tp,hp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
#define mi_heap_zalloc_tp(tp,hp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
#define mi_heap_calloc_tp(tp,hp,n) ((tp*)mi_heap_calloc(hp,n,sizeof(tp)))
#define mi_heap_mallocn_tp(tp,hp,n) ((tp*)mi_heap_mallocn(hp,n,sizeof(tp)))
#define mi_heap_reallocn_tp(tp,hp,p,n) ((tp*)mi_heap_reallocn(hp,p,n,sizeof(tp)))
#define mi_heap_recalloc_tp(tp,hp,p,n) ((tp*)mi_heap_recalloc(hp,p,n,sizeof(tp)))
#endif

// <mimalloc-stats.h>: a statistics structure declared and initialised, through
// the module's adaptation of upstream's `static inline' mi_stats_init.
#ifndef mi_stats_t_decl
#define mi_stats_t_decl(name) mi_stats_t name; ::mcpplibs::mwrap::mimalloc::mi_stats_init(&name);
#endif

#endif
Loading
Loading