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