2011-03-03 35 views
40

我尝试使用make将目标文件放置在单独的子目录中,可能是非常基本的技术,但遇到问题。我曾尝试使用这些信息在本页面: http://www.gnu.org/software/hello/manual/make/Prerequisite-Types.html#Prerequisite-Types如何将目标文件放置在单独的子目录中

我从make以下的输出: 化妆:***没有规则,使目标ku.h', needed by OBJ/kumain.o”。停止。

然而,ku.h是一个不依赖于目标的依赖项(虽然它明显包含在c源文件中)。当我不尝试使用目录文件的子目录(即错过OBJDIR部分)时,它工作正常。为什么认为ku.h是一个目标?

我的makefile是这样的:(风格读取各种信息源后)

.SUFFIXES: 
.SUFFIXES: .c .o 

CC=gcc 
CPPFLAGS=-Wall 
LDLIBS=-lhpdf 
VPATH=%.c src 
VPATH=%.h src 
VPATH=%.o obj 
OBJDIR=obj 

objects= $(addprefix $(OBJDIR)/, kumain.o kudlx.o kusolvesk.o kugetpuz.o kuutils.o \ 
    kurand.o kuASCboard.o kuPDFs.o kupuzstrings.o kugensud.o \ 
    kushapes.o) 

ku : $(objects) 
    $(CC) $(CPPFLAGS) -o ku $(objects) $(LDLIBS) 

$(objects) : ku.h kudefines.h kuglobals.h kufns.h | $(OBJDIR) 

$(OBJDIR): 
    mkdir $(OBJDIR) 

.PHONY: clean 
clean : 
    rm $(objects) 

编辑: 我申请使用VPATH指令的变化。我的版本是VPATH = xxx和vpath%.c xxx的混合。然而,我现在又遇到了另一个问题(这是我添加错误vpath之前的原始问题)。这是现在的输出:

gcc -o ku -lhpdf obj/kumain.o obj/kudlx.o obj/kusolvesk.o ..etc 
    gcc: obj/kumain.o: No such file or directory 
    gcc: obj/kudlx.o: No such file or directory 
    gcc: obj/kusolvesk.o: No such file or directory 
    gcc: obj/kugetpuz.o: No such file or directory 
    gcc: obj/kuutils.o: No such file or directory 
    gcc: obj/kurand.o: No such file or directory 
    gcc: obj/kuASCboard.o: No such file or directory 
    gcc: obj/kuPDFs.o: No such file or directory 
    gcc: obj/kupuzstrings.o: No such file or directory 
    gcc: obj/kugensud.o: No such file or directory 
    gcc: obj/kushapes.o: No such file or directory 
    make: *** [ku] Error 1 

看来,虽然手册上说 “潜规则告诉make如何使用常规技术,这样你就不必指定,让没有申请目标文件中的隐含规则例如,C编译有一个隐含的规则,文件名决定运行哪个隐式规则,例如,C编译通常需要一个.c文件并生成一个.o文件。当它看到这个文件名结尾的组合时,使用C编译的隐式规则。“还有“在VPATH或vpath中指定的目录中搜索也会在考虑隐式规则时发生(请参阅使用隐式规则)”。

再次在这里“例如,当一个文件foo.o没有明确的规则时,make会考虑隐式规则,如内置规则来编译foo.c,如果该文件存在。在当前目录中搜索相应的目录,如果任何目录中存在foo.c(或在makefile中提及),则应用隐含的C编译规则。

任何帮助获取隐式规则为我的生成文件工作将不胜感激。

编辑否2: 感谢杰克凯利我做了一个明确的规则编译.c文件,因为我无法在任何地方尝试使用隐式规则。还要感谢al_miro的vpath信息。

这里是工作makfile:

.SUFFIXES: 
.SUFFIXES: .c .o 

CC=gcc 
CPPFLAGS=-Wall 
LDLIBS=-lhpdf 
OBJDIR=obj 
vpath %.c src 
vpath %.h src 

objects = $(addprefix $(OBJDIR)/, kumain.o kudlx.o kusolvesk.o kugetpuz.o kuutils.o \ 
    kurand.o kuASCboard.o kuPDFs.o kupuzstrings.o kugensud.o \ 
    kushapes.o) 

ku : $(objects) 
    $(CC) $(CPPFLAGS) -o ku $(objects) $(LDLIBS) 

