核心概念:为什么用 Jenkins 管理C语言项目?
对于 C 语言项目,手动编译、测试和发布流程不仅耗时,而且容易出错,Jenkins 可以自动化这一切:

- 自动化构建:每次代码提交到代码仓库(如 Git),Jenkins 就能自动拉取最新代码并编译。
- 自动化测试:在构建成功后,自动运行单元测试、集成测试,确保代码质量。
- 快速反馈:如果构建或测试失败,Jenkins 会立即通知开发者,帮助快速定位问题。
- 版本管理:可以自动为每次成功的构建创建一个可部署的软件包(如
.deb或.zip),并记录版本号。 - 标准化环境:确保所有构建和测试都在一个干净、一致的环境中运行,避免“在我电脑上能跑”的问题。
环境准备
在开始之前,你需要准备以下环境:
1 Jenkins 服务器
- 安装 Jenkins,你可以使用 Docker、直接在 Linux 上安装,或者使用 Jenkins 的官方镜像。
- 确保你的 Jenkins 服务器上安装了必要的工具,这些工具将在 Jenkins Job 中使用:
- Git: 用于拉取代码。
- Make / CMake: 用于构建 C/C++ 项目,我们将以
Make为例。 - GCC / Clang: C 语言编译器。
- GDB (可选): 调试工具。
- Valgrind (可选): 内存错误检测工具。
- Gcov / Lcov (可选): 代码覆盖率工具。
- Doxygen (可选): 文档生成工具。
在 Jenkins 服务器上安装这些工具的命令(以 Ubuntu 为例):
sudo apt-get update sudo apt-get install -y git make gcc gdb valgrind lcov doxygen
2 代码仓库
- 创建一个 Git 仓库(例如在 GitHub, GitLab, Gitee 上),并上传一个简单的 C 语言项目作为示例。
3 示例 C 语言项目
我们创建一个简单的计算器项目,包含一个源文件 calculator.c,一个头文件 calculator.h,一个测试文件 test_calculator.c,以及一个 Makefile。
项目结构:

my-c-project/
├── src/
│ ├── calculator.c
│ └── calculator.h
├── tests/
│ └── test_calculator.c
├── Makefile
└── README.md
src/calculator.h
#ifndef CALCULATOR_H #define CALCULATOR_H int add(int a, int b); int subtract(int a, int b); #endif // CALCULATOR_H
src/calculator.c
#include "calculator.h"
int add(int a, int b) {
return a + b;
}
int subtract(int a, int b) {
return a - b;
}
tests/test_calculator.c
#include <stdio.h>
#include <assert.h>
#include "calculator.h"
void test_add() {
assert(add(1, 2) == 3);
assert(add(-1, 5) == 4);
printf("test_add passed!\n");
}
void test_subtract() {
assert(subtract(5, 3) == 2);
assert(subtract(2, 5) == -3);
printf("test_subtract passed!\n");
}
int main() {
test_add();
test_subtract();
printf("All tests passed successfully!\n");
return 0;
}
Makefile

