makefile编写规则
在一个makefile中通常包含如下内容:
1 需要由make工具创建的目标体(target),通常是目标文件或可执行文件
2 要创建的目标体所依赖的文件(dependency_file)
3 创建每个目标体时需要运行的命令(command),这一行必须以制表符(tab键)开头
格式:
target: dependency_files
command /* 该行必须以tab键开头*/
例如,有两个文件分别为hello.c和hello.h,创建的目标体为hello.o,执行的命令为gcc编译指令:gcc –c hello.c,那么,对应的makefile就可以写为:
#The simplest example
hello.o: hello.c hello.h
gcc –c hello.c –o hello.o
执行:
[root@yunduan makefile]# make hello.o
gcc –c hello.c –o hello.o
[root@yunduan makefile]# ls
hello.c hello.h hello.o makefile
makefile变量
用户自定义变量:
makefile变量定义的两种方式:(使用格式为:$(VAR))
递归展开方式:能很好的完成用户指令,但变量后不可追加内容,可能造成无穷循环:定义格式:VAR=var
简单方式:变量的值在定义处展开,并且只展开一次,不包含任何对其他变量的引用:定义格式:VAR:=var
变量名:
变量名大小写敏感
推荐在makefile内部使用小写字母作为变量名,预留大写字母作为控制隐含规则参数或用户重载命令选项参数的变量名。
不包括“:”、“#”、“=”以及结尾空格的任何字符串,同时,变量名中包含字母、数字以及下划线以外的情况应尽量避免,因为它们可能在将来被赋予特别的含义
常见预定义变量:
AR 库文件维护程序的名称,默认值为ar
AS 汇编程序的名称,默认值为as
CC C编译器的名称,默认值为cc
CPP C预编译器的名称,默认值为$(CC) –E
CXX C++编译器的名称,默认值为g++
FC Fortran编译器的名称,默认值为f77
RM 文件删除程序的名称,默认值为rm –f
ARFLAGS 库文件维护程序的选项,无默认值
ASFLAGS 汇编程序的选项,无默认值
CFLAGS C编译器的选项,无默认值
CPPFLAGS C预编译的选项,无默认值
CXXFLAGS C++编译器的选项,无默认值
FFLAGS Fortran编译器的选项,无默认值
常见的自动变量:
$@ 目标文件的完整名称
$* 不包含扩展名的目标文件名称
$< 第一个依赖文件的名称
$% 如果目标是归档成员,则该变量表示目标的归档成员名称
$+ 所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件
$? 所有时间戳比目标文件晚的依赖文件,并以空格分开
$^ 所有不重复的依赖文件,以空格分开
在makefile中还可以使用环境变量。使用环境变量的方法相对比较简单,make 在启动时会自动读取系统当前已经定义了的环境变量,并且会创建与之具有相同名称和数值的变量。用户自定义变量会覆盖同名的环境变量。
makefile规则
隐式规则:只需把目标文件列出即可,make 会自动搜索隐式规则目录来确定如何生成目标文件,它只能查找到相同文件名的不同后缀名文件,如“kang.o”文件必须由“kang.c”文件生成
makefile中常见隐式规则目录
C编译: .c变为.o $(CC) –c $(CPPFLAGS) $(CFLAGS)
C++编译: .cc或.C变为.o $(CXX) -c $(CPPFLAGS) $(CXXFLAGS)
Pascal编译: .p变为.o $(PC) -c $(PFLAGS)
Fortran编译:.r变为-o $(FC) -c $(FFLAGS)
模式规则:用来定义相同处理规则的多个文件,隐式规则仅仅能够用make 默认的变量来进行操作,而模式规则还能引入用户自定义变量,为多个文件建立相同的规则,实用模式规则时相关文件前必须用“%”标明
例如:
david:kang.o yul.o
gcc kang.o bar.o -o myprog
kang.o : kang.c kang.h head.h
gcc –Wall –O -g –c kang.c -o kang.o
yul.o : bar.c head.h
gcc - Wall –O -g –c yul.c -o yul.o
修改后:(递归展开方式)
OBJS = kang.o yul.o
CC = gcc
CFLAGS = -Wall -O -g
david : $(OBJS)
$(CC) $(OBJS) -o david
kang.o : kang.c kang.h
$(CC) $(CFLAGS) -c kang.c -o kang.o
yul.o : yul.c yul.h
$(CC) $(CFLAGS) -c yul.c -o yul.o
改写后:(自动变量)
OBJS = kang.o yul.o
CC = gcc
CFLAGS = -Wall -O -g
david : $(OBJS)
$(CC) $^ -o $@
kang.o : kang.c kang.h
$(CC) $(CFLAGS) -c $< -o $@
yul.o : yul.c yul.h
$(CC) $(CFLAGS) -c $< -o $@
修改后:(隐式规则)
OBJS = kang.o yul.o
CC = gcc
CFLAGS = -Wall -O -g
david : $(OBJS)
$(CC) $^ -o $@
改写后:(模式规则)
OBJS = kang.o yul.o
CC = gcc
CFLAGS = -Wall -O -g
david : $(OBJS)
$(CC) $^ -o $@
%.o : %.c
$(CC) $(CFLAGS) -c $< -o $@
make命令的使用
只需在make命令的后面键入目标名即可建立指定的目标,如果直接运行make,则建立makefile中的第一个目标
make的命令行选项
-C dir 读入指定目录下的makefile
-f file 读入当前目录下的file文件作为makefile
-I 忽略所有的命令执行错误
-I dir 指定被包含的makefile所在目录
-n 只打印要执行的命令,但不执行这些命令
-p 显示make变量数据库和隐含规则
-s 在执行命令时不显示命令
-w 如果make在执行过程中改变目录,则打印当前目录名
autotools
生成makefile 同时又能拥有make的功能
which命令进行查看aclocal autoscan autoconf autoheader automake是否安装
vim hello.c
#include
int sum(int);
int main(){
printf("the sum of 1-50 is %d\n",sum(50));
}
int sum(int n){
int i,sum;
for(i = 1,sum = 0; i <= n; ++i){
sum += i;
}
return sum;
}
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.63)
#AC_INIT(FULL-PACKAGE-NAME,VERSION,BUG-REPORT-ADDRESS)
AC_INIT(hello,1.0)
AM_INIT_AUTOMAKE(hello,1.0)
AC_CONFIG_SRCDIR([hello.c])
AC_CONFIG_HEADER([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_CONFIG_FILES([makefile])
AC_OUTPUT
3.autoheader
接着使用autoheader 命令,它负责生成config.h.in 文件。该工具通常会从"acconfig.h"文件中复制用户附加的符号定义,因为这里没有附加符号定义,所以不需要创建"acconfig.h"文件
4 aclocal
使用aclocal生成一个"aclocal.m4"文件,该文件主要处理本地的宏定义
5.automake
这一步是创建makefile 很重要的一步,automake 要用的脚本配置文件是makefile.am,用户需要自己创建相应的文件。之后,automake工具转换成makefile.in。
AUTOMAKE_OPTIONS=foreign
bin_PROGRAMS= hello
hello_SOURCES= hello.c
[root@yunduan automake]# autoscan
[root@yunduan automake]# ls
autoscan.log configure.scan hello.c
[root@yunduan automake]# vim configure.scan
[root@yunduan automake]# mv configure.scan configure.in
[root@yunduan automake]# ls
autoscan.log configure.in hello.c
[root@yunduan automake]# autoheader
[root@yunduan automake]# ls
autom4te.cache autoscan.log config.h.in configure.in hello.c
[root@yunduan automake]# aclocal
[root@yunduan automake]# ls
aclocal.m4 autom4te.cache autoscan.log config.h.in configure.in hello.c
[root@yunduan automake]# vim makefile.am
[root@yunduan automake]# automake -a
configure.in:6: installing `./install-sh'
configure.in:6: installing `./missing'
makefile.am: installing `./depcomp'
[root@yunduan automake]# ls
aclocal.m4 autom4te.cache autoscan.log config.h.in configure.in depcomp hello.c install-sh makefile.am makefile.in missing
[root@yunduan automake]# autoconf
[root@yunduan automake]# ls
aclocal.m4 autom4te.cache autoscan.log config.h.in configure configure.in depcomp hello.c install-sh makefile.am makefile.in missing
[root@yunduan automake]# ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for gcc... gcc
checking for C compiler default output file name... a.out
checking whether the C compiler works... yes
checking whether we are cross compiling... no
checking for suffix of executables...
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking for style of include used by make... GNU
checking dependency style of gcc... gcc3
configure: creating ./config.status
config.status: creating makefile
config.status: creating config.h
config.status: executing depfiles commands
[root@yunduan automake]# ls
aclocal.m4 autoscan.log config.h.in config.status configure.in hello.c makefile makefile.in stamp-h1
autom4te.cache config.h config.log configure depcomp install-sh makefile.am missing
[root@yunduan automake]# cat makefile