Rus*_*llG 56 makefile gnu-make
我在尝试使用make将目标文件放在一个单独的子目录中时遇到了麻烦,这可能是一种非常基本的技术.我尝试使用此页面中的信息:http: //www.gnu.org/software/hello/manual/make/Prerequisite-Types.html#Prerequisite-Types
我从make获得以下输出:
make: *** No rule to make target `ku.h', needed by `obj/kumain.o'. Stop.
Run Code Online (Sandbox Code Playgroud)
但是ku.h是一个依赖而不是一个目标(尽管它显然是在c源文件中的#included).当我不尝试使用目标文件的子目录(即错过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)
Run Code Online (Sandbox Code Playgroud)
编辑:我应用了更改以使用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
Run Code Online (Sandbox Code Playgroud)
似乎make没有对目标文件应用隐式规则,尽管手册中说"隐式规则告诉如何使用习惯技术,这样您就不必在使用它们时详细指定它们.例如,那里是C编译的隐式规则.文件名确定运行哪些隐式规则.例如,C编译通常采用.c文件并生成.o文件.因此,当看到这种组合时,make会应用C编译的隐式规则.文件名结尾." 以及"在审查隐式规则时,也会在查看VPATH或vpath中指定的目录时进行搜索(请参阅使用隐式规则)."
再次在这里"例如,当文件foo.o没有明确的规则时,make考虑隐式规则,例如编译foo.c的内置规则,如果该文件存在.如果当前目录中缺少这样的文件,搜索适当的目录.如果在任何目录中存在(或在makefile中提到)foo.c,则应用C编译的隐式规则.
任何帮助获取隐式规则以使我的makefile工作将不胜感激.
编辑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 $@
.PHONY : clean
clean :
rm $(objects)
Run Code Online (Sandbox Code Playgroud)
Jac*_*lly 63
由于您使用的是GNUmake,因此请使用模式规则来编译目标文件:
$(OBJDIR)/%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
Run Code Online (Sandbox Code Playgroud)
Nic*_*ton 49
这是我用于大多数项目的makefile,
它允许将源文件,标题和内联文件放在子文件夹和子文件夹的子文件夹等中,并自动为每个对象生成一个依赖文件.这意味着修改标题和内联文件将触发重新编译依赖的文件.
源文件是通过shell find命令检测到的,因此无需明确指定,只需对您的内容进行编码即可.
在编译项目时,它还会将所有文件从'resources'文件夹复制到bin文件夹中,这在大多数时候我都很方便.
为了提供应有的信用,自动依赖功能主要基于Scott McPeak的页面,可以在这里找到,并根据我的需要进行一些额外的修改/调整.
示例Makefile
#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 $@)
$(CC) $(CFLAGS) $(INC) -c -o $@ $<
@$(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
Run Code Online (Sandbox Code Playgroud)
al_*_*iro 23
VPATH线是错的,它们应该是
vpath %.c src
vpath %.h src
Run Code Online (Sandbox Code Playgroud)
即不是资本而没有=.就像现在一样,它找不到.h文件并认为它是一个目标.
通常,您必须$(OBJDIR)在所有放置文件的规则的左侧指定$(OBJDIR),或者您可以运行make from $(OBJDIR).
VPATH是源,而不是对象.
请查看这两个链接以获得更多解释,以及"聪明"的解决方法.
不要从顶级目录构建,而是从输出目录构建。您可以通过设置 vpath 来访问源目录。该选项的优点是可以使用内置规则。
build.sh#!/bin/bash
mkdir -p obj
cp Makefile.template obj/Makefile
cd obj
make "$*"
Run Code Online (Sandbox Code Playgroud)
.SUFFIXES:
.SUFFIXES: .c .o
CC=gcc
CPPFLAGS=-Wall
LDLIBS=-lhpdf
VPATH=%.c ../src
VPATH=%.h ../src
objects=kumain.o kudlx.o kusolvesk.o kugetpuz.o kuutils.o \
kurand.o kuASCboard.o kuPDFs.o kupuzstrings.o kugensud.o \
kushapes.o
ku : $(objects)
$(objects) : ku.h kudefines.h kuglobals.h kufns.h
.PHONY: clean
clean :
rm $(objects)
Run Code Online (Sandbox Code Playgroud)
缺点是错误消息与 CWD 不匹配。build.sh这可以通过跳过并直接从目录构建来解决obj。
这种方法的另一个优点是它有点受欢迎。cmake以类似的方式工作。
在我看来,以下解决方案并不好,因为我真的很喜欢内置规则。然而,GNU make 不支持vpath输出目录之类的东西。并且内置规则无法匹配,因为%in%.o会匹配obj/foo,obj/foo.o而会make在 in 中搜索vpath %.c src/诸如src/obj/foo.c, 但不是之类的内容src/foo.c。
但这是尽可能接近内置规则的,因此据我所知,这是可用的最好的解决方案。
$(OBJDIR)/%.o: %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
Run Code Online (Sandbox Code Playgroud)
说明:$(COMPILE.c) $(OUTPUT_OPTION) $<实际上是如何.c.o实现的,请参阅http://git.savannah.gnu.org/cgit/make.git/tree/default.c(甚至在手册中提到)
此外,如果$(OBJDIR)只包含自动生成的文件,您可以使用仅订单先决条件即时创建它,使 clean 规则稍微简单一些:
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: %.c | $(OBJDIR)
$(COMPILE.c) $(OUTPUT_OPTION) $<
.PHONY: clean
clean:
$(RM) -r $(OBJDIR)
Run Code Online (Sandbox Code Playgroud)
这要求仅功能订单可用,您可以使用 进行检查$(filter order-only, $(.FETAURES))。我检查过 Kubuntu 14.04 GNU make 3.81 和 OpenSUSE 13.1 GNU make 3.82。两者都是在仅启用订单的情况下构建的,现在我很困惑为什么 Kubuntu 14.04 附带的 GNU make 版本比 OpenSUSE 13.1 更旧。不管怎样,现在就下载 make 4.1 :)