2011-03-03 7 views
40

Tôi đang gặp khó khăn khi cố gắng sử dụng để đặt các tệp đối tượng trong một thư mục con riêng biệt, có lẽ là một kỹ thuật rất cơ bản. Tôi đã cố gắng sử dụng các thông tin trong trang này: http://www.gnu.org/software/hello/manual/make/Prerequisite-Types.html#Prerequisite-TypesCách đặt các tệp đối tượng trong thư mục con riêng biệt

tôi nhận được đầu ra sau đây từ thực hiện: thực hiện: *** Không có quy tắc để thực hiện mục tiêu ku.h', needed by obj/kumain.o'. Dừng lại.

Tuy nhiên ku.h là phụ thuộc không phải là mục tiêu (mặc dù rõ ràng là #included trong các tệp nguồn c). Khi tôi không cố gắng sử dụng một thư mục con cho các tệp đối tượng (nghĩa là bỏ qua các phần OBJDIR) nó hoạt động tốt. Tại sao nghĩ rằng ku.h là một mục tiêu?

makefile của tôi là thế này: (phong cách là sau khi đọc các nguồn thông tin khác nhau)

.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) 

Edit: tôi áp dụng sự thay đổi để sử dụng các chỉ thị vpath. Phiên bản của tôi là một hỗn hợp xấu của VPATH = xxx và vpath% .c xxx. Tuy nhiên bây giờ tôi nhận được một vấn đề khác (đó là vấn đề ban đầu trước khi tôi thêm vào các vpath sai). Điều này bây giờ là kết quả:

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 

Có vẻ làm mà không áp dụng các quy tắc ngầm cho một tập tin đối tượng mặc dù hướng dẫn nói "quy tắc ngầm nói làm thế nào để sử dụng các kỹ thuật thông để bạn không cần phải chỉ định Ví dụ, có một quy tắc ngầm cho việc biên dịch C. Các tên tệp xác định các quy tắc ngầm định được chạy, ví dụ, trình biên dịch C thường lấy một tệp .c và tạo một tệp .o. áp dụng quy tắc ngầm cho việc biên dịch C khi nó thấy sự kết hợp của đuôi tên tệp. " và cũng "Tìm kiếm thông qua các thư mục được chỉ định trong VPATH hoặc với vpath cũng xảy ra trong khi xem xét các quy tắc ngầm định (xem Sử dụng quy tắc ngầm định)."

Một lần nữa ở đây "Ví dụ: khi tệp foo.o không có quy tắc rõ ràng, hãy xem xét các quy tắc ngầm định, chẳng hạn như quy tắc dựng sẵn để biên dịch foo.c nếu tệp đó tồn tại. thư mục hiện tại, các thư mục thích hợp được tìm kiếm cho nó.Nếu foo.c tồn tại (hoặc được đề cập trong makefile) trong bất kỳ thư mục nào, thì quy tắc ngầm cho việc biên dịch C được áp dụng. "

Bất kỳ hỗ trợ nào trong việc đưa ra các quy tắc ngầm để làm việc cho makefile của tôi sẽ được đánh giá cao.

Chỉnh sửa số 2: Cảm ơn Jack Kelly Tôi đã thực hiện một quy tắc rõ ràng để biên dịch tệp .c vì tôi không thể tìm bất kỳ nơi nào cố gắng sử dụng quy tắc ngầm. Cũng nhờ al_miro cho thông tin vpath.

Đây là makfile làm việc:

.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

Phong cách lưu ý: '$ (CPPFLAGS)' theo truyền thống được sử dụng cho cờ C Preprocessor, trong khi '$ (CFLAGS)' được sử dụng cho cờ cho trình biên dịch. –

Trả lời

51

Vì bạn đang sử dụng gnumake, sử dụng một quy tắc khuôn mẫu cho việc biên soạn các file đối tượng:

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

Điều này không hiệu quả đối với tôi: Tìm kiếm $ (OBJDIR) /%. C và không phải% .c. Bất kỳ ý tưởng làm thế nào tôi có thể nhận được điều này để sử dụng các tập tin C trong thư mục hiện tại như là sự phụ thuộc trong khi sử dụng $ (OBJDIR) là mục tiêu? – Lelanthran

+0

@Lelanthran, ở trên giải pháp nhận tệp C nằm trong thư mục hiện tại. Nếu bạn sử dụng "$ (OBJDIR) /%. C" thay vì "% .c", mã C của bạn nên đặt trong "$ (OBJDIR)". – Neal

22

Các VPATH dòng này là sai, họ sẽ có

vpath %.c src 
vpath %.h src 

ví dụ: không vốn, mà không =. Vì bây giờ, nó không tìm thấy tệp .h và nghĩ rằng đó là một mục tiêu được thực hiện.

4

