CSDN GitHub
Linux kernel compiler LOCALVERSION configuration (analyze the kernel version number automatically added “+” number) AderXCoding/system/tools


This work is licensed under creative Commons Attribution – Non-commercial Use – Same way Share 4.0 International license, please indicate the source of reproduction, thank you for your cooperation

Because my technical level and knowledge is limited, if there is a flaw or need to correct the content, welcome you to correct, but also welcome you to provide some other good debugging tools for inclusion, I thank you here


1 Problem Discovery


When compiling the mainline kernel version, the version number generated by the mainline kernel version is “X.Y.Z +”, why there is a plus sign?

In the beginning, I was thinking about whether CONFIG_LOCALVERSION is the problem. If CONFIG_LOCALVERSION is configured, or if a “+” is added at the end of the kernel version, after installation, every time uname -a will appear +, I really feel depressed. I can’t stand the ocD.

2 Cause Analysis


The problem must be with version control during the Linux build, and since it was added during the build, we can see some clues in the Makefile.

2.1 MakefileLOCALVERSIONinformation


VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 35
EXTRAVERSION = 7.
NAME = Yokohama
Copy the code

These are the version numbers of our kernel version, and the generated version numbers should theoretically not have + signs, but why?

The two configuration macros CONFIG_LOCALVERSION and CONFIG_LOCALVERSION_AUTO in the kernel configure the system kernel version number and suffix information.

2.2 MakefileRead and set the version number in