$(OBJDIR) obj/%.o : %.c ku.h kudefines.h kuglobals.h kufns.h 
    $(CC) -c $(CPPFLAGS) $< -o [email protected] 

.PHONY : clean 
clean : 
    rm $(objects) 
+14

样式注意:'$(CPPFLAGS)'传统上用于C预处理标志,而'$(CFLAGS)采用'的编译器的标志。 –

回答

51

由于您使用gnumake的,用一个模式规则编译目标文件:

$(OBJDIR)/%.o: %.c 
    $(CC) $(CFLAGS) $(CPPFLAGS) -c -o [email protected] $< 
+4

这对我不起作用:它寻找$(OBJDIR)/%。c而不是%.c。任何想法如何我可以得到这个使用当前目录中的C文件作为依赖关系,同时使用$(OBJDIR)作为目标? – Lelanthran

+0

@Lelanthran,获取C文件的上述解决方案位于当前目录中。如果你使用“$(OBJDIR)/%。c”而不是“%.c”,你的C代码应该把它放在“$(OBJDIR)”中。 – Neal

22

的VPATH线接错,他们应该是

vpath %.c src 
vpath %.h src 

即没有资金和没有=。就像现在一样,它没有找到.h文件,并认为它是要制作的目标。

4

在一般情况下,你要么必须对所有的规则左侧指定$(OBJDIR)那个地方文件$(OBJDIR) ,或者你可以从$(OBJDIR)运行make。 VPATH适用于源,不适用于对象。

看看这两个链接的更多解释和一个“聪明”的解决方法。

+1

其实这是最好的答案。有趣的是,它是如何得到零赞成的(在我的之前),而所有的绝望,不完整,破碎等尝试都有它......;)感谢Theo B.,为我节省了一些时间! –

2

下面的解决方案是不是在我看来不错,因为我真的很喜欢内置的规则。但是,GNU make不支持类似vpath的输出目录。而内置的规则不能匹配,如%.o%将匹配的obj/foo.oobj/foo,留下make与像src/obj/foo.c的东西在vpath %.c src/搜索,但不src/foo.c

但是,这与您可以获得的内置规则非常接近,因此根据我的最佳知识,可以使用最好的解决方案。

$(OBJDIR)/%.o: %.c 
     $(COMPILE.c) $(OUTPUT_OPTION) $< 

说明:$(COMPILE.c) $(OUTPUT_OPTION) $<实际上是如何.c.o实现,见http://git.savannah.gnu.org/cgit/make.git/tree/default.c(和它甚至在手册中提到的)

此外,如果$(OBJDIR)永远只能包含自动gererated文件,你可以在创建它与订单,唯一的前提-the飞,使干净的原则稍微简单:

$(OBJDIR): 
     mkdir -p $(OBJDIR) 

$(OBJDIR)/%.o: %.c | $(OBJDIR) 
     $(COMPILE.c) $(OUTPUT_OPTION) $< 

.PHONY: clean 
clean: 
     $(RM) -r $(OBJDIR) 

这就需要功能订单仅可用,您可以使用$(filter order-only, $(.FETAURES))进行检查。我检查过Kubuntu 14.04 GNU make 3.81和OpenSUSE 13.1 GNU make 3.82。两者都使用订单启用,现在让我感到困惑的是,为什么Kubuntu 14.04带有比OpenSUSE 13.1更早版本的GNU make。不管怎么说,要下载使用4.1现在:)

32

这是我用我的大多数项目的makefile文件,

它允许把源文件,头文件和子文件夹内联文件和子文件夹和所谓的子文件夹并且会自动为每个对象生成一个依赖文件这意味着修改头文件和内联文件将触发相关文件的重新编译。

源文件通过shell查找命令检测到,因此不需要明确指定,只需继续对您的心内容进行编码即可。

当项目编译时,它也会将'resources'文件夹中的所有文件复制到bin文件夹中,这在大多数情况下都很方便。

为了提供应有的功劳,自动依赖功能基本上基于Scott McPeak的页面,可以找到HERE,并根据我的需要进行一些额外的修改/调整。

实施例生成文件

#Compiler and Linker 
CC   := g++-mp-4.7 

#The Target Binary Program 
TARGET  := program 