Nói chung, bạn có thể sở để xác định $(OBJDIR) ở phía bên tay trái của tất cả các quy tắc mà nơi tập tin trong $(OBJDIR) hoặc bạn có thể chạy từ $(OBJDIR). VPATH là dành cho các nguồn, không phải cho các đối tượng.

Hãy xem hai liên kết này để giải thích thêm và giải pháp "thông minh".

+1

Thực ra, đây là câu trả lời hay nhất. Hài hước như thế nào nó đã không upvotes (trước khi tôi), trong khi tất cả các nỗ lực tuyệt vọng, không đầy đủ, bị hỏng vv có tất cả ...;) Cảm ơn, Theo B., tiết kiệm một số giờ cho tôi! –

2

Các giải pháp sau đây là không thoải mái theo ý kiến ​​của tôi, như tôi đã thực sự yêu các quy tắc được xây dựng trong. Tuy nhiên, GNU thực hiện không hỗ trợ một cái gì đó như vpath cho các thư mục đầu ra. Và các quy tắc tích hợp không thể khớp, vì số % trong %.o sẽ khớp với obj/foo của obj/foo.o, để lại make với tìm kiếm trong vpath %.c src/ cho các nội dung như src/obj/foo.c, nhưng không phải là src/foo.c.

Nhưng điều này là gần với các quy tắc tích hợp như bạn có thể nhận được, và do đó tôi có kiến ​​thức tốt nhất là giải pháp tốt nhất có sẵn.

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

Giải thích: $(COMPILE.c) $(OUTPUT_OPTION) $< thực sự là như thế nào .c.o được thực hiện, xem http://git.savannah.gnu.org/cgit/make.git/tree/default.c (và nó thậm chí còn đề cập trong cuốn hướng dẫn)

Bên cạnh đó, nếu $(OBJDIR) sẽ chỉ bao giờ chứa các file tự động gererated, bạn có thể tạo ra nó trên -the-bay với một điều kiện tiên quyết để chỉ, làm cho sự cai trị sạch hơi đơn giản:

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

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

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

Điều này đòi hỏi các tính năng lệnh chỉ có sẵn, bạn có thể kiểm tra bằng cách sử dụng $(filter order-only, $(.FETAURES)). Tôi đã kiểm tra trên Kubuntu 14.04 GNU làm 3,81 và OpenSUSE 13,1 GNU làm cho 3,82. Cả hai được xây dựng với chỉ được đặt hàng được bật và giờ đây đã bị bỏ ngỏ vì sao Kubuntu 14.04 đi kèm với phiên bản cũ hơn của GNU hơn OpenSUSE 13.1. Anyways, gonna tải làm cho 4,1 bây giờ :)

32

Đây là makefile mà tôi sử dụng cho hầu hết các dự án của tôi,

Nó cho phép đặt file nguồn, tiêu đề và các tập tin nội tuyến trong các thư mục con, và thư mục con của thư mục con và Somali và sẽ tự động tạo tệp phụ thuộc cho từng đối tượng Điều này có nghĩa là sửa đổi tiêu đề và tệp nội tuyến sẽ kích hoạt biên dịch lại các tệp phụ thuộc.

Tệp nguồn được phát hiện thông qua lệnh tìm vỏ, do đó không cần chỉ định rõ ràng, chỉ cần giữ mã hóa cho nội dung trái tim của bạn.

Nó cũng sẽ sao chép tất cả các tệp từ thư mục 'tài nguyên', vào thư mục bin khi dự án được biên soạn, mà tôi thấy thuận tiện nhất trong thời gian.

Để cung cấp tín dụng khi đến hạn, tính năng phụ thuộc tự động dựa chủ yếu vào trang của Scott McPeak có thể được tìm thấy HERE, với một số sửa đổi/chỉnh sửa bổ sung cho nhu cầu của tôi.

Ví dụ 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 [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' có nghĩa là MacPorts. g ++ - mp-4.7 là trình biên dịch C++ từ GCC cho MacPorts –

1

Đối với tất cả những người làm việc với các quy tắc ngầm (và GNU MAKE). Đây là một makefile đơn giản mà hỗ trợ các thư mục khác nhau:

#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) 

Cho phép có một cái nhìn gần gũi hơn (Tôi sẽ giới thiệu vào danh mục hiện tại với curdir):

dòng này được sử dụng để có được một danh sách các sử dụng. o tập tin nằm trong curdir/src.

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

Qua biến đầu ra được đặt thành một thư mục khác (curdir/objects).

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

Để đảm bảo trình biên dịch tìm thấy đối tượng trong thư mục đối tượng mới, đường dẫn sẽ được thêm vào tên tệp.

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

Đây là ví dụ và chắc chắn có chỗ để cải thiện.

Đối với thông tin thêm tham khảo: Make documetation. See chapter 10.2

Hoặc: Oracle: Programming Utilities Guide