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


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

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

    编译: make   or   make -f Makefile all

    清除: make clean  or  make -f Makefile clean

    1. CC = g++
    2. CUR_PATH = $(PWD)
    3. FLAGS = -std=c++11 -O2 -W -Wall
    4. FLAGS += -I/home/project/opencv/build/ -I/home/project/opencv/include/
    5. FLAGS += -I/home/project/opencv/modules/calib3d/include
    6. #FLAGS += ... 其他必要的头文件的路径
    7. LDFLAGS = -L../libopencv_calib3d.a
    8. LDFLAGS += ./libopencv_core.a
    9. LDFLAGS += ./libopencv_dnn.a
    10. LDFLAGS += ./libopencv_core.a
    11. LDFLAGS += ./libopencv_features2d.a
    12. LDFLAGS += ./libopencv_flann.a
    13. LDFLAGS += ./libopencv_gapi.a
    14. LDFLAGS += ./libopencv_highgui.a
    15. LDFLAGS += ./libopencv_imgcodecs.a
    16. LDFLAGS += ./libopencv_imgproc.a
    17. LDFLAGS += ./libopencv_ml.a
    18. LDFLAGS += ./libopencv_objdetect.a
    19. LDFLAGS += ./libopencv_photo.a
    20. LDFLAGS += ./libopencv_stitching.a
    21. LDFLAGS += ./libopencv_video.a
    22. LDFLAGS += ./libopencv_videoio.a
    23. LDFLAGS += ./libade.a
    24. LDFLAGS += ./libIlmImf.a
    25. LDFLAGS += ./libippicv.a
    26. LDFLAGS += ./libippiw.a
    27. LDFLAGS += ./libittnotify.a
    28. LDFLAGS += ./liblibopenjp2.a
    29. LDFLAGS += ./liblibprotobuf.a
    30. LDFLAGS += ./liblibtiff.a
    31. LDFLAGS += -ldl -lm -lpthread -lrt
    32. TARGET = main
    33. SMP_SRCS = test_resize.cpp
    34. OBJS := $(SMP_SRCS:%.c=%.o)
    35. CFLAGS += $(FLAGS)
    36. MPI_LIBS = $(LDFLAGS)
    37. .PHONY : clean all
    38. all: $(TARGET)
    39. $(TARGET):$(OBJS)
    40. @$(CC) $(CFLAGS) -o $@ $^ -Wl,--start-group $(MPI_LIBS) \
    41. Wl,--end-group,-gc-sections,-g
    42. @echo "start the compilexxxxxxxxxxxxxxxxxxxxxxx"
    43. @echo $(MPI_LIBS)
    44. @echo $@
    45. @echo $^
    46. @echo $(CFLAGS)
    47. @echo $(OBJS)
    48. @echo $(TARGET)
    49. clean:
    50. @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博客

        

  • 相关阅读:
    openssl漏洞检查修复
    聊聊自制的探索大全扑克牌
    K8s-Helm
    Win11蓝屏开不了机进入安全模式的快速方法
    从零实现ORM框架GeoORM-对象表结构映射-02
    深入理解linux shell 中的exec内置命令&ubuntu bash
    RockTree TOKEN2049 Party 火爆的背后,千亿美元规模的“超级聚会”
    产品设计如何提升客户体验?
    Spring MVC
    客户:我们系统太多,能不能实现多账号互通?
  • 原文地址:https://blog.csdn.net/yangsong4353/article/details/126606513