Ubuntu 16.04虚拟机下含内核头文件的GCC代码/Makefile编译求助
嘿,我来帮你搞定这个编译的问题!首先得先给你提个关键的点:你写的代码里直接访问dev_base这种内核空间的结构体和符号,在用户态程序里是没法正常运行的——毕竟内核空间和用户态是完全隔离的,用户态程序不能直接碰内核的内部数据结构和符号。不过我先告诉你怎么编译这类引用内核头文件的代码,再给你指条正确的用户态获取网卡信息的路子~
一、直接用GCC编译的指令
如果只是想先把代码编译通过(虽然运行会报错),你需要指定内核头文件的搜索路径。Ubuntu 16.04的内核头文件一般在/usr/src/linux-headers-$(uname -r)目录下,直接用这条指令编译:
gcc -o net_info net_info.c -I/usr/src/linux-headers-$(uname -r)/include -I/usr/src/linux-headers-$(uname -r)/arch/x86/include
简单解释下参数:
-I:用来告诉GCC额外的头文件搜索路径,因为内核头文件不在默认的搜索列表里net_info.c是你的源代码文件名,net_info是编译后生成的可执行文件名称,你可以根据自己的需求修改
二、编写Makefile来自动化编译
如果不想每次都敲长指令,写个Makefile会方便很多。创建一个名为Makefile的文件,把下面的内容粘进去:
# 自动获取当前系统的内核头文件路径 KERNEL_HEADERS := /usr/src/linux-headers-$(shell uname -r) # 定义可执行文件和源文件的名称 TARGET := net_info SRC := net_info.c # 编译选项,指定内核头文件的搜索路径 CFLAGS := -I$(KERNEL_HEADERS)/include -I$(KERNEL_HEADERS)/arch/x86/include # 默认执行的编译目标 all: $(TARGET) # 编译规则:从源文件生成可执行文件 $(TARGET): $(SRC) gcc $(CFLAGS) -o $@ $< # 清理生成的可执行文件 clean: rm -f $(TARGET)
之后在终端里进入代码所在目录,敲make就能自动编译,敲make clean可以删掉生成的可执行文件。
三、重要提示:用户态获取网卡信息的正确姿势
刚才说了,你原来的代码在用户态跑不起来,因为dev_base是内核内部的符号,用户态程序根本访问不到。这里给你一个能用的示例代码,用标准的用户态API getifaddrs()来获取网卡名称和IP地址:
#include <stdio.h> #include <stdlib.h> #include <ifaddrs.h> #include <netinet/in.h> #include <arpa/inet.h> int main() { struct ifaddrs *ifap, *ifa; struct sockaddr_in *sa; char addr[INET_ADDRSTRLEN]; // 获取所有网卡信息 if (getifaddrs(&ifap) == -1) { perror("getifaddrs"); exit(EXIT_FAILURE); } // 遍历每个网卡 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr == NULL) continue; // 只处理IPv4地址(如果需要IPv6可以加AF_INET6的判断) if (ifa->ifa_addr->sa_family == AF_INET) { sa = (struct sockaddr_in *)ifa->ifa_addr; inet_ntop(AF_INET, &sa->sin_addr, addr, INET_ADDRSTRLEN); printf("dev name: %s\nIP address: %s\n\n", ifa->ifa_name, addr); } } // 释放资源 freeifaddrs(ifap); return 0; }
这个代码就很省心了,直接用普通GCC指令编译就行:
gcc -o net_info net_info.c
运行./net_info就能看到所有网卡的名称和对应的IP地址啦~
内容的提问来源于stack exchange,提问作者user9692088
相关产品推荐
相关产品推荐

