The Relationship Between Makefile, Kconfig, and .config in Linux Kernel

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:

The Relationship Between Makefile, Kconfig, and .config in Linux Kernel

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 Relationship Between Makefile, Kconfig, and .config in Linux Kernel

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 Relationship Between Makefile, Kconfig, and .config in Linux Kernel

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

The Relationship Between Makefile, Kconfig, and .config in Linux Kernel

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:

The Relationship Between Makefile, Kconfig, and .config in Linux Kernel

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 Relationship Between Makefile, Kconfig, and .config in Linux Kernel

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 Relationship Between Makefile, Kconfig, and .config in Linux Kernel

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:

The Relationship Between Makefile, Kconfig, and .config in Linux Kernel

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:

The Relationship Between Makefile, Kconfig, and .config in Linux Kernel

As shown in the image above, I can see the menu I created named my Dribers.

The Relationship Between Makefile, Kconfig, and .config in Linux Kernel

The Relationship Between Makefile, Kconfig, and .config in Linux Kernel

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.

WeChat ID: maker-edu

The Relationship Between Makefile, Kconfig, and .config in Linux Kernel

Long press the QR code to follow me

Leave a Comment