【问题标题】:How to write Makefile to include multi directories如何编写 Makefile 以包含多个目录
【发布时间】:2013-12-25 03:04:46
【问题描述】:

我有以下设置。在主文件夹和同一个文件夹中有两个名为 /driverlib 和 /inc 的文件夹,我有一个链接器文件和两个 c 文件,startup_gcc 和 blink.c。

我遵循了我在网上找到的 STM32F4 模板。我对其进行了修改并尝试在我的文件夹中包含这两个目录。但是我收到以下错误:

C:\Users\D\Documents\ARM-Tiva\blinky3>make
driverlib/adc.c:49:24: fatal error: inc/hw_adc.h: No such file or directory
compilation terminated.
make: *** [driverlib/adc.o] Error 1

有人可以向我解释如何包含这两个目录,以便 /inc 文件夹对 /driverlib 文件夹可见。

这是生成文件:

OBJCOPY     = $(TC)-objcopy
OBJDUMP     = $(TC)-objdump
SIZE        = $(TC)-size

###################################################
# Set Include Paths
INCLUDES    = -I /inc 
INCLUDES    = -I /driverlib

# Set Sources
LIB_SRCS    = $(wildcard driverlib/*.c)
USER_SRCS   = $(wildcard src/*.c)

# Set Objects
LIB_OBJS    = $(LIB_SRCS:.c=.o)
USER_OBJS   = $(USER_SRCS:.c=.o) startup_gcc.o


# Set Libraries
LIBS        = -lm -lc

###################################################
# Set Board
MCU         = -mthumb -mcpu=cortex-m4
DEFINES     = -DPART_LM4F120H5QR -DTARGET_IS_BLIZZARD_RA1

# Set Compilation and Linking Flags
CFLAGS      = $(MCU) $(FPU) $(DEFINES) $(INCLUDES) \
            -g -Wall -std=gnu90 -O0 -ffunction-sections -fdata-sections
ASFLAGS     = $(MCU) $(FPU) -g -Wa,--warn -x assembler-with-cpp
LDFLAGS     = $(MCU) $(FPU) -g -gdwarf-2 \
            -Ttivalinker.ld \
            -Xlinker --gc-sections -Wl,-Map=$(PROJ_NAME).map \
            $(LIBS) \
            -o $(PROJ_NAME).elf

###################################################
# Default Target
all: $(PROJ_NAME).bin info

# elf Target
$(PROJ_NAME).elf: $(LIB_OBJS) $(USER_OBJS)
    @$(CC) $(LIB_OBJS) $(USER_OBJS) $(LDFLAGS)
    @echo $@

# bin Target
$(PROJ_NAME).bin: $(PROJ_NAME).elf
    @$(OBJCOPY) -O binary $(PROJ_NAME).elf $(PROJ_NAME).bin
    @echo $@

#$(PROJ_NAME).hex: $(PROJ_NAME).elf
#   @$(OBJCOPY) -O ihex $(PROJ_NAME).elf $(PROJ_NAME).hex
#   @echo $@

#$(PROJ_NAME).lst: $(PROJ_NAME).elf
#   @$(OBJDUMP) -h -S $(PROJ_NAME).elf > $(PROJ_NAME).lst
#   @echo $@

# Display Memory Usage Info
info: $(PROJ_NAME).elf
    @$(SIZE) --format=berkeley $(PROJ_NAME).elf

# Rule for .c files
.c.o:
    @$(CC) $(CFLAGS) -c -o $@ $<
    @echo $@

# Rule for .s files
.s.o:
    @$(CC) $(ASFLAGS) -c -o $@ $<
    @echo $@

# Clean Target
clean:
    $(RM) $(LIB_OBJS)
    $(RM) $(USER_OBJS)
    $(RM) $(PROJ_NAME).elf
    $(RM) $(PROJ_NAME).bin
    $(RM) $(PROJ_NAME).map

问题显然出在这一段:

###################################################
# Set Include Paths
INCLUDES    = -I /inc 
INCLUDES    = -I /driverlib

# Set Sources
LIB_SRCS    = $(wildcard driverlib/*.c)
USER_SRCS   = $(wildcard src/*.c)

# Set Objects
LIB_OBJS    = $(LIB_SRCS:.c=.o)
USER_OBJS   = $(USER_SRCS:.c=.o) startup_gcc.o

我不明白为什么 driverlib 不包含 inc 目录文件。

编辑

我想澄清我的设置以供将来参考:在名为 blinky 的主文件夹中,我有三个文件夹:driverlib、inc 和 src。 driverlib 和inc 文件夹取自TivaWARE 文件夹,而src 文件夹包含blinky.c 和startup_gcc.c 文件。如果您使用 make ,则给出以下内容:

C:\Users\D\Documents\ARM-Tiva\blinky>make
driverlib/adc.c:49:24: fatal error: inc/hw_adc.h: No such file or directory
compilation terminated.
make: *** [driverlib/adc.o] Error 1   

这说明driverlib文件夹中的文件adc.c不能包含文件hw_adc.h

我按照以下建议修改了 Makefile:

# Set Sources
LIB_SRCS    = $(wildcard driverlib/*.c)
USER_SRCS   = $(wildcard src/*.c)

# Set Objects
LIB_OBJS    = $(LIB_SRCS:.c=.o)
USER_OBJS   = $(USER_SRCS:.c=.o) src/startup_gcc.o

# Set Include Paths
INCLUDES    = -Idriverlib/ \
            -Iinc \
            -Isrc/

Betas 解决方案很有帮助,唯一的问题是我不想编辑 driverlib 文件夹中的所有文件。目录的命名约定不是我的决定。如果您可以看到 driverlib 文件夹中的所有文件,您会发现每个驱动程序文件(例如 CAN 驱动程序或 ADC)都遵循此约定:

#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_can.h"
#include "inc/hw_ints.h"
#include "inc/hw_nvic.h"
#include "inc/hw_memmap.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_types.h"
#include "driverlib/can.h"
#include "driverlib/debug.h"
#include "driverlib/interrupt.h" 

所以现在我知道问题出在哪里,但我缺乏编辑 Makefile 的理解。 通常,如果文件 can.c 和 can.h 位于 driverlib 文件夹中,使用 #include "can.h" 就足够了,所以我不明白如果所有 .h 和 .c 都使用 #include "driverlib/can.h" 有什么意义文件位于同一 driverlib 文件夹中。如果我编辑所有 inc/ 标头,那么我可以获得一个工作二进制文件。然而,目的不是修改从 TI 获得的默认库存驱动程序文件和文件夹,而是使用 Makefile。

因此,为了澄清您是否遵循 Betas 解决方案并编辑所有文件,或者如果您将所有文件放在一个大目录中,那么您可以获得一个工作二进制文件。另外,为了将来参考,我发现我可以使用 Energia 来做我正在做的事情,因为它使用相同的编译器,并且 TIVA 包括刻录在 ROM 上的完整外围库。

【问题讨论】:

  • 可能是重复的问题:stackoverflow.com/questions/4134764/…
  • 我已经试过了。我仍然得到同样的错误。我也尝试阅读 Make 手册,但没有取得太大的成功。
  • “inc/hw_adc.h”不在“/inc”或“/driverlib”中。如果您已经在包含路径中添加了“inc/”,也许您可​​以将“inc/hw_adc.h”替换为“hw_adc.h”。
  • 我这样做了,如果我从主文件的标题中删除目录部分,它就会以这种方式工作。我所做的是将所有文件放在一个大目录中,发现它们编译得很好,我可以得到一个 bin 文件。当它们被放回目录时,一切都会停止工作。以下是主文件的标题: #include #include #include "inc/tm4c123gh6pm.h" #include "inc/hw_types.h" #include "inc/hw_memmap.h" #include "driverlib/sysctl.h" #include "driverlib/rom.h" #include "driverlib/rom_map.h" #include "driverlib/gpio.h" #include "driverlib/systick.h"
  • #include 指令中拼出路径通常是个坏主意。你能告诉我们adc.c 中的#include 指令吗?

标签: gcc makefile arm


【解决方案1】:

我不确切知道错误的原因,但这不正确:

INCLUDES    = -I /inc 

# Now INCLUDES is "-I /inc"

INCLUDES    = -I /driverlib

# Now INCLUDES is "-I /driverlib", and inc has been forgotten.

我认为你的意思是:

INCLUDES    = -I /inc 
INCLUDES    += -I /driverlib

编辑:

在#include 指令中拼出路径通常是个坏主意。在adc.c 中,更改:

#include "inc/hw_adc.h"

到这里:

#include "hw_adc.h"

并在 makefile 中删除前导斜杠(因为您不会总是在根目录中):

INCLUDES    = -I inc 
INCLUDES    += -I driverlib

【讨论】:

  • 我尝试了同样的结果。在 WKPlus 的建议之后,我尝试以这种方式包含它 INCLUDES = -I /inc -I /driverlib 并且我仍然再次得到相同的结果。
  • 好的,正如我之前提到的,如果我将所有文件放在一个大目录中,它就可以工作,因为我得到了一个工作 bin 文件。我想通过保持默认结构来组织混乱
  • @Dimo:保持什么“默认结构”?你不喜欢我解决方案的哪一部分?
  • 默认结构只包含两个目录和未修改的源文件。我不想修改驱动程序库中的所有文件以从头文件中删除 inc 部分,因为每个特定驱动程序都包含此#include“inc/hw_something.h”。您提出的解决方案的第一部分不起作用,即我仍然收到相同的错误消息。我认为这样做的方法是在每个目录中使用 Makefiles。我也不能以某种方式给你投票。
  • @Dimo:也许我们有语言问题,但不清楚你想要什么,而且你似乎在尝试解决方案而不理解它们。我能做的就是祝你好运。
【解决方案2】:

如果您在您的问题中提供了一个未找到的头文件的实际完整路径,并且除了错误消息之外还提供了一个由 make 运行的示例编译行,那么最有帮助的事情将是。鉴于这些信息,很容易看出哪里出了问题。

似乎发生了一些误传。您在主文件夹中写入两个名为 /driverlib 和 /inc 的文件夹。以/ 开头的文件夹名称根据定义位于目录结构的根目录,而不是在任何其他文件夹中。我不知道你说的在主文件夹上是什么意思。

我要说的第一件事是您使用的是 Windows(从命令行提示符可以看出),因此您需要确保您使用的 make 版本能够执行正确的操作将 Windows 路径名转换为 UNIX 路径名。例如,如果您使用的是 Cygwin 版本的 GNU make,那么我认为您使用的路径不正确。

其次,我注意到您使用的是-I /inc;也就是说,inc 目录位于文件系统的根目录。那是你的意图吗? Beta 的答案已将其更改为-I inc,这意味着目录inc 作为当前工作目录的子目录,这可能会有很大不同。

第三,如果标题的路径名是/inc/hw_adc.h,并且你的命令行上有-I /inc#include "inc/hw_adc.h",我相信你可以看到这绝对行不通。编译器将寻找名为/inc/inc/hw_adc.h 的头文件。如果你想在你的#include 行中保留相对路径名inc/hw_adc.h,并且头文件的路径是/inc/hw_adc.h,那么你应该在编译命令行上只使用-I /(根目录)。

最后,我要说的是,我实际上不同意 Beta 的建议,即在包含行中拼出路径是一个坏主意。这很常见:如果您使用的库包含大量头文件,则通常将头文件收集在子目录中(考虑诸如 Boost 或 X11 等)并且它是 IMO, em> 练习在源代码的#include 行中使用子目录的名称。

不过,另一方面,我同意 Beta 的观点,即像 inc 这样的目录名称完全是蹩脚的,而且几乎没有任何用处。该目录的名称应该能够以某种方式唤起可以在其中找到的各种标题,而不是像“inc”这样无用的通用名称。

【讨论】:

  • 我同意将路径放入#include 指令是一种常见 做法,但我仍然认为这是一种糟糕 做法(即使我'我是少数)。 Demasiada cordura puede ser la peor de las locuras, ver la vida como es y no como deberíade ser.
  • 我完全不同意。将目录放在那里提供了一个通常很关键的命名空间。如果没有目录前缀,只需要两个带有socket.htypes.h 头文件的不同库,你就有麻烦了。将文件收集到目录中是一种很好的做法,一旦将其保存在目录中,将库名称作为前缀添加到每个文件(foobar/foobar_types.hfoobar/types.h)是多余的。
  • 等等...我认为我们在某种程度上达成了激烈的协议,至少关于有单独的标题目录。我开始在#include 指令中针对路径编写我的论点(更喜欢让 Make 选择适合源文件的目录),但意识到如果baz.c 必须#include 两者foo/types.h bar/types.h。我仍然认为不必要地在源代码中放置路径是不好的,我不确定它是否是最好的解决方案,但我必须重新考虑这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多