使用make命令来编译应用程序或驱动程序时,Makefile的作用有以下几点:
1. 决定编译哪些文件;
2. 怎样编译这些文件;
3. 怎样链接这些文件,他们的顺序是什么样的
编译驱动模块的Makefile:
例子:
KERN_DIR = /home/development/linux-kernel-2.6.37
#KERN_DIR = /usr/src/$(shell uname -r)
#KERN_DIR = /lib/modules/$(shell uname -r)/build
all:
make -C $(KERN_DIR) M=$(shell pwd) modules
clean:
make -C $(KERN_DIR) M=$(shell pwd) modules clean
rm -rf modules.order
obj-m += xxx.o
第一行KERN_DIR表示内核源码目录,是指虚拟机中所放的与你使用的开发板上的linux版本相同的linux内核源码的位置,这种方法适用于嵌入式交叉编译的场合,意思是在使用交叉编译工具链编译时才采用这种写法。注意:在交叉编译驱动时,我们在make之前要将/home/development/linux-kernel-2.6.37这个目录下的源码先编译一边,这样才能顺利make并生成.ko文件。假如是在宿主机上开发和测试驱动则需要使用第2或3行的写法。不大明白?关于linux源码的目录有两个,分别"/lib/modules/$(shell uname -r)/build" 和"/usr/src/linux-header-$(shell uname -r)/",但如果编译过内核就会知道,usr目录下那个源代码一般是我们自己下载后解压的,而lib目录下的则是在编译时自动copy过去的,两者的文件结构完全一样,因此有时也将内核源码目录设置成/usr/src/linux-header-$(shell uname -r)/。关于内核源码目录可以根据自己的存放位置进行修改。shell uname -r会取得当前内核的版本号。
-C选项的作用是指将当前工作目录转移到你所指定的位置,当make的目标为all时,-C $( KERN_DIR) 指明跳转到内核源码目录下读取那里的Makefile。M=$(shell pwd)选项让该Makefile在构造modules目标之前返回到模块源代码目录,并在当前目录生成obj-m指定的xxx.o目标模块。shell pwd会取得当前工作路径。
clean这个目标表示将模块清理掉。
驱动用Makefile另一种写法:
ifneq ($(KERNELRELEASE),)
obj-m:=hello.o
else
#generate the path
CURRENT_PATH:=$(shell pwd)
#the absolute path
LINUX_KERNEL_PATH:=/lib/modules/$(shell uname -r)/build
#complie object
default:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean
endif
按照顺序分析以下make的执行步骤:在模块的源代码目录下执行make,此时,宏“KERNELRELEASE”没有定义,因此进入else。由于make 后面没有目标,所以make会在Makefile中的第一个不是以.开头的目标作为默认的目标执行。于是default成为make的目标。make会执行 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 。
-C 表示到存放内核的目录执行其makefile,在执行过程中会定KERNELRELEASE,
然后M=$(CURDIR)表示返回到当前目录,再次执行makefile,modules表示编译成模块的意思。而此时KERNELRELEASE已定义,则会执行obj-m += hello.o,表示会将hello.o目标编译成.ko模块。若有多个源文件,则采用如下方法:
obj-m := hello.o
hello-objs := file1.o file2.o file3.o
如果把hello模块移动到内核源代码中。例如放到/usr/src/linux/driver/中, KERNELRELEASE就有定义了。在/usr/src/linux/Makefile中有KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)$(LOCALVERSION)。这时候,hello模块也不再是单独用make编译,而是在内核中用make modules进行编译,此时驱动模块便和内核编译在一起。
应用程序Makefile编写方法:
例子:
编译helloworld.c
第一种方法:
使用gcc进行编译:gcc -o helloworld helloworld.c (要在开发板上运行的话需要arm-linux-gcc)
第二种方法:
编写makefile然后执行make命令进行编译。
helloworld : file1.o file2.o: //helloworld依赖file1.o file2.o两个目标文件。
gcc File1.o File2.o -o helloworld://编译出helloworld可执行文件。-o表示你指定 的目标文件名。
file1.o : file1.c: //file1.o依赖file1.c文件。
gcc -c file1.c -o file1.o: //编译出file1.o文件。-c表示gcc 只把给它的文件编译成目标文件, 用源码文件的文件名命名但把其后缀由“.c”或“.cc”变成“.o”。在这句中,可以省略-o file1.o,编译器默认生成file1.o文件,这就是-c的作用。
file2.o : file2.c file2.h
gcc -c file2.c -o file2.o
这两句和上两句相同。
clean:
rm -rf *.o helloworld
当用户键入make clean命令时,会删除*.o 和helloworld文件。
如果要编译cpp文件,只要把gcc改成g++就行了。
写好Makefile文件,在命令行中直接键入make命令,就会执行Makefile中的内容了。