实用的GCC Makefile语法及参数详解

二话不说,先上一个Makefile的源码。

基于下述的Makefile,可以直接执行命令:

编译: make   or   make -f Makefile all

清除: make clean  or  make -f Makefile clean

CC = g++

CUR_PATH = $(PWD)

FLAGS = -std=c++11 -O2 -W -Wall
FLAGS += -I/home/project/opencv/build/ -I/home/project/opencv/include/
FLAGS += -I/home/project/opencv/modules/calib3d/include
#FLAGS += ... 其他必要的头文件的路径

LDFLAGS = -L../libopencv_calib3d.a
LDFLAGS += ./libopencv_core.a
LDFLAGS += ./libopencv_dnn.a
LDFLAGS += ./libopencv_core.a
LDFLAGS += ./libopencv_features2d.a
LDFLAGS += ./libopencv_flann.a
LDFLAGS += ./libopencv_gapi.a
LDFLAGS += ./libopencv_highgui.a
LDFLAGS += ./libopencv_imgcodecs.a
LDFLAGS += ./libopencv_imgproc.a
LDFLAGS += ./libopencv_ml.a
LDFLAGS += ./libopencv_objdetect.a
LDFLAGS += ./libopencv_photo.a
LDFLAGS += ./libopencv_stitching.a
LDFLAGS += ./libopencv_video.a
LDFLAGS += ./libopencv_videoio.a
LDFLAGS += ./libade.a
LDFLAGS += ./libIlmImf.a
LDFLAGS += ./libippicv.a
LDFLAGS += ./libippiw.a
LDFLAGS += ./libittnotify.a
LDFLAGS += ./liblibopenjp2.a
LDFLAGS += ./liblibprotobuf.a
LDFLAGS += ./liblibtiff.a
LDFLAGS += -ldl -lm -lpthread -lrt

TARGET = main

SMP_SRCS = test_resize.cpp

OBJS  := $(SMP_SRCS:%.c=%.o)

CFLAGS += $(FLAGS)

MPI_LIBS = $(LDFLAGS)

.PHONY : clean all

all: $(TARGET)
$(TARGET):$(OBJS)
    @$(CC) $(CFLAGS) -o $@ $^ -Wl,--start-group $(MPI_LIBS)  \
    Wl,--end-group,-gc-sections,-g
    @echo "start the compilexxxxxxxxxxxxxxxxxxxxxxx"
    @echo $(MPI_LIBS)
    @echo $@
    @echo $^
    @echo $(CFLAGS)
    @echo $(OBJS)
    @echo $(TARGET)

clean:
    @rm -f *.o main

1. 分析Makefile的入口在 .PHONY的位置。

    Makefile的target默认是文件,何为target?拿make clean举例,clean就可以认为是target。但是这里的clean并不希望是文件,而希望是Makefile中clean标识,所以使用.PHONY来伪造一下。总结就是:.PHONY后面的target表示的是一个伪造的target, 而不是真实存在的target文件。 .PHONY后面的target也是此Makefile所支持的命令。默认只执行make命令时,实际就想当于执行make all.

    make则执行“all:”下面的内容,直到出现另外一个标识。

    make clean则执行“clean:”下面的内容,直到出现另外一个标识。

    注意:标识内容下面的空白(例如@echo $^之前的空白)均是tab,不是空格。

2. 依赖关系

    all: $(TARGET)  或者 $(TARGET):$(OBJS) 这种,由冒号隔开,即存在依赖关系,表示前面的标识依赖后面的内容。其中$(TARGET) 表示取出TARGET中的值(即main),故all: $(TARGET)可以翻译为all: main。详细的可以参考下面链接中的说明:makefile文件中的依赖关系理解_墨墨无文的博客-CSDN博客_makefile 依赖

