Skip to content

feat: add fmt 12.2.0 as C++23 module package (import fmt;)#63

Open
1115040131 wants to merge 1 commit into
mcpplibs:mainfrom
1115040131:add-fmt-module
Open

feat: add fmt 12.2.0 as C++23 module package (import fmt;)#63
1115040131 wants to merge 1 commit into
mcpplibs:mainfrom
1115040131:add-fmt-module

Conversation

@1115040131

@1115040131 1115040131 commented Jul 7, 2026

Copy link
Copy Markdown

概述

新增公开的 fmt 包(空命名空间),将 {fmt} 12.2.0 以 C++23 模块形态收录,
用户可直接 import fmt;。它是 header 版 compat.fmt 的模块孪生包,两者
消费模型不同、可共存。

形态:module wrapper(generated_files)

fmt 的 release 自带官方模块单元 src/fmt.cc(export module fmt;),但不能
逐字喂给 mcpp
:mcpp 的 M1 模块扫描器拒绝任何位于条件预处理块内的 import
(即使是不启用的死分支),而 fmt.cc 把 import std; 包在 #ifdef FMT_IMPORT_STD
里。该限制在 mcpp 0.0.81 / 0.0.82 / main 均存在,非版本问题。

因此描述符用 generated_files 复刻 fmt.cc,仅删除那 3 行(#ifdef /
import std; / #endif),其余逐字保留:

  • 全局模块片段的 #include(std 头挂到全局模块)
  • export module fmt;(mcpp 据此注册 provider)
  • FMT_EXPORT 宏机制(fmt 头文件在 FMT_MODULE 下自行 export)
  • 末尾 #include "format.cc" / "os.cc"(把实现附着到模块 fmt;若作为独立 TU
    编译会留在全局模块,破坏模块链接)

include_dirs 暴露 */include(模块单元的 #include <fmt/*.h> 可解析)与
*/src(末尾 impl include 可解析)。import_std = false(默认走文本 std 头)。

CI

空命名空间包无法作为 workspace 成员(同公开的 imgui 包:空命名空间映射到
mcpp 内建默认索引,[indices] 无法把默认索引重定向到本地 path)。故新增
tests/smoke_fmt_module.sh —— reseed 默认索引后消费 import fmt;,在
validate.yml 中作为 fmt-module job 运行(与 imgui-module 同构)。

镜像

无 mcpp-res 写权限,下载 url 采用纯上游字符串(lint 对纯字符串 url 放行),
CN 镜像待维护者后续补充。

验证

mcpp 0.0.81(与 CI MCPP_VERSION 一致)本地跑 smoke:构建模块 fmt 并通过
行为断言。

Compiling fmt v12.2.0
Finished release [optimized]
Running target/.../bin/fmt-module-smoke
fmt module package ok: 2 + 3 = 5

本地复现 CI lint 全过,validate.yml YAML 校验通过。

Module sibling of the header-based compat.fmt: the public `fmt` package
(empty namespace) exposes the C++23 module `fmt` so users write
`import fmt;`.

fmt's release ships an official module unit at src/fmt.cc, but mcpp's M1
scanner rejects any `import` inside a conditional preprocessor block (even
a dead one), and fmt.cc guards `import std;` behind `#ifdef FMT_IMPORT_STD`.
So the descriptor reproduces fmt.cc via generated_files with exactly those
three lines removed — everything else verbatim, including the tail
`#include "format.cc"/"os.cc"` that attaches the implementation to module
fmt. include_dirs exposes */include and */src so both the module unit and
its impl includes resolve.

Empty-namespace packages can't be workspace members (like the imgui module
package), so a thin driver tests/smoke_fmt_module.sh reseeds the default
index and consumes `import fmt;`, wired into validate.yml as the fmt-module
job.

Verified locally on mcpp 0.0.81 (== CI): the smoke builds module fmt and
its behavioral assertions pass. No mcpp-res write access, so the download
url is a plain upstream string (CN mirror to be added by a maintainer).

Co-Authored-By: Claude <noreply@anthropic.com>
# thin driver that reseeds the default index and consumes `import fmt;`.
fmt-module:
runs-on: ubuntu-latest
timeout-minutes: 60

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不用加这个

