Linux kernel 在 Git 目录和 SVN 目录编译行为不一致的解决方法

近期把开发从 SVN 迁移到了 Git 上。其实一早就遇到一个问题,那就是 Linux kernel 在 SVN 的版本控制下编译得好好的,但是换成 Git 做版本控制之后,即便是完全一模一样的两套目录树,编译出来就是不一样!

我晕,Linux 编译结果还跟版本控制环境有关?查了资料,还真是有关……

本文地址:https://segmentfault.com/a/1190000007226913

Reference

Linux内核模块加载时的版本检查
修改utsrelease.h 文件里面的版本号后
向linux内核版本号添加字符/为何有时会自动添加“+”号
关于CONFIG_LOCALVERSION_AUTO设置去掉内核版本号SVN后缀
去掉SVN管理kernel编译后版本自动变化
非开源的驱动程序如何绕过version magic的检查
繞過linux Driver Vermagic檢查

主要知识点归纳

内核基础版本号

Linux 内核在编译时,在根目录的 Makefile 最开头有几个宏,决定了编译出来的 Linux 基本版本号。
我用的内核版本比较老,是这样的:

VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 36
EXTRAVERSION =
...

而内核代码在获得这个基本版本号,则需要包含include/linux/version.h文件:

#define LINUX_VERSION_CODE 132644
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))

其中LINUX_VERSION_CODE就是(2 << 16) + (6 << 8) + (36 << 0)

这个宏很重要,举个例子:不同的 Linux 内核的 ioctl 函数原型是不同的,但是你的驱动又不想写两套,这个时候就应该这么写:

#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
static long my_ioctl (struct file *file, 
                      unsigned int req, 
                      unsigned long arg)
#else
static int my_ioctl (struct inode *inode, 
                     struct file *file, 
                     unsigned int req, 
                     unsigned long arg)
#endif
{
    // brah brah brah ...
}

内核扩展版本号

这里请注意内核的include/vermagic.h文件,有一个VERMAGIC_STRING宏,定义如下:

...
#define VERMAGIC_STRING                         \
    UTS_RELEASE " "                            \
    MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT             \
    MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS    \
    MODULE_ARCH_VERMAGIC

其中UTS_RELEASE宏来自于include/generated/utsrelease.h文件。
首先,这个文件是自动创建的,你修改了也没用。
其次,这个版本号的来源很复杂,除了 Linux 基础版本号(也就是 Makefile 的前三个变量)之外,还依赖很多变量:

  1. Makefile 里面的EXTRAVERSION宏,这是紧跟在基础版本号后面的
  2. make menuconfig 时指定的CONFIG_LOCALVERSION_AUTO配置宏,决定了到scripts/setlocalversion里面去添加什么样的附加内容
  3. LOCALVERSION,貌似一般情况下这个宏是没有定义的

而这个VERMAGIC_STRING有什么用呢?这经常是用在一些自定义的内核模块里面。如果内核模块的实现依赖于具体 Linux 内核发行版的话,在 insmod 的时候就需要判断内核的 VERMAGIC_STRING。很多情况下,这里面会包含很多信息。
比如我遇到问题的内核模块,其完整的VERMAGIC_STRING就是:“2.6.36+ mod_unload MIPS32_R2 32BIT

Version magic 不匹配问题的解决

我遇到的错误是这样的,内核执行时,网卡无法加载,以致设备没有网络。可以看到串口有这么一句错误信息:

my_net_adapt: version magic '2.6.36+ mod_unload MIPS32_R2 32BIT ' should be '2.6.36 mod_unload MIPS32_R2 32BIT '

根本的解决办法,是消除掉前面的 magic 里的加号,让两个 version magic 变成一模一样的。但是我找了资料也没找到为啥。这里要求各路大神了。
将就的解决办法,就是让两个 version magic 都加上加号,这样 magic 检查就可以通过啦。

查看我的 utsrelease.h 文件,可以看到其内容是 “2.6.36”。那么解决方案就有两种:

  1. 在目录的 Makefile,改第四个变量为 “EXTRAVERSION = +”。
  2. 在 Linux 的根目录下,创建一个没有用的 “.git” 空文件夹,让 setlocalversion 以为这是一个 Git 项目,从而自动加上加号。

第二个方案是基于一个前提的:Linux 根目录不是我整个工程的根目录,因而整个工程的 .git 文件夹在别处。

于是,问题解决了。我们测试也确认这台内核编译出来是 OK 的。但说实话,具体原因是什么,还要研究研究
——为什么在 SVN 下面就没问题,在 Git 就有问题呢?


后台 / 嵌入式全栈之路
曾经的嵌入式 / 后台开发一枚,现在开始走向架构。本专栏没有高深技术,只讲基础组件、工具,请放心食用

电子和互联网深耕多年,拥有丰富的嵌入式和服务器开发经验。现负责腾讯心悦俱乐部后台开发

889 声望
204 粉丝
0 条评论
推荐阅读
Go http.Transport 主要参数说明
在 Go 中创建一个 http client 时,一般会使用 Go http 包的 Transport 类型。本文主要说明 http.Transport 需要关注的主要参数。

amc

封面图
git 常用命令 记录
有错误和改进的地方望留言,谢谢 : )顺便推荐一下,git入门教程Git 教程图解 GitPro Git 2(中文版)Git 使用Git 使用规范流程Git 工作流程Commit message 和 Change log 编写指南全局设置git config --system //...

Luff阅读 3.2k

关于 Ubuntu 20.04 LTS 的网络(dchp/dns/route/PPPoE)
前言旧时代网络管理软件 net-tools、NetworkManager新时代网络管理软件 iproute2、resolvectl新时代旧时代大致可按 2010 年划分检查网卡是否已插入网线直接查看文件 {代码...} ip addr 或 ip link 命令查看网卡状...

qbit2阅读 15k

git/pip/easy_install/apt代理/源设置
在公司内网环境中,访问公网往往需要经过公司的代理,对于浏览器、IDE等开发工具,都提供了设置代理的配置,而git、pip、easy_install等CLI工具,则需要通过命令或配置文件进行代理设置;对于Python、Ubuntu、Mav...

乘着风1阅读 5.5k

Laravel入门及实践,快速上手ThinkSNS+二次开发
【摘要】自从ThinkSNS+不使用ThinkPHP框架而使用Laravel框架之后,很多人都说技术门槛抬高了,其实你与TS+的距离仅仅只是学习一个新框架而已,所以,我们今天来说说Laravel的入门。

ThinkSNS1阅读 2.4k

confluence7.2.1的部署与迁移---呕心沥血版
Confluence是一个专业的企业知识管理与协同软件,也可以用于构建企业wiki。使用简单,但它强大的编辑和站点管理特征能够帮助团队成员之间共享信息、文档协作、集体讨论,信息推送。 到官网下载最新版本,截止目前...

暗涌阅读 7.8k

C++编译器和链接器的完全指南
C++是一种强类型语言,它的编译和链接是程序开发过程中不可或缺的两个环节。编译器和链接器是两个非常重要的概念。本文将详细介绍C++中的编译器和链接器以及它们的工作原理和使用方法。

小万哥2阅读 1k

封面图

电子和互联网深耕多年,拥有丰富的嵌入式和服务器开发经验。现负责腾讯心悦俱乐部后台开发

889 声望
204 粉丝
宣传栏