Makefile

  • 什么是Makefile?
  • Makefile结构说明
  • Makefile的优点
  • Makefile的工作流程
  • Makefile基本语法
  • Makefile中CFLAGS,LDFLAGS,LIBS的说明
  • Makefile中的缩进
  • Makefile 静态模式 %.o:%.c
  • Makefile 赋值语句 =,:=,?=,+= 符号的含义
  • Makefile 符号@ - $ $$含义
  • Makefile ifeq、ifneq、ifdef和ifndef(条件判断)
  • Makefile 通配符
  • Makefile 内嵌变量 $(CURDIR) $0 $1 $2 $#
  • Makefile中的常见自动变量$@, $^, $< , $?, $%, $+, $*
  • Makefile示例
  • Makefile中.PHONY和.SUFFIXES的含义
  • Makefile中patsubst(扩展通配符)的含义
  • Makefile模版

什么是Makefile?

Makefile 可以简单的认为是一个工程文件的编译规则,描述了整个工程的编译和链接等规则。其中包含了那些文件需要编译,那些文件不需要编译,那些文件需要先编译,那些文件需要后编译,那些文件需要重建等等。编译整个工程需要涉及到的,在 Makefile 中都可以进行描述。换句话说,Makefile 可以使得我们的项目工程的编译变得自动化,不需要每次都手动输入一堆源文件和参数。
以 Linux 下的C语言开发为例来具体说明一下,多文件编译生成一个文件,编译的命令如下所示:
gcc -o outfile name1.c name2.c ... outfile 要生成的可执行程序的名字,nameN.c 是源文件的名字。这是我们在 Linux 下使用 gcc 编译器编译 C 文件的例子。如果我们遇到的源文件的数量不是很多的话,可以选择这样的编译方式。如果源文件非常的多的话,就会遇到下面的这些问题。


1) 编译的时候需要链接库的的问题。拿C语言来说,编译的时候 gcc 只会默认链接一些基本的C语言标准库,很多源文件依赖的标准库都需要我们手动链接。
下面列举了一些需要我们手动链接的标准库:
name1.c 用到了数学计算库 math 中的函数,我们得手动添加参数 -Im;
name4.c 用到了小型数据库 SQLite 中的函数,我们得手动添加参数 -lsqlite3;
name5.c 使用到了线程,我们需要去手动添加参数 -lpthread。
因为有很多的文件,还要去链接很多的第三方库。所以在编译的时候命令会很长,并且在编译的时候我们可能会涉及到文件链接的顺序问题,所以手动编译会很麻烦。
如果我们学会使用 Makefile 就不一样了,它会彻底简化编译的操作。把要链接的库文件放在 Makefile 中,制定相应的规则和对应的链接顺序。这样只需要执行 make 命令,工程就会自动编译。每次想要编译工程的时候就执行 make ,省略掉手动编译中的参数选项和命令,非常的方便。

2) 编译大的工程会花费很长的时间。
如果我们去做项目开发,免不了要去修改工程项目的源文件,每次修改后都要去重新编译。一个大的工程项目可不止有几个的源文件,里面的源文件个数可能有成百上千个。例如一个内核,或者是一个软件的源码包。这些都是我们做开发经常会遇到的。要完成这样的文件的编译,我们消耗的时间可不是一点点。如果文件特别大的话我们可能要花上半天的时间。
对于这样的问题我们 Makefile 可以解决吗?当然是可以的,Makefile 支持多线程并发操作,会极大的缩短我们的编译时间,并且当我们修改了源文件之后,编译整个工程的时候,make 命令只会编译我们修改过的文件,没有修改的文件不用重新编译,也极大的解决了我们耗费时间的问题。
这其实是我们遇到的比较常见的问题,当然可能遇到的问题还会有很多,比如:工程文件中的源文件的类型很多,编译的话需要选择的编译器;文件可能会分布在不同的目录中,使用时需要调价路径。这些问题都可以通过 Makefile 解决。并且文件中的 Makefile 只需要完成一次,一般我们只要不增加或者是删除工程中的文件,Makefile 基本上不用去修改,编译时只用一个 make 命令。为我们提供了极大的便利,很大程度上提高编译的效率。

Makefile结构说明

Makefile里主要包含了五个东西:变量定义、显式规则、隐晦规则、文件指示和注释。
1、变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点像C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。
2、显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。 刚才写的疑似shell脚本的Makefile全部都是显示规则。
3、隐晦规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。
4、文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样。
5、注释。Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。如果你要在你的Makefile中使用“#”字符。

Makefile的优点

  • 管理代码的编译,决定该编译什么文件,编译顺序,以及是否需要重新编译;
  • 节省编译时间。如果文件有更改,只需重新编译此文件即可,无需重新编译整个工程;
  • 一劳永逸。Makefile通常只需编写一次,后期就不用过多更改。

Makefile的工作流程

我们推荐使用 Makefile(一般在工程中都这么写,大写的会比较的规范)。如果文件不存在,make 就会给我们报错,提示:
make:*** 没有明确目标并且找不到 makefile。停止
Makefile的工流程
Makefile 的具体工作流程可以通过例子来看一下:创建一个包含有多个源文件和 Makefile 的目录文件,源文件之间相互关联。在 Makefile 中添加下面的代码:

main:main.o test1.o test2.o
gcc main.o test1.o test2.o -o main
main.o:main.c test.h
gcc -c main.c -o main.o
test1.o:test1.c test.h
gcc -c test1.c -o test1.o
test2.o:test2.c test.h
gcc -c test2.c -o test2.o


在我们编译项目文件的时候,默认情况下,make 执行的是 Makefile 中的第一规则(Makefile 中出现的第一个依赖关系),此规则的第一目标称之为“最终目标”或者是“终极目标”。
在 shell 命令行执行的 make 命令,就可以得到可执行文件 main 和中间文件 main.o、test1.o 和 test2.o,main 就是我们要生成的最终文件。通过 Makefile 我们可以发现,目标 main"在 Makefile 中是第一个目标,因此它就是 make 的终极目标,当修改过任何 C 文件后,执行 make 将会重建终极目标 main。
它的具体工作顺序是:当在 shell 提示符下输入 make 命令以后。 make 读取当前目录下的 Makefile 文件,并将 Makefile 文件中的第一个目标作为其执行的“终极目标”,开始处理第一个规则(终极目标所在的规则)。在我们的例子中,第一个规则就是目标 “main” 所在的规则。规则描述了 “main” 的依赖关系,并定义了链接 “.o” 文件生成目标 “main” 的命令;make 在执行这个规则所定义的命令之前,首先处理目标 “main” 的所有的依赖文件(例子中的那些 “.o” 文件)的更新规则(以这些 “.o” 文件为目标的规则)。
对这些 “.o” 文件为目标的规则处理有下列三种情况:
目标 “.o” 文件不存在,使用其描述规则创建它;
目标 “.o” 文件存在,目标 “.o” 文件所依赖的 “.c” 源文件 “.h” 文件中的任何一个比目标 “.o” 文件“更新”(在上一次 make 之后被修改)。则根据规则重新编译生成它;
目标 “.o” 文件存在,目标 “.o” 文件比它的任何一个依赖文件(“.c” 源文件、“.h” 文件)“更新”(它的依赖文件在上一次 make 之后没有被修改),则什么也不做。
通过上面的更新规则我们可以了解到中间文件的作用,也就是编译时生成的 “.o” 文件。作用是检查某个源文件是不是进行过修改,最终目标文件是不是需要重建。我们执行 make 命令时,只有修改过的源文件或者是不存在的目标文件会进行重建,而那些没有改变的文件不用重新编译,这样在很大程度上节省时间,提高编程效率。小的工程项目可能体会不到,项目工程文件越大,效果才越明显。
当然 make 命令能否顺利的执行,还在于我们是否制定了正确的的依赖规则,当前目录下是不是存在需要的依赖文件,只要任意一点不满足,我们在执行 make 的时候就会出错。所以完成一个正确的 Makefile 不是一件简单的事情。


