美文网首页
Makefile遍历当前目录源文件及其子目录下源文件

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

作者: Nothing_655f | 来源:发表于2021-01-06 19:31 被阅读0次

    之前学的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 <stdio.h>
    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 <stdio.h>
    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遍历当前目录源文件及其子目录下源文件

          本文链接:https://www.haomeiwen.com/subject/cxeooktx.html