CDLinux 是一个非常轻量级的、基于 BusyBox 和 UCI (Unified Configuration Interface) 框架的嵌入式 Linux 发行版,广泛应用于路由器、防火墙等网络设备中,在 CDLinux 上进行 C 语言开发,其核心目标是为嵌入式设备编写和编译程序。

这个过程与在桌面 Linux(如 Ubuntu)上开发有很大不同,主要体现在交叉编译上。
核心概念:交叉编译
由于 CDLinux 运行在资源受限的嵌入式设备上(如 MIPS、ARM 架构的 CPU),而我们通常在功能强大的 x86/x86_64 架构的 PC(宿主机 Host)上进行开发和编译,我们不能直接在 PC 上编译出能在 CDLinux 设备上运行的程序。
交叉编译 就是指在一个架构(如 x86)的计算机上,编译出另一个架构(如 ARM 或 MIPS)的可执行文件。
这个过程需要:

- 宿主机: 你的 PC,运行 Ubuntu 或其他 Linux 发行版。
- 交叉编译工具链: 一套特殊的编译器(如
arm-linux-gcc)、链接器、库文件等,它们知道如何为目标架构生成代码。 - 目标平台: CDLinux 设备运行的硬件平台(如 ARMv7, MIPSel)。
开发流程详解
以下是完整的开发步骤,从环境搭建到最终运行。
第 1 步:搭建宿主机开发环境
在你的 PC(Ubuntu 20.04)上安装必要的软件。
-
安装基本工具
sudo apt update sudo apt install -y build-essential git
build-essential包含了gcc,make,autoconf等基础编译工具。
(图片来源网络,侵删) -
安装交叉编译工具链 这是最关键的一步,你需要根据你的 CDLinux 设备的 CPU 架构选择正确的工具链。
-
针对 ARM 架构 (最常见):
# 以 32 位 ARMv7 为例 sudo apt install -y gcc-arm-linux-gnueabihf # 编译器命令是 arm-linux-gnueabihf-gcc
-
针对 MIPS 架构:
# 以 32 位小端 MIPS 为例 sudo apt install -y gcc-mips-linux-gnu # 编译器命令是 mips-linux-gnu-gcc
-
验证安装:
# 查看编译器版本,确认目标架构 arm-linux-gnueabihf-gcc -v # 输出中应该包含 "Target: arm-linux-gnueabihf"
-
第 2 步:创建你的第一个 C 程序
在你的 PC 上创建一个工作目录,并编写一个简单的 hello.c 文件。
mkdir cdlinux_dev
cd cdlinux_dev
# 创建 hello.c
cat > hello.c << EOF
#include <stdio.h>
int main() {
printf("Hello from CDLinux!\n");
return 0;
}
EOF
第 3 步:交叉编译程序
使用你刚刚安装的交叉编译器来编译 hello.c。
# 使用 ARM 交叉编译器 arm-linux-gnueabihf-gcc -o hello_arm hello.c # 使用 MIPS 交叉编译器 mips-linux-gnu-gcc -o hello_mips hello.c
-o hello_arm: 指定输出的可执行文件名为hello_arm。hello.c: 源文件。
编译成功后,你会在当前目录下看到两个可执行文件。注意: 这些文件是不能在你的 PC (x86架构) 上直接运行的。
# 尝试运行,会报错 ./hello_arm # bash: ./hello_arm: cannot execute binary file: Exec format error
第 4 步:将程序传输到 CDLinux 设备
你需要一种方式将编译好的 hello_arm 文件传输到你的 CDLinux 设备上,常用的方法有:
-
TFTP (最常用):
- 在宿主机上安装 TFTP 服务器:
sudo apt install tftpd-hpa # 创建一个共享目录,/tftpboot sudo mkdir -p /tftpboot sudo chmod 777 /tftpboot # 将你的可执行文件复制过去 cp hello_arm /tftpboot/
- 在 CDLinux 设备上使用
tftp命令下载:# 在 CDLinux 设备的命令行中执行 tftp -g -r hello_arm -l /tmp/hello_arm 192.168.1.100 # -g: get # -r: remote filename # -l: local filename # 192.168.1.100 是你宿主机的 IP 地址
- 在宿主机上安装 TFTP 服务器:
-
NFS (网络文件系统):
- 在宿主机上安装和配置 NFS 服务器,将工作目录共享出去。
- 在 CDLinux 设备上挂载这个共享目录,然后直接运行里面的程序。
-
U 盘/串口:
- 通过串口(如
minicom,screen)或 U 盘将文件拷贝到设备上。
- 通过串口(如
第 5 步:在 CDLinux 设备上运行程序
-
给程序添加可执行权限 (在 CDLinux 设备上):
chmod +x /tmp/hello_arm
-
运行程序:
/tmp/hello_arm
如果一切顺利,你将在 CDLinux 设备的终端上看到输出:
Hello from CDLinux!
高级主题:与 CDLinux 系统交互
在实际开发中,你的程序可能需要与 CDLinux 的核心组件(如 UCI 配置、网络等)交互。
使用 UCI 库
CDLinux 使用 UCI 来管理配置,如果你的程序需要读取或修改配置(如网络设置、无线等),你需要链接 UCI 库。
示例:读取 system.@system[0].hostname
宿主机上:
// uci_example.c
#include <stdio.h>
#include <uci.h>
#include <stdlib.h>
int main() {
struct uci_context *ctx;
struct uci_package *pkg;
struct uci_element *e;
struct uci_section *s;
ctx = uci_alloc_context();
if (!ctx) {
perror("Failed to allocate UCI context");
return 1;
}
if (uci_load(ctx, "system", &pkg) != UCI_OK) {
uci_perror(ctx, "Failed to load package 'system'");
uci_free_context(ctx);
return 1;
}
uci_foreach_element(&pkg->sections, e) {
s = uci_to_section(e);
if (strcmp(s->type, "system") == 0) {
struct uci_ptr ptr;
char *value;
// 构造一个指向特定选项的指针
snprintf(ptr.package, sizeof(ptr.package), "system");
ptr.section = s->e.name;
ptr.option = "hostname";
if (uci_lookup(ctx, &ptr) == UCI_OK) {
value = ptr.o->v.string;
printf("Hostname: %s\n", value ? value : "(not set)");
} else {
printf("Failed to lookup hostname.\n");
}
break;
}
}
uci_free_context(ctx);
return 0;
}
编译时需要链接 UCI 库:
# arm-linux-gnueabihf-gcc -o uci_example uci_example.c -luci
注意: 你需要确保 CDLinux 设备上安装了 libuci 库,并且你的程序在运行时有权限访问 /etc/config/ 目录。
使用 OpenWrt SDK
对于更复杂的项目,最佳实践是使用 OpenWrt SDK (Software Development Kit),CDLinux 是 OpenWrt 的一个分支,其 SDK 是一个完整的交叉编译环境,包含了所有库和头文件。
- 下载 SDK: 从 CDLinux 或 OpenWrt 的官方固件页面下载对应平台(如
arm_cortex-a9)的 SDK。 - 解压并配置环境: 解压 SDK 后,通常会提供一个
staging_dir目录和feeds.conf,你需要设置一些环境变量(如PATH,STAGING_DIR)。 - 使用 Makefile: 在你的项目根目录创建一个
Makefile,使用 SDK 提供的变量来编译你的程序,这是最规范和推荐的方式。
常见问题与调试
-
undefined reference to 'xxx': 链接错误,通常是因为缺少对应的库文件,使用-lxxx参数指定库。 -
Segmentation Fault: 最常见的错误,原因可能是:
- 目标设备缺少程序运行时依赖的共享库。
- 程序代码本身存在内存访问错误(如空指针、越界访问)。
-
如何查看依赖库? 在宿主机上,使用
file命令和readelf命令:file hello_arm # 输出: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, ... # 查看依赖的共享库 readelf -d hello_arm | grep NEEDED # 输出: 0x00000001 (NEEDED) Shared library: [libc.so.6]
你需要确保 CDLinux 设备上安装了这些库(如
libc.so.6)。
在 CDLinux 上进行 C 语言开发,核心是交叉编译,流程可以概括为:
- 宿主机准备: 安装基础工具和交叉编译器。
- 编写代码: 在宿主机上编写 C 语言源码。
- 交叉编译: 使用目标平台的编译器(如
arm-linux-gcc)生成可执行文件。 - 传输文件: 通过 TFTP/NFS 等方式将可执行文件拷贝到 CDLinux 设备。
- 设备运行: 在设备上赋予执行权限并运行程序。
- 交互与调试: 学习使用 UCI 等 CDLinux 特有接口,并通过工具分析依赖和错误。
对于大型项目,强烈建议学习和使用 OpenWrt SDK,它能极大地简化开发和依赖管理。
