C语言 Makefile -将.o文件放入子文件夹

t8e9dugd  于 2023-10-16  发布在  其他
关注(0)|答案(2)|浏览(129)

我有一个简单的makefile:

run: myprogram
    ./myprog.out

myprogram: main.o otherfile.o
        gcc -o myprog.out main.o otherfile.o
    
%.o : %.c
    gcc -c $<

现在这把所有的.o文件放在我的c和h文件旁边,这很烦人。我想有一个名为“myObj”的子文件夹,例如所有的.o文件都被转储到其中,但仍然希望它将myprog构建到根文件夹中。这个问题的在线示例都过于复杂,我不确定其中的哪些行对我实现这一点至关重要,但它们似乎都有基本的$(OBJDIR)/%.o : %.c。所以我试着:

OBJDIR=myObj

run: myprogram
    ./myprog.out

myprogram: main.o otherfile.o
        gcc -o myprog.out main.o otherfile.o
    
$(OBJDIR)/%.o : %.c
    gcc -c $<

然而,这做了完全相同的事情,并转储根文件夹中的所有.o文件。我怎么能把它们放到子文件夹里呢?

nnsrf1az

nnsrf1az1#

正如注解中提到的,您需要在链接二进制文件的规则中指定.o文件在目录中,并且编译.c文件的规则需要指定输出文件(在目录中)。
你还有些其他奇怪的东西。run依赖于一个名为myprogram的文件,该文件永远不会存在,并运行一个名为myprogram.out的命令。
同样,您有一个规则,声称要构建一个名为myprogram的文件,但实际上构建了一个名为myprogram.out的文件。
这些可能会导致你的代码被不必要地重新编译(或重新链接)。每个规则都应该构建它声称要构建的文件。所以你可能想要这样的东西:

OBJDIR = myObj

run:    myprogram
        ./myprogram

myprogram: $(OBJDIR)/main.o $(OBJDIR)/otherfile.o
    gcc -o $@ $^

$(OBJDIR)/%.o : %.c | $(OBJDIR)
    gcc -c $^ -o $@

$(OBJDIR):
    mkdir $@
dsekswqp

dsekswqp2#

我已经修复了这些错误,并将你的makefile扩展为一个最小的变体:

# Disable built-in rules.
# Group the output by target when doing parallel builds.
MAKEFLAGS += -r -Otarget

# The source files.
SOURCES := main.c otherfile.c

# The object directory.
OBJDIR := myObj

# The object files.
OBJECTS := $(patsubst %,$(OBJDIR)/%.o,$(SOURCES))

# Create the object directory.
$(OBJDIR):
    mkdir -p $@

# Create the object files.
$(OBJDIR)/%.o: % | $(OBJDIR)
    $(COMPILE.c) $< -o $@ -MMD -MP

# Set linking the program as the default target.
.DEFAULT_GOAL := myprogram
# Link the program.
myprogram: $(OBJECTS)
    $(LINK.c) $^ -o $@

# Indicate that the `run` target doesn't generate a file literally named `run`.
.PHONY: run

# Run the program.
run: myprogram
    ./myprogram

# Include the `.d` files.
-include $(OBJECTS:.o=.d)

我所做的改变:

  • 确保每个目标都以它生成的文件命名(如果它不生成文件,则标记为.PHONY,如run)。这可确保在不必要时不会重新生成最新文件。
  • 要在源文件包含的标头更改时自动重新生成源文件,请执行以下操作:
  • 添加-MMD -MP到GCC标志,以生成.d文件和.o文件。
  • 添加了-include以包含这些文件。
  • 如果缺少myObj目录,则会自动创建该目录。
  • 目标现在使用魔术变量$@(输出文件名),$<(第一个先决条件),$^(所有先决条件),而不是硬编码的文件名。
  • MAKEFLAGS被修改为禁用内置规则,并在并行编译期间产生正常的输出。
  • gcc -c被替换为$(COMPILE.c),并且对于链接,gcc被替换为$(LINK.c)。这允许您使用一些预定义的环境或Make变量(CC用于编译器,CFLAGS用于标志等)更改编译器及其标志。(感谢@TobySpeight)
  • 为清晰起见,对象文件名是从源文件名自动生成的。
  • 变量赋值使用:=而不是=(微优化,每次使用时都不重新计算)。
  • 对象文件名包括原始扩展名(.c),以避免将来添加.cpp文件时.c.cpp文件之间的名称冲突。

相关问题