4.makefile自动推导目标代码配置和伪目标clean清理

4.makefile自动推导目标代码配置和伪目标clean清理

4.1 make和makefile

  • makefile文件主要包含了5部分内容:
  1. 显式规则。说明了如何生成一个或多个目标文件。由makefile文件的创作者指出,包括要生成的文件、文件的依赖文件、生成的命令。
  2. 隐式规则。由于make有自动推导的功能,所以隐式的规则可以比较粗糙地简略书写makefile文件,这是由make所支持的。
  3. 变量定义。在makefile文件中要定义一系列的变量,变量一般都是字符串,这与C语言中的宏有些类似。当makefile文件执行时,其中的变量都会扩展到相应的引用位置上。
  4. 文件指示。其包括3个部分,一个是在一个makefile文件中引用另一个makefile文件;另一个是指根据某些情况指定makefile文件中的有效部分;还有就是定义一个多行的命令。
  5. 注释。makefile文件中只有行注释,其注释用“#”字符。如果要在makefile文件中使用“#”字符,可以用反斜框进行转义,如:“#”。

  make 是一个功能强大的构建工具,虽然 make 需要根据 makefile 中指定的规则来完成源文件的编译。我们编写 makefile 的时候难免写的不是那么严谨从而漏写一些构建规则,但是会发现程序还是会被编译成功。这是因为 make 有自动推导的能力,不会完全依据makefile。

4.2 自动推导

​ 如果说某个依赖项是由它能推导出来,它自己可以生成编译代码,自动推导涉及.o文件

# first_make
# $^ 依赖 不重复
# $@ 目标
# @ 不显示命令执行 -失败不停止
TARGET=first_make
LIBS=-lpthread
$(TARGET):first_make.o xdata.o
        @#-rm test
        @echo "begin build $(TARGET)"
        $(CXX) $^ -o $@ $(LIBS)
        @echo "$(TARGET) build success!"
root@cmt-virtual-machine:/home/cmt/src/first_make# ls
first_make.cpp  makefile  xdata.cpp  xdata.h
root@cmt-virtual-machine:/home/cmt/src/first_make# make
g++    -c -o first_make.o first_make.cpp
g++    -c -o xdata.o xdata.cpp
begin build first_make
g++ first_make.o xdata.o -o first_make -lpthread
first_make build success!
root@cmt-virtual-machine:/home/cmt/src/first_make# 

g++针对.o文件生成,这里涉及了自动推导。

但是自动推导这里有一个问题,如果说自动推导涉及头文件的引用,

//first_make.cpp
#include <iostream>
#include <thread>
#include "xdata.h"
#include "test.h"
using namespace std;

void ThreadMain()
{
        cout << "Thread Main" << endl;
}

int main(int argc, char *argv[])
{
        thread th(ThreadMain);
        cout << "test make" << endl;
        th.join();
        XData d;
        return 0;
}

test.h

//../test_gcc
#define CONF_PATH "/user/local/xcj/"
root@cmt-virtual-machine:/home/cmt/src/first_make# ls
first_make  first_make.cpp  first_make.o  makefile  xdata.cpp  xdata.h  xdata.o
root@cmt-virtual-machine:/home/cmt/src/first_make# make
g++    -c -o first_make.o first_make.cpp
first_make.cpp:5:10: fatal error: test.h: 没有那个文件或目录
    5 | #include "test.h"
      |          ^~~~~~~~
compilation terminated.
make: *** [<内置>:first_make.o] 错误 1
root@cmt-virtual-machine:/home/cmt/src/first_make# 

编译时找不头文件

手动做

root@cmt-virtual-machine:/home/cmt/src/first_make# g++    -c -o first_make.o first_make.cpp -I../test_gcc

自动推导如何加这个命令?

# first_make
# $^ 依赖 不重复
# $@ 目标
# @ 不显示命令执行 -失败不停止
TARGET=first_make
LIBS=-lpthread
OBJS=first_make.o xdata.o
CXXFLAGS=-I../test_gcc
$(TARGET):$(OBJS)
        @#-rm test
        @echo "begin build $(TARGET)"
        $(CXX) $^ -o $@ $(LIBS)
        @echo "$(TARGET) build success!"
root@cmt-virtual-machine:/home/cmt/src/first_make# make
begin build first_make
g++ first_make.o xdata.o -o first_make -lpthread
first_make build success!

Makefile 中添加一个清理目标(clean target)是一个常见的做法,用于自动清理编译过程中生成的中间文件或可执行文件。这样可以避免手动清理的麻烦。

清理和编译目标有一个区别,所谓的目标项都有一个对应的目标式文件,添加清理,没有目标也没有依赖项

