makefile编程
⑴ 如何调试makefile
调试makefile的步骤如下,
一、make的退出码
make命令执行后有三个退出码:
0 —— 表示成功执行。
1 —— 如果make运行时出现任何错误,其返回1。
2 —— 如果你使用了make的“-q”选项,并且make使得一些目标不需要更新,那么返回2。
Make的相关参数我们会在后续章节中讲述。
二、指定Makefile
前面我们说过,GNU make找寻默认的Makefile的规则是在当前目录下依次找三个文件——“GNUmakefile”、“makefile”和“Makefile”。其按顺序找这三个文件,一旦找到,就开始读取这个文件并执行。
当前,我们也可以给make命令指定一个特殊名字的Makefile。要达到这个功能,我们要使用make的“-f”或是“--file”参数(“--makefile”参数也行)。例如,我们有个makefile的名字是“hchen.mk”,那么,我们可以这样来让make来执行这个文件:
make –f hchen.mk
如果在make的命令行是,你不只一次地使用了“-f”参数,那么,所有指定的makefile将会被连在一起传递给make执行。
三、指定目标
一般来说,make的最终目标是makefile中的第一个目标,而其它目标一般是由这个目标连带出来的。这是make的默认行为。当然,一般来说,你的makefile中的第一个目标是由许多个目标组成,你可以指示make,让其完成你所指定的目标。要达到这一目的很简单,需在make命令后直接跟目标的名字就可以完成(如前面提到的“make clean”形式)
任何在makefile中的目标都可以被指定成终极目标,但是除了以“-”打头,或是包含了“=”的目标,因为有这些字符的目标,会被解析成命令行参数或是变量。甚至没有被我们明确写出来的目标也可以成为make的终极目标,也就是说,只要make可以找到其隐含规则推导规则,那么这个隐含目标同样可以被指定成终极目标。
四、检查规则
让的makefile中的规则执行起来,检查一下我们的命令,或是执行的序列。于是可以使用make命令的下述参数:
“-n”
“--just-print”
“--dry-run”
“--recon”
不执行参数,这些参数只是打印命令,不管目标是否更新,把规则和连带规则下的命令打印出来,但不执行,这些参数对于我们调试makefile很有用处。
“-t”
“--touch”
这个参数的意思就是把目标文件的时间更新,但不更改目标文件。也就是说,make假装编译目标,但不是真正的编译目标,只是把目标变成已编译过的状态。
五、make的参数
下面列举了所有GNU make 3.80版的参数定义。其它版本和产商的make大同小异,不过其它产商的make的具体参数还是请参考各自的产品文档。
“-b”
“-m”
这两个参数的作用是忽略和其它版本make的兼容性。
“-B”
“--always-make”
认为所有的目标都需要更新(重编译)。
⑵ 用makefile编辑的文件怎么编译
我们在linux下进行编程的时候,会发现我们没有工程文件,然后,我们在不同目录下
的文件如此杂乱无章,让我们感到头疼,怎么可以把它们进行同步在一起,然后,一起进行编译呢,
这里,就是我们需要用到的工具了,makefile文件的作用了,makefile可以有效地组织文件和目录,
把处于不同目录下的文件进行同时编译,而不会因为目录的不同,而有所差别。
这里,我来分享一下makefile的简单的用法。
1:基本的格式:
magproc:magproc.o dbproc.o
$(EC) -o $(BINPATH)/$@ $? $(LIB)
可执行文件名:链接文件
编译工具 (参数) (链接库) 文件名
2:工程文件Make.defines
3:makefile文件
http://jingyan..com/article/48206aeaf9e82e216ad6b335.html
⑶ 如何调试makefile
makefile 的调试有点像魔法。可惜,并不存在makefile 调试器之类的东西可用来查看特定规则是如何被求值的,或某个变量是如何被扩展的。相反,大部分的调试过程只是在执
行输出的动作以及查看makefile。事实上,GNU make 提供了若干可以协助调试的内置函数以及命令行选项。
用来调试makefile 的一个最好方法就是加入调试挂钩以及使用具保护的编程技术,让你能够在事情出错时恢复原状。我将会介绍若干基本的调试技术以及我所发现的最有用的具保
护能力的编码习惯。
1.make 的调试功能
warning函数非常适合用来调试难以捉摸的makefile。因为warning函数会被扩展成空字符串,所以它可以放在makefile 中的任何地方:开始的位置、工作目标或必要条件列表中以
及命令脚本中。这让你能够在最方便查看变量的地方输出变量的值。例如:
$(warning A top-level warning)
FOO := $(warning Right-hand side of a simple variable)bar
BAZ = $(warning Right-hand side of a recursive variable)boo
$(warning A target)target: $(warning In a prerequisite list)makefile
$(BAZ)
$(warning In a command script)
ls
$(BAZ):
这会产生如下的输出:
$ make
makefile:1: A top-level warning
makefile:2: Right-hand side of a simple variable
makefile:5: A target
makefile:5: In a prerequisite list
makefile:5: Right-hand side of a recursive variable
makefile:8: Right-hand side of a recursive variable
makefile:6: In a command script
ls
makefile
请注意,warning函数的求值方式是按照make标准的立即和延后求值算法。虽然对BAZ的赋值动作中包含了一个warning函数,但是直到BAZ在必要条件列表中被求值后,这个信息才
会被输出来。
“可以在任何地方安插warning调用”的这个特性,让它能够成为一个基本的调试工具。
2.命令行选项
我找到了三个最适合用来调试的命令行选项:
--just-print(-n)
--print-database(-p)
--warn-undefined-variables。
2.1 --just-print
在一个新的makefile 工作目标上,我所做的第一个测试就是以--just-print(-n)选项来调用make。这会使得make读进makefile并且输出它更新工作目标时将会执行的命令,但是
不会真的执行它们。GNU make 有一个方便的功能,就是允许你为将被输出的命令标上安静模式修饰符(@)。
这个选项被假设可以抑制所有命令的执行动作,然而这只在特定的状况下为真。实际上,你必须小心以对。尽管make不会运行命令脚本,但是在立即的语境之中,它会对shell函数
调用进行求值动作。例如:
REQUIRED_DIRS = ...
_MKDIRS := $(shell for d in $(REQUIRED_DIRS); \
do \
[[ -d $$d ]] || mkdir -p $$d; \
done)
$(objects) : $(sources)
正如我们之前所见,_MKDIRS 简单变量的目的是触发必要目录的创建动作。如果这个makefile 是以--just-print 选项的方式运行的,那么当make 读进makefile 时,shell命令将
会一如往常般被执行。然后,make 将会输出(但不会执行)更新$(objects)文件列表所需要进行的每个编译命令。
2.2 --print-data-base
--print-data-base(-p)是另一个你常会用到的选项。它会运行makefile,显示GNU版权信息以及make 所运行的命令,然后输出它的内部数据库。数据库里的数据将会依种类划分
成以下几个组:variables、directories、implicit rules、pattern-specific variables、files(explicit rules)以及vpath earch path。如下所示:
# GNU Make 3.80
# Copyright (C) 2002 Free Software Foundation, Inc.
# This is free software; see the source for ing conditions.
# There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
正常的命令将会在此处执行
# Make data base, printed on Thu Apr 29 20:58:13 2004
# Variables
...
# Directories
...
# Implicit Rules
...
# Pattern-specific variable values
...
# Files
...
# VPATH Search Paths
让我们更详细地查看以上这几个区段。
变量区段(variable)将会列出每个变量以及具描述性的注释:
# automatic
<D = $(patsubst %/,%,$(dir $<))
# environment
EMACS_DIR = C:/usr/emacs-21.3.50.7
# default
CWEAVE = cweave
# makefile (from `../mp3_player/makefile', line 35)
CPPFLAGS = $(addprefix -I ,$(include_dirs))
# makefile (from `../ch07-separate-binaries/makefile', line 44)
RM := rm -f
# makefile (from `../mp3_player/makefile', line 14)
define make-library
libraries += $1
sources += $2
$1: $(call source-to-object,$2)
$(AR) $(ARFLAGS) $$@ $$^
endef
自动变量不会被显示出来,但是通过它们可以方便变量的获得,像$(<D)。注释所指出的是origin 函数所返回的变量类型(参见“较不重要的杂项函数”一节)。如果变量被定义
在一个文件中,则会在注释中指出其文件名以及该定义所在的行号。简单变量和递归变量的差别在于赋值运算符。简单变量的值将会被显示成右边部分被求值的形式。
下一个区段标示为Directories,它对make 开发人员比对make 用户有用。它列出了将会被make 检查的目录,包括可能会存在的SCCS 和RCS 子目录,但它们通常不存在。对每个目
录来说,make 会显示实现细节,比如设备编号、inode 以及文件名模式匹配的统计数据。
接着是Implicit Rules 区段。这个区段包含了make 数据库中所有的内置的和用户自定义的模式规则。此外,对于那些定义在文件中的规则,它们的注释将会指出文件名以及行号
:
%.c %.h: %.y
# commands to execute (from `../mp3_player/makefile', line 73):
$(YACC.y) --defines $<
$(MV) y.tab.c $*.c
$(MV) y.tab.h $*.h
%: %.c
# commands to execute (built-in):
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.c
# commands to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<
查看这个区段,是让你能够熟悉make 内置规则的变化和结构的最佳方法。当然,并非所有的内置规则都会被实现成模式规则。如果你没有找到你想要的规则,可以查看Files区段
,旧式后缀规则就列在该处。
下一个区段被标示为Pattern-specific variables,此处所列出的是定义在makefile 里的模式专属变量。所谓模式专属变量,就是变量定义的有效范围被限定在相关的模式规则执
行的时候。例如,模式变量YYLEXFLAG 被定义成:
%.c %.h: YYLEXFLAG := -d
%.c %.h: %.y
$(YACC.y) --defines $<
$(MV) y.tab.c $*.c
$(MV) y.tab.h $*.h
将会被显示成:
# Pattern-specific variable values
%.c :
# makefile (from `Makefile', line 1)
# YYLEXFLAG := -d
# variable set hash-table stats:
# Load=1/16=6%, Rehash=0, Collisions=0/1=0%
%.h :
# makefile (from `Makefile', line 1)
# YYLEXFLAG := -d
# variable set hash-table stats:
# Load=1/16=6%, Rehash=0, Collisions=0/1=0%
# 2 pattern-specific variable values
接着是Files 区段,此处所列出的都是与特定文件有关的自定义和后缀规则:
# Not a target:
.p.o:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(COMPILE.p) $(OUTPUT_OPTION) $<
lib/ui/libui.a: lib/ui/ui.o
# Implicit rule search has not been done.
# Last modified 2004-04-01 22:04:09.515625
# File has been updated.
# Successfully updated.
# commands to execute (from `../mp3_player/lib/ui/mole.mk', line 3):
ar rv $@ $^
lib/codec/codec.o: ../mp3_player/lib/codec/codec.c ../mp3_player/lib/codec/codec.c ../mp3_player/include/codec/codec.h
# Implicit rule search has been done.
# Implicit/static pattern stem: `lib/codec/codec'
# Last modified 2004-04-01 22:04:08.40625
# File has been updated.
# Successfully updated.
# commands to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<
中间文件与后缀规则会被标示为Not a target,其余是工作目标。每个文件将会包含注释,用以指出make 是如何处理此规则的。被找到的文件在被显示的时候将会通过标准的
vpath 搜索来找出其路径。
最后一个区段被标示为VPATH Search Paths,列出了VPATH 的值以及所有的vpath模式。
对于大规模使用eval 以及用户自定义函数来建立复杂的变量和规则的makefile 来说,查看它们的输出结果通常是确认宏是否已被扩展成预期值的唯一方法。
2.3 --warn-undefined-variables
这个选项会使得make 在未定义的变量被扩展时显示警告信息。因为未定义的变量会被扩展成空字符串,这常见于变量名称打错而且很长一段时间未被发现到。这个选项有个问题,
这也是为什么我很少使用这个选项的原因,那就是许多内置规则都会包含未定义的变量以作为用户自定义值的挂钩。所以使用这个选项来运行make必然会产生许多不是错误的警告
信息,而且对用户的makefile 没有什么用处。例如:
$ make --warn-undefined-variables -n
makefile:35: warning: undefined variable MAKECMDGOALS
makefile:45: warning: undefined variable CFLAGS
makefile:45: warning: undefined variable TARGET_ARCH
...
makefile:35: warning: undefined variable MAKECMDGOALS
make: warning: undefined variable CFLAGS
make: warning: undefined variable TARGET_ARCH
make: warning: undefined variable CFLAGS
make: warning: undefined variable TARGET_ARCH
...
make: warning: undefined variable LDFLAGS
make: warning: undefined variable TARGET_ARCH
make: warning: undefined variable LOADLIBES
make: warning: undefined variable LDLIBS
不过,此命令在需要捕获此类错误的某些场合上可能非常有用。
3.--debug 选项
当你需要知道make 如何分析你的依存图时,可以使用--debug 选项。除了运行调试器,这个选项是让你获得最详细信息的另一个方法。你有五个调试选项以及一个修饰符可用,分
别是:basic、verbose、implicit、jobs、all 以及makefile。
如果调试选项被指定成--debug,就是在进行basic 调试;如果调试选项被指定成-d,就是在进行all调试;如果要使用选项的其他组合,则可以使用--debug=option1,option2 这
个以逗号为分隔符的列表,此处的选项可以是下面任何一个单词(实际上,make 只会查看第一个字母):
⑷ 如何编写makefile
你先用gcc把它给编译出来。然后再想用makefile
gcc最一般的用法就是:
gcc -o 要生成的可执行文件名 源代码文件名
如:gcc -o hello.x hello.c
如果一些头文件要指明的话,可以这样:
gcc -o hello.x -I头文件所在的文件夹 -l一些库名 hello.c
最通常,我们用到一些数学库。gcc -o hello.x -lm hello.c
makefile的话,你可以基于上述的语句进行修改:建议你看点资料,或一些典型的例子。但是注意的是规则那一行,得用Tab键打头。
hello.x : hello.o
gcc -o hello.x hello.o (这一行,得用Tab打头)
hello.o : hello.c 头文件
gcc -c hello.o hello.c -I头文件所在目录 -lm (这一行,得用Tab打头)
⑸ unix高级环境编程 makefile 怎么使用
创建一个makefile文件。
然后根据makefile的规则编写编译规则。
使用命令make all,编译所有。
⑹ Linux平台Makefile文件的编写基础篇
目的:
基本掌握了 make 的用法,能在Linux系统上编程。
环境:
Linux系统,或者有一台Linux服务器,通过终端连接。一句话:有Linux编译环境。
准备:
准备三个文件:file1.c, file2.c, file2.h
file1.c:
#include
#include "file2.h"
int main()
{
printf("print file1$$$$$$$$$$$$ ");
File2Print();
return 0;
}
file2.h:
#ifndef FILE2_H_
#define FILE2_H_
#ifdef __cplusplus
extern "C" {
#endif
void File2Print();
#ifdef __cplusplus
}
#endif
#endif
file2.c:
#include "file2.h"
void File2Print()
{
printf("Print file2********************** ");
}
基础:
先来个例子:
有这么个Makefile文件。(文件和Makefile在同一目录)
=== makefile 开始 ===
helloworld:file1.o file2.o
gcc file1.o file2.o -o helloworld
file1.o:file1.c file2.h
gcc -c file1.c -o file1.o
file2.o:file2.c file2.h
gcc -c file2.c -o file2.o
clean:
rm -rf *.o helloworld
=== makefile 结束 ===
一个 makefile 主要含有一系列的规则,如下:
A: B
(tab)
(tab)
每个命令行前都必须有tab符号。
上面的makefile文件目的就是要编译一个helloworld的可执行文件。让我们一句一句来解释:
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中的内容了。
到这步我想你能编一个Helloworld程序了。
上一层楼:使用变量
上面提到一句,如果要编译cpp文件,只要把gcc改成g++就行了。但如果Makefile中有很多gcc,那不就很麻烦了。
第二个例子:
=== makefile 开始 ===
OBJS = file1.o file2.o
CC = gcc
CFLAGS = -Wall -O -g
helloworld : $(OBJS)
$(CC) $(OBJS) -o helloworld
file1.o : file1.c file2.h
$(CC) $(CFLAGS) -c file1.c -o file1.o
file2.o : file2.c file2.h
$(CC) $(CFLAGS) -c file2.c -o file2.o
clean:
rm -rf *.o helloworld
=== makefile 结束 ===
这里我们应用到了变量。要设定一个变量,你只要在一行的开始写下这个变量的名字,后 面跟一个 = 号,后面跟你要设定的这个变量的值。以后你要引用 这个变量,写一个 $ 符号,后面是围在括号里的变量名。
CFLAGS = -Wall -O –g,解释一下。这是配置编译器设置,并把它赋值给CFFLAGS变量。
-Wall: 输出所有的警告信息。
-O: 在编译时进行优化。
-g: 表示编译debug版本。
这样写的Makefile文件比较简单,但很容易就会发现缺点,那就是要列出所有的c文件。如果你添加一个c文件,那就需要修改Makefile文件,这在项目开发中还是比较麻烦的。
再上一层楼:使用函数
学到这里,你也许会说,这就好像编程序吗?有变量,也有函数。其实这就是编程序,只不过用的语言不同而已。
第三个例子:
=== makefile 开始 ===
CC = gcc
XX = g++
CFLAGS = -Wall -O –g
TARGET = ./helloworld
%.o: %.c
$(CC) $(CFLAGS) -c lt; -o [email protected]
%.o:%.cpp
$(XX) $(CFLAGS) -c lt; -o [email protected]
SOURCES = $(wildcard *.c *.cpp)
OBJS = $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES)))
$(TARGET) : $(OBJS)
$(XX) $(OBJS) -o $(TARGET)
chmod a+x $(TARGET)
clean:
rm -rf *.o helloworld
=== makefile 结束 ===
函数1:wildcard
产生一个所有以 '.c' 结尾的文件的列表。
SOURCES = $(wildcard *.c *.cpp)表示产生一个所有以 .c,.cpp结尾的文件的列表,然后存入变量 SOURCES 里。
函数2:patsubst
匹配替换,有三个参数。第一个是一个需要匹配的式样,第二个表示用什么来替换它,第三个是一个需要被处理的由空格分隔的列表。
OBJS = $(patsubst %.c,%.o,$(patsubst %.cc,%.o,$(SOURCES)))表示把文件列表中所有的.c,.cpp字符变成.o,形成一个新的文件列表,然后存入OBJS变量中。
%.o: %.c
$(CC) $(CFLAGS) -c lt; -o [email protected]
%.o:%.cpp
$(XX) $(CFLAGS) -c lt; -o [email protected]
这几句命令表示把所有的.c,.cpp编译成.o文件。
这里有三个比较有用的内部变量。 [email protected] 扩展成当前规则的目的文件名, lt; 扩展成依靠 列表中的第一个依靠文件,而 $^ 扩展成整个依靠的列表(除掉了里面所有重 复的文件名)。
chmod a+x $(TARGET)表示把helloworld强制变成可执行文件。
⑺ Makefile 到底是什么
首先要知道什么是编译,然后要知道命令行编译,然后什么是依赖,
make就是为了解决命令行编译时的依赖的自动化编译工具,makefile是make的参数,告诉make具体的依赖关系
举个例子,编程相当于做饭,你可以像美食家一样做得很有艺术,也可以像工厂流水线一样自动化,命令行编译就是流水线,先后顺序就是依赖关系,makefile就是菜谱,菜谱里说清楚了一个菜由哪些步骤组成
⑻ 什么是makefile
这里简单说一下,更多细节可以去找一些深入的材料去了解。make一般主要被用来管理一个软件程序项目(用来完成大型软件的自动编译),但是它不仅仅可以用来管理软件程序,还可以做很多其他的事情,比如文件同步等。makefile是被make使用的“描述”文件,它描述要被make所管理的项目中的文件间的关系(比如对于一个C程序项目来说,.h文件和.c文件之间的关系,.c和.o之间的关系等),和如何维护这个项目的状态(比如对于一个程序项目来说,就有编译可执行文件,产生文档,清除所有除源代码文件之外的文件等).脚本是和make/makefile没有任何关系的,就是一种编程语言,一般都是解释型的编程语言,好处是容易开发,写完就能用,不需要编译,多用于系统维护等。
⑼ make makefile cmake qmake都是什么,有什么区别
1. make 是用来执行Makefile的。
2. Makefile是类unix环境下(比如Linux)的类似于批处理的"脚本"文件。其基本语法是: 目标+依赖+命令,只有在目标文件不存在,或目标比依赖的文件更旧,命令才会被执行。由此可见,Makefile和make可适用于任意工作,不限于编程。比如,可以用来管理latex。
3. Makefile+make可理解为类unix环境下的项目管理工具,但它太基础了,抽象程度不高,而且在windows下不太友好(针对visual studio用户),于是就有了跨平台项目管理工具cmake
4. cmake是跨平台项目管理工具,它用更抽象的语法来组织项目。虽然,仍然是目标,依赖之类的,但更为抽象和友好,比如可用math表示数学库,而不需要再具体指定到底是math.dll还是libmath.so,在windows下它会支持生成visual studio的工程,在linux下它会生成Makefile,甚至它还能生成eclipse工程文件。也就是说,从同一个抽象规则出发,它为各个编译器定制工程文件。
5. cmake是抽象层次更高的项目管理工具,cmake命令执行的CMakeLists.txt文件
6. qmake是Qt专用的项目管理工具,对应的工程文件是*.pro,在Linux下面它也会生成Makefile,当然,在命令行下才会需要手动执行qmake,完全可以在qtcreator这个专用的IDE下面打开*.pro文件,使用qmake命令的繁琐细节不用管了。
总结一下,make用来执行Makefile,cmake用来执行CMakeLists.txt,qmake用来处理*.pro工程文件。Makefile的抽象层次最低,cmake和qmake在Linux等环境下最后还是会生成一个Makefile。cmake和qmake支持跨平台,cmake的做法是生成指定编译器的工程文件,而qmake完全自成体系。
⑽ 写个makefile就这么难,该怎么解决
UNIX/Linux 系统下面的 make 工具,主要用来解决多个 C 语言源程序之间的编译与连接问题。它的最大好处就是:当 C 语言源程序很多时,如果只有其中一个源程序作了修改,而其它的所有源程序未作任何修改,那么只要对这一个源程序进行编译,然后再与其它程序的目标文件(*.o)进行连接即可,非常节约时间。其实不是写 makefile 文件难,而是必须要按照一定的规范来书写 makefile 文件。而在编辑 makefile 的过程中,被编译、连接的文件的先后次序是最、最重要的。如果先后次序写反了,那么肯定是不能够达到预期的目的的。至于说如何把 makefile 文件写得非常自如,那就需要有丰富的多模块编程经验了。