Skip to content

Commit 064d42b

Browse files
authored
feat(pkg): add libevent 2.1.13 compat package (#503)
* feat(pkg): add libevent 2.1.13 compat package * docs(pkg): record libevent LLVM verification * fix(pkg): run libevent configure through cmd on Windows * test(pkg): initialize Winsock in libevent matrix smoke * docs(pkg): record libevent platform matrix results * docs(pkg): keep package examples out of README * chore(ci): remove temporary libevent matrix workflow * fix(pkg): use host compiler for libevent probes * docs(pkg): record libevent GCC probe fix
1 parent 265f3c6 commit 064d42b

8 files changed

Lines changed: 215 additions & 4 deletions

File tree

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Libevent 2.1.13 compat package
2+
3+
- Source: `libevent/libevent`, latest stable tag observed `release-2.1.13-stable` (2.2 tags were alpha prereleases); GitHub tag archive SHA-256 `1a0885e17dc78afbaeddf13cf849f9238bbc24acdc178464a0d1934d7c5ffbd5`, calculated twice.
4+
- Shape: Form B, C source package. The release needs `event2/event-config.h` and `evconfig-private.h` generated by CMake feature probes. `install()` invokes declared `xim:cmake` only to produce those platform headers; mcpp compiles the upstream C translation units so the library follows the consumer's toolchain. Its source list mirrors CMake's `SRC_CORE` and `SRC_EXTRA`, plus the per-platform backends (Linux epoll, macOS kqueue, Windows IOCP/select), and POSIX/Win32 threading. TLS integrations are not part of the default library and are deliberately excluded, not exposed as unverified features.
5+
- Platforms: linux, macosx, windows all declared against the same archive and sha256. The test member executes the same event timer, evbuffer round trip, and HTTP object construction on each. Windows system libraries are explicitly linked.
6+
- License: BSD-3-Clause for the main sources, ISC for arc4random included by `evutil_rand.c`, and MIT for the Windows timer code derived from libutp (`evutil_time.c`; see upstream LICENSE). The separate wepoll and TLS integrations are not compiled.
7+
- Mirror: no GitCode credentials/assets available; use a plain upstream URL (not a fictional CN URL).
8+
- Local Linux verification: mcpp 2026.10.1.2 `mcpp xpkg parse --all-os pkgs/c/compat.libevent.lua` reports 24/24/25 sources; cold `mcpp test -p libevent --cache off` passed under GCC 16.1.0. The test deliberately uses `EVLOOP_ONCE` because `event_base_dispatch()` returns one after a one-shot timer drains the queue even when its callback ran.
9+
- PR #503 initially failed only on Linux default GCC: CMake's host probes produced an incomplete `event-config.h` (missing pointer-size and socket/address-family macros) when using the ambient toolchain wrapper. The hook now selects native `/usr/bin/cc` for CMake's Linux/macOS host probes; mcpp still compiles the sources with the selected consumer compiler. The fix passed a cold local Linux GCC build and the full PR matrix on Linux GCC/LLVM, macOS and Windows.
10+
- The final PR validation run passed lint, mirror checks, build, Linux default, all Linux LLVM shards, macOS, and Windows. Results: [PR #503 checks](https://github.com/mcpplibs/mcpp-index/pull/503/checks).

‎CHANGELOG.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99

1010
### Added
1111

12+
- **`compat.libevent` 2.1.13。** Linux、macOS、Windows 分别通过上游 CMake 生成
13+
平台配置头,再由 mcpp 编译 libevent 核心、HTTP/DNS 扩展和对应系统后端;
14+
TLS 可选组件未收录。workspace 成员测试事件分派、缓冲区和 HTTP 对象。
15+
1216
- **`compat.muduo` 2.0.3 与 Boost 头组件。** muduo 仅支持 Linux;内联构建
1317
`muduo_base`/`muduo_net` 源码,按上游 2.0.3 的依赖补充 `compat.boost-any`、
1418
`compat.boost-circular-buffer`、`compat.boost-concept-check` 并复用既有 `compat.boost-utility`。

‎README.md‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,7 @@ One descriptor per common shape:
3838
| Native module library (Form A) | [`mcpplibs.tinyhttps`](pkgs/t/tinyhttps.lua) · [`gzj-creator.galay`](pkgs/g/gzj-creator.galay.lua) |
3939
| C sources + `features` | [`compat.cjson`](pkgs/c/compat.cjson.lua) |
4040
| C++ sources, several versions | [`compat.yaml-cpp`](pkgs/c/compat.yaml-cpp.lua) |
41-
| Boost header-only components | [`compat.boost-any`](pkgs/c/compat.boost-any.lua) · [`compat.boost-circular-buffer`](pkgs/c/compat.boost-circular-buffer.lua) · [`compat.boost-concept-check`](pkgs/c/compat.boost-concept-check.lua) · [`compat.boost-utility`](pkgs/c/compat.boost-utility.lua) |
4241
| Header-only | [`compat.gtl`](pkgs/c/compat.gtl.lua) |
43-
| Linux-only C++ network library | [`compat.muduo`](pkgs/c/compat.muduo.lua) |
4442
| Generated config header | [`compat.c-ares`](pkgs/c/compat.c-ares.lua) |
4543
| C++23 module wrapper | [`nlohmann.json`](pkgs/n/nlohmann.json.lua) |
4644
| C++23 module shipped by upstream | [`khronos.vulkan-hpp`](pkgs/k/khronos.vulkan-hpp.lua) |

‎README.zh-CN.md‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ mcpp self config --mirror CN # 切换至国内镜像,默认使用 GLOBAL 上
3737
| 原生模块库(Form A) | [`mcpplibs.tinyhttps`](pkgs/t/tinyhttps.lua) · [`gzj-creator.galay`](pkgs/g/gzj-creator.galay.lua) |
3838
| C 源码 + `features` | [`compat.cjson`](pkgs/c/compat.cjson.lua) |
3939
| C++ 源码,多版本 | [`compat.yaml-cpp`](pkgs/c/compat.yaml-cpp.lua) |
40-
| Boost 头文件组件 | [`compat.boost-any`](pkgs/c/compat.boost-any.lua) · [`compat.boost-circular-buffer`](pkgs/c/compat.boost-circular-buffer.lua) · [`compat.boost-concept-check`](pkgs/c/compat.boost-concept-check.lua) · [`compat.boost-utility`](pkgs/c/compat.boost-utility.lua) |
41-
| 仅 Linux 的 C++ 网络库 | [`compat.muduo`](pkgs/c/compat.muduo.lua) |
4240
| header-only | [`compat.gtl`](pkgs/c/compat.gtl.lua) |
4341
| 生成 config 头 | [`compat.c-ares`](pkgs/c/compat.c-ares.lua) |
4442
| C++23 module wrapper | [`nlohmann.json`](pkgs/n/nlohmann.json.lua) |

‎mcpp.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ members = [
107107
"tests/examples/libassert",
108108
"tests/examples/libcoro",
109109
"tests/examples/libdrm",
110+
"tests/examples/libevent",
110111
"tests/examples/libffi",
111112
"tests/examples/expat",
112113
"tests/examples/spirv-headers",

‎pkgs/c/compat.libevent.lua‎

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
-- libevent 2.1.13-stable: configure headers with upstream CMake, then compile
2+
-- core and extra sources with mcpp's C toolchain on Linux, macOS and Windows.
3+
package = {
4+
spec = "1",
5+
namespace = "compat",
6+
name = "libevent",
7+
description = "Libevent asynchronous event notification and networking library",
8+
licenses = {"BSD-3-Clause", "ISC", "MIT"},
9+
repo = "https://github.com/libevent/libevent",
10+
type = "package",
11+
12+
xpm = {
13+
linux = {
14+
deps = { "xim:cmake@latest" },
15+
["2.1.13"] = {
16+
url = "https://github.com/libevent/libevent/archive/refs/tags/release-2.1.13-stable.tar.gz",
17+
sha256 = "1a0885e17dc78afbaeddf13cf849f9238bbc24acdc178464a0d1934d7c5ffbd5",
18+
},
19+
},
20+
macosx = {
21+
deps = { "xim:cmake@latest" },
22+
["2.1.13"] = {
23+
url = "https://github.com/libevent/libevent/archive/refs/tags/release-2.1.13-stable.tar.gz",
24+
sha256 = "1a0885e17dc78afbaeddf13cf849f9238bbc24acdc178464a0d1934d7c5ffbd5",
25+
},
26+
},
27+
windows = {
28+
deps = { "xim:cmake@latest" },
29+
["2.1.13"] = {
30+
url = "https://github.com/libevent/libevent/archive/refs/tags/release-2.1.13-stable.tar.gz",
31+
sha256 = "1a0885e17dc78afbaeddf13cf849f9238bbc24acdc178464a0d1934d7c5ffbd5",
32+
},
33+
},
34+
},
35+
36+
mcpp = {
37+
language = "c++23",
38+
import_std = false,
39+
c_standard = "c11",
40+
include_dirs = { "*/include", "config/include", "*/compat", "*/WIN32-Code" },
41+
cflags = { "-DHAVE_CONFIG_H" },
42+
sources = {
43+
"*/buffer.c", "*/bufferevent.c", "*/bufferevent_filter.c",
44+
"*/bufferevent_pair.c", "*/bufferevent_ratelim.c",
45+
"*/bufferevent_sock.c", "*/event.c", "*/evmap.c",
46+
"*/evthread.c", "*/evutil.c", "*/evutil_rand.c",
47+
"*/evutil_time.c", "*/listener.c", "*/log.c",
48+
"*/signal.c", "*/strlcpy.c", "*/event_tagging.c",
49+
"*/http.c", "*/evdns.c", "*/evrpc.c",
50+
},
51+
targets = { ["event"] = { kind = "lib" } },
52+
deps = {},
53+
linux = {
54+
sources = { "*/select.c", "*/poll.c", "*/epoll.c", "*/evthread_pthread.c" },
55+
},
56+
macosx = {
57+
sources = { "*/select.c", "*/poll.c", "*/kqueue.c", "*/evthread_pthread.c" },
58+
},
59+
windows = {
60+
sources = { "*/buffer_iocp.c", "*/bufferevent_async.c", "*/event_iocp.c",
61+
"*/win32select.c", "*/evthread_win32.c" },
62+
cflags = { "-D_CRT_SECURE_NO_WARNINGS", "-D_CRT_NONSTDC_NO_DEPRECATE" },
63+
ldflags = { "-lws2_32", "-lshell32", "-ladvapi32", "-liphlpapi" },
64+
},
65+
},
66+
}
67+
68+
import("xim.libxpkg.pkginfo")
69+
import("xim.libxpkg.log")
70+
71+
local function quote(s)
72+
return '"' .. tostring(s):gsub('"', '\\"') .. '"'
73+
end
74+
75+
function install()
76+
local wrap = "libevent-release-" .. pkginfo.version() .. "-stable"
77+
if not os.isfile(path.join(wrap, "CMakeLists.txt")) then
78+
log.error("compat.libevent: expected %s/CMakeLists.txt", wrap)
79+
return false
80+
end
81+
local prefix = pkginfo.install_dir()
82+
os.tryrm(prefix)
83+
os.mkdir(prefix)
84+
local srcroot = path.join(prefix, wrap)
85+
os.mv(wrap, srcroot)
86+
87+
local pkg = pkginfo.build_dep("xim:cmake")
88+
local cmake
89+
if pkg then
90+
for _, candidate in ipairs({
91+
pkg.bin and path.join(pkg.bin, "cmake") or "",
92+
pkg.bin and path.join(pkg.bin, "cmake.exe") or "",
93+
pkg.path and path.join(pkg.path, "cmake.app/Contents/bin/cmake") or "",
94+
pkg.path and path.join(pkg.path, "CMake.app/Contents/bin/cmake") or "",
95+
}) do
96+
if os.isfile(candidate) then cmake = candidate; break end
97+
end
98+
end
99+
if not cmake then
100+
log.error("compat.libevent: xim:cmake executable not found")
101+
return false
102+
end
103+
local command = quote(cmake) .. " -S " .. quote(srcroot)
104+
.. " -B " .. quote(path.join(prefix, "config"))
105+
.. " -DCMAKE_POLICY_VERSION_MINIMUM=3.5"
106+
-- Probe the native platform with its system compiler, not a toolchain
107+
-- wrapper whose sysroot may differ from the generated headers' ABI.
108+
.. (os.host() == "windows" and "" or " -DCMAKE_C_COMPILER=/usr/bin/cc")
109+
.. " -DEVENT__DISABLE_OPENSSL=ON -DEVENT__DISABLE_MBEDTLS=ON"
110+
.. " -DEVENT__DISABLE_TESTS=ON -DEVENT__DISABLE_SAMPLES=ON"
111+
.. " -DEVENT__DISABLE_BENCHMARK=ON -DEVENT__LIBRARY_TYPE=STATIC"
112+
local logfile = path.join(prefix, "mcpp_cmake_configure.log")
113+
if os.host() == "windows" then
114+
-- Windows xlings does not reliably execute a quoted .exe directly.
115+
-- Drive it through cmd as compat.openssl does, and inspect its output.
116+
local bat = path.join(prefix, "mcpp_configure.bat")
117+
io.writefile(bat, "@echo off\r\n" .. command .. " > " .. quote(logfile)
118+
.. " 2>&1\r\nif errorlevel 1 exit /b 1\r\n")
119+
command = "cmd /c " .. quote(bat)
120+
end
121+
local ok, result = pcall(os.exec, command)
122+
if not ok or not result then
123+
log.error("compat.libevent: CMake configuration failed: %s; log: %s",
124+
tostring(result), os.isfile(logfile) and io.readfile(logfile) or "<not written>")
125+
return false
126+
end
127+
local generated = path.join(prefix, "config/include/event2/event-config.h")
128+
if not os.isfile(generated) then
129+
log.error("compat.libevent: CMake did not generate %s", generated)
130+
return false
131+
end
132+
return true
133+
end

‎tests/examples/libevent/mcpp.toml‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "libevent-tests"
3+
version = "0.1.0"
4+
5+
[dependencies.compat]
6+
libevent = "2.1.13"
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#ifdef _WIN32
2+
#include <winsock2.h>
3+
#endif
4+
5+
#include <event2/buffer.h>
6+
#include <event2/event.h>
7+
#include <event2/http.h>
8+
9+
#include <cstring>
10+
#include <cstdio>
11+
12+
static void fired(evutil_socket_t, short, void* arg) {
13+
++*static_cast<int*>(arg);
14+
}
15+
16+
int main() {
17+
#ifdef _WIN32
18+
WSADATA winsock;
19+
if (WSAStartup(MAKEWORD(2, 2), &winsock) != 0) return 1;
20+
#endif
21+
event_base* base = event_base_new();
22+
if (!base) {
23+
#ifdef _WIN32
24+
WSACleanup();
25+
#endif
26+
return 1;
27+
}
28+
int count = 0;
29+
timeval delay = {0, 0};
30+
const int scheduled = event_base_once(base, -1, EV_TIMEOUT, fired, &count, &delay);
31+
const int dispatched = scheduled == 0 ? event_base_loop(base, EVLOOP_ONCE) : -1;
32+
bool ok = scheduled == 0 && dispatched == 0 && count == 1;
33+
if (!ok) std::fprintf(stderr, "event loop: schedule=%d dispatch=%d count=%d\n", scheduled, dispatched, count);
34+
35+
evbuffer* buffer = evbuffer_new();
36+
if (!buffer) {
37+
event_base_free(base);
38+
#ifdef _WIN32
39+
WSACleanup();
40+
#endif
41+
return 1;
42+
}
43+
const char text[] = "libevent";
44+
char out[sizeof(text)] = {};
45+
const bool buffer_ok = evbuffer_add(buffer, text, sizeof(text) - 1) == 0
46+
&& evbuffer_remove(buffer, out, sizeof(text) - 1) == sizeof(text) - 1
47+
&& std::strcmp(out, text) == 0 && evbuffer_get_length(buffer) == 0;
48+
if (!buffer_ok) std::fprintf(stderr, "buffer round trip failed\n");
49+
ok = ok && buffer_ok;
50+
51+
evhttp* http = evhttp_new(base);
52+
ok = ok && http != nullptr;
53+
if (!http) std::fprintf(stderr, "evhttp_new failed\n");
54+
if (http) evhttp_free(http);
55+
evbuffer_free(buffer);
56+
event_base_free(base);
57+
#ifdef _WIN32
58+
WSACleanup();
59+
#endif
60+
return ok ? 0 : 1;
61+
}

0 commit comments

Comments
 (0)