为什么我的makefile没有按预期工作?

时间:2016-12-10 10:02:58

标签: makefile

这是我的makefile:

SHELL = /bin/sh
CC=g++
CFLAGS=-I.
DEPS = settings.h
OBJ = settings.o tomato.o
EXDIR = $(ROOT_TOMATO)/bin
OBJDIR = $(ROOT_TOMATO)/obj

$(OBJDIR)/%.o: %.cpp $(DEPS)
    $(CC) -c -o $@ $<

$(EXDIR)/tomato: $(OBJ)
    $(CC) -o $@ $^ $(CFLAGS)

clean:
    rm -f a.out *.o

all: tomato

在第9行和第10行,我试图让它创建目标文件并将它们放在OBJDIR中,但它将obj文件放在当前目录中,ROOT_TOMATO / src:

$(OBJDIR)/%.o: %.cpp $(DEPS)
    $(CC) -c -o $@ $<

我无法弄清楚它为什么不起作用。也许有更好的方法,但我也想知道为什么我的代码在这种特殊情况下不起作用。

作为旁注,makefile由另一个makefile调用:

#Main makefile for project

#Get root compile directory
ROOT_TOMATO = $(shell pwd)
export ROOT_TOMATO

All:
   $(MAKE) -C src

2 个答案:

答案 0 :(得分:3)

你说的地方

$(EXDIR)/tomato: $(OBJ)

$(EXDIR)/tomato的先决条件不是$(OBJDIR)/settings.o$(OBJDIR)/tomato.o,而是settings.otomato.o,正如您在OBJ中定义的那样。因此,模式规则不用于构建它们,并且可以使用隐式规则来构建settings.otomato.o

您可以改为使用

$(EXDIR)/tomato: $(OBJ:%=$(OBJDIR)/%)

...或设置OBJ以便它从一开始就包含这些路径。

请注意,您的clean规则存在类似问题,因此拥有包含实际对象路径的变量是明智的。您可以在$(EXDIR)/tomato先决条件和clean食谱中使用它。

另请注意,内部Makefile的默认规则不是all而是$(EXDIR)/tomato,因为它是特定目标的第一个。这里有点好事; all规则不会按预期工作,因为它的先决条件是tomato,没有规则,而不是$(EXDIR)/tomato。我怀疑你会想要解决这个问题并在某些时候将all规则移到顶端。

答案 1 :(得分:0)

Make是一种语言,“保持简单”是伟大的建议。它是一种简单易懂的语言;困难的事情看起来像线路噪音。

请记住,Make是一种可执行的构建过程文档 - 可读性是一件好事。

我将您的Makefile重写为

之类的内容
CXX=g++
OBJ=settings.o tomato.o
TARGET=tomato

%.o: %.cpp
    $(CXX) -c -o $@ $<


# default target
$(TARGET): $(OBJ)
    $(CXX) -o $(TARGET) $(OBJ) $(CFLAGS)

tomato.o: settings.h
settings.o: settings.h

clean:
    rm $(TARGET) *.o

那是:

  1. 使用CXX作为C ++编译器的宏是常规的,并为C编译器保留CC - 这会提示任何阅读规则的人都跳到正确的结论。< / LI>
  2. 简化%.o: %cpp规则。所以,你最终在当前目录中有很多*.o个文件 - 这很重要!将它们放入Mercurial / Git忽略文件中并继续。你可以将它们放到另一个目录中,而@Wintermute会显示如何做到这一点,但它需要更多的标点符号,而且并没有真正获得太多。
  3. 请注意我没有必要使用任何$(VAR:sub=result)构造。它们非常有用,但是如果你使用它们太多,结果很快就会变得难以理解。
  4. 不愿意将依赖项放在%规则中。在无操作规则中单独表达这些(与tomato.osettings.o的依赖关系)文档“对于这些模块没什么好看的东西可以保留所有内容看起来更干净。
  5. 一个复杂的makefile自动所有是拖延的好方法(从我这里拿走,兄弟......)。