별도의 하위 디렉토리에 개체 파일을 배치하는 방법
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.
그러나 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
It appears that make is not applying the implicit rule for an object file although the manual says "Implicit rules tell make how to use customary techniques so that you do not have to specify them in detail when you want to use them. For example, there is an implicit rule for C compilation. File names determine which implicit rules are run. For example, C compilation typically takes a .c file and makes a .o file. So make applies the implicit rule for C compilation when it sees this combination of file name endings." and also "The search through the directories specified in VPATH or with vpath also happens during consideration of implicit rules (see Using Implicit Rules)."
다시 여기에서 "예를 들어, foo.o 파일에 명시 적 규칙이없는 경우 make는 해당 파일이 존재하면 foo.c를 컴파일하는 내장 규칙과 같은 암시 적 규칙을 고려합니다. 이러한 파일이 현재 디렉토리에 부족하면 적절한 디렉토리가 검색됩니다. 디렉토리에 foo.c가 존재하거나 (또는 makefile에 언급 된 경우) C 컴파일에 대한 암시 적 규칙이 적용됩니다. "
내 makefile에서 작동하는 암시 적 규칙을 얻는 데 도움을 주시면 대단히 감사하겠습니다.
편집 2 번 : Jack Kelly 덕분에 묵시적 규칙을 사용하려고 할 수 없기 때문에 .c 파일을 컴파일하는 명시 적 규칙을 만들었습니다. 또한 vpath 정보에 대한 al_miro에게 감사드립니다.
다음은 작동중인 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)
GNUmake를 사용하고 있으므로 객체 파일을 컴파일하는 데 패턴 규칙을 사용하십시오.
$(OBJDIR)/%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
이것은 대부분의 프로젝트에 사용하는 메이크 파일입니다.
소스 파일, 헤더 및 인라인 파일을 하위 폴더, 하위 폴더의 하위 폴더 및 그 이후에 넣을 수 있으며 각 개체에 대한 종속성 파일을 자동으로 생성합니다. 즉, 헤더 및 인라인 파일을 수정 하면 종속 된 파일의 재 컴파일이 트리거됩니다.
소스 파일은 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
The VPATH lines are wrong, they should be
vpath %.c src
vpath %.h src
i.e. not capital and without the = . As it is now, it doesn't find the .h file and thinks it is a target to be made.
In general, you either have to specify $(OBJDIR)
on the left hand side of all the rules that place files in $(OBJDIR)
, or you can run make from $(OBJDIR)
. VPATH
is for sources, not for objects.
Take a look at these two links for more explanation, and a "clever" workaround.
The following solution isn't nice in my opinion, as I really love the built-in rules. However, GNU make doesn't support something like vpath
for output directories. And the built-in rules cannot match, as the %
in %.o
would match obj/foo
of obj/foo.o
, leaving make
with a search in vpath %.c src/
for stuff like src/obj/foo.c
, but not src/foo.c
.
But this is as close to the built-in rules as you can get, and therefore to my best knowledge the nicest solution that's available.
$(OBJDIR)/%.o: %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
Explanation: $(COMPILE.c) $(OUTPUT_OPTION) $<
actually is how .c.o
is implemented, see http://git.savannah.gnu.org/cgit/make.git/tree/default.c (and it's even mentioned in the manual)
Besides, if $(OBJDIR)
would only ever contain auto-gererated files, you could create it on-the-fly with an order-only prerequisite, making the clean rule slightly simpler:
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: %.c | $(OBJDIR)
$(COMPILE.c) $(OUTPUT_OPTION) $<
.PHONY: clean
clean:
$(RM) -r $(OBJDIR)
This requires that the feature order-only is available, which you can check using $(filter order-only, $(.FETAURES))
. I've checked on Kubuntu 14.04 GNU make 3.81 and OpenSUSE 13.1 GNU make 3.82. Both were built with order-only enabled, and am now left puzzled why Kubuntu 14.04 comes with an older version of GNU make than OpenSUSE 13.1. Anyways, gonna download make 4.1 now :)
For all those working with implicit rules (and GNU MAKE). Here is a simple makefile which supports different directories:
#Start of the makefile
VPATH = ./src:./header:./objects
OUTPUT_OPTION = -o objects/$@
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)
Lets have a closer look (I will refer to the current Directory with curdir):
This line is used to get a list of the used .o files which are in curdir/src.
Objects := $(notdir $(patsubst %.cpp,%.o,$(wildcard src/*.cpp)))
#expands to "foo.o myfoo.o otherfoo.o"
Via variable the output is set to a different directory (curdir/objects).
OUTPUT_OPTION = -o objects/$@
#OUTPUT_OPTION will insert the -o flag into the implicit rules
To make sure the compiler finds the objects in the new objects folder, the path is added to the filename.
$(Target): $(Objects)
$(CXX) $(CXXFLAGS) -o $(Target) $(addprefix objects/,$(Objects))
# ^^^^^^^^^^^^^^^^^^^^
This is meant as an example and there is definitly room for improvement.
For additional Information consult: Make documetation. See chapter 10.2
Or: Oracle: Programming Utilities Guide
ReferenceURL : https://stackoverflow.com/questions/5178125/how-to-place-object-files-in-separate-subdirectory
'developer tip' 카테고리의 다른 글
NSMutableArray에서 요소 교체 (0) | 2021.01.10 |
---|---|
분수를 이진수로 어떻게 변환합니까? (0) | 2021.01.10 |
NewtonSoft를 사용하여 한 줄로 JSON 개체 생성 (0) | 2021.01.10 |
두 범위 함수 결과 연결 (0) | 2021.01.10 |
CSS에서 이미지 위에 오버레이를 만드는 방법은 무엇입니까? (0) | 2021.01.10 |