Makefile基本语法

target(目标文件) ...: prerequisites(依赖的文件) ... command(命令) ... ...指令:屏蔽指令
#定义变量(变量大写)
变量名=值1 值2 ...
#使用变量 $(变量名)

Makefile中CFLAGS,LDFLAGS,LIBS的说明

CFLAGS:
C编译器选项,而CPPFLAG/CXXFLAGS表示C++编译器的选项.
目的:输出文件名称,可调试,编译告警,指定头文件目录.

LDFLAGS:
链接器从哪里寻找库文件,围绕着编译时使用的库文件,添加库文件的路径
LIBS:
告诉链接器要链接哪些库文件,如LIBS = -lpthread,-lm(链接线程库和数学库)


有关具体参数可查看gcc编译选项


Makefile中的缩进

makefile中有两种不同的语言,shell语法(recipe)和makefile语法(non-recipe),为了区分这两种语言所以使用tab。以tab开头的是shell(recipe)。

  • 在写makefile语法,非recipe的时候,缩进应该使用空格。
  • 在写shell语法,recipe时,缩进使用TAB。因为实际上我们写的是希望shell执行的语句,所以使用的是shell syntax。而make识别recipe的方式就是。

Makefile 静态模式 %.o:%.c

静态模式可以更加容易地定义多目标的规则,可以让我们的规则变得更加的有弹性和灵活。
语法:

<targets ...>: <target-pattern>: <prereq-patterns ...><commands>
...

如果我们的定义成“%.o”,意思是我们的集合中都是以“.o”结尾的,而如果我们的定义成“%.c”,
意思是对所形成的目标集进行二次定义,其计算方法是,取模式中的“%”(也就是去掉了[.o]这个结尾),
并为其加上[.c]这个结尾,形成的新集合。所以,我们的“目标模式”或是“依赖模式”中都应该有“%”这个字符。


Makefile 赋值语句 =,:=,?=,+= 符号的含义

  • =
    最简单的赋值.用=赋值的变量,在被解析时他的值取决于最后一次赋值时的值,所以你看变量引用的值时不能只往前面看,还要往后面看。
  • :=
    最简单的赋值.用:=来赋值的,则是就地直接解析 ,只用往前看即可。
  • ?=
    ?=如果变量前面并没有赋值过则执行这条赋值,如果前面已经赋值过了则本行被忽略 。(实验可以看出:所谓的没有赋值过其实就是这个变量没有被定义过)
  • +=
    +=用来给一个已经赋值的变量接续赋值,意思就是把这次的值加到原来的值的后面 ,有点类似于strcat。(在shell makefile等文件中,可以认为所有变量都是字符串,+=就相当于给字符串stcat接续内容)(注意一个细节,+=续接的内容和原来的内容之间会自动加一个空格隔开)

Makefile 符号@ - $ $$含义

  • @(用于静默执行)
#示例
DIR_OBJ=./obj
CMD_MKOBJDIR=if [ -d ${DIR_OBJ} ]; then exit 0; else
mkdir ${DIR_OBJ}; fimkobjdir:
@${CMD_MKOBJDIR}
#命令行执行如下: make mkobjdir
#此时不会显示在命令行不会显示出if [ -d ${DIR_OBJ} ]; then exit 0; else mkdir ${DIR_OBJ}; fi,
#但如果规则行的TAB后没有以@开头,则会显示
  • -
    这个符串通常用在“规则”行中,表示不显示命令本身,而只显示它的结果
    -rm dir; -mkdir aaadir;
  • $
    美元符号$,主要扩展打开makefile中定义的变量
  • $$
    $$ 符号主要扩展打开makefile中定义的shell变量

Makefile ifeq、ifneq、ifdef和ifndef(条件判断)

#ifeq 表示如果比较相等,语法如下:ifeq(<参数 1>, <参数 2>) #ifneq 表示如果不相等,语法如下: ifneq(<参数 1>, <参数 2>) #ifdef 表示如果定义了变量,语法如下:  ifdef <变量名> #ifndef 表示如果没有定义变量,语法如下:  ifndef <变量名>

Makefile 通配符

$*   #不包含扩展名的目标文件名称。$+   #所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件。$<   #第一个依赖文件的名称。$?   #所有的依赖文件,以空格分开,这些依赖文件的修改日期比目标的创建日期晚。$@    #目标的完整名称。$^   #所有的依赖文件,以空格分开,不包含重复的依赖文件。$%     #如果目标是归档成员,则该变量表示目标的归档成员名称。

Makefile 内嵌变量 $(CURDIR) $0 $1 $2 $#

$(CURDIR)   #   CURDIR是make的内嵌变量, 为当前目录SRCTREE       := $(CURDIR)    *$(CURDIR)为当前目录,相当于SRCTREE=./  MKCONFIG   := $(SRCTREE)/mkconfig  *相当于MKCONFIG=./mkconfig$0 # Shell本身的文件名 $1    #添加到Shell的第一个参数$2 #添加到Shell的第二个参数$# #添加到Shell的总参数个数

Makefile中的常见自动变量$@, $^, $< , $?, $%, $+, $*

Makefile用一些特殊的符号来替代符合某种条件的文件集,这就形成了自动变量。
自动变量的含义:预定义的特殊意义的符号。就类似于C语言编译器中预制的那些宏__FILE__一样。

$@
#表示目标文件,表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。$^
#表示所有的依赖文件
#所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。$<
#表示第一个依赖文件,依赖目标中的第一个目标名字。
#如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。$?
#表示比目标还要新的依赖文件列表/集合,以空格分隔。$%
#仅当目标是函数库文件中,表示规则中的目标成员名。
#例如,如果一个目标是“foo.a(bar.o)”,那么,“$%”就是“bar.o”,“$@”就是“foo.a”。
#如果目标不是函数库文件(Unix下是[.a],Windows下是[.lib]),那么,其值为空。$+
#这个变量很像“$^”,也是所有依赖目标的集合。只是它不去除重复的依赖目标。$*
#这个变量表示目标模式中“%”及其之前的部分。
#如果目标是“dir/a.foo.b”,并且目标的模式是“a.%.b”,那么,“$*”的值就是“dir/a.foo”。
#这个变量对于构造有关联的文件名是比较有较
#。如果目标中没有模式的定义,那么“$*”也就不能被推导出,但是,
#如果目标文件的后缀是make所识别的,那么“$*”就是除了后缀的那一部分。
#例如:如果目标是“foo.c”,因为“.c”是make所能识别的后缀名,所以,“$*”的值就是“foo”。
#这个特性是GNU make的,很有可能不兼容于其它版本的make,所以,你应该尽量避免使用“$*”,除非是在隐含规则或是静态模式中。
#如果目标中的后缀是make所不能识别的,那么“$*”就是空值。

Makefile示例

SRCS = $(wildcard *.c)
OBJS = $(patsubst %c, %o, $(Message_SRCS))
# wildcard 扩展通配符,指定目录 ./ 和 ./sub/ 下的所有后缀是c的文件全部展开
# patsubst 替换通配符
# $^ 代表所有依赖文件
# $@ 代表所有目标文件
# $< 代表第一个依赖文件
#  % 代表通配符 CFLAGS/CXXFLAGS: #编译器会用到的一些优化参数 , 并指定头文件(.h文件)的路径,如:CFLAGS=-I/usr/include -I/path/include。LDFLAGS:#指定库文件的位置。LIBS: #告诉链接器要链接哪些库文件,如LIBS = -lpthread -liconv$(CC) $(CFLAGS) $(LDFLAGS) main.c gfifo.c queue.c usbmonitor.c socket_rcv_360_server.c ./lib/srs_librtmp.a ./lib/libcrypto.a ./lib/libssl.a ./lib/libtinyalsa.a -o media_record -static -ldl -lstdc++ -lm -lpthread
#使用定的编译器、编译选项参数、链接选项参数,编译.c文件,并使用静态方式链接制定的库文件,以及编译器目录下的libdl.a、libstdc++.a、libm.a、libpthread.a库文件生成media_record 可执行目标文件。

Makefile中.PHONY和.SUFFIXES的含义

  • 内容过长,放链接:Makefile中.SUFFIXES的含义
  • 内容过长,放链接:Makefile中.PHONY的含义

Makefile中patsubst(扩展通配符)的含义

内容过长,放链接:Makefile中patsubst(扩展通配符)的含义


Makefile模版

提供一个模版,里面内容按需修改.