Comment thread pkgs/f/fmt.lua
modules = { "fmt" },
include_dirs = { "*/include", "*/src" },
generated_files = {
["mcpp_generated/fmt_module.cc"] = "// Formatting library for C++ - C++20 module\n//\n// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors\n// All rights reserved.\n//\n// For the license information refer to format.h.\n\nmodule;\n\n#define FMT_MODULE\n\n#ifdef _MSVC_LANG\n# define FMT_CPLUSPLUS _MSVC_LANG\n#else\n# define FMT_CPLUSPLUS __cplusplus\n#endif\n\n// Put all implementation-provided headers into the global module fragment\n// to prevent attachment to this module.\n#ifndef FMT_IMPORT_STD\n# include <algorithm>\n# include <bitset>\n# include <chrono>\n# include <cmath>\n# include <complex>\n# include <cstddef>\n# include <cstdint>\n# include <cstdio>\n# include <cstdlib>\n# include <cstring>\n# include <ctime>\n# include <exception>\n# if FMT_CPLUSPLUS > 202002L\n# include <expected>\n# endif\n# include <filesystem>\n# include <fstream>\n# include <functional>\n# include <iterator>\n# include <limits>\n# include <locale>\n# include <memory>\n# include <optional>\n# include <ostream>\n# include <source_location>\n# include <stdexcept>\n# include <string>\n# include <string_view>\n# include <system_error>\n# include <thread>\n# include <type_traits>\n# include <typeinfo>\n# include <utility>\n# include <variant>\n# include <vector>\n#else\n# include <limits.h>\n# include <stdint.h>\n# include <stdio.h>\n# include <stdlib.h>\n# include <string.h>\n# include <time.h>\n#endif\n#include <cerrno>\n#include <climits>\n#include <version>\n\n#if __has_include(<cxxabi.h>)\n# include <cxxabi.h>\n#endif\n#if defined(_MSC_VER) || defined(__MINGW32__)\n# include <intrin.h>\n#endif\n#if defined __APPLE__ || defined(__FreeBSD__)\n# include <xlocale.h>\n#endif\n#if __has_include(<winapifamily.h>)\n# include <winapifamily.h>\n#endif\n#if (__has_include(<fcntl.h>) || defined(__APPLE__) || \\\n defined(__linux__)) && \\\n (!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))\n# include <fcntl.h>\n# include <sys/stat.h>\n# include <sys/types.h>\n# ifndef _WIN32\n# include <unistd.h>\n# else\n# include <io.h>\n# endif\n#endif\n#ifdef _WIN32\n# if defined(__GLIBCXX__)\n# include <ext/stdio_filebuf.h>\n# include <ext/stdio_sync_filebuf.h>\n# endif\n# define WIN32_LEAN_AND_MEAN\n# include <windows.h>\n#endif\n\nexport module fmt;\n\n\n#define FMT_EXPORT export\n#define FMT_BEGIN_EXPORT export {\n#define FMT_END_EXPORT }\n\n// If you define FMT_ATTACH_TO_GLOBAL_MODULE\n// - all declarations are detached from module 'fmt'\n// - the module behaves like a traditional static library, too\n// - all library symbols are mangled traditionally\n// - you can mix TUs with either importing or #including the {fmt} API\n#ifdef FMT_ATTACH_TO_GLOBAL_MODULE\nextern \"C++\" {\n#endif\n\n#ifndef FMT_OS\n# define FMT_OS 1\n#endif\n\n// All library-provided declarations and definitions must be in the module\n// purview to be exported.\n#include \"fmt/args.h\"\n#include \"fmt/chrono.h\"\n#include \"fmt/color.h\"\n#include \"fmt/compile.h\"\n#include \"fmt/format.h\"\n#if FMT_OS\n# include \"fmt/os.h\"\n#endif\n#include \"fmt/ostream.h\"\n#include \"fmt/printf.h\"\n#include \"fmt/ranges.h\"\n#include \"fmt/std.h\"\n#include \"fmt/xchar.h\"\n\n#ifdef FMT_ATTACH_TO_GLOBAL_MODULE\n}\n#endif\n\n#ifdef FMT_ATTACH_TO_GLOBAL_MODULE\nextern \"C++\" {\n#endif\n\n#if FMT_HAS_INCLUDE(\"format.cc\")\n# include \"format.cc\"\n#endif\n#if FMT_OS && FMT_HAS_INCLUDE(\"os.cc\")\n# include \"os.cc\"\n#endif\n\n#ifdef FMT_ATTACH_TO_GLOBAL_MODULE\n}\n#endif\n",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个可以使用多行语法展开 不用使用 \n 放到单行。类似下面

        generated_files = {
            ["mcpp_generated/nlohmann.json.cppm"] = [[
// L1
// L2
// ....
            ]],
        },

Comment thread tests/smoke_fmt_module.sh
if [[ -z "$MCPP_BIN" || ! -x "$MCPP_BIN" ]]; then
echo "FATAL: set MCPP=/path/to/mcpp or put mcpp on PATH" >&2
exit 1
fi

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个老式的ci方式已经废弃 可以不用添加

Comment thread pkgs/f/fmt.lua
-- (no glob), like nlohmann.json / compat.eigen.
package = {
spec = "1",
namespace = "",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个可以加上 作者名 或 org 名 作为命名空间

@Sunrisepeak

Copy link
Copy Markdown
Member

这个62PR 很规范, 建议 本PR直接 作为支持模块化的 fmt 库 然后 添加类似 62的 tests 最小测试工程。就可以省略 62 compat 模式了

@Sunrisepeak

Copy link
Copy Markdown
Member

最新版本好像默认就是支持 模块化的 不用额外 使用 generated_files 好像

@Sunrisepeak

Copy link
Copy Markdown
Member

#ifdef FMT_IMPORT_STD 包描述文件直接定义这个宏就可以了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants