Skip to content
Open
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
34 changes: 34 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -206,3 +206,37 @@ jobs:
run: |
"$MCPP" --version
timeout 1800 bash tests/smoke_imgui_module.sh

# ── Exception: the public `fmt` C++23-module package (namespace "") ──
# Same story as imgui-module above: empty namespace maps to the builtin default
# index, which a workspace member can't point at a local path, so it keeps a
# 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.

不用加这个

steps:
- uses: actions/checkout@v4
- name: Restore mcpp registry cache
uses: actions/cache@v4
with:
path: ~/.mcpp/registry
key: mcpp-registry-${{ runner.os }}-${{ env.MCPP_VERSION }}-${{ hashFiles('pkgs/**/*.lua', 'tests/**', '.github/workflows/validate.yml') }}
restore-keys: |
mcpp-registry-${{ runner.os }}-${{ env.MCPP_VERSION }}-
- name: Download mcpp
run: |
curl -L -fsS -o mcpp.tar.gz \
"https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/mcpp-${MCPP_VERSION}-linux-x86_64.tar.gz"
tar -xzf mcpp.tar.gz
root="$PWD/mcpp-${MCPP_VERSION}-linux-x86_64"
mkdir -p "$HOME/.mcpp/registry"
cp -a "$root/registry/." "$HOME/.mcpp/registry/"
echo "MCPP=$root/bin/mcpp" >> "$GITHUB_ENV"
echo "MCPP_VENDORED_XLINGS=$root/registry/bin/xlings" >> "$GITHUB_ENV"
echo "$root/bin" >> "$GITHUB_PATH"
- name: fmt module package smoke
env:
MCPP_INDEX_MIRROR: GLOBAL
run: |
"$MCPP" --version
timeout 1800 bash tests/smoke_fmt_module.sh
67 changes: 67 additions & 0 deletions pkgs/f/fmt.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
-- Form B inline descriptor for {fmt} exposed as the C++23 module `fmt`, so
-- users can write `import fmt;` out of the box (no `#include` needed). This is
-- the module sibling of the header-based `compat.fmt` package. Empty namespace
-- (like the public `imgui` module package) so the dependency key and the module
-- name are both simply `fmt`.
--
-- fmt's release DOES ship an official C++20 module interface unit at
-- `src/fmt.cc` (`export module fmt;`), but it cannot be fed to mcpp verbatim:
-- mcpp's M1 module scanner rejects ANY `import` that appears inside a
-- conditional preprocessor block (even a dead one), and fmt.cc carries
-- `#ifdef FMT_IMPORT_STD / import std; / #endif`. So we reproduce fmt.cc via
-- `generated_files` with exactly those three lines removed — everything else is
-- upstream fmt.cc verbatim: the global-module-fragment `#include`s, the
-- `export module fmt;` line, the FMT_EXPORT macro plumbing (fmt's headers
-- self-`export` under FMT_MODULE), and the tail `#include "format.cc"` /
-- `"os.cc"` that pulls the implementation INTO the module (so its definitions
-- attach to module `fmt`; compiling them as standalone TUs would leave them on
-- the global module and break module linkage).
--
-- include_dirs exposes BOTH `*/include` (so the module unit's `#include
-- <fmt/*.h>` resolves) and `*/src` (so the tail `#include "format.cc"` /
-- `"os.cc"` resolve). The wrapper path under mcpp_generated/ is verdir-relative
-- (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 名 作为命名空间

name = "fmt",
description = "A modern formatting library for C++, exposed as C++23 module fmt",
licenses = {"MIT"},
repo = "https://github.com/fmtlib/fmt",
type = "package",

xpm = {
linux = {
["12.2.0"] = {
url = "https://github.com/fmtlib/fmt/archive/refs/tags/12.2.0.tar.gz",
sha256 = "8b852bb5aa6e7d8564f9e81394055395dd1d1936d38dfd3a17792a02bebd7af0",
},
},
macosx = {
["12.2.0"] = {
url = "https://github.com/fmtlib/fmt/archive/refs/tags/12.2.0.tar.gz",
sha256 = "8b852bb5aa6e7d8564f9e81394055395dd1d1936d38dfd3a17792a02bebd7af0",
},
},
windows = {
["12.2.0"] = {
url = "https://github.com/fmtlib/fmt/archive/refs/tags/12.2.0.tar.gz",
sha256 = "8b852bb5aa6e7d8564f9e81394055395dd1d1936d38dfd3a17792a02bebd7af0",
},
},
},

mcpp = {
schema = "0.1",
language = "c++23",
import_std = false,
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
// ....
            ]],
        },

},
sources = { "mcpp_generated/fmt_module.cc" },
targets = { ["fmt"] = { kind = "lib" } },
deps = { },
},
}
101 changes: 101 additions & 0 deletions tests/smoke_fmt_module.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#!/usr/bin/env bash
# Smoke-test the public `fmt` module package through this checkout as a local
# mcpp path index. Validates user-facing import-only consumption (`import fmt;`).
# Mirrors tests/smoke_imgui_module.sh — the empty-namespace `fmt` package maps to
# the builtin default index (mcpplibs), which a workspace member cannot point at
# a local path, so it needs this thin driver that reseeds the default index.
set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
MCPP_BIN="${MCPP:-}"
if [[ -z "$MCPP_BIN" ]]; then
MCPP_BIN="$(command -v mcpp || true)"
fi
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方式已经废弃 可以不用添加


TMP="$(mktemp -d)"
if [[ "${MCPP_INDEX_KEEP_SMOKE_TMP:-0}" == "1" ]]; then
echo "KEEP: $TMP"
else
trap 'rm -rf "$TMP"' EXIT
fi

if [[ -n "${MCPP_INDEX_SMOKE_MCPP_HOME:-}" ]]; then
export MCPP_HOME="$MCPP_INDEX_SMOKE_MCPP_HOME"
else
export MCPP_HOME="$TMP/mcpp-home"
fi
mkdir -p "$MCPP_HOME/registry/data/xpkgs"

USER_MCPP="${HOME}/.mcpp"
link_xpkgs() {
local src="$1"
[[ -d "$src" ]] || return 0
find "$src" -mindepth 1 -maxdepth 1 -type d | while read -r pkg; do
ln -s "$pkg" "$MCPP_HOME/registry/data/xpkgs/$(basename "$pkg")" 2>/dev/null || true
done
}
link_xpkgs "${MCPP_INDEX_SMOKE_XPKGS_DIR:-}"
link_xpkgs "$USER_MCPP/registry/data/xpkgs"
if [[ -d "$USER_MCPP/registry/data/xim-pkgindex" ]]; then
mkdir -p "$MCPP_HOME/registry/data/xim-pkgindex"
cp -a "$USER_MCPP/registry/data/xim-pkgindex/." "$MCPP_HOME/registry/data/xim-pkgindex/" 2>/dev/null || true
rm -f "$MCPP_HOME/registry/data/xim-pkgindex/.xlings-index-cache.json"
fi
if [[ -d "$USER_MCPP/registry/bin" ]]; then
mkdir -p "$MCPP_HOME/registry"
ln -s "$USER_MCPP/registry/bin" "$MCPP_HOME/registry/bin" 2>/dev/null || true
fi
if [[ -f "$USER_MCPP/config.toml" ]]; then
cp -f "$USER_MCPP/config.toml" "$MCPP_HOME/config.toml" 2>/dev/null || true
fi

default_index="$MCPP_HOME/registry/data/mcpplibs"
# Reseed cleanly (see smoke_imgui_module.sh for why .git is skipped).
rm -rf "$default_index"
mkdir -p "$default_index"
( cd "$ROOT" && find . -mindepth 1 -maxdepth 1 ! -name .git -exec cp -a {} "$default_index/" \; )
rm -f "$default_index/.xlings-index-cache.json"
printf 'ok\n' > "$default_index/.mcpp-index-updated"

"$MCPP_BIN" self config --mirror "${MCPP_INDEX_MIRROR:-GLOBAL}" >/dev/null

mkdir -p "$TMP/fmt-module-smoke/src"
cd "$TMP/fmt-module-smoke"
cat > mcpp.toml <<EOF
[package]
name = "fmt-module-smoke"
version = "0.1.0"
[toolchain]
default = "${MCPP_INDEX_FMT_MODULE_TOOLCHAIN:-gcc@16.1.0}"
[dependencies]
fmt = "12.2.0"
[targets.fmt-module-smoke]
kind = "bin"
main = "src/main.cpp"
EOF

cat > src/main.cpp <<'EOF'
import std;
import fmt;
int main() {
std::string a = fmt::format("{} + {} = {}", 2, 3, 2 + 3);
std::string b = fmt::format("{:08.3f}", 3.14159);
std::string c = fmt::format("{0}-{1}-{0}", "x", "y");
std::string d = fmt::format("{:#x}", 255);
bool ok = a == "2 + 3 = 5" && b == "0003.142" && c == "x-y-x" && d == "0xff";
std::println("fmt module package ok: {}", a);
return ok ? 0 : 1;
}
EOF

"$MCPP_BIN" build
"$MCPP_BIN" run