We retrieve information related to these macros, checking the LOCALVERSION macro to exclude directories such as ARCH /*/ Configs and Documentation.

grep -r LOCALVERSION * grep --exclude-dir={arch,Documentation,Kconfig}
Copy the code

! [Checking LOCALVERSION information]

You can see that the scripts/ setlocalVersion script reads the relevant information.

Let’s take our time and see how the Makefile reads and sets this information. Continue analyzing LOVALVERSION information from the Makefile.

define filechk_kernel.release
	echo "$(KERNELVERSION)$$($(CONFIG_SHELL) $(srctree)/scripts/setlocalversion $(srctree))"
endef

# Store (new) KERNELRELEASE string in include/config/kernel.release
include/config/kernel.release: include/config/auto.conf FORCE
	$(call filechk,kernel.release)
Copy the code

Makefile using scripts/setlocalversion tool to generate include/config/kernel. The “+” is added when invoking the script.

You can run the following command to generate the version file

make include/config/kernel.release
OR
make include/generated/utsrelease.h
Copy the code

Look at the information for the two files to see the version number information

Makefiles also have the following definitions:

kernelrelease:
         @echo "$(KERNELVERSION)$$($(CONFIG_SHELL) $(srctree)/scripts/setlocalversion $(srctree))"
Copy the code

You can also run the following command to display the version number

make kernelrelease
Copy the code

2.3 setlocalversionFunction to set the version number information


Read the scripts/setlocalversion file and look it up, making the following notes:

If the current kernel is hosted by SVN, only version number information is read from.scmversionif $scm_only; then
	if test ! -e .scmversion; then
		res=$(scm_version)
		echo "$res">.scmversion fi exit fiautoConf file existsif test -e include/config/auto.conf; then
	. include/config/auto.conf
else
	echo "Error: kernelrelease not valid - run 'make prepare' to update it"> &2
	exit 1Fi # calls localVersion to read information from the localVersion file in the source code root# localversion* files in the build and source directory
res="$(collect_files localversion*)"
if test ! "$srctree" -ef .; then
	res="$res$(collect_files "$srctree"/localversion*)"Fi # Set LOCALVERSION information # CONFIG_LOCALVERSIONand LOCALVERSION (if set)
res="${res}${CONFIG_LOCALVERSION}${LOCALVERSION}"Call scm_version to read the suffix information# scm version string if not at a tagged commit
if test "$CONFIG_LOCALVERSION_AUTO" = "y"; then
	# full scm version string
	res="$res$(scm_version)"
else
	# append a plus sign if the repository is not in a clean
	# annotated or signed tagged state (as git describe only
	# looks at signed or annotated tags - git tag -a/-s) and
	# LOCALVERSION= is not specified
	if test "${LOCALVERSION+set}"! ="set"; then
		scm=$(scm_version --short)
		res="$res${scm:++}"
	fi
fi
Copy the code

2.3.1 Setting LOCALVERSION


There is also a paragraph in the scripts/setlocalversion file:

# CONFIG_LOCALVERSION and LOCALVERSION (if set)
res="${res}${CONFIG_LOCALVERSION}${LOCALVERSION}"
Copy the code

You can see that if CONFIG_LOCALVERSION and LOCALVERSION are configured, this suffix will be added to the version number.

Res is the obtained local version number information, such as 4.14-RC8

2.3.2 Adding suffix information about SCM_VERSION


Finally, add the version suffix information according to whether the CONFIG_LOCALVERSION_AUTO and CONFIG_LOCALVERSION macros are configured

If I define

CONFIG_LOCALVERSION_AUTO=y
Copy the code

Execution is performed

res="$res$(scm_version)"
Copy the code

Where res is our version number information, and the scm_version function takes the version number suffix.

Otherwise, if CONFIG_LOCALVERSION_AUTO is not set, the following section is executed.

Call scm_version to read the suffix information# scm version string if not at a tagged commit
if test "$CONFIG_LOCALVERSION_AUTO" = "y"; then
	# full scm version string
	res="$res$(scm_version)"
else
	# append a plus sign if the repository is not in a clean
	# annotated or signed tagged state (as git describe only
	# looks at signed or annotated tags - git tag -a/-s) and
	# LOCALVERSION= is not specified
	if test "${LOCALVERSION+set}"! ="set"; then
		scm=$(scm_version --short)
		res="$res${scm:++}"
	fi
fi
Copy the code

To explain a syntax in setLocalVersion:

grammar describe
${var:-value1} In the variablevarWhen not empty, holdvarThe original value remains the same; ifvarThe variable is not set or empty and the result of this expression isvalue1, but the variablevarIs not changed (not set or null)
${var:+value1} In the variablevarWhen not null, the expression results invalue1; ifvarThe variable is not set or empty. The result of this expression is empty.${var+value1}Have the same effect
${var:=value1} In the variablevarWhen not empty, holdvarThe original value remains the same; ifvarThe variable is not set or empty and the result of this expression isvalue1, the variablevarIt’s also assigned tovalue1
${var:? value1} In the variablevarWhen not set or empty, the script exits with an error message (containingvalue1)

So the shell statement above

  1. The CONFIG_LOCALVERSION_AUTO = y program uses the scm_version function (no arguments) to configure the local version number.

  2. If CONFIG_LOCALVERSION_AUTO is not set and LOVALVERSION is null, then “${LOCALVERSION+set}”! = “set”, then calling scm_version –short will add a + sign at the end.

I see. The plus sign is added like this. How the plus sign is added, and what scm_version does, and how these configuration macros affect the version number and suffix information, is the scm_version function.

2.3.3 Obtaining the Version Suffix Information


scm_version()
{
	local short
	short=false

	cd "$srctree"If the.scmversion file exists, the suffix of the file will be obtained directlyif test -e .scmversion; then
		cat .scmversion
		return
	fi

    # --shortParameter Settingif test "$1" = "--short"; then
		short=true
	fi

	# Check for git andA git reposhortBe set directly print + # # or read the git version number information, # if git tag number is git the describe | awk - F -'{printf("-%05d-%s", $(NF-1),$(NF))}'Otherwise, print the commit numberif test -z "$(git rev-parse --show-cdup 2>/dev/null)" &&
	   head=`git rev-parse --verify --short HEAD 2>/dev/null`; then

		# If we are at a tagged commit (like "V2.6.30 - rc6"), we ignore
		# it, because this version is defined in the top level Makefile.
		if [ -z "`git describe --exact-match 2>/dev/null`" ]; then

			# If only the short version is requested, don't bother
			# running further git commands
			if $short; then
				echo "+"
				return
			fi
			# If we are past a tagged commit (like
			# "V2.6.30 - rc5-302 - g72357d5"), we pretty print it.
			if atag="`git describe 2>/dev/null`"; then
				echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}'

			# If we don't have a tag at all we print -g{commitish}.
			else
				printf '%s%s' -g $head
			fi
		fi

		# Is this git on svn?
		if git config --get svn-remote.svn.url >/dev/null; then
			printf -- '-svn%s' "`git svn find-rev $head`"
		fi

		# Check forUncommitted changes # Add the -dirty suffix if there are files that are not committedif git diff-index --name-only HEAD | grep -qv "^scripts/package"; then
			printf '%s' -dirty
		fi

		# All done with git
		return
	fi

	# Check for mercurial and a mercurial repo.
	if test -d .hg && hgid=`hg id 2>/dev/null`; then
		# Do we have an tagged version?  If so, latesttagdistance == 1
		if [ "`hg log -r . --template '{latesttagdistance}'`"= ="1" ]; then
			id=`hg log -r . --template '{latesttag}'`
			printf '%s%s' -hg "$id"
		else
			tag=`printf '%s' "$hgid" | cut -d' ' -f2` if [ -z "$tag" -o "$tag" = tip ]; then id=`printf '%s' "$hgid" | sed 's/[+ ].*//'`
				printf '%s%s' -hg "$id"
			fi
		fi

		# Are there uncommitted changes?
		# These are represented by + after the changeset id.
		case "$hgid" in
			*+|*+\ *) printf '%s' -dirty ;;
		esac

		# All done with mercurial
		return
	fi

	# Check for svn andA SVN repo. # Obtain the version suffix of the SVN repositoryif rev=`LANG= LC_ALL= LC_MESSAGES=C svn info 2>/dev/null | grep '^Last Changed Rev'`; then
		rev=`echo $rev | awk '{print $NF}'`
		printf -- '-svn%s' "$rev"

		# All done with svn
		return
	fi
}
Copy the code