3. 编译

    @$(CC) $(CFLAGS) -o $@ $^ -Wl,--start-group $(MPI_LIBS)  -Wl,--end-group,-gc-sections,-g

    $(xxx)是取xxx中的值,用前面的内容,替换其中的值,就可以得到正常的编译命令。

4. 参数说明

    1)@

          放在整行之前,表示不打印此行内容。举例:@echo "start the compilexxxxxxxxx",实际打印出来的内容为“start the compilexxxxxxxxx”, 如果没有此@,则打印出两行,分别是:

echo "start the compilexxxxxxxxx" 

start the compilexxxxxxxxx

    2)-o

        生成指定的输出文件。用在生成可执行文件时。默认的时候, gcc 编译出来的文件是 a.out,如果不想使用这个名字,则可以使用此关键字,后面跟你想要的可执行文件的名字即可。本事例使用的名字是-o $@

    3)$@

        表示目标文件。在此文中,$@的内容即是$(TARGET),即是main。所以-o $@即是-o main.

    4)  $^

        表示所有的依赖文件,以空格分隔。如果依赖文件中有重复,那么这个变量会去除重复文件,只保留一份。在此文中,$^的内容即是$(OBJS),即是$(SMP_SRCS:%.c=%.o),即是test_resize.cpp。更多符号意思可以参考下面的链接:Makefile中的一些符号介绍_guanghma的博客-CSDN博客_makefile 符号

     5)--start-group and --end-group

        如果有多个静态库文件需要一起编译,那可以使用这两个参数将库包含起来。并且静态库要放在源码的后面,gcc是对文件的放置顺序有要求的。切记切记。此文中源码$^ 放在了库文件$(MPI_LIBS)之前。大致原因是gcc先编译的文件,如果其中没有找到对应的函数,则将这些函数暂存为未解析的符号,然后再编译后面的文件是,从后面的文件中找此未解析符号对应的源码,如果有,则将未解析的符号进行删除。此过程只顺序进行一次,如果反过来,则未解析的符号就找不到对应的源码了,对导致编译错误。相信解释可以参考下面的链接:为什么gcc中'-l'选项的顺序很重要? [重复]_编程黑洞网

        --start-group ... --end-group:之间的内容只能为文件名或-l选项;为了保证内容项中的符号能被解析,链接器会在所有的内容项中循环查找。这种用法存在性能开销,最好是当有两个或两个以上内容项之间存在有循环引用时才使用。

    6)-l

        指定静态库的名称(例如-lgcc、 -lgcc_eh 、-lc实际是指文件名为libgcc.a、libgcc_eh.a、libc.a的库),此文中用到了-ldl -lm -lpthread -lrt。

    7)-g

        告知编译器,在编译的时候,产生调试信息   

    8)-L

        链接外部静态库与动态库的查找路径。编译器会自动解析后面的一个参数。此文中的语句LDFLAGS = -L../libopencv_calib3d.a实际可以拆分为2行即 LDFLAGS = -L. 和 LDFLAGS += ./libopencv_calib3d.a。

    9)-std=c++11

         使用C++11的标准。

    10)-O2

        优化级别。分为-O0 、-O1 、-O2 、-O3。编译器的优化选项的 4 个级别,-O0 表示没有优化, -O1 为默认值,-O3 优化级别最高

    11)-I

        头文件所在的路径。此文中使用多个-Ixxx,表示有多个头文件的路径。

    12)echo

        打印命令,可以作为调试时打印一些参数的值。

    13)SMP_SRCS:%.c=%.o

        将SMP_SRCS中所有的.c替换为.o

参考链接:

GCC编译器30分钟入门教程

GCC 参数详解 | 菜鸟教程

gcc 命令,Linux gcc 命令详解:基于C/C++的编译器 - Linux 命令搜索引擎

程序的编译链接过程 - 可可西 - 博客园

OpenCV : undefined reference to cv::imread()_Sunshine_in_Moon的博客-CSDN博客

    

你可能感兴趣的:(makefile,gcc,opencv,编辑器)