Makefile写法总结

       使用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文件。假如是在宿主机上开发和测试驱动则需要使用第23行的写法。不大明白?关于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中的内容了。

猜你喜欢

转载自blog.csdn.net/hahaha_2017/article/details/81269266
今日推荐