Use the bash statement to determine

git rev-parse --verify --short
Copy the code

Check whether the current git repository is managed, and output a short code of the HEAD Revision repository.

git rev-parse --verify --short HEAD 2>/dev/null
Copy the code

The key is the result of the following statement

git describe --exact-match
Copy the code

This sentence describes the current tag. If it is empty without a tag, then the entire if statement is true and executes, and the following echo “+” prints a + sign in the version number.

If we were in the repository

git tag -a -m "v0.1" v01.
Copy the code

Git describe –exact-match git describe –exact-match git describe –exact-match Then the if statement will not be inside, it will not echo “+”.

If there is any uncommitted code, git diff checks are done in printf-dirty, which means I have modified files that have not been uploaded. Basically, all the reasons have been found out. After I uploaded the file and made prepare again, the generated kernel.release was correct as expected.

In conclusion, Linux is quite strict on version management, which makes us have to be strict with ourselves in code management. For example, before releasing a version, check whether there are any files modified to upload, and then tag git version library.

If the code is managed by Git

  • If a tag is typed, tag-related characters are added

    • If the tag is just a simple tag, such as 4.14-rc8, skip it because the information is already fetched from the previous makefile

    • If the tag has additional suffixes, such as V2.6.30-RC5-302-G72357D5, print them out

  • If there is no tag, log characters such as the latest commit are added

    commit cdebe039ded3e7fcd00c6e5603a878b14d7e564e
    Copy the code

    The compiled files include/config/kernel release content for 4.14.0 rc8 — gcdebe03

Follow the arguments passed in from before

  • If I don’t have a definitionCONFIG_LOCALVERSION_AUTOLOCALVERSIONThe scm_version function is passed--shortThe parameter version number is added later"+"Number.
if $short; then
 echo "+"
 return
fi
Copy the code

2.4 summarize


2.4.1 Setting the version number


The version number is read in script/ setlocalVersion

# localversion* files in the build and source directory
res="$(collect_files localversion*)"
if test ! "$srctree" -ef .; then
	res="$res$(collect_files "$srctree"/localversion*)"
fi

# CONFIG_LOCALVERSION and LOCALVERSION (if set)
res="${res}${CONFIG_LOCALVERSION}${LOCALVERSION}"
Copy the code

As you can see, if you want to add characters to the version number, there are several ways:

  • Use the LOCALVERSION variable (either on the command line or added as an environment variable)

  • Adding the localversion file to the root directory of the kernel source code automatically adds the content to the version number. Add in the local create file

  • Define the CONFIG_LOCALVERSION variable

  • The way to add characters to the version number

The LOCALVERSION variable can be defined on the command line:

make LOCALVERSION=44. include/config/kernel.release
Copy the code

Or add it as an environment variable

export LOCALVERSION=44.
make include/config/kernel.release
Copy the code