#The Directories, Source, Includes, Objects, Binary and Resources 
SRCDIR  := src 
INCDIR  := inc 
BUILDDIR := obj 
TARGETDIR := bin 
RESDIR  := res 
SRCEXT  := cpp 
DEPEXT  := d 
OBJEXT  := o 

#Flags, Libraries and Includes 
CFLAGS  := -fopenmp -Wall -O3 -g 
LIB   := -fopenmp -lm -larmadillo 
INC   := -I$(INCDIR) -I/usr/local/include 
INCDEP  := -I$(INCDIR) 

#--------------------------------------------------------------------------------- 
#DO NOT EDIT BELOW THIS LINE 
#--------------------------------------------------------------------------------- 
SOURCES  := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT)) 
OBJECTS  := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT))) 

#Defauilt Make 
all: resources $(TARGET) 

#Remake 
remake: cleaner all 

#Copy Resources from Resources Directory to Target Directory 
resources: directories 
    @cp $(RESDIR)/* $(TARGETDIR)/ 

#Make the Directories 
directories: 
    @mkdir -p $(TARGETDIR) 
    @mkdir -p $(BUILDDIR) 

#Clean only Objecst 
clean: 
    @$(RM) -rf $(BUILDDIR) 

#Full Clean, Objects and Binaries 
cleaner: clean 
    @$(RM) -rf $(TARGETDIR) 

#Pull in dependency info for *existing* .o files 
-include $(OBJECTS:.$(OBJEXT)=.$(DEPEXT)) 

#Link 
$(TARGET): $(OBJECTS) 
    $(CC) -o $(TARGETDIR)/$(TARGET) $^ $(LIB) 

#Compile 
$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT) 
    @mkdir -p $(dir [email protected]) 
    $(CC) $(CFLAGS) $(INC) -c -o [email protected] $< 
    @$(CC) $(CFLAGS) $(INCDEP) -MM $(SRCDIR)/$*.$(SRCEXT) > $(BUILDDIR)/$*.$(DEPEXT) 
    @cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp 
    @sed -e 's|.*:|$(BUILDDIR)/$*.$(OBJEXT):|' < $(BUILDDIR)/$*.$(DEPEXT).tmp > $(BUILDDIR)/$*.$(DEPEXT) 
    @sed -e 's/.*://' -e 's/\\$$//' < $(BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(BUILDDIR)/$*.$(DEPEXT) 
    @rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp 

#Non-File Targets 
.PHONY: all remake clean cleaner resources 
+0

'mp'表示MacPorts。 g ++ - mp-4.7是GCC for MacPorts的C++编译器 –

1

对于所有那些具有隐式规则(和GNU MAKE)工作。下面是支持不同的目录中一个简单的makefile:

#Start of the makefile 

VPATH = ./src:./header:./objects 

OUTPUT_OPTION = -o objects/[email protected] 

CXXFLAGS += -Wall -g -I./header 

Target = $(notdir $(CURDIR)).exe 

Objects := $(notdir $(patsubst %.cpp,%.o,$(wildcard src/*.cpp))) 



all: $(Target) 

$(Target): $(Objects) 
    $(CXX) $(CXXFLAGS) -o $(Target) $(addprefix objects/,$(Objects)) 


#Beware of -f. It skips any confirmation/errors (e.g. file does not exist) 

.PHONY: clean 
clean: 
    rm -f $(addprefix objects/,$(Objects)) $(Target) 

让我们来仔细看看(我指的是当前目录的curdir):

用这条线来获得所使用的列表。 o在curdir/src中的文件。

Objects := $(notdir $(patsubst %.cpp,%.o,$(wildcard src/*.cpp))) 
#expands to "foo.o myfoo.o otherfoo.o" 

通过变量将输出设置为不同的目录(curdir/objects)。

OUTPUT_OPTION = -o objects/[email protected] 
#OUTPUT_OPTION will insert the -o flag into the implicit rules 

为确保编译器在新对象文件夹中找到对象,路径将添加到文件名。

$(Target): $(Objects) 
    $(CXX) $(CXXFLAGS) -o $(Target) $(addprefix objects/,$(Objects)) 
#         ^^^^^^^^^^^^^^^^^^^^  

这意味着作为一个例子,有definitly改进的余地。

更多信息请参阅: Make documetation. See chapter 10.2

或者: Oracle: Programming Utilities Guide

相关问题