【makefile】什么是makefile?实际用例分析|比较通用的架构

目录

第一部分:

第二部分:

makefile中的一些特殊字符:

什么是makefile 

实例

如何在makefile中指定头文件目录

Makefile中的-Wall -O2 -Os -g等选项介绍


make 属于第二代工具,尽量转到最新的构建工具吧,目前最新的构建工具应该是cmake和scons。

 

第一部分:

这里不再说Makefile的基本知识,如果需要学习,那么请参考: 下载:makefile 中文手册或者点击打开链接或者跟我一起写Makefile( 陈皓 )

这里说的是一般的实际的一个工程应该怎么去写。

环境:ubuntu 10.04

先看看我的文件的分布情况:

顶层:

然后src中:是所有的源程序以及头文件( 我这里是使用自己的IR树的代码作为实验 )

而build文件夹是为了编译使用的!下面有:

obj文件夹里面放的是编译过程中的.o和.d文件,还有一个subdir.mk的子文件,用于指示怎么生成.o

obj中:

下面我们从顶层开始慢慢分析:

*******温馨提示:下面的注释是为了方便处理,写在每一条语句后面,其实这样的风格是不好的,所以,如果

       你使用了这个makefile,请将注释换行...或者去掉,否则可能编译异常!谢谢记住!

*******

最外层的makefile:

SHELL = /bin/sh             # 这个地方是指示使用的shell是sh  
EXEC = ir_tree              # 最终生成的binary的名称  
BUILD_DIR = build           # 这个子文件夹,此处也就是我们build文件夹  
  
all:                        # all在此处是终极目标,这个你应该知道的。一般我们make的时候,第一个目标作为终极目标  
    @( cd ${BUILD_DIR}; make )  # 这句是进去build文件夹去执行那个makefile  
                                
clean:                      # clean就不说了  
    @echo 'start clean...'  
    @($(RM) $(EXEC))  
    @(cd ${BUILD_DIR}; make clean)  
    @echo 'Finished!'  
    @echo ''  

现在进入build文件夹,看这个文件夹下面的makefile

SHELL = /bin/sh            # 同上  
  
INCLUDE_DIR :=             # include文件夹,一般我们在引用库的时候,需要将其头文件放在一个include中,然后自己的程序                           # 编译的时候需要包含这个include,例如-I$(<span style="font-family: SimHei;">INCLUDE_DIR</span><span style="font-family: SimHei;">)</span>  
LIB_DIR := -lm             # 引入的库  
EXEC = ../ir_tree          # 这是一个最终binary名称,这里是将这个可执行放在了上层文件夹中  
  
-include obj/subdir.mk     # 这个地方是include了一个子文件  
                           # 这里子文件作用是,为了生成所有的.o文件(当然附带生成.d文件!),生成.o之后,才能回到这一       # 层的makefile进行链接成最终的可执行的操作!具体操作我们稍后再看  
  
all:${EXEC}                # 好!这里是这个makefile的第一个目标。即终极目标,所有需要找
  
${EXEC}: ${OBJS}           # ${EXEC}的生成规则,注意这里我们没有看到$(OBJS),那是因为在obj/subdir.mk中!  
    @echo ' Building target: $@ '  
    gcc -o $@ $(OBJS) $(LIB_DIR)   # 这一句就是为了将所有的.o文件 + 引用的库 链接起来,生成最后的$@,也就是$(EXEC),也就是最后的binary!  
    @echo 'Finished building target: $@'  
    @echo ''  
  
clean:  
    @echo 'start rm objs and deps ...'  
    $(RM) $(OBJS) \  
    $(C_DEPS)  
    @echo 'Finish rm objs and deps ...'  
  
.PHONY: all clean          # 伪目标  
.SECONDARY:  

下面需要看看obj中的subdir.mk的内容了!这个是为了生成所有的.o文件。

同时!请注意:当我们的一个.c或者.h被修改之后,需要重新编译!这一点非常重要!

特别是.h被修改的时候,不能忘记重新编译( 当然,有些时候.h修改,我们不需要编译,这个先暂时不说,后面在讨论!其实,你使用一个make --touch就可以~ )

C_SRCS += \            # 所有的.c文件,当然你喜欢使用wildcard也是可的!  
../src/card.c \        # $(wildcard ../src/*.c)</span>  
../src/index.c \  
../src/node.c \  
../src/rect.c \  
../src/split_l.c \  
../src/test.c  
  
OBJS += \            # 所有的.c文件,当然你喜欢使用wildcard也是可的!</span>  
./obj/card.o \       # OBJS = $(patsubst %.c,%.o,$(wildcard ../src/*.c))  
./obj/index.o \      # 但是你要将src文件目录改成obj OBJS := $(addprefix "./obj/",$(notdir $(OBJS)))
./obj/node.o \  
./obj/rect.o \  
./obj/split_l.o \  
./obj/test.o  
  
C_DEPS += \          # deps  
./obj/card.d \  
./obj/index.d \  
./obj/node.d \  
./obj/rect.d \  
./obj/split_l.d \  
./obj/test.d  
  
all: $(OBJS)                     # 注意在这个subdir中,这个是终极目标,也就是所有的objs  
  
obj/%.o: ../src/%.c ./obj/%.d    #这里是o文件的依赖规则:注意是.c和.d同时成为依赖,.d文件中是一个目标的所有的依赖文             # 件,包括.c和.h文件,所有一旦.h被修改,这个地方也是可以识别的!  
    @echo 'start building $< ...'  
    gcc -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" \  
-MT"$(@:%.o=%.d)" -o "$@" "$<"  
    @echo 'Finished building: $< '  
    @echo ''  
  
-include $(C_DEPS)                # 注意:这里将所有的.d文件引入!注意,第一次引入时候,没有.d文件,会寻找.d的生成规则,也就是下面 # 的,这个.d又是依赖.c文件的,所有,一旦一个.c文件中多了一个头文件之类,又可以跟新.d,从而,执行 # 上面的.o生成时候,就能够实时跟新  
  
./obj/%.d: ../src/%.c             # 注意:这里为了生成.d  
    @echo 'start building $(notdir $@)...'  
    $(CC) $< $(INCLUDE) -MM -MD -o $@  

如果你要下载这个工程,我已经上传了,你可以免费下载:ir_tree
 

第二部分:

之前已经讲了这一篇文章:Makefile实际用例分析(一)-----比较通用的一种架构

现在这篇其实和那个差的不是很多,只是在布局上有些差别(这个makefile也是论坛上一起讨论过的,囧,忘了哪个论坛)

还是先看看基本的文件布局:

介绍:

debug是调试版本的binary文件夹

release是发行版本binary文件夹

src是所有的源文件文件夹、

lib是引用库

include一般是引用库头文件之类,或者其他头文件

obj所有.o文件和.d文件

src中:依然使用之前的那个ir_tree的例子

在lib中有一个外来的引用库,命名为libnew.a,

在include中是这个库的头文件new.h:

我们对于最基本的文件分别已经清楚了,这种架构下只使用了一个makefile,下面我们具体看看:

---------------->>>>>> 我无语了,对csdn格式彻底无语了!这是第三次修改代码格式了,

算了,直接贴成文字吧。。。。。。。。。。。。。。。。。。。。。。。。。。。


#################################
# 常见的配置,不多说
#
SHELL=/bin/sh
CC=gcc
MAKE=make

#################################
# 下面定义的是一些目录路径
# 
MAKE_DIR=.                                           # 当前文件夹
SRC_DIR=$(MAKE_DIR)/src/ # 源文件夹
OBJ_DIR=$(MAKE_DIR)/obj/ # obj文件夹
LIB_DIR=$(MAKE_DIR)/lib/ # 引用库文件夹
INCLUDE_DIR=$(MAKE_DIR)/include/ # include文件夹
DEBUG_DIR=$(MAKE_DIR)/debug/ # debug文件夹

