When compiling the Linux kernel, we often execute some commands in the top-level directory of the Linux kernel. Taking RK3288 as an example, commands such as: make firefly-rk3288-linux_defconfig
, make menuconfig
, make firefly-rk3288.img
, make zImage
, etc. are used. Without getting into the specifics of these commands, let’s raise a few questions.
(1) Given the vastness of the Linux kernel (tens of thousands of files) and its many-layered directory structure, how does it relate files across various directories?
(2) With Linux supporting so many architectures (X86, ARM, AVR, MIPS, etc.), why is it that when using a specific architecture chip like RK3288, the code for other architectures is not compiled? Also, why is code related to other SOC architectures under ARM not compiled?
(3) What is the significance of executing the command: make menuconfig
before compiling the kernel?
(4) What is the significance of executing the command: make zImage
during kernel compilation?
(5) How are the Makefile and Kconfig files in the various directories of the Linux kernel written?
I believe that once the above questions are understood, the queries posed in the title of this article will naturally be resolved. Below, I will answer these questions one by one:
Question 1: Given the vastness of the Linux kernel (tens of thousands of files) and its many-layered directory structure, how does it relate files across various directories?
To accurately answer this question, only true experts could provide a definitive response, so I will share my understanding. The management of the Linux kernel source code is highly scientific. In the top-level directory of the Linux kernel source code, appropriate directories are allocated, where each directory represents a cluster of functionalities or attributes, achieving modularization for easier management. For example, the arch
directory relates to platform architectures, the include
directory contains numerous kernel header files, the drivers
directory holds various driver codes such as for graphics cards, network cards, USB buses, PCI buses, etc., the kernel
directory implements features specific to architecture such as semaphore handling and SMP, and the mm
directory contains implementations of architecture-specific memory management programs, etc. Furthermore, each subdirectory is further categorized. For example, under the arch
directory, there are directories related to the x86 architecture, ARM architecture, MIPS architecture, etc. Thus, a tree structure is formed.
Those who have studied data structures should know that there are ways to traverse a non-standard tree, although the algorithms may be more complex. In the Linux kernel source code, this tree is traversed using Kconfig files to establish connections between subdirectories, while Makefile files determine whether the corresponding files in each directory should be compiled. The .config
file acts as a master control panel, directing the Makefile to compile specified source code files (mainly C and assembly). All these control relationships are established by the Kconfig files.
In my understanding, this is essentially a method used for traversing a tree structure, akin to asking for directions. Whenever we ask for directions in an unfamiliar place, the scenario typically unfolds as follows:
Usually, we can accurately find our destination E based on the directions given by passersby. Similarly, in a program or code architecture, the .config
file acts as the passerby, the Kconfig as the person asking for directions, and the Makefile as the legs following instructions to do the work! Haha!
Question 2: With Linux supporting so many architectures (X86, ARM, AVR, MIPS, etc.), why is it that when using a specific architecture chip like RK3288, the code for other architectures is not compiled? Also, why is code related to other SOC architectures under ARM not compiled?
This question is actually related to the commands we execute when compiling the Linux kernel: make firefly-rk3288-linux_defconfig
or make menuconfig
. The purpose of executing these two commands is to generate the .config
file. Often, we execute the command make menuconfig
just to modify some driver modules and the programs to be compiled, and we usually do not choose architecture-related options. For example, we could choose the RK3288 SOC and select the Firefly platform board, but typically we do not do this. We usually first execute make firefly-rk3288-linux_defconfig
to generate a .config
file related to RK3288 based on the Firefly platform and then execute make menuconfig
to select some module codes for compilation, which reduces a lot of workload. Of course, there is a problem: what if the kernel to be compiled does not support the existing development board? For instance, if the original Linux kernel source downloaded from the official website only supports the RK3288 SOC but does not support the specific RK3288 development board for Firefly, what should we do? This involves the porting of the Linux kernel, which I will not elaborate on here. A reminder is that you can look for a configuration of a development board based on the RK3288 SOC (in the official released initial Linux kernel source, there is usually a corresponding official development board supported for each SOC) to perform porting and simulation, ultimately generating a configuration file similar to firefly-rk3288-linux_defconfig
to create the basic .config
file.
Once the above relationships are clear, understanding the reason for question 1 becomes easy. Yes, the basic default .config
configuration file is generated based on the firefly-rk3288-linux_defconfig
file, and this file contains architecture-related items. Thus, during the compilation of the Linux kernel source code, the architecture-related code is compiled based on the basic configuration of the .config
file. In summary, everything is based on the .config
control panel.
Question 3: What is the significance of executing the command: make menuconfig
before compiling the kernel?
This question has basically been answered in the first two questions. make menuconfig
opens the tree structure of the kernel source code in a menu format, allowing programmers to configure and select the module codes to be compiled based on the default configuration.
There are many commands that can accomplish this task, such as:
• make config
: A traditional text-based configuration interface that is too complex and not intuitive; not recommended.
• make xconfig
: A graphical window-based configuration interface that is intuitive and clear; recommended for use under Xwindow.
• make oldconfig
: If you only want to modify a few small parts based on the original kernel configuration, this can save a lot of trouble.
• make menuconfig
: A text menu-based configuration interface that is intuitive and clear; recommended for use under character terminals.
There are probably these few types, but there is also the option to manually modify the .config
file, though I believe hardly anyone would do that.
Question 4: What is the significance of executing the command: make zImage
during kernel compilation?
Usually, during compilation, we execute this command or the make uImage
command. What is the significance? It is to generate a kernel image named zImage
or uImage
. Of course, some may wonder, when compiling for the Firefly RK3288 development board, the command executed is make firefly-rk3288.img
, not any of the above. This is actually a modified method by Firefly; in essence, it’s just a name. Don’t get too hung up on this; if you want to understand it in detail, the answer lies in the kernel source provided by Firefly.
After executing the compilation command, using the .config
file, Kconfig files, and Makefile files, the source code can be compiled in an orderly and selective manner.
Question 5: How are the Makefile and Kconfig files in the various directories of the kernel written?
The first four questions serve as a foundation, and this is the key point, but it must rely on the principles mentioned earlier.
First, we must establish that in each directory of the Linux kernel source code, there exists a Kconfig file and a Makefile, while the .config
file exists in the top-level directory. As shown in the figure below:
The above image basically proves everything.
To better illustrate, I created a directory called my_dr
under the drivers
directory, primarily to store my own kernel driver code. This directory contains various driver codes I have written, and I need to connect them so that when executing the make menuconfig
command, I can find my own kernel driver code. Here, I will use a hello program as an example.
So how exactly should this be done? The answer is simple: “Imitate”!
As shown in the figure below:
The image above illustrates the directory structure I want to discuss. The hello directory contains the hello.c program; the my_dr directory is where I want to store my own driver program; the drivers directory is the Linux kernel driver directory; and the firefly-rk3288-kernel directory is the top-level directory of the Linux kernel source code. Therefore, based on the previous deductions, there will be a Makefile and Kconfig file in every layer of the directory. Now, let’s analyze the Makefile and Kconfig files at each level from the bottom hello directory to the drivers directory.
(1) hello directory
As shown in the image above, the left side is the Makefile, and the right side is the Kconfig file. In the Makefile, if the variable CONFIG_HELLO
is true or false, it checks whether to compile the hello.c
file into hello.o
. The value of the CONFIG_HELLO
variable comes from the configuration of the .config
file, which is derived from explicit selection through the Kconfig file (that is, through menu selection). Looking at the Kconfig file, as shown in the image below:
Config is the configuration keyword; HELLO is the configuration item; tristate is a tri-state selector, which provides three choices when offering a menu configuration to upper layers: not compile, compile into the kernel image, and compile as a module driver. In addition to this keyword, there is also a bool, which is easy to understand, providing two choices: compile or not compile; help provides help prompts. This is basically a classic format. Therefore, when writing such configurations, the usual practice is to refer to existing Kconfig files and Makefile files in the Linux kernel source code and imitate their formats.
(2) my_dr directory
The image above shows the contents of the Makefile and Kconfig files in the my_dr directory. In the Makefile, one line points to the hello directory. In the Kconfig file, since the my_dr directory may contain many driver programs, it is necessary to establish a menu for selecting each driver program. Thus, the first line of code creates a menu named my Drivers
; the fifth line indicates that the Kconfig resource can be found at the relative path drivers/my_dr/hello/Kconfig
(note that this path is relative to the top-level directory of the Linux kernel source code). Finally, line seven indicates the end of the menu with the keyword endmenu
.
(3) drivers directory
The image above shows the Makefile and Kconfig files in the drivers directory. Similarly, in the Makefile, the menu directory path for the washing song resources is added; and in the Kconfig file, the path for the resources of this directory’s Kconfig file is also added. They are used in conjunction. Moreover, in these two documents, many reference examples can be directly referenced! One question arises: in the Makefile, for example, line 158, as shown in the image below:
There exists the variable CONFIG_GATOR
; what is this for? The explanation is that if you want to display the selection regarding the gator directory menu in the menu, the value of the CONFIG_GATOR
variable must be set to y
. Only then will you see the gator directory menu when using the make menuconfig
command. The CONFIG_GATOR
variable is dependent on some code in the upper layer, and after selection, its value becomes y
. The variable I wrote directly uses the statement obj-y
, indicating that the variable value is y
(which is yes), thus it can be seen directly without relying on other code.
The entire process is as described above. Now, execute the make menuconfig
command to check if I can see the menu I created earlier. As shown in the figure below:
As shown in the image above, I can see the menu I created named my Dribers
.
As shown in the two images above, this is the result displayed by the tristate keyword, which shows three states. One can choose appropriately as needed.
Conclusion:This article mainly records my understanding of the writing and usage of Makefile, Kconfig, and .config files in the Linux kernel source code. From a certain perspective, it runs through the entire Linux kernel source code and is most prominently reflected to developers in the form of a graphical menu for compilation development and selection.
Disclaimer:The above content is purely my personal understanding; if there are any inaccuracies, I hope experts will enlighten me!
Click to read the original text: Sign up now to receive a 5 million red envelope, come to Huqing to help youachieveyour high salary dream!
【Weekly Hot ArticlesRecommended】
1.Top 10 Majors for Science Students with High Employment Rates, Computer Science Ranks First!
2.Should Computer Graduates Choose a Company or an Industry?
3.Four Tips for Beginners Learning Programming
4.Things to Consider for Fresh Graduates in Interviews
5.Interview Insights: Skills Expected of a Programmer with 3 Years of Experience
6.Interviewing an Embedded Driver Engineer: There Are Skills to Interviews
Follow the Huqing Maker Online WeChat account,
to get more information on smart hardware development.

Long press the QR code to follow me