# Compiler
CC = gcc
CFLAGS = -Wall -Wextra -g
# Directories
SRC_DIR = src
TEST_DIR = tests
BUILD_DIR = build
# Source and object files
SRC_FILES = $(wildcard $(SRC_DIR)/*.c)
OBJ_FILES = $(SRC_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)
TEST_FILE = $(TEST_DIR)/test_calculator.c
TEST_EXEC = $(BUILD_DIR)/test_calculator
# Default target
all: $(TEST_EXEC)
# Rule to compile source files into object files
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c | $(BUILD_DIR)
$(CC) $(CFLAGS) -c $< -o $@
# Rule to link object files into the test executable
$(TEST_EXEC): $(OBJ_FILES) | $(BUILD_DIR)
$(CC) $(CFLAGS) $^ -o $@
# Rule to create the build directory
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
# Rule to run tests
test: $(TEST_EXEC)
./$(TEST_EXEC)
# Rule to clean build artifacts
clean:
rm -rf $(BUILD_DIR)
.PHONY: all test clean
在 Jenkins 中创建流水线
我们将使用 Jenkins 的声明式流水线 来自动化我们的项目。
1 安装必要插件
在 Jenkins 管理界面,进入 Manage Jenkins -> Manage Plugins -> Available,安装以下插件:
- Git Plugin: 用于与 Git 仓库交互。
- Pipeline Utility Steps: 提供一些有用的步骤,如
readJSON。 - HTML Publisher Plugin: 用于发布测试报告(可选)。
2 创建 Jenkins Item
- 在 Jenkins 首页,点击
New Item。 - 输入一个名称(
c-project-pipeline),选择Pipeline,然后点击OK。 - 在配置页面,滚动到 Pipeline 部分。
3 编写 Jenkinsfile
在 Pipeline 部分,选择 Pipeline script from SCM。
- SCM: 选择
Git。 - Repository URL: 填写你的 Git 仓库地址。
- Credentials: 如果你的仓库是私有的,添加你的 Git 凭据。
- Branch Specifier:
*/main或*/master。
在 Script Path 字段中,输入 Jenkinsfile,我们将在项目的根目录下创建这个文件。
Jenkinsfile (声明式流水线)
pipeline {
// 定义 Agent(执行环境)。'any' 表示在任何可用的 Jenkins agent 上运行。
agent any
// 定义环境变量,可以在整个流水线中使用。
environment {
// 定义项目名称,方便构建产物命名
PROJECT_NAME = "my-c-project"
// 定义构建输出的目录
BUILD_DIR = "build"
}
// 定义流水线的阶段
stages {
// 1. 拉取代码
stage('Checkout') {
steps {
script {
// 清理工作区,确保每次都是最新的代码
cleanWs()
// 从 SCM 拉取代码
checkout scm
}
echo '代码已成功拉取到 Jenkins 工作区。'
}
}
// 2. 编译项目
stage('Build') {
steps {
echo '开始编译项目...'
// 执行 make all 命令
sh 'make all'
echo '项目编译成功!'
// (可选) 显示编译出的可执行文件
sh "ls -l ${BUILD_DIR}/"
}
}
// 3. 运行单元测试
stage('Test') {
steps {
echo '开始运行单元测试...'
// 执行 make test 命令
sh 'make test'
echo '单元测试完成!'
// (可选) 运行 Valgrind 进行内存检查
echo '开始运行 Valgrind 内存检查...'
sh "valgrind --leak-check=full --show-leak-kinds=all --verbose ${BUILD_DIR}/test_calculator"
echo 'Valgrind 内存检查完成!'
}
}
// 4. (可选) 代码覆盖率分析
stage('Coverage') {
steps {
echo '开始生成代码覆盖率报告...'
// 修改 Makefile 以生成覆盖率信息,或者直接使用 gcov
// 这里我们假设 Makefile 已经配置好,可以生成 gcov 文件
sh 'make coverage'
echo '覆盖率报告生成完毕。'
// (可选) 使用 Lcov 生成 HTML 报告并发布
// publishHTML([
// allowMissing: false,
// alwaysLinkToLastBuild: true,
// keepAll: true,
// reportDir: 'coverage',
// reportFiles: 'index.html',
// reportName: 'Code Coverage Report'
// ])
}
}
// 5. (可选) 构建软件包
stage('Package') {
steps {
echo '开始构建软件包...'
// 这里可以创建一个 .tar.gz 或 .deb 文件
// sh 'tar -czf ${PROJECT_NAME}-${BUILD_ID}.tar.gz src/ Makefile'
// 或者使用 `dpkg-deb` 来创建 .deb 包
def package_name = "${PROJECT_NAME}-${env.BUILD_ID}.tar.gz"
sh "tar -czf ${package_name} src/ tests/ Makefile"
echo "软件包 ${package_name} 创建成功!"
// 将构建产物归档,以便后续下载
archiveArtifacts artifacts: "${package_name}", fingerprint: true
}
}
}
// 定义后置操作,无论成功或失败都会执行
post {
// 成功时执行
success {
echo '流水线执行成功!'
// 可以在这里发送成功通知,例如邮件、Slack等
}
// 失败时执行
failure {
echo '流水线执行失败!'
// 可以在这里发送失败通知
}
// 总是执行,例如清理工作区
always {
echo '流水线执行完毕,正在清理工作区...'
// cleanWs() // 如果需要,可以取消注释
}
}
}
运行和解释
- 保存 Jenkins Item 的配置。
- 回到项目首页,点击 "Build Now"。
Jenkins 会开始执行你的流水线,你可以在 "Console Output" 中查看详细的执行日志。
流水线解释:
agent any: Jenkins 会在任何一个可用的节点上执行这个任务。environment { ... }: 定义了PROJECT_NAME和BUILD_DIR,这样在后续步骤中可以直接使用${PROJECT_NAME}和${BUILD_DIR},方便维护。stages { ... }: 流水线的核心,包含多个stage。Checkout: 使用checkout scm语句,这是 Jenkins Pipeline 插件提供的标准方式,它会自动从配置的 SCM 仓库拉取代码。Build: 使用sh 'make all'执行编译。sh步骤用于在 shell 中执行命令。Test: 使用sh 'make test'运行我们编写的测试用例,我们集成了valgrind来检查内存泄漏。Coverage: 这是一个可选的高级步骤,用于衡量测试覆盖了多少代码,你需要修改Makefile来支持生成.gcov文件,然后使用lcov工具将其转换为 HTML 报告。Package: 将构建产物(源码、Makefile等)打包成一个.tar.gz文件,并使用archiveArtifacts将其保存到 Jenkins 服务器,方便下载。
post { ... }: 定义了流水线结束后的操作。success/failure: 可以在这里集成通知系统,比如当构建失败时通过邮件或 Slack 通知开发人员。always: 无论成功失败都会执行,通常用于清理工作区cleanWs()。
进阶与最佳实践
1 使用 Docker 确保环境一致性
为了避免 "在我电脑上能跑" 的问题,最佳实践是使用 Docker,你可以创建一个 Dockerfile 来定义一个纯净的构建环境。
Dockerfile
FROM ubuntu:22.04
# 安装构建和测试所需的工具
RUN apt-get update && apt-get install -y \
git \
make \
gcc \
gdb \
valgrind \
lcov \
doxygen \
&& rm -rf /var/lib/apt/lists/*
# 设置工作目录
WORKDIR /workspace
# 默认命令
CMD ["/bin/bash"]
然后修改你的 Jenkinsfile,使其在 Docker 容器中运行:
pipeline {
agent {
dockerfile {
filename 'Dockerfile'
dir '.' // Dockerfile 所在的目录
}
}
stages {
// ... (其他阶段保持不变)
}
}
这样,Jenkins 会自动构建这个 Docker 镜像,并在容器中执行你的整个流水线,确保了环境的一致性。
2 代码质量分析 (静态分析)
集成像 Cppcheck 或 Clang Static Analyzer 这样的静态分析工具,可以在不运行代码的情况下发现潜在的错误。
在 Makefile 中添加一个 check target:
# ... (其他内容)
check:
cppcheck --enable=all --suppress=missingIncludeSystem src/
.PHONY: all test clean check
然后在 Jenkinsfile 的 Test 阶段之前添加一个新的 Static Analysis 阶段:
stage('Static Analysis') {
steps {
echo '开始进行静态代码分析...'
sh 'make check'
echo '静态代码分析完成。'
}
}
3 部署
部署阶段通常与你的目标环境相关。
- 部署到服务器: 使用
ssh步骤插件将编译好的二进制文件或软件包复制到远程服务器。 - 部署到 Docker 镜像: 在
Package阶段构建一个包含你应用的 Docker 镜像,并推送到镜像仓库(如 Docker Hub, Harbor)。
通过以上步骤,你就拥有了一个功能完善的、用于 C 语言的 Jenkins 持续集成/持续交付流水线,它可以极大地提高开发效率和软件质量。
