linux下可以通过 cat /proc/version 命令查看内核版本信息。
root@am57xx-evm:~# cat /proc/version
Linux version 4.14.79-gbde58ab01e (allen@david-virtual-machine) (gcc version 7.2.1 20171011 (Linaro GCC 7.2-2017.11)) #248 SMP PREEMPT Mon Dec 16 14:39:09 CST 2019
这个proc文件是在内核源码 fs/proc/version.c 里面创建的:
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/utsname.h>
static int version_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, linux_proc_banner,
utsname()->sysname,
utsname()->release,
utsname()->version);
return 0;
}
static int version_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, version_proc_show, NULL);
}
static const struct file_operations version_proc_fops = {
.open = version_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int __init proc_version_init(void)
{
proc_create("version", 0, NULL, &version_proc_fops);
return 0;
}
fs_initcall(proc_version_init);
proc_create("version", 0, NULL, &version_proc_fops):
在proc目录下创建了version文件,打开这个文件时,会去调用其open方法,open里调用version_proc_show(),即执行下面这行代码:
seq_printf(m, linux_proc_banner,utsname()->sysname,utsname()->release,utsname()->version);
linux_proc_banner的定义在 init/version.c里:
const char linux_proc_banner[] =
"%s version %s"
" (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ")"
" (" LINUX_COMPILER ") %s\n";
utsname()->sysname,->release,->version也在 init/version.c里初始化
struct uts_namespace init_uts_ns = {
.kref = KREF_INIT(2),
.name = {
.sysname = UTS_SYSNAME,
.nodename = UTS_NODENAME,
.release = UTS_RELEASE,
.version = UTS_VERSION,
.machine = UTS_MACHINE,
.domainname = UTS_DOMAINNAME,
},
.user_ns = &init_user_ns,
.ns.inum = PROC_UTS_INIT_INO,
#ifdef CONFIG_UTS_NS
.ns.ops = &utsns_operations,
#endif
};
等价于:
seq_printf(m, "%s version %s (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") %s\n",UTS_SYSNAME,UTS_RELEASE,UTS_VERSION);
以我的环境为例:
UTS_SYSNAME:linux
UTS_RELEASE:4.14.79-gbde58ab01e ---根据MAkefile和内核配置生成
LINUX_COMPILE_BY:编译内核的用户
LINUX_COMPILE_HOST:编译内核的主机
LINUX_COMPILER:编译内核使用的编译器版本
UTS_VERSION:scripts/mkcompile_h里生成:
if [ -z "$KBUILD_BUILD_VERSION" ]; then
if [ -r .version ]; then
VERSION=`cat .version`
else
VERSION=0
echo 0 > .version
fi
else
VERSION=$KBUILD_BUILD_VERSION
fi
if [ -z "$KBUILD_BUILD_TIMESTAMP" ]; then
TIMESTAMP=`date`
else
TIMESTAMP=$KBUILD_BUILD_TIMESTAMP
fi
if test -z "$KBUILD_BUILD_USER"; then
LINUX_COMPILE_BY=$(whoami | sed 's/\\/\\\\/')
else
LINUX_COMPILE_BY=$KBUILD_BUILD_USER
fi
if test -z "$KBUILD_BUILD_HOST"; then
LINUX_COMPILE_HOST=`hostname`
else
LINUX_COMPILE_HOST=$KBUILD_BUILD_HOST
fi
UTS_VERSION="#$VERSION"
CONFIG_FLAGS=""
if [ -n "$SMP" ] ; then CONFIG_FLAGS="SMP"; fi
if [ -n "$PREEMPT" ] ; then CONFIG_FLAGS="$CONFIG_FLAGS PREEMPT"; fi
UTS_VERSION="$UTS_VERSION $CONFIG_FLAGS $TIMESTAMP"
在这里UTS_VERSION="#$VERSION $CONFIG_FLAGS $TIMESTAMP",VERSION在KBUILD_BUILD_VERSION为空时,就是 .version文件的内容。.version里面记录的是内核编译次数,每编译一次这个文件中的值便会加1,删掉即可清零。