【鸿蒙 PC 命令行适配】c-ares 在鸿蒙 PC 上的移植与交叉编译实战(可复现指南)

文章目录

【鸿蒙 PC 命令行适配】c-ares 在鸿蒙 PC 上的移植与交叉编译实战(可复现指南)

前言

在网络型应用中,DNS 解析 是一个绕不开的基础能力。虽然系统通常提供同步的 getaddrinfo() 接口,但在高并发、事件驱动或网络库内部,阻塞式 DNS 往往成为性能瓶颈。

c-ares 是一个由 Google 维护的、成熟稳定的 异步 DNS 解析库 ,被广泛用于 curl、Node.js、libuv 等核心项目。它采用纯 C 实现、系统依赖极少,非常适合作为 鸿蒙 PC 层的基础网络库

本文将基于 OHOS SDK + Clang/LLVM ,完整演示 c-ares 在鸿蒙 PC(AArch64)上的交叉编译、部署与真机验证流程,所有步骤均可直接复现。


一、OHOS SDK

OHOS SDK之前的文章也有写过,大体步骤如下

官方下载地址:

bash 复制代码
https://ci.openharmony.cn/workbench/cicd/dailybuild/dailylist

下载完成后,通常得到一个类似如下名称的压缩包:

ohos-sdk-full_linux_xxx.tar.gz

解压 OHOS SDK

将下载好的 SDK 压缩包解压到一个固定目录(建议统一放在 /opt 或 $HOME 下,便于长期维护):

bash 复制代码
tar -xzf ohos-sdk-full_linux_xxx.tar.gz

解压完成后,会得到顶层目录:

bash 复制代码
ohos-sdk/

进入 ohos-sdk/linux 目录,可以看到多个子组件,其中交叉编译只需要关注以下目录:

接下来分别解压这两个子包(如果它们仍是压缩文件):

bash 复制代码
cd ohos-sdk/linux
tar -xzf native*.tar.gz
tar -xzf toolchains*.tar.gz

其中:

llvm包含 Clang、LLVM、lld、llvm-ar 等交叉编译工具

二、前置环境

已经完成以下准备:

  • 已安装 OHOS SDK
  • 已配置 Clang/LLVM 工具链
  • 开发机为 Linux x86_64

关键环境变量如下:

bash 复制代码
export OHOS_SDK=/opt/ohos-sdk/linux/native
export PATH=$OHOS_SDK/llvm/bin:$PATH
export SYSROOT=$OHOS_SDK/sysroot

验证:

bash 复制代码
clang --version

确认输出来自 OHOS SDK。


三、下载 c-ares 源码

c-ares 官方仓库:

text 复制代码
https://github.com/c-ares/c-ares

这里使用稳定版本 1.19.x

bash 复制代码
wget https://github.com/c-ares/c-ares/releases/download/cares-1_19_1/c-ares-1.19.1.tar.gz
tar -xzf c-ares-1.19.1.tar.gz
cd c-ares-1.19.1

目录结构:

四、配置交叉编译环境(核心步骤)

c-ares 使用 CMake,推荐独立构建目录

bash 复制代码
mkdir build-ohos
cd build-ohos

4.1 CMake 交叉编译参数

bash 复制代码
cmake .. \
  -DCMAKE_SYSTEM_NAME=Linux \
  -DCMAKE_C_COMPILER=clang \
  -DCMAKE_C_FLAGS="--target=aarch64-linux-ohos --sysroot=$SYSROOT" \
  -DCARES_STATIC=ON \
  -DCARES_SHARED=OFF \
  -DCARES_BUILD_TESTS=OFF \
  -DCMAKE_INSTALL_PREFIX=$(pwd)/install

参数说明:

参数 说明
CMAKE_SYSTEM_NAME=Linux 鸿蒙 PC 在 ABI 层与 Linux 兼容
CARES_STATIC=ON 优先验证静态库
CARES_SHARED=OFF 避免动态库部署干扰
CARES_BUILD_TESTS=OFF 交叉编译不跑测试

五、编译与安装

bash 复制代码
make -j$(nproc)
make install


安装完成后得到:

text 复制代码
install/
├── include/ares.h
├── include/ares_version.h
└── lib/libcares.a

这说明:

  • c-ares 已成功生成 AArch64 鸿蒙 ELF 静态库
  • 头文件与符号导出正常

六、部署到鸿蒙 PC

将目录拷贝到鸿蒙 PC:

七、真机验证(关键)

7.1 测试程序(DNS 查询)

在鸿蒙 PC 上创建测试文件 test_ares.c

c 复制代码
#include <stdio.h>
#include <ares.h>

void callback(void *arg, int status, int timeouts, struct ares_addrinfo *res) {
    if (status == ARES_SUCCESS && res) {
        printf("DNS resolve success\n");
        ares_freeaddrinfo(res);
    } else {
        printf("DNS resolve failed\n");
    }
}

int main() {
    ares_library_init(ARES_LIB_INIT_ALL);

    ares_channel channel;
    if (ares_init(&channel) != ARES_SUCCESS) {
        printf("ares_init failed\n");
        return 1;
    }

    struct ares_addrinfo_hints hints = {0};
    hints.ai_family = AF_INET;

    ares_getaddrinfo(channel, "www.example.com", NULL, &hints, callback, NULL);

    for (;;) {
        fd_set r, w;
        int nfds;
        struct timeval tv;

        FD_ZERO(&r);
        FD_ZERO(&w);
        nfds = ares_fds(channel, &r, &w);
        if (nfds == 0) break;

        ares_timeout(channel, NULL, &tv);
        select(nfds, &r, &w, NULL, &tv);
        ares_process(channel, &r, &w);
    }

    ares_destroy(channel);
    ares_library_cleanup();
    return 0;
}

说明:

这里使用 select + ares_process,这是 c-ares 最标准、最可移植的用法。


7.2 编译链接(鸿蒙 PC)

bash 复制代码
clang test_ares.c -I$(pwd)/include $(pwd)/lib/libcares.a -o test_ares

运行:

bash 复制代码
./test_ares

输出示例:

text 复制代码
DNS resolve success

此时证明:

c-ares 静态库正常工作

libcares.a 已经可以在鸿蒙 PC 上被正确链接和调用。

DNS 查询功能正常

ares_getaddrinfo 能够正确向系统 DNS 解析服务器发送请求,并成功返回 IP 地址信息。

输出 DNS resolve success 表示解析 "www.baidu.com" 成功。

交叉编译环境配置正确

用 AArch64 交叉编译生成的静态库,在鸿蒙 PC 的 Linux ABI 层能正确运行,没有出现符号缺失或运行错误。

基础网络调用可用

说明鸿蒙 PC 上的网络栈、select/select-based 事件处理等都可用,c-ares 可以正常工作。

可以写一个更加完善的代码。

bash 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ares.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/select.h>

struct query {
    const char *hostname;
    int done;
};

void query_callback(void *arg, int status, int timeouts, struct ares_addrinfo *res) {
    struct query *q = (struct query *)arg;
    q->done = 1; // 标记查询完成

    if (status == ARES_SUCCESS && res) {
        printf("[%s] DNS resolve success:\n", q->hostname);

        for (struct ares_addrinfo_node *node = res->nodes; node; node = node->ai_next) {
            char ip[INET6_ADDRSTRLEN];
            if (node->ai_family == AF_INET) {
                struct sockaddr_in *sa = (struct sockaddr_in *)node->ai_addr;
                inet_ntop(AF_INET, &sa->sin_addr, ip, sizeof(ip));
                printf("  IPv4: %s\n", ip);
            } else if (node->ai_family == AF_INET6) {
                struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)node->ai_addr;
                inet_ntop(AF_INET6, &sa6->sin6_addr, ip, sizeof(ip));
                printf("  IPv6: %s\n", ip);
            }
        }

        ares_freeaddrinfo(res);
    } else {
        printf("[%s] DNS resolve failed (status=%d)\n", q->hostname, status);
    }
}