#############################################################
# Generic Makefile for C/C++ Program
#
# License: GPL (General Public License)
# Description:
# ------------
# This is an easily customizable makefile template. The purpose is to
# provide an instant building environment for C/C++ programs.
#
# It searches all the C/C++ source files in the specified directories,
# makes dependencies, compiles and links to form an executable.
#
# Besides its default ability to build C/C++ programs which use only
# standard C/C++ libraries, you can customize the Makefile to build
# those using other libraries. Once done, without any changes you can
# then build programs using the same or less libraries, even if source
# files are renamed, added or removed. Therefore, it is particularly
# convenient to use it to build codes for experimental or study use.
#
# GNU make is expected to use the Makefile. Other versions of makes
# may or may not work.
#
# Usage:
# ------
# 1. Copy the Makefile to your program directory.
# 2. Customize in the "Customizable Section" only if necessary:
#    * to use non-standard C/C++ libraries, set pre-processor or compiler
#      options to <MY_CFLAGS> and linker ones to <MY_LIBS>
#      (See Makefile.gtk+-2.0 for an example)
#    * to search sources in more directories, set to <SRCDIRS>
#    * to specify your favorite program name, set to <PROGRAM>
# 3. Type make to start building your program.
#
# Make Target:
# ------------
# The Makefile provides the following targets to make:
#   $ make           compile and link
#   $ make NODEP=yes compile and link without generating dependencies
#   $ make objs      compile only (no linking)
#   $ make tags      create tags for Emacs editor
#   $ make ctags     create ctags for VI editor
#   $ make clean     clean objects and the executable file
#   $ make cleanall clean objects, the executable, TAGS and dependencies
#   $ make help      get the usage of the makefile
#
#===========================================================================## Customizable Section: adapt those variables to suit your program.
##==========================================================================# The pre-processor and compiler options.
MY_CFLAGS = -I/usr/include# The linker options.
MY_LIBS   = -lpthread -Wl,-rpath-link=-Wl,-rpath=/usr/lib# The pre-processor options used by the cpp (man cpp for more).
CPPFLAGS  = -Wall# The options used in linking as well as in any direct use of ld.
LDFLAGS   =# The directories in which source files reside.
# If not specified, only the current directory will be serached.
SRCDIRS   = .# The executable file name.
# If not specified, current directory name or `a.out' will be used.
PROGRAM   = name_app## Implicit Section: change the following only when necessary.
##==========================================================================# The source file types (headers excluded).
# .c indicates C source files, and others C++ ones.
SRCEXTS = .c .C .cc .cpp .CPP .c++ .cxx .cp# The header file types.
HDREXTS = .h .H .hh .hpp .HPP .h++ .hxx .hp# The pre-processor and compiler options.
# Users can override those variables from the command line.
# The GCC default, if no C language dialect options are given, is -std=gnu17.
# The GCC default, if no C++ language dialect options are given, is -std=gnu++17.
CFLAGS  =  -O3 -std=gnu11
CXXFLAGS=  -O3 -std=gnu++14# The C program compiler.
CC     = /usr/bin/gcc# The C++ program compiler.
CXX    = /usr/bin/g++# Un-comment the following line to compile C programs as C++ ones.
#CC     = $(CXX)# The command used to delete file.
RM     = rm -fETAGS = etags
ETAGSFLAGS =CTAGS = ctags
CTAGSFLAGS =## Stable Section: usually no need to be changed. But you can add more.
##==========================================================================
SHELL   = /bin/sh
EMPTY   =
SPACE   = $(EMPTY) $(EMPTY)
ifeq ($(PROGRAM),)CUR_PATH_NAMES = $(subst /,$(SPACE),$(subst $(SPACE),_,$(CURDIR)))PROGRAM = $(word $(words $(CUR_PATH_NAMES)),$(CUR_PATH_NAMES))ifeq ($(PROGRAM),)PROGRAM = a.outendif
endif
ifeq ($(SRCDIRS),)SRCDIRS = .
endif
SOURCES = $(foreach d,$(SRCDIRS),$(wildcard $(addprefix $(d)/*,$(SRCEXTS))))
HEADERS = $(foreach d,$(SRCDIRS),$(wildcard $(addprefix $(d)/*,$(HDREXTS))))
SRC_CXX = $(filter-out %.c,$(SOURCES))
OBJS    = $(addsuffix .o, $(basename $(SOURCES)))
DEPS    = $(OBJS:.o=.d)## Define some useful variables.
DEP_OPT = $(shell if `$(CC) --version | grep "GCC" >/dev/null`; then \echo "-MM -MP"; else echo "-M"; fi )
DEPEND      = $(CC)  $(DEP_OPT)  $(MY_CFLAGS) $(CFLAGS) $(CPPFLAGS)
DEPEND.d    = $(subst -g ,,$(DEPEND))
COMPILE.c   = $(CC)  $(MY_CFLAGS) $(CFLAGS)   $(CPPFLAGS) -c
COMPILE.cxx = $(CXX) $(MY_CFLAGS) $(CXXFLAGS) $(CPPFLAGS) -c
LINK.c      = $(CC)  $(MY_CFLAGS) $(CFLAGS)   $(CPPFLAGS) $(LDFLAGS)
LINK.cxx    = $(CXX) $(MY_CFLAGS) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS).PHONY: all objs tags ctags clean cleanall help show# Delete the default suffixes
.SUFFIXES:all: $(PROGRAM)# Rules for creating dependency files (.d).
#------------------------------------------%.d:%.c@echo -n $(dir $<) > $@@$(DEPEND.d) $< >> $@%.d:%.C@echo -n $(dir $<) > $@@$(DEPEND.d) $< >> $@%.d:%.cc@echo -n $(dir $<) > $@@$(DEPEND.d) $< >> $@%.d:%.cpp@echo -n $(dir $<) > $@@$(DEPEND.d) $< >> $@%.d:%.CPP@echo -n $(dir $<) > $@@$(DEPEND.d) $< >> $@%.d:%.c++@echo -n $(dir $<) > $@@$(DEPEND.d) $< >> $@%.d:%.cp@echo -n $(dir $<) > $@@$(DEPEND.d) $< >> $@%.d:%.cxx@echo -n $(dir $<) > $@@$(DEPEND.d) $< >> $@# Rules for generating object files (.o).
#----------------------------------------
objs:$(OBJS)%.o:%.c$(COMPILE.c) $< -o $@%.o:%.C$(COMPILE.cxx) $< -o $@%.o:%.cc$(COMPILE.cxx) $< -o $@%.o:%.cpp$(COMPILE.cxx) $< -o $@%.o:%.CPP$(COMPILE.cxx) $< -o $@%.o:%.c++$(COMPILE.cxx) $< -o $@%.o:%.cp$(COMPILE.cxx) $< -o $@%.o:%.cxx$(COMPILE.cxx) $< -o $@# Rules for generating the tags.
#-------------------------------------
tags: $(HEADERS) $(SOURCES)$(ETAGS) $(ETAGSFLAGS) $(HEADERS) $(SOURCES)ctags: $(HEADERS) $(SOURCES)$(CTAGS) $(CTAGSFLAGS) $(HEADERS) $(SOURCES)# Rules for generating the executable.
#-------------------------------------
$(PROGRAM):$(OBJS)
ifeq ($(SRC_CXX),)              # C program$(LINK.c)   $(OBJS) $(MY_LIBS) -o $@@echo Type ./$@ to execute the program.else                            # C++ program$(LINK.cxx) $(OBJS) $(MY_LIBS) -o $@@echo Type ./$@ to execute the program.
endififndef NODEP
ifneq ($(DEPS),)sinclude $(DEPS)
endif
endif# Commands to clean and help etc.
#-------------------------------------
.PHONY: clean
clean:$(RM) $(OBJS) $(PROGRAM).PHONY: cleanall
cleanall:$(RM) $(DEPS) $(OBJS) TAGS $(PROGRAM)# Show help..PHONY: help
help:@echo 'Usage: make [TARGET]'@echo 'TARGETS:'@echo '  all       (=make) compile and link.'@echo '  NODEP=yes make without generating dependencies.'@echo '  objs      compile only (no linking).'@echo '  tags      create tags for Emacs editor.'@echo '  ctags     create ctags for VI editor.'@echo '  clean     clean objects and the executable file.'@echo '  distclean clean objects, the executable and dependencies.'@echo '  show      show variables (for debug use only).'@echo '  help      print this message.'@echo@echo 'Report bugs to <whyglinux AT gmail DOT com>.'# Show variables (for debug use only.)
.PHONY: show
show:@echo 'PROGRAM     :' $(PROGRAM)@echo 'SRCDIRS     :' $(SRCDIRS)@echo 'HEADERS     :' $(HEADERS)@echo 'SOURCES     :' $(SOURCES)@echo 'SRC_CXX     :' $(SRC_CXX)@echo 'OBJS        :' $(OBJS)@echo 'DEPS        :' $(DEPS)@echo 'DEPEND      :' $(DEPEND)@echo 'COMPILE.c   :' $(COMPILE.c)@echo 'COMPILE.cxx :' $(COMPILE.cxx)@echo 'link.c      :' $(LINK.c)@echo 'link.cxx    :' $(LINK.cxx)## End of the Makefile ##  Suggestions are welcome  ## All rights reserved ##
##############################################################

Makefile 教程(超详细)相关推荐

  1. maven配置阿里云_阿里云OSS PicGo 配置图床教程 超详细

    阿里云OSS和PicGo配置图床教程 超详细 废话不多说,直接开始 购买阿里云OSS服务 登录阿里云 打开侧边栏,选择对象存储OSS,如下图: 对象存储界面右部选择创建Bucket,如下图所示: 之后 ...

  2. svn安装教程 mysql_CentOS6.4 下安装SVN的详细教程(超详细)

    1.检查系统是否已经安装如果安装就卸载 rpm -qa subversion yum remove subversion 2.安装 yum install subversion 3.建立SVN库 mk ...

  3. 新版Android Studio(4.1.1 for Windows 64-bit)的安装教程(超详细)

    新版Android Studio(4.1.1 for Windows 64-bit)的安装教程(超详细) 获取Android Studio软件 在心仪的磁盘新建文件夹:AndroidStudio(文件 ...

  4. 【台大郭彦甫】Matlab入门教程超详细学习笔记二:基本操作与矩阵运算(附PPT链接)

    Matlab入门教程超详细学习笔记二:基本操作与矩阵运算 前言 一.基本操作 1.把matlab当作计算器使用 2.变量 3.控制格式输出 二.矩阵运算 1.矩阵 2.矩阵索引 3.使用:创建向量 4 ...

  5. windows安装Weblogic教程(图文教程超详细版)

    windows安装Weblogic教程(超详细) 一. 下载 WebLogic 到Oracle官网http://www.oracle.com/ 下载WebLogic(根据自己的情况选择),本文档下载的 ...

  6. 阿里云OSS PicGo 配置图床教程 超详细

    阿里云OSS和PicGo配置图床教程 超详细 废话不多说,直接开始 购买阿里云OSS服务 登录阿里云 打开侧边栏,选择对象存储OSS,如下图: 对象存储界面右部选择创建Bucket,如下图所示: 之后 ...

  7. linux下如何make文件夹,Linux makefile 教程 非常详细,且易懂

    http://blog.csdn.net/liang13664759/article/details/1771246 Linux makefile 教程 非常详细,且易懂 1.Makefile用途 使 ...

  8. exe电子书制作教程(超详细)【申明:来源于网络】

    exe电子书制作教程(超详细)[申明:来源于网络] 地址:http://wenku.baidu.com/view/0b046907eff9aef8941e0631.html

  9. Centos7环境下安装Mysql8详细教程(超详细,亲测百分百成功)

    Centos7环境下安装Mysql8详细教程(超详细,亲测百分百成功) 文章目录 Centos7环境下安装Mysql8详细教程(超详细,亲测百分百成功) 1.上传或者下载mysql安装包 2.检查是否 ...

  10. Redis安装教程超详细

    Redis安装教程超详细 一.Redis安装 1.windows下安装 2.Linux下安装 一.Redis安装 1.windows下安装 默认端口:6379 1.下载链接 https://githu ...

最新文章

  1. easyui的combobox下拉框初始化默认值以及保持该值一直显示的方法
  2. Zepto.js简介
  3. xshell无法连接linux虚拟机问题的解决办法
  4. linux samba默认端口,Linux 指定端口挂载samba 亲测可用!
  5. C语言库自带的二分查找函数bsearch函数的使用示例
  6. linux怎么装mac系统,Linux/macos系统怎么安装nvm
  7. 完全二叉树的结点个数
  8. pptv手机端html,影视资源持续更新,PPTV手机化身看片神器
  9. python标准库之socket
  10. 北京一女子乘公交车遇车祸 惨遭钢筋穿胸
  11. Oracle Certified Master For Java EE 5/6 Comes
  12. WebPack 简明学习教程
  13. [转载] Python数据分析与可视化学习笔记(一)数据分析与可视化概述
  14. IDEA 常用快捷键介绍
  15. struts2上传 zip和rar文件类型
  16. 前端代码检测重复率工具
  17. Leetcode_med 17. 电话号码的字母组合
  18. 在web上制作动画(css3)
  19. 人工智能如何自己玩游戏?
  20. java 组织机构代码_JAVA实现社会统一信用代码校验的方法|chu

热门文章

  1. tomcat 设置编码格式
  2. eclipse汉化包安装步骤(附eclipse汉化包下载地址)
  3. Java课程报告实验总结,java实验报告总结 [Java课程设计实验报告]
  4. 学会计为什么要学计算机基础,会计专业学生为什么要学数据库
  5. 国内博客(blog)搬家工具(服务)大全
  6. C++ IE缓存管理研究
  7. 【计算机二级】公共基础知识总结
  8. 先锋网络电视 v3.36.4 钻石版 怎么用
  9. VS2015 Visual Assist X 破解版安装教程
  10. 通过BigInteger真正实现无限大的十进制转N(任意整数)进制