编译openEuler内核并用虚拟机启动
本文是开发openEuler内核系列的第一篇,由编译内核和运行内核组成;主要参考了[1]和[7]两篇文章。
编译内核
编译基础知识
-
GCC与编译知识
-
GCC是在linux系统下常用的C语言编译工具,全称从GNU C Compiler变为GNU Compiler Collection;
-
它是GNU工具集的一员,这个工具集包含:
-
GNU Compiler Collection (GCC): a compiler suite that supports many languages, such as C/C++ and Objective-C/C++
-
GNU Make: an automation tool for compiling and building applications
-
GNU Binutils: a suite of binary utility tools, including linker and assembler
-
GNU Debugger (GDB)
-
GNU Autotools: A build system including Autoconf, Autoheader, Automake and Libtool
-
GNU Bison: a parser generator (similar to lex and yacc)
-
-
-
编译过程
-
编译是将高级语言翻译成机器语言,我们在编译原理中所学的是语法分析,解析,语义分析,将高级语言翻译成机器语言并进行优化这几个步骤,这些知识主要是用来写编译器的。而编译器在整个编译过程中是一个组成部分,还有预处理,汇编器,链接器等内容,我们作为一个编译器的使用者更多的关注整体的编译流程,而不是如何写出一个编译器。具体的编译流程如下图所示:
-
具体过程
-
预处理
-
将#include和#define等展开
cpp hello.c > hello.i
-
头文件查找范围
-
-Idir选项
-
CPATH环境变量,C_INCLUDE_PATH和CPLUS_INCLUDE_PATH可以分别来指定C和C++的头文件位置
-
可以使用“cpp -v”命令查看查找范围
-
-
-
编译器
-
将高级语言翻译为汇编
gcc -S hello.i
-
-
汇编器
-
将汇编翻译为机器码
as -o hello.o hello.s
-
-
链接器
-
分为静态链接和动态链接,默认来说,是采用动态链接
ld -o hello.exe hello.o ...libraries...
-
链接查找范围
-
文件夹
-
-Ldir选项
-
LIBRARY_PATH环境变量
-
-
库名
-
Unix下,根据选项-lxxx
-
Windows下,根据选项-lxxx.lib
-
-
还可以在Path环境变量下查找
-
可以打开-v选项观察用了哪些库,其中-L是表示库的路径,-l表示库的名字
-
-
-
-
-
GCC入门用法
-
一个常用的选项的示例:
gcc -std=c99 -v -Wall -g -o myprog file1.c file2.c
-
常用的选项
-
-std 选项可以指定一个用来表示编译版本的参数
-
-v 选项表示可以将编译的相关信息输出
-
-Wall 选项代表输出所有的warning信息
-
-g 选项表示附带debug信息
-
-o 选项表示输出的应用文件名由-o后面的参数指定
-
-shared 选项可以动态链接
-
其余的参数视为需要编译的文件,可以指定多个文件
-
-
-
GCC进阶用法
-
编译器会在将高级语言翻译为汇编语言的过程中,展开优化
-
可以单独将每一步的过程分别运行,而不是合成整体
-
预处理 gcc -E hello.c -o hello.i
-
编译,生成汇编代码 gcc -S hello.i -o hello.s
-
汇编,生成.o汇编文件 gcc -c hello.s -o hello.o
-
链接生成可执行文件 gcc hello.o -o hello
-
-
-
-
makefile
-
Make工具是GCC工具集中的一员,主要是利用一个叫做“makefile”的文件,来简化编译生成可执行文件的过程;
-
makefile文件的基本规则与进阶用法
-
基本规则
-
语法规则
target1 [target2 ...]: [pre-req-1 pre-req-2 ...] [command1 command2 ......]
-
例子
all: hello.exe hello.exe: hello.o gcc -o hello.exe hello.o hello.o: hello.c gcc -c hello.c clean: rm hello.o hello.exe
-
规则讲解
-
target是文件名或者是一个命令
-
作为文件名出现时,它会出现在另外的pre-req部分,作为一个前置条件来被调用,整个过程是递归的,调用的方法是:如果target代表的这个文件不存在的话,就会考察前置条件是否存在,前置条件不存在的话,递归调用,寻找其它target是否和这些前置条件匹配;如果前置条件存在的话,就调用command部分的命令,生成target表示的这个文件
-
作为命令出现时,在make命令的参数中传递进来一个参数,来和target进行匹配,执行make all就会调用all命令,具体的命令含义:all命令表示后面将会根据规则执行整个makefile文件,从而作为整个makefile文件的起始;clean命令表示执行编译完成后的清理工作
-
-
pre-req-n在冒号的右侧出现,表示执行命令前必须拥有的前置条件,就像if判断语句中的条件一样。这个条件是可以被省略的,表示如果想要生成target中文件不需要任何的前置条件
-
command命令前面必须是一个tab键,表示如果满足条件,就会执行的命令
-
在这个例子中,调用流程如下:调用make all就会执行all部分的命令,前置条件是hello.exe,前置条件缺失,开始寻找;寻找到target为hello.exe的部分,前置条件是hello.o,前置条件缺失,开始寻找;寻找到target为hello.o的部分,前置条件存在;所以依次执行“gcc -c hello.”"和“gcc -o hello.exe hello.o”
-
如果执行make clean命令,就会执行“rm hello.o hello.exe”
-
-
调用方法
-
make命令会自动寻找makefile文件来执行,这个文件可以被命名为makefile,Makefile或者是GNUMakefile
-
make默认表示执行make all,执行文件中的all部分
-
make clean表示执行makefile文件中的clean部分
-
-
-
进阶知识
-
注释以#开头
-
可以使用\来隔断太长的命令
-
[6]中给出了一个可以解决makefile每条命令单独执行的方法,尤其是在cd到某个目录执行的情况下
-
在之前规则讲解部分,所说的寻找前置条件是否存在的过程中,和文件生成的时间也有一定的关系,下面详细讲解:
-
只有在前置条件的生成日期比target文件的生成日期更加晚的情况下,才会运行command部分的命令来更新target文件
-
但是如果target表示一个命令,那么就不考虑时间的问题,在满足前置条件的情况下,一定会执行这个命令。
-
-
makefile文件中可以采用变量进一步简化
-
变量的定义是采用“文件名=内容”
-
变量的引用采用“$(变量名)”
-
可以采用一些特殊的变量
-
$@: target文件名
-
$*: 不加后缀名的target文件名
-
$<: 前置条件中的第一个文件名
-
$^: 去除掉重复的文件名后,用空格分割的前置条件文件名,
-
$+: 和$^相似,但是包含重复的文件名
-
$?: 生成日期比target更近的,用空格分割的前置条件文件名
-
-
采用变量重写之前的示例
all: hello.exe # $@ matches the target; $< matches the first dependent hello.exe: hello.o gcc -o $@ $< hello.o: hello.c gcc -c $< clean: rm hello.o hello.exe
-
-
系统环境变量
-
VPATH
-
指定文件夹,用来寻找依赖文件和targets,文件夹用逗号分隔
-
例子
VPATH = src include
-
-
vpath
-
指定文件夹和目标文件的类型,用来寻找依赖文件和targets,文件夹用逗号分隔
vpath %.c src vpath %.h include
-
-
-
规则匹配
-
规则匹配是另一种写makefile的方式,结合了变量,环境变量和%通配符匹配的方式,比基本规则中讲解的方法更为方便,也是我们在实际的makefile中经常见到的一种模式
-
%通配符:匹配不包含后缀的文件名
-
makefile文件示例
-
示例
# A sample Makefile # This Makefile demonstrates and explains # Make Macros, Macro Expansions, # Rules, Targets, Dependencies, Commands, Goals # Artificial Targets, Pattern Rule, Dependency Rule. # Comments start with a # and go to the end of the line. # Here is a simple Make Macro. LINK_TARGET = test_me.exe # Here is a Make Macro that uses the backslash to extend to multiple lines. OBJS = \ Test1.o \ Test2.o \ Main.o # Here is a Make Macro defined by two Macro Expansions. # A Macro Expansion may be treated as a textual replacement of the Make Macro. # Macro Expansions are introduced with $ and enclosed in (parentheses). REBUILDABLES = $(OBJS) $(LINK_TARGET) # Here is a simple Rule (used for "cleaning" your build environment). # It has a Target named "clean" (left of the colon ":" on the first line), # no Dependencies (right of the colon), # and two Commands (indented by tabs on the lines that follow). # The space before the colon is not required but added here for clarity. clean : rm -f $(REBUILDABLES) echo Clean done # There are two standard Targets your Makefile should probably have: # "all" and "clean", because they are often command-line Goals. # Also, these are both typically Artificial Targets, because they don't typically # correspond to real files named "all" or "clean". # The rule for "all" is used to incrementally build your system. # It does this by expressing a dependency on the results of that system, # which in turn have their own rules and dependencies. all : $(LINK_TARGET) echo All done # There is no required order to the list of rules as they appear in the Makefile. # Make will build its own dependency tree and only execute each rule only once # its dependencies' rules have been executed successfully. # Here is a Rule that uses some built-in Make Macros in its command: # $@ expands to the rule's target, in this case "test_me.exe". # $^ expands to the rule's dependencies, in this case the three files # main.o, test1.o, and test2.o. $(LINK_TARGET) : $(OBJS) g++ -g -o $@ $^ # Here is a Pattern Rule, often used for compile-line. # It says how to create a file with a .o suffix, given a file with a .cpp suffix. # The rule's command uses some built-in Make Macros: # $@ for the pattern-matched target # $< for the pattern-matched dependency %.o : %.cpp g++ -g -o $@ -c $< # These are Dependency Rules, which are rules without any command. # Dependency Rules indicate that if any file to the right of the colon changes, # the target to the left of the colon should be considered out-of-date. # The commands for making an out-of-date target up-to-date may be found elsewhere # (in this case, by the Pattern Rule above). # Dependency Rules are often used to capture header file dependencies. Main.o : Main.h Test1.h Test2.h Test1.o : Test1.h Test2.h Test2.o : Test2.h # Alternatively to manually capturing dependencies, several automated # dependency generators exist. Here is one possibility (commented out)... # %.dep : %.cpp # g++ -M $(FLAGS) $< > $@ # include $(OBJS:.o=.dep)
-
讲解
-
定义环境变量(宏)
-
定义LINK_TARGET,目标的执行文件
-
定义OBJS,中间生成的文件
-
定义REBUILDABLES,是可以重新定义的文件
-
-
规则
-
clean是用来清理环境中的文件
-
all是用来编译目标文件
-
$(LINK_TARGET)是来生成exe文件
-
接着用%通配符来匹配文件名,生成.o文件
-
然后是一些依赖规则,可以用来检测.o文件是否过时,依赖规则需要很精确的写法
-
这里首先补充一下依赖规则是如何起作用的[4]
-
-
-
-
-
-
-
-