int main() {
    ares_library_init(ARES_LIB_INIT_ALL);

    ares_channel channel;
    if (ares_init(&channel) != ARES_SUCCESS) {
        fprintf(stderr, "ares_init failed\n");
        return 1;
    }

    const char *hosts[] = {
        "www.baidu.com",
        "www.bing.com",
        "www.csdn.net"
    };
    const int n_hosts = sizeof(hosts)/sizeof(hosts[0]);

    struct query queries[n_hosts];
    memset(queries, 0, sizeof(queries));

    // 初始化查询
    for (int i = 0; i < n_hosts; ++i) {
        queries[i].hostname = hosts[i];
        queries[i].done = 0;

        struct ares_addrinfo_hints hints;
        memset(&hints, 0, sizeof(hints));
        hints.ai_family = AF_UNSPEC; // IPv4 + IPv6

        ares_getaddrinfo(channel, hosts[i], NULL, &hints, query_callback, &queries[i]);
    }

    // 事件循环
    int unfinished;
    do {
        fd_set read_fds, write_fds;
        FD_ZERO(&read_fds);
        FD_ZERO(&write_fds);

        int nfds = ares_fds(channel, &read_fds, &write_fds);
        if (nfds == 0) break;

        struct timeval tv;
        struct timeval *tvp = ares_timeout(channel, NULL, &tv);

        select(nfds, &read_fds, &write_fds, NULL, tvp);

        ares_process(channel, &read_fds, &write_fds);

        // 检查是否所有查询完成
        unfinished = 0;
        for (int i = 0; i < n_hosts; ++i) {
            if (!queries[i].done) {
                unfinished = 1;
                break;
            }
        }
    } while (unfinished);

    ares_destroy(channel);
    ares_library_cleanup();

    return 0;
}

命令:

bash 复制代码
clang test_ares_multi.c \
  -I$(pwd)/include \
  $(pwd)/lib/libcares.a \
  -o test_ares_multi

运行

bash 复制代码
./test_ares_multi

支持 IPv4 + IPv6

可同时查询多个域名

使用标准 C 回调,无需 Lambda 或 C++

结论:

c-ares AArch64 静态库在鸿蒙 PC 已经 可用

可以继续开发使用 c-ares 的应用,例如异步 DNS 查询、HTTP 客户端、网络工具等

八、适配过程中的经验总结

在鸿蒙 PC 上移植 c-ares 的过程中,最大的感受是 系统的开发环境非常友好。OHOS SDK 提供了完整的 AArch64 交叉编译工具链和清晰的 sysroot 配置,使得从源码到静态库的构建几乎零障碍。即便是网络库这样涉及底层系统调用和事件处理的组件,也能顺利编译、链接并在真机上运行。鸿蒙 PC 的 Linux ABI 兼容性出色,使得 select、poll 等标准接口无需额外适配即可使用,同时静态库部署简单,调试效率高,整体开发体验非常顺畅。

九、总结

通过本次 c-ares 的移植与验证实践,可以看出 鸿蒙 PC 的平台生态已经非常成熟且高效。无论是交叉编译工具链、系统兼容性,还是运行时的网络栈和事件机制,都表现出企业级开发所需的稳定性和可靠性。开发者可以放心地在鸿蒙 PC 上构建高性能网络应用,享受到极佳的开发体验,同时充分利用 AArch64 架构优势,实现跨平台、高效、安全的网络服务。鸿蒙 PC 不仅降低了移植门槛,也为网络库和系统组件的创新提供了坚实的基础。

欢迎加入开源鸿蒙PC社区:https://harmonypc.csdn.net/

相关推荐
摘星编程2 小时前
React Native鸿蒙版:forwardRef组件引用转发
react native·react.js·harmonyos
俺不理解2 小时前
鸿蒙 Stage Arkts HSP+HAR 的集成
华为·harmonyos·模块化·har·hsp
小雨青年2 小时前
鸿蒙 HarmonyOS 6 | AI Kit 集成 CANN Kit 异构计算服务
人工智能·华为·harmonyos
代码无bug抓狂人2 小时前
(蓝桥杯省B)R格式
c语言·蓝桥杯
养军博客2 小时前
C语言五天速成(可用于蓝桥杯备考)
c语言·数据结构·算法
Yupureki2 小时前
《算法竞赛从入门到国奖》算法基础:搜索-BFS初识
c语言·数据结构·c++·算法·visual studio·宽度优先
前端不太难2 小时前
HarmonyOS 游戏卡顿,问题不在渲染
华为·状态模式·harmonyos
讯方洋哥2 小时前
HarmonyOS App开发——一多图片浏览器应用App开发
华为·harmonyos
叫我辉哥e110 小时前
### 技术文章大纲:C语言造轮子大赛
c语言·开发语言