Makefile 使用标志$(@:.o=.d)后生成文件依赖项错误

Makefile 使用标志$(@:.o=.d)后生成文件依赖项错误,makefile,gnu-make,Makefile,Gnu Make,我已经为下面的代码结构创建了一个Makefile work ├── code | | | ├──inc/ | | └── main.h and test.h files here | | | ├──src/ │ └── main.c and test.c files here ├── _Build/ │ └── Makefile here 这是生成文件 # All path are referenced with the d

我已经为下面的代码结构创建了一个Makefile

work
├── code
|     | 
|     ├──inc/
|     |   └── main.h and test.h files here
|     |
|     ├──src/
│         └── main.c and test.c files here
├── _Build/
│     └── Makefile here
这是生成文件

# All path are referenced with the directory path of Makefile

# Directory Path for workspace
WORKSPACE          = ..

# Directory path for code 
PATH_DIR_CODE      = $(WORKSPACE)/code

# Directory path for c source files 
PATH_DIR_C_SOURCES = $(PATH_DIR_CODE)/src

# Directory path for c header files
DIR_PATH_C_HEADERS = $(PATH_DIR_CODE)/inc

# Directory path for obj files
DIR_PATH_OBJ       = $(WORKSPACE)/obj

# Directory path for executables
DIR_PATH_BIN       = $(WORKSPACE)/bin

# Executable name declaration
FILE_PATH_EXE      = $(DIR_PATH_BIN)/main

# Command mkdir 
MKDIR               = mkdir

FILE_PATH_C_HEADER  = $(shell find $(PATH_DIR_CODE) -name *.h)
DIR_PATH_C_HEADER   = $(patsubst %/,%,$(sort $(dir $(FILE_PATH_C_HEADER)))) 

FILE_PATH_C_SRC     = $(shell find $(PATH_DIR_CODE) -name *.c)
DIR_PATH_C_SRC      = $(patsubst %/,%,$(sort $(dir $(FILE_PATH_C_SRC))))

INC_FILE_C_HEADER   = $(addprefix -I, $(DIR_PATH_C_HEADER))

FILE_PATH_OBJ       = $(patsubst $(DIR_PATH_C_SRC)/%.c, $(DIR_PATH_OBJ)/%.o, $(FILE_PATH_C_SRC))

CC       = gcc
CFLAGS   = -Werror -Wall
CDEPS    = -MMD -MP -MF $(@:.o=.d)
LDFLAGS  = -Llib
LDLIBS   = -lm
MKDIR    = mkdir

-include $(FILE_PATH_OBJ:.o=.d)

all : $(FILE_PATH_EXE)  

.PHONY : all

$(FILE_PATH_EXE) : $(FILE_PATH_OBJ) | $(DIR_PATH_BIN)
    $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@     

$(DIR_PATH_OBJ)/%.o : $(DIR_PATH_C_SRC)/%.c | $(DIR_PATH_OBJ)   
    $(CC) $(CFLAGS) -c $< $(CDEPS) -o $@

$(DIR_PATH_BIN) $(DIR_PATH_OBJ):
    $(MKDIR) -p $@

clean : 
    $(RM) -rv $(DIR_PATH_BIN) $(DIR_PATH_OBJ)

我仍然得到以下错误

mkdir -p ../obj
gcc -Werror -Wall -c ../code/src/main.c -MMD -MP -MF ../obj/main.d -o ../obj/main.o
../code/src/main.c:4:10: fatal error: test.h: No such file or directory
 #include "test.h"
          ^~~~~~~~
compilation terminated.
make: *** [Makefile:56: ../obj/main.o] Error 1
要删除此错误,Makefile中应该包含什么


依赖项应该通过此逻辑删除,或者应该使用其他一些逻辑?

您将两个不同的东西混为一谈

.d
文件告诉make在哪里查找目标的先决条件。在本例中,目标是一个对象文件(
.o
),前提条件是一个头文件,但要使它们只是“目标”和“前提条件”。Make不仅限于编译C程序:它基本上可以执行任何任务,其中更改某些文件意味着需要更新某些其他文件:编译程序(不仅仅是C程序)是一种常见用途,但它可以生成文档、网站、运行测试等。Make通过运行命令来完成其工作,就像您自己在命令行中所做的那样(make永远不会忘记添加选项,也不会出现拼写错误)。在内部,它对“编译器”和“链接器”一无所知

您得到的错误来自编译器(或者是学究,预处理器),而不是make,并且必须告诉编译器在哪里查找需要包含的头文件。这是两件完全不同的事情,需要不同的操作:编译器要求您使用
-I
命令行选项提供要搜索的目录

我想,如果编译器能够解析make的
.d
文件并找出在哪里查找头,那就太好了,但它不能。您必须自己指定标志


在您的情况下,更清楚的是:您实际上是在使用编译器生成
.d
文件!因此存在一个鸡和蛋的问题:如果编译器可以从
.d
文件中获取路径,但是
.d
文件是从编译器中创建的,那么路径首先从何而来?

看起来像是
CFLAGS
需要
-I../code/inc
@Milag在这种情况下,如果包含头文件文件夹,则不需要依赖关系逻辑。那么如何在不指定包含头文件文件夹的情况下删除依赖关系呢?如果我给出了include文件夹的详细信息,那么编译器就不需要.d文件。我不知道“删除依赖项”是什么意思。没有必要不是真的。我已经在上面解释了为什么您需要
.d
文件(用于了解文件何时过期)和
-I
选项(用于编译器查找头文件)。它们用于不同的程序(make vs compiler),用于不同的目的,您不能没有它们中的任何一个。如果所有源文件和头文件都在同一个文件夹中,则不需要include-I标志。这并不总是正确的。详细信息取决于您的编译器,但通常
语法中包含的标题不在工作目录中查找,它们只在
-I
目录中查找。但是,如果您使用的是
“…”
包含,则大多数编译器(当然是GCC)将自动查找与正在编译的源文件相同的文件。但是,这与您的情况无关,因为您已经清楚地指出头文件与源文件不在同一目录中;您有
code/src/main.c
但是
code/inc/test.h
。您必须添加
-I
,编译器才能找到
test.h
。我不理解.d在这里的用法。如果使用-I标志并且指定了include目录,那么.d文件的意义是什么?
-include $(FILE_PATH_OBJ:.o=.d)
mkdir -p ../obj
gcc -Werror -Wall -c ../code/src/main.c -MMD -MP -MF ../obj/main.d -o ../obj/main.o
../code/src/main.c:4:10: fatal error: test.h: No such file or directory
 #include "test.h"
          ^~~~~~~~
compilation terminated.
make: *** [Makefile:56: ../obj/main.o] Error 1