(1)伪目标

伪目标(Phony Targets)是在 Makefile 中一种特殊的目标,它们并不对应于实际的文件,而是用于执行特定的命令。使用伪目标的主要目的是避免文件名和目标名冲突,并确保目标总是被执行。

①伪目标的定义

伪目标通常通过在 Makefile 中使用 .PHONY 来声明。下面是一个例子:

.PHONY: clean

在这个例子中,clean 被定义为一个伪目标。无论当前目录下是否存在名为 clean 的文件,make clean 命令都会执行对应的命令(如删除文件),而不会试图将其视为一个文件目标。

②为什么使用伪目标?

  1. 避免冲突
    如果你有一个目标名与文件名相同,而你不希望 make 把它当成一个文件目标(即不会尝试通过规则去生成这个文件),你可以将其定义为伪目标。例如:

    clean:
        rm -f *.o first_make
    
    .PHONY: clean
    

    如果没有 .PHONY,且当前目录中有一个名为 clean 的文件,make 将认为 clean 已经是最新的,并且不会执行 rm -f *.o first_make 这条命令。

  2. 确保执行
    伪目标总是被认为需要执行,而不会受制于文件的时间戳。即使在不需要重新构建的情况下,你仍然希望某些命令被执行,如清理操作。

  3. 提高可读性
    伪目标通常用于表示一个动作或一组命令,而非生成某个文件。例如,cleaninstalltest 等动作就是常见的伪目标。定义伪目标可以使 Makefile 更具可读性。

③多个伪目标

你可以在 .PHONY 中定义多个伪目标,用空格分隔:

.PHONY: all clean install

在这个例子中,allcleaninstall 都被定义为伪目标。

④使用 .PHONY 的例子

一个简单的 Makefile 示例:

.PHONY: all clean install

all: program

program: main.o lib.o
    gcc -o program main.o lib.o

main.o: main.c
    gcc -c main.c

lib.o: lib.c
    gcc -c lib.c

clean:
    rm -f *.o program

install:
    cp program /usr/local/bin/

在这个例子中:

  • allcleaninstall 都是伪目标。
  • make clean 会执行 rm -f *.o program,无论当前目录中是否存在 clean 文件。
  • make install 会将 program 复制到 /usr/local/bin/,无论当前目录中是否存在 install 文件。

总结来说,伪目标是 Makefile 中一种重要的机制,可以确保某些命令总是被执行,同时避免与文件名的冲突,从而增强 Makefile 的灵活性和可靠性。

# first_make
# $^ 依赖 不重复
# $@ 目标
# @ 不显示命令执行 -失败不停止
TARGET=first_make
LIBS=-lpthread
OBJS=first_make.o xdata.o
CXXFLAGS=-I../test_gcc

$(TARGET):$(OBJS)
        @#-rm test
        @echo "begin build $(TARGET)"
        $(CXX) $^ -o $@ $(LIBS)
        @echo "$(TARGET) build success!"

clean:
        $(RM) $(OBJS) $(TARGET)
.PHONY: clean *clean
root@cmt-virtual-machine:/home/cmt/src/first_make# ls
first_make  first_make.cpp  makefile  xdata.cpp  xdata.h
root@cmt-virtual-machine:/home/cmt/src/first_make# make
g++ -I../test_gcc   -c -o first_make.o first_make.cpp
g++ -I../test_gcc   -c -o xdata.o xdata.cpp
begin build first_make
g++ first_make.o xdata.o -o first_make -lpthread
first_make build success!
root@cmt-virtual-machine:/home/cmt/src/first_make# vi makefile
root@cmt-virtual-machine:/home/cmt/src/first_make# make clean
rm -f first_make.o xdata.o first_make
root@cmt-virtual-machine:/home/cmt/src/first_make# make clean
rm -f first_make.o xdata.o first_make
root@cmt-virtual-machine:/home/cmt/src/first_make# make
g++ -I../test_gcc   -c -o first_make.o first_make.cpp
g++ -I../test_gcc   -c -o xdata.o xdata.cpp
begin build first_make
g++ first_make.o xdata.o -o first_make -lpthread
first_make build success!
root@cmt-virtual-machine:/home/cmt/src/first_make# 

每次想重新编译就进行一下清理

(2)为什么涉及到清理?

因为用了时间戳的问题可能涉及到大家代码的复制、从版本库上拿到代码时间上有时候会产生问题。一般会清理掉重新编译一下。

参考资料来源:夏曹俊

posted @ 2024-08-10 22:03  CodeMagicianT  阅读(47)  评论(0编辑  收藏  举报