土法炼钢兴趣小组的算法知识备份

多构建工具链集成 (Build Systems)

目录

在上一篇 环境搭建与 Hello World 中,我们使用 gcc 命令行编译了 Echo Server。但在实际工程中,我们通常使用构建系统来管理依赖和编译流程。

本篇将介绍如何在三种主流构建系统中集成 Libevent:Makefile (传统)、CMake (现代 C++ 标准) 和 Bazel (Google 风格大仓)。

1. Makefile (传统方式)

对于小型 C 项目,Makefile 依然是简单高效的选择。为了避免硬编码路径(如 /usr/local/include),推荐使用 pkg-config 工具。

1.1. 检查 pkg-config

安装 Libevent 后,它通常会提供 .pc 文件。检查是否能被识别:

pkg-config --cflags --libs libevent
# 输出示例: -I/usr/local/include -L/usr/local/lib -levent

1.2. 编写 Makefile

CC = gcc
CFLAGS = -g -Wall $(shell pkg-config --cflags libevent)
LDFLAGS = $(shell pkg-config --libs libevent)

TARGET = echo_server
SRCS = echo_server.c
OBJS = $(SRCS:.c=.o)

all: $(TARGET)

$(TARGET): $(OBJS)
    $(CC) -o $@ $^ $(LDFLAGS)

%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@

clean:
    rm -f $(OBJS) $(TARGET)

.PHONY: all clean

这样,无论 Libevent 安装在 /usr 还是 /usr/localpkg-config 都会自动填充正确的路径。

2. CMake (现代 C++ 标配)

CMake 是目前 C/C++ 开源项目的事实标准。集成 Libevent 主要有两种方式:系统预装查找 (find_package) 和 源码自动下载 (FetchContent)。

2.1. 方式一:find_package (依赖系统库)

这种方式要求运行环境已经安装了 Libevent(通过 apt 或源码安装)。

CMakeLists.txt:

cmake_minimum_required(VERSION 3.10)
project(LibeventDemo C)

# 查找 Libevent 包
find_package(Libevent CONFIG REQUIRED)

add_executable(echo_server echo_server.c)

# 链接 Libevent::core 和 Libevent::extra
# 注意:Libevent 的 CMake 配置通常导出为 Libevent::Libevent 或 Libevent::core
if(TARGET Libevent::core)
    target_link_libraries(echo_server PRIVATE Libevent::core)
else()
    # 兼容旧版本或非标准安装
    include_directories(${LIBEVENT_INCLUDE_DIRS})
    target_link_libraries(echo_server PRIVATE ${LIBEVENT_LIBRARIES})
endif()

提示: 如果 CMake 报错找不到,可以尝试使用 PkgConfig 模块作为回退方案。

2.2. 方式二:FetchContent (源码集成)

这种方式无需预先安装 Libevent,CMake 会在构建时自动下载源码并编译。适合追求环境一致性的项目。

CMakeLists.txt:

cmake_minimum_required(VERSION 3.14)
project(LibeventDemo C)

include(FetchContent)

# 定义下载源
FetchContent_Declare(
  libevent
  URL https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz
)

# 禁用 Libevent 的测试和示例,加快构建
set(EVENT__DISABLE_OPENSSL ON CACHE BOOL "" FORCE)
set(EVENT__DISABLE_BENCHMARK ON CACHE BOOL "" FORCE)
set(EVENT__DISABLE_TESTS ON CACHE BOOL "" FORCE)
set(EVENT__DISABLE_SAMPLES ON CACHE BOOL "" FORCE)

# 下载并引入
FetchContent_MakeAvailable(libevent)

add_executable(echo_server echo_server.c)
# 链接 FetchContent 引入的目标
target_link_libraries(echo_server PRIVATE event_core event_extra)

3. Bazel (大仓构建实践)

Bazel 是 Google 开源的构建系统,擅长处理多语言、大规模依赖。

3.1. WORKSPACE 配置

在项目根目录的 WORKSPACE 文件中定义外部依赖:

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
    name = "com_github_libevent_libevent",
    urls = ["https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz"],
    strip_prefix = "libevent-2.1.12-stable",
    build_file = "//third_party:libevent.BUILD", # 我们需要自己写 BUILD 文件
)

3.2. 编写 BUILD 文件适配

由于 Libevent 官方源码包没有自带 Bazel 支持,我们需要在 third_party/libevent.BUILD 中描述如何编译它(这通常是最麻烦的一步,因为涉及 config.h 的生成)。

一个简化的 libevent.BUILD 示例(仅供参考,实际可能需要运行 configure 生成头文件):

cc_library(
    name = "libevent",
    srcs = glob([
        "*.c",
        "*.h",
        "compat/*.h",
        "include/*.h",
    ], exclude = [
        "test/**",
        "sample/**",
        "win32/**",
    ]),
    hdrs = glob(["include/event2/*.h"]),
    includes = ["include"],
    copts = [
        "-DHAVE_CONFIG_H",
        "-Iexternal/com_github_libevent_libevent/include",
    ],
    visibility = ["//visibility:public"],
)

: 生产环境通常会先在 Docker 中运行 ./configure 生成好 config.h,然后将其作为 patch 打入 Bazel 构建中,或者使用 rules_foreign_cc 规则集来调用 make

使用 rules_foreign_cc (推荐):

load("@rules_foreign_cc//foreign_cc:defs.bzl", "configure_make")

configure_make(
    name = "libevent",
    lib_source = "@com_github_libevent_libevent//:all_srcs",
    out_static_libs = ["libevent.a"],
    configure_options = [
        "--disable-openssl",
        "--disable-samples",
    ],
)

3.3. 项目 BUILD 文件

cc_binary(
    name = "echo_server",
    srcs = ["echo_server.c"],
    deps = ["@com_github_libevent_libevent//:libevent"],
)

4. 总结

掌握了构建系统的集成,我们就可以在复杂的工程中自如地使用 Libevent 了。下一篇,我们将深入 Libevent 的核心,剖析 event_base 和事件循环的内部机制。


上一篇: 00-intro/env-setup.md - 环境搭建与 Hello World 下一篇: 01-core/event-base-loop.md - Event Base 与 Event Loop

返回 Libevent 专题索引


By .