The current kernel version is 4.14.0-rc8. If there is a file localversion in the root directory (with a content of.33), the localversion variable (CONFIG_LOCALVERSION=”.xyz “) is also used (as specified when making).

make LOCALVERSION=44. include/config/kernel.release
Copy the code

At this time on the kernel 4.14 – rc8, include/config/kernel release 4.14 – rc8.33. The content of the XYZ. 55.

You can see the order of the three characters added

The localversion content of the file is preceded by the CONFIG_LOCALVERSION value and then the localVersion value

namely

The version number logo content
The major version number VERSION 4
The release PATCHLEVEL 14
Second version number SUBLEVEL 0
Extended version number EXTRAVERSION -rc8
file localversion 33
Configuration macro CONFIG_LOCALVERSION XYZ
Local macro LOCALVERSION 55

2.4.2 Obtaining suffix Information


  1. The CONFIG_LOCALVERSION_AUTO = y program configures the local version number suffix through the scm_version function (no arguments). The suffix information is usually the version number of the managed repository, such as Git Tag /commit

  2. If CONFIG_LOCALVERSION_AUTO is not set and LOVALVERSION is null, then “${LOCALVERSION+set}”! = “set”, then calling scm_version –short will add a + sign at the end.

Also, about the scripts/setlocalversion file.

In the ‘scripts/setlocalversion’ file, you can use echo “aaa” >&2 to display related information, for example, echo “LOCALVERSION=${LOCALVERSION}” >&2

Need careful attention

Use Modinfo to view the kernel version number of the compiled KO file

Use uname or cat /proc/version to view the kernel version number on the target system.

To view the kernel compilation process generated files include/config/kernel release or include/generated/utsrelease h, determine the compiled version of the kernel.

2.4.3 validation


  • LOCALVERSIONYou can append suffix information to the version number, if defined againCONFIG_LOCALVERSION_AUTO, will be further appended at the endgitThe version number is a suffix
The macro define
CONFIG_LOCALVERSION “”
CONFIG_LOCALVERSION_AUTO y
LOCALVERSION not set or set

  • Does not defineCONFIG_LOCALVERSION_AUTOWill not showgitWarehouse information if at this timeLOCALVERSIONThe variable definition is also undefined and will be appended with “+”.
The macro define
CONFIG_LOCALVERSION “”
CONFIG_LOCALVERSION_AUTO not set
LOCALVERSION not set

At this point scM_version –short adds a “+” sign

cat .config | grep -E "CONFIG_LOCALVERSION"
make kernelrelease
Copy the code

  • As long as LOCALVERSION is defined even if defined asNULLWill not append “+”
The macro define
CONFIG_LOCALVERSION “”
CONFIG_LOCALVERSION_AUTO not set
LOCALVERSION Set to null

make LOCALVERSION= kernelrelease

make LOCALVERSION="" kernelrelease

Copy the code

The “+” sign will not be added

3 to solve


  • LOCALVERSION can append a suffix to the version number. If you define CONFIG_LOCALVERSION_AUTO, the git version number will be appended to the suffix at the end.

  • If you do not define CONFIG_LOCALVERSION_AUTO, git repository information will not be displayed. If the LOCALVERSION variable definition is not defined at this time, “+” will be appended.

  • If you don’t want either a suffix or a “+” sign: CONFIG_LOCALVERSION_AUTO is not defined and the LOCALVERSION variable is defined as null: LOCALVERSION=.

  • As long as LOCALVERSION is defined, the “+” sign is not appended

4 Reference Materials


tolinuxKernel version numbers add characters/why are they sometimes added automatically+

Add characters to Linux kernel version numbers/why sometimes “+” or “xxx-dirty” are automatically added

Adding characters to Linux kernel version numbers/why is the “+” sign sometimes added automatically

Remove the “+” sign automatically added to the Linux kernel version

A + sign is added to the compiled version of the LINUX KERNEL.


  • This work/blog (AderStep- Purple Night Appendix – Qingling Lane Grass Copyright ©2013-2017), created by Cheng Jian (Gatieme),

  • usingCreative Commons Attribution – Non-commercial Use – Same way Share 4.0 International LicenseWelcome to reprint, use and re-publish the article, but be sure to keep the bylineAs thou dost gatieme(Includes links to:blog.csdn.net/gatieme) shall not be used for commercial purposes.

  • Any work modified based on this article must be distributed under the same license. If you have any questions, please contact me.