RELEASE_DIR=$(MAKE_DIR)/release/# release文件夹

EXEC_DIR= # 最终的binary文件夹


#################################
# 下面是include路径和库的路径
# 

INCLUDE=-I$(INCLUDE_DIR) -I$(SRC_DIR)
LIB=$(LIB_DIR)/libnew.a -L$(OBJ_DIR) -lm      # 引入库,包括自己的库文件( 如果你将libnew.a放到/usr/lib中了, )

  # 那么直接-lnew就可以了

#################################
# 下面是可执行名称
# 
EXEC=ir_tree

#################################
# 
# 注意:当我们下面出现%.c的时候,先在当前文件夹寻找,如果找不到,那么
#       到下面指定的文件夹中寻找!!!
# 
# 说白就是:如果依赖文件在本文件夹找不到,那么到下面文件夹寻找!仅仅是依赖文件!
# 

vpath %.h $(INCLUDE_DIR)
vpath %.c $(SRC_DIR)
vpath %.o $(OBJ_DIR)
vpath %.d $(OBJ_DIR)

#################################
# 下面是指定SRC  OBJ  DEP
# 注意:都是不带目录的basename
# 
SRC_TMP:=$(wildcard $(SRC_DIR)*.c)
C_SRCS:=$(notdir $(SRC_TMP))                            # 源文件
C_OBJS:=$(patsubst %.c,%.o,$(C_SRCS)) # o文件
C_DEPS:=$(patsubst %.c,%.d,$(C_SRCS)) # deps


#################################
# 编译选项!
#
FLAG_DEBUG=-g
CFLAGS=-O2 -Wall -c

# 下面判断是debug还是release
# 
DEBUG:=1
ifeq ($(DEBUG),1)
EXEC_DIR:=$(DEBUG_DIR)
CFLAGS:=$(CFLAGS) $(FLAG_DEBUG)
else
EXEC_DIR:=$(RELEASE_DIR)
endif


# 最终binary的名称( 路径+名称 )
# 
EXEC:=$(EXEC_DIR)$(EXEC)


################################
# 下面是终极目标all
#

#################################################################
# 关于下面的执行: 
#
# 首先-include $(addprefix $(OBJ_DIR),$(C_DEPS))
# 目的是为了将所有的.d文件包含进来,那么.d文件里面是所有的.o的
# 完整的依赖,那么即使.h被修改了,那么也是可以识别编译的!在第一次
# 处理时,没有.d文件,那么需要找.d的生成规则。因为我们include的是
# $(addprefix $(OBJ_DIR),$(C_DEPS)),那么需要找的依赖是$(OBJ_DIR)%.d
# ,那么OK,这个地方必须注意!如果你include的.d是例如card.d,那么
# 规则必须是:%.d: %.c,而不是$(OBJ_DIR)%.d: %.c。好!现在生成.d文件了
# 然后执行all:$(EXEC),那么需要找依赖$(C_OBJS),本文件夹没有,那么到
# vpath %.o $(OBJ_DIR)中寻找!那么可以因为开始.o是不存在(或者过期的),
# 那么需要寻找生成规则:%.o: %.c %.d,OK生成!
# 等所有的.o处理OK,链接成可执行!
#
#################################################################

#
# 重要理解:
#    1: 你有什么样的依赖,那么就是什么样的一个子规则的目标!
#           例如:$(C_OBJS)是不带目录路径的.o的集合,例如a.o b.o c.o
#           那么,我们需要寻找生成他们的规则,那么肯定有一个子伪目标
#           名称是:(%.o:依赖),而不是($(OBJ_DIR)%.o:依赖),所以
#           要理解哦!
# 
#    2: 注意vpath用途,当“依赖”在本文件夹下找不到的时候,去指定
#           文件夹寻找!
#
#    3:注意Include是将.d文件中的内容加载到当前文件夹中!那么,如果.d
#           里的是例如:card.o: card.c card.h,那么$(C_OBJS)也应该是不带目录
#           路径的*.o形式!!!
#

all:$(EXEC)

$(EXEC): $(C_OBJS)
@echo 'start building  $(notdir $@) ...'
@$(CC)  $(addprefix $(OBJ_DIR),$(notdir $^)) $(LIB) -o $@

#
# 注意关系:每次makefile的时候,需要加载.d文件,那么所有的依赖被加进来
# 但是也必须有$(OBJ_DIR)%.d: %.c,这个是为了当我们的.c改变的时候,例如
# 可能心增加一个include,那么可以改变.d文件!那么后面的处理又是连带关系!
#

# 与上一篇说的一样

%.o: %.c %.d
@echo 'start building $(notdir $@)...'
@$(CC) $(CFLAGS) $< $(INCLUDE) -o $(OBJ_DIR)$@

$(OBJ_DIR)%.d: %.c
@echo 'start building $(notdir $@)...'
@$(CC) $< $(INCLUDE) -MM -MD -o $@

# 将所有的d文件引入,作用,为了更新~
-include $(addprefix $(OBJ_DIR),$(C_DEPS))

clean:
@$(RM) $(OBJ_DIR)*
@$(RM) $(EXEC)
@clear

run:
@$(EXEC)

debug:
@echo $(C_OBJS)
@echo $(C_DEPS)

.PHONY:all clean debug run



OK,现在你可以make,然后make run看结果、、、



如果你需要这个工程,同样可以免费下载:ir_tree

from:http://blog.csdn.net/shanshanpt/article/details/17199695



makefile中的一些特殊字符:

在makefile中,有时会接触到一些以特殊字符打头的命令,比如@, -, +,如果之前没有接触过的话,会感觉比较奇怪,其实,多是一些为了实现特定行为模式而引入的标记符。

命令行以'@'打头的含义: 在执行到的时候不回显相应的命令内容,只显示命令的输出。

命令行以'-'打头的含义: 在执行到的时候如果发生错误(退出返回非零状态)时,不中断make过程。

命令行以'+'打头的含义: makefile中以+开头的命令的执行不受到 make的-n,-t,-q三个参数的影响。我们知道,在make的时候,如果加上-n, -t, -q这样的参数,都是不执行相应命令的,而以'+'开头的命令,则无论make命令后面是否跟着三个参数,都会被执行。

@ 禁止回显 := 只找前面定义的 = 前后都找,最后的为主  $(B) :输出变量 B  $B 输出变量B的值

先看下面的Makefile:

 
#example
B := $(A)
A = later
all:
    @echo $(B)

 执行make命令,我们发现什么都没输出,我们将第3行的:=换成=。
 
#example
B = $(A)
A = later
all:
    @echo $(B)

执行make,输出later。
分析:B :=$(A)时,它只会到这句语句之前去找A的值,因A没有定义所以什么都没有输出。
      B = $(A)时,虽然该语句之前A没有定义,但是在其后定义了,所以能输出later。
 
#example
A = before1
A = before2
B := $(A)
A = later1
all:
    @echo $(B)

执行make,输出before2。
解释:上面Makefile最后一句echo前面的@符号的作用是禁止回显。如我们的Makefile改为如下:
 
#example
A = before1
B = $(A)
B = before2
C = $(B)
A = later1
B = later2
all:
    echo $(C)

执行make:
echo later2
later2
分析:C = $(B),应该从Makefile文件最后往前找B,得到B = later2,将最后一句全部变量代替即为:echo later2,因echo前没有@符号,回显该语句,然后再输出later2。
注意:当我们直接在终端上要用echo输出某个变量的值时,是不能加()的。如我们要输出PAHT
应该用echo $PATH,而不能用echo $(PATH),否则会报错,注意'$'不能少了。
Makefile中"?=",含义为:如没定义,则赋值。
如:TEMP ?= var 等价于
    ifeq($(TEMP),undefined)
    TEMP = var
    endif

附:make命令参数


 

make的参数 

下面列举了所有GNU make 3.80版的参数定义。其它版本和产商的make大同小异,不过其它产商的make的具体参数还是请参考各自的产品文档。 

“-b” 
“-m” 
这两个参数的作用是忽略和其它版本make的兼容性。 

“-B” 
“--always-make” 
认为所有的目标都需要更新(重编译)。 

“-C 


“--directory=

指定读取makefile的目录。如果有多个“-C”参数,make的解释是后面的路径以前面的作为相对路径,并以最后的目录作为被指定目录。如:“make –C ~hchen/test –C prog”等价于“make –C ~hchen/test/prog”。 

“—debug[=;]” 
输出make的调试信息。它有几种不同的级别可供选择,如果没有参数,那就是输出最简单的调试信息。下面是;的取值: 
    a —— 也就是all,输出所有的调试信息。(会非常的多) 
    b —— 也就是basic,只输出简单的调试信息。即输出不需要重编译的目标。 
    v —— 也就是verbose,在b选项的级别之上。输出的信息包括哪个makefile被解析,不需要被重编译的依赖文件(或是依赖目标)等。 
    i —— 也就是implicit,输出所以的隐含规则。 
    j —— 也就是jobs,输出执行规则中命令的详细信息,如命令的PID、返回码等。 
    m —— 也就是makefile,输出make读取makefile,更新makefile,执行makefile的信息。 

“-d” 
相当于“--debug=a”。 

“-e” 
“--environment-overrides” 
指明环境变量的值覆盖makefile中定义的变量的值。 

“-f=;” 
“--file=;” 
“--makefile=;” 
指定需要执行的makefile。 

“-h” 
“--help” 
显示帮助信息。 

“-i” 
“--ignore-errors” 
在执行时忽略所有的错误。 

“-I 

“--include-dir=

指定一个被包含makefile的搜索目标。可以使用多个“-I”参数来指定多个目录。 

“-j [;]” 
“--jobs[=;]” 
指同时运行命令的个数。如果没有这个参数,make运行命令时能运行多少就运行多少。如果有一个以上的“-j”参数,那么仅最后一个“-j”才是有效的。(注意这个参数在MS-DOS中是无用的) 

“-k” 
“--keep-going” 
出错也不停止运行。如果生成一个目标失败了,那么依赖于其上的目标就不会被执行了。 

“-l ;” 
“--load-average[=
“—max-load[=;]” 
指定make运行命令的负载。 

“-n” 
“--just-print” 
“--dry-run” 
“--recon” 
仅输出执行过程中的命令序列,但并不执行。 

“-o ;” 
“--old-file=;” 
“--assume-old=;” 
不重新生成的指定的;,即使这个目标的依赖文件新于它。 

“-p” 
“--print-data-base” 
输出makefile中的所有数据,包括所有的规则和变量。这个参数会让一个简单的makefile都会输出一堆信息。如果你只是想输出信息而不想执行makefile,你可以使用“make -qp”命令。如果你想查看执行makefile前的预设变量和规则,你可以使用“make –p –f /dev/null”。这个参数输出的信息会包含着你的makefile文件的文件名和行号,所以,用这个参数来调试你的makefile会是很有用的,特别是当你的环境变量很复杂的时候。 

“-q” 
“--question” 
不运行命令,也不输出。仅仅是检查所指定的目标是否需要更新。如果是0则说明要更新,如果是2则说明有错误发生。 

“-r” 
“--no-builtin-rules” 
禁止make使用任何隐含规则。 

“-R” 
“--no-builtin-variabes” 
禁止make使用任何作用于变量上的隐含规则。 

“-s” 
“--silent” 
“--quiet” 
在命令运行时不输出命令的输出。 

“-S” 
“--no-keep-going” 
“--stop” 
取消“-k”选项的作用。因为有些时候,make的选项是从环境变量“MAKEFLAGS”中继承下来的。所以你可以在命令行中使用这个参数来让环境变量中的“-k”选项失效。 

“-t” 
“--touch” 
相当于UNIX的touch命令,只是把目标的修改日期变成最新的,也就是阻止生成目标的命令运行。 

“-v” 
“--version” 
输出make程序的版本、版权等关于make的信息。 

“-w” 
“--print-directory” 
输出运行makefile之前和之后的信息。这个参数对于跟踪嵌套式调用make时很有用。 

“--no-print-directory” 
禁止“-w”选项。 

“-W ;” 
“--what-if=;” 
“--new-file=;” 
“--assume-file=;” 
假定目标;需要更新,如果和“-n”选项使用,那么这个参数会输出该目标更新时的运行动作。如果没有“-n”那么就像运行UNIX的“touch”命令一样,使得;的修改时间为当前时间。 

“--warn-undefined-variables” 
只要make发现有未定义的变量,那么就输出警告信息。 
源地址:http://www.cnblogs.com/iamfy/archive/2012/04/20/2459497.html

 ​《Makefile经典教程(掌握这些足够)》https://blog.csdn.net/ruglcc/article/details/7814546​


什么是makefile 

2012-09-25 16:30:41

我自己的理解是:

Makefile 就是 罗列要编译和链接的文件,要编译和链接的条件,然后只要一执行 make命令 ,就按照Makefile里面的内容开始链接和编译。

具体的请看全文:

全文:http://blog.csdn.net/yeqishi/article/details/5505332

Makefile 介绍
———————
make命令执行时,需要一个 Makefile 
文件,以告诉make命令需要怎么样的去编译和链接程序。
首先,我们用一个示例来说明Makefile的书写规则。以便给大家一个感兴认识。这个示例来源于GNU的make使用手册,在这个示例中,我们的工程有8个C文件,和3个头文件,我们要写一个Makefile来告诉make命令如何编译和链接这几个文件。我们的规则是:
1)如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。
    
2)如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。
    
3)如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。
只要我们的Makefile写得够好,所有的这一切,我们只用一个make命令就可以完成,make命令会自动智能地根据当前的文件修改的情况来确定哪些文件需要重编译,从而自己编译所需要的文件和链接目标程序。

makefile中的all和.PHONY的作用http://blog.chinaunix.net/uid-28458801-id-3452277.html

实例

请编写一个makefile同时编译、链接下面两个程序:

main1.c:

#include

int main(void)

{

    printf("main1\n");

}

main2.c:

#include

int main(void)

{

    printf("main2\n");

}

【分析】:这里需要生成两个可执行文件main1main2(两个目标)。由于makefile只能有一个目标,所以可以构造一个没有规则的终极目标all,并以这两个可执行文件作为依赖。如下:

makefile:

all:main1 main2

main1: main1.c

    @gcc main1.c -o main1

main2: main2.c

    @gcc main2.c -o main2

很多时候我们在执行make时会产生许多过程文件,比如将上面的makefile改为:

makefile:

all:main1 main2

main1: main1.c

    @gcc main1.c -o main1

main2: main2.o

    @gcc main2.o -o main2

main2.o: main2.c

    @gcc -c main2.c 

这样就会生成一个我们不需要的过程文件main2.o

如果希望将生成的过程文件删掉,根据前面再增加一个目标clean

all:main1 main2 clean

main1: main1.c

    @gcc main1.c -o main1

main2: main2.o

    @gcc main2.o -o main2

main2.o: main2.c

    @gcc -c main2.c 

clean:

    @rm -f main2.o

但是当我们make之后main2.o仍然存在,怎么回事呢makefile中的all和.PHONY的作用

原来这里的目标clean没有任何依赖,make执行时认为这已经到“根上”了(就是认为磁盘上有clean,就像main2.c),将其忽略(尽管它有规则)。

关键字.PHONY可以解决这问题,告诉make该目标是“假的”(磁盘上其实没有clean),这时make为生成这个目标就会将其规则执行一次。.PHONY修饰的目标就是只有规则没有依赖。

加上一句.PHONY:clean即可:

all:main1 main2 clean

main1: main1.c

    @gcc main1.c -o main1

main2: main2.o

    @gcc main2.o -o main2

main2.o: main2.c

    @gcc -c main2.c 

.PHONY:clean

clean:

    @rm -f main2.o

【附】

phony ['fəuni] a. 假的

GNU的make能够使整个软件工程的编译、链接只需要一个命令就可以完成。

makefile的术语:

规则:用于说明如何生成一个或多个目标文件

规则的格式:

targets:prerequisites

    command

目标: 依赖

    命令

+++++命令需要以[TAB]键开始++++

如何在makefile中指定头文件目录

指定头文件目录,一般都bai是通过编译器参du数-I(大写的I)来指定的,

假设头文zhi件目录在:
/home/develop/include

则可以通过:
-I/home/develop/include
将该目录添加到头文件搜索路径中

在makefile中则可以这样写:


CFLAGS=-I/home/develop/include
然后在你编译的时候,引用CFLAGS即可,如:


yourapp:*.c
    gcc $(CFLAGS) -o yourapp

Makefile中的-Wall -O2 -Os -g等选项介绍

-Wall:选项可以打印出编译时所有的错误或者警告信息。这个选项很容易被遗忘,编译的时候,没有错误或者警告提示,以为自己的程序很完美,其实,里面有可能隐藏着许多陷阱。变量没有初始化,类型不匹配,或者类型转换错误等警告提示需要重点注意,错误就隐藏在这些代码里面。没有使用的变量也需要注意,去掉无用的代码,让整个程序显得干净一点。下次写Makefile的时候,一定加-Wall编译选项。

-O0: 表示编译时没有优化。

-O1: 表示编译时使用默认优化。

-O2: 表示编译时使用二级优化。

-O3: 表示编译时使用最高级优化。

-Os:相当于-O2.5优化,但又不所见代码尺寸,具体见链接:点击打开链接 点击打开链接

CFLAGS 表示用于 C 编译器的选项,
CXXFLAGS 表示用于 C++ 编译器的选项。
这两个变量实际上涵盖了编译和汇编两个步骤。

CFLAGS 指定头文件(.h文件)的路径,如:CFLAGS=-I/usr/include -I/path/include。同样地,安装一个包时会在安装路径下建立一个include目录,当安装过程中出现问题时,试着把以前安装的包的include目录加入到该变量中来。

LDFLAGSgcc 等编译器会用到的一些优化参数,也可以在里面指定库文件的位置。用法:LDFLAGS=-L/usr/lib -L/path/to/your/lib。每安装一个包都几乎一定的会在安装目录里建立一个lib目录。如果明明安装了某个包,而安装另一个包时,它愣是说找不到,可以抒那个包的lib路径加入的LDFALGS中试一下。

LIBS:告诉链接器要链接哪些库文件,如LIBS = -lpthread -liconv

简单地说,LDFLAGS是告诉链接器从哪里寻找库文件,而LIBS是告诉链接器要链接哪些库文件。不过使用时链接阶段这两个参数都会加上,所以你即使将这两个的值互换,也没有问题。

有时候LDFLAGS指定-L虽然能让链接器找到库进行链接,但是运行时链接器却找不到这个库,如果要让软件运行时库文件的路径也得到扩展,那么我们需要增加这两个库给"-Wl,R":

LDFLAGS = -L/var/xxx/lib -L/opt/mysql/lib -Wl,R/var/xxx/lib -Wl,R/opt/mysql/lib

如果在执行./configure以前设置环境变量export LDFLAGS="-L/var/xxx/lib -L/opt/mysql/lib -Wl,R/var/xxx/lib -Wl,R/opt/mysql/lib" ,注意设置环境变量等号两边不可以有空格,而且要加上引号(shell的用法)。那么执行configure以后,Makefile将会设置这个选项,链接时会有这个参数,编译出来的可执行程序的库文件搜索路径就得到扩展了。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值