Makefile遍历当前目录源文件及其子目录下源文件

之前学的Makefile 不用的话经常会忘掉一些规则,记录下一些常用的功能的随笔,方便查找。

先来看一个Makefile文件,通过 foreach 和 patsubst 方法和 ^、$< 变量来构建遍历的编译

CROSS =   
CC = $(CROSS)gcc  
CXX = $(CROSS)g++  
DEBUG = -g
CFLAGS = $(DEBUG) -Wall -c -fPIC
MV = mv -f  
RM = rm -rf  
LN = ln -sf  

TARGET = libhello.so 

TOP_PATH = $(shell pwd)
INC_PATH = $(TOP_PATH)/include
SRC_PATH = $(TOP_PATH)
SRC_PATH += $(TOP_PATH)/src
MOD_PATH = $(TOP_PATH)/modules
MOD_LIB_PATH = $(MOD_PATH)/lib
MOD_INC_PATH = $(MOD_PATH)/include
DIRS = $(shell find $(SRC_PATH) -maxdepth 3 -type d)
FILES = $(foreach dir, $(DIRS), $(wildcard $(dir)/*.cpp))

##########################################################  
# modules  
##########################################################  
modules =
MODULES_PATH = $(foreach m, $(modules), $(MOD_PATH)/$(m))  

##########################################################  
# srcs  
##########################################################  
SRCS_CPP += $(foreach dir, $(DIRS), $(wildcard $(dir)/*.cpp))  
SRCS_CC += $(foreach dir, $(DIRS), $(wildcard $(dir)/*.cc))  
SRCS_C += $(foreach dir, $(DIRS), $(wildcard $(dir)/*.c))  

##########################################################  
# objs  
##########################################################  
OBJS_CPP = $(patsubst %.cpp, %.o, $(SRCS_CPP))  
OBJS_CC = $(patsubst %.cc, %.o, $(SRCS_CC))  
OBJS_C = $(patsubst %.c, %.o, $(SRCS_C))  

##########################################################  
# paths
##########################################################  
INC_PATH += -I$(MOD_INC_PATH)  
INC_PATH += -I$(MOD_PATH)  
LIB_PATH += -L$(TOP_PATH)/lib  
LIB_PATH += -L$(MOD_LIB_PATH)  

##########################################################  
# libs
##########################################################  

##########################################################  
# building
##########################################################  
all:$(TARGET)

$(TARGET) : $(OBJS_CPP) $(OBJS_CC) $(OBJS_C)  
    @ for i in $(MODULES_PATH); \  
    do \  
    make -C $$i; \  
    done  

    @ $(CXX) $^ -o $@ $(LIB_PATH) $(LIBS)  
    @ echo Create $(TARGET) ok...  

$(OBJS_CPP):%.o : %.cpp
    $(CXX) $(CFLAGS) $< -o $@ $(INC_PATH)

$(OBJS_CC):%.o : %.cc
    $(CXX) $(CFLAGS) $< -o $@ $(INC_PATH)

$(OBJS_C):%.o : %.c
    $(CXX) $(CFLAGS) $< -o $@ $(INC_PATH)

$(OBJS_C):%.o : %.c
    $(CC) $(CFLAGS) $< -o $@ $(INC_PATH)

.PHONY : clean  
clean:  
    @ $(RM) $(TARGET) $(OBJS_C)  

一些常见参数说明

-c
编译文件,但是没有链接,产生的结果就是目标文件(Object file)

-o
产生输出文件,不管是可执行的二进制文件,目标文件,汇编文件还是预处理文件。如果 -o 没有指明,默认的可执行文件为 a.out;目标文件为 .o;汇编文件为 .s;预处理文件为 .i

-O
在程序编译,链接的过程中,对源代码进行优化,导致的结果就是产生的二进制文件的执行效率会提高,但是编译链接的过程会变慢

-O2
更 -O 相比执行更好的优化,一般选这个

-Wall
产生详细的警告,出错信息,建议开启

-shared
生成动态库文件 

# 指定编译时查找共享库的路径 -l 添加共享库名称,-L添加共享库路径。
DLIBS := -lmdroid -lrt 
LDFLAGS = -L./lib/linux-arm/

# 指定运行时的库文件路径
RPATH = -Wl,-rpath=./lib/linux-arm/

生成位置无关的代码参数

-fpic
Generate position-independent code (PIC) suitable for use in a shared library, if supported for the target machine. Such code accesses all constant addresses through a global offset table (GOT). The dynamic loader resolves the GOT entries when the program starts (the dynamic loader is not part of GCC; it is part of the operating system). If the GOT size for the linked executable exceeds a machine-specific maximum size, you get an error message from the linker indicating that -fpic does not work; in that case, recompile with -fPIC instead. (These maximums are 8k on the SPARC, 28k on AArch64 and 32k on the m68k and RS/6000\. The x86 has no such limit.)

Position-independent code requires special support, and therefore works only on certain machines. For the x86, GCC supports PIC for System V but not for the Sun 386i. Code generated for the IBM RS/6000 is always position-independent.

When this flag is set, the macros __pic__ and __PIC__ are defined to 1.

-fPIC
If supported for the target machine, emit position-independent code, suitable for dynamic linking and avoiding any limit on the size of the global offset table. This option makes a difference on AArch64, m68k, PowerPC and SPARC.

Position-independent code requires special support, and therefore works only on certain machines.

When this flag is set, the macros __pic__ and __PIC__ are defined to 2.

-fpie
-fPIE
These options are similar to -fpic and -fPIC, but the generated position-independent code can be only linked into executables. Usually these options are used to compile code that will be linked using the -pie GCC option.

理解 Linux下Makefile的编写及四个特殊符号的意义@、^、$< ,参考自 https://blog.csdn.net/runfarther/article/details/50036115

我们先看三段C++程序:

一、line1的源码

line1.h

#ifndef _LINE_1_H 
#define _LINE_1_H
void line1_print(const char *strMsg);
#endif

line1.cpp

#include "line1.h"
#include 
void line1_print(const char *strMsg)
{   
    printf("This is line1 print %s.\r\n",strMsg);
}

二、line2的源码

line2.h

#ifndef _LINE_2_H 
#define _LINE_2_H
void line2_print(const char *strMsg);
#endif

line2.cpp

#include "line2.h"
#include 
void line2_print(const char *strMsg)
{   
    printf("This is line2 print %s.\r\n",strMsg);
}

三、main的源码

main.cpp

#include "line1.h"
#include "line2.h"

int main(int argc,char **argv)
{
    line1_print("hello runfarther");
    line2_print("hello runfarther");

    return 0;
}

对上面的代码,在不用Makefile时,我们可以直接用命令行来编译,得到我们的可执行程序main.out:

g++ -c main.c 
g++ -c line1.c 
g++ -c line2.c 
g++ -o main.out main.o line1.o line2.o

为了编译工作更加方便,我们通常会编写Makefile来完成编译,我们先看一个用于编译和链接上面代码的例子:

main.out:main.o line1.o line2.o
    g++ -o main.out main.o line1.o line2.o
main.o:main.c line1.h line2.h
    g++ -c main.c
line1.o:line1.c line1.h
    g++ -c line1.c
line2.o:line2.c line2.h
    g++ -c line2.c

从例子可以看出,Makefile一般的格式是:

target:components   rule

第一行表示的是依赖关系,第二行是规则,特别要注意,rule这行必须是TAB键开头。

比如说我们上面的那个Makefile文件的前面二行:

main.out:main.o line1.o line2.o
    g++ -o main.out main.o line1.o line2.o

表示我们的目标(target)main.out的依赖对象(components)是main.o line1.o line2.o,当依赖的对象在被修改的话,就要去执行规则一行所指定的命令g++ -o main.out main.o line1.o line2.o。注意规则这行是以一个TAB键开头。 接下来我来介绍下Makefile中的四个有用的特殊符号意义和使用,他们分别是@、^、$<

一、@

这个符串通常用在“规则”行中,表示不显示命令本身,而只显示它的结果,例如Makefile中的内容为:

DIR_OBJ=./obj
CMD_MKOBJDIR=if [ -d ${DIR_OBJ} ]; then exit 0; else mkdir ${DIR_OBJ}; fi

mkobjdir:
    @${CMD_MKOBJDIR}

命令行执行如下:

make mkobjdir

命令行不会显示出

if [ -d ${DIR_OBJ} ]; then exit 0; else mkdir ${DIR_OBJ}; fi

二、^、$<

这三个分别表示:

$@ --代表目标文件(target)

$^ --代表所有的依赖文件(components)

$< --代表第一个依赖文件(components中最左边的那个)。

好了,知道了他们的意义后,如果使用上面三个变量,那么简化的Makefile文件为:

main.out:main.o line1.o line2.o
    g++ -o $@ $^
main.o:main.c line1.h line2.h
    g++ -c $<
line1.o:line1.c line1.h
    g++ -c $<
line2.o:line2.c line2.h
    g++ -c $<

你可能感兴趣的:(Makefile遍历当前目录源文件及其子目录下源文件)