2008-11-18 51 views
80

Tôi có các makefile sau đây mà tôi sử dụng để xây dựng một chương trình (một hạt nhân, thực sự) mà tôi đang làm việc trên. Nó từ đầu và tôi đang học về quá trình, vì vậy nó không hoàn hảo, nhưng tôi nghĩ rằng nó đủ mạnh mẽ vào thời điểm này cho mức độ kinh nghiệm của tôi viết makefiles.Làm cách nào để có một tệp Makefile tự động tạo lại các tệp nguồn bao gồm tệp tiêu đề đã sửa đổi? (Trong C/C++)

AS = nasm 
CC = gcc 
LD = ld 

TARGET  = core 
BUILD  = build 
SOURCES  = source 
INCLUDE  = include 
ASM   = assembly 

VPATH = $(SOURCES) 

CFLAGS = -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions \ 
      -nostdinc -fno-builtin -I $(INCLUDE) 
ASFLAGS = -f elf 

#CFILES  = core.c consoleio.c system.c 
CFILES  = $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 
SFILES  = assembly/start.asm 

SOBJS = $(SFILES:.asm=.o) 
COBJS = $(CFILES:.c=.o) 
OBJS = $(SOBJS) $(COBJS) 

build : $(TARGET).img 

$(TARGET).img : $(TARGET).elf 
    c:/python26/python.exe concat.py stage1 stage2 pad.bin core.elf floppy.img 

$(TARGET).elf : $(OBJS) 
    $(LD) -T link.ld -o [email protected] $^ 

$(SOBJS) : $(SFILES) 
    $(AS) $(ASFLAGS) $< -o [email protected] 

%.o: %.c 
    @echo Compiling $<... 
    $(CC) $(CFLAGS) -c -o [email protected] $< 

#Clean Script - Should clear out all .o files everywhere and all that. 
clean: 
    -del *.img 
    -del *.o 
    -del assembly\*.o 
    -del core.elf 

Vấn đề chính của tôi với makefile này là khi tôi sửa đổi tệp tiêu đề mà một hoặc nhiều tệp C bao gồm, các tệp C không được xây dựng lại. Tôi có thể sửa lỗi này khá dễ dàng bằng cách có tất cả các tệp header của tôi là phụ thuộc cho tất cả các tệp C của tôi, nhưng điều đó có hiệu quả sẽ gây dựng lại hoàn toàn dự án bất cứ khi nào tôi thay đổi/thêm tệp tiêu đề.

Điều tôi muốn chỉ dành cho các tệp C mà bao gồm tệp tiêu đề tôi thay đổi để được xây dựng lại và để toàn bộ dự án được liên kết lại. Tôi có thể thực hiện liên kết bằng cách làm cho tất cả các tệp tiêu đề là phụ thuộc của đích, nhưng tôi không thể tìm ra cách làm cho tệp C bị vô hiệu khi tệp tiêu đề được bao gồm của chúng mới hơn.

Tôi nghe nói rằng GCC có một số lệnh để thực hiện điều này (vì vậy makefile bằng cách nào đó có thể tìm ra tệp nào cần được xây dựng lại) nhưng tôi không thể cho tôi thấy một ví dụ triển khai thực tế để xem . Ai đó có thể gửi một giải pháp mà sẽ cho phép hành vi này trong một makefile?

EDIT: Tôi nên làm rõ, tôi quen thuộc với khái niệm đặt các mục tiêu riêng lẻ vào và có mỗi target.o yêu cầu các tệp tiêu đề. Điều đó đòi hỏi tôi phải chỉnh sửa các makefile mỗi khi tôi bao gồm một tập tin tiêu đề ở đâu đó, đó là một chút đau đớn. Tôi đang tìm một giải pháp có thể lấy được các phụ thuộc tập tin tiêu đề của riêng nó, mà tôi khá chắc chắn tôi đã nhìn thấy trong các dự án khác.

Trả lời

25

Như đã chỉ ra ở đâu đó trên trang web này, xem trang này: http://make.paulandlesley.org/autodep.html

Nói tóm lại, gcc có thể tự động tạo tập tin phụ thuộc .d cho bạn, đó là mảnh makefile nhỏ chứa các phụ thuộc của file .c bạn đã biên soạn. Mỗi khi bạn thay đổi tệp .c và biên dịch nó, tệp .d sẽ được cập nhật.

Ngoài việc thêm cờ -M vào gcc, bạn sẽ cần bao gồm các tệp .d trong tệp makefile (như Chris đã viết ở trên). Có một số vấn đề phức tạp hơn trong trang được giải quyết bằng sed, nhưng bạn có thể bỏ qua chúng và làm "dọn dẹp" để xóa các tệp .d bất cứ khi nào khiếu nại về việc không thể tạo tệp tiêu đề không còn tồn tại.

+2

Tôi có thể bị nhầm lẫn, nhưng tôi nghĩ GCC đã thực sự thêm một tính năng để thử và giải quyết vấn đề đó. Xem http://gcc.gnu.org/onlinedocs/gcc-4.3.1/gcc/Preprocessor-Options.html cụ thể -MP. –

+0

Có, -MP tồn tại kể từ GCC 3, tồn tại trong clang và icc, và không có nhu cầu về sed. http://bruno.defraine.net/techtips/makefile-auto-dependencies-with-gcc/#comment-50775 – hmijail

6

Bạn sẽ phải tạo các mục tiêu riêng cho từng tệp C, sau đó liệt kê tệp tiêu đề dưới dạng phụ thuộc. Bạn vẫn có thể sử dụng các mục tiêu chung của bạn, và chỉ cần đặt .h phụ thuộc sau đó, như vậy:

%.o: %.c 
     @echo Compiling $<... 
     $(CC) $(CFLAGS) -c -o [email protected] $< 

foo.c: bar.h 
# And so on... 
3

Vượt lên trên những gì @mipadi nói, bạn cũng có thể khám phá việc sử dụng các '-M' tùy chọn để tạo ra một kỷ lục của các phụ thuộc. Thậm chí bạn có thể tạo những tệp đó thành một tệp riêng biệt (có lẽ là 'depend.mk') mà sau đó bạn đưa vào tệp makefile. Hoặc bạn có thể tìm quy tắc 'make depend' chỉnh sửa tệp makefile với các phụ thuộc chính xác (các điều khoản của Google: "không xóa dòng này" và phụ thuộc).

3

Về cơ bản, bạn cần phải tạo động các quy tắc makefile để xây dựng lại các tệp đối tượng khi các tệp tiêu đề thay đổi. Nếu bạn sử dụng gcc và gnumake, điều này khá dễ dàng; chỉ cần đặt một cái gì đó như:

$(OBJDIR)/%.d: %.c 
     $(CC) -MM -MG $(CPPFLAGS) $< | sed -e 's,^\([^:]*\)\.o[ ]*:,$(@D)/\1.o $(@D)/\1.d:,' >[email protected] 

ifneq ($(MAKECMDGOALS),clean) 
include $(SRCS:%.c=$(OBJDIR)/%.d) 
endif 

trong makefile của bạn.

+2

Tôi hiểu điều này, ngoại trừ điều đó (ngoài cờ -MM và -MG mới) Tôi không hiểu dòng văn bản khó hiểu của regex là gì. Điều đó sẽ không làm cho các đồng đội của tôi hạnh phúc ...^_^Tôi sẽ thử nó và xem tôi có kết quả gì không. –

+0

sed viết tắt của "trình chỉnh sửa luồng" có thể sửa đổi luồng văn bản mà không cần sử dụng tệp. Nó là một công cụ Unix tiêu chuẩn và nhỏ hơn và nhanh hơn nên nó được sử dụng thường xuyên hơn awk hoặc perl. –

+0

Ah, có vấn đề: Tôi đang làm điều này trong Windows. –

16

này tương đương với Chris Dodd's answer, nhưng sử dụng một quy ước đặt tên khác nhau (và tình cờ không yêu cầu sed kỳ diệu. Sao chép từ a later duplicate.


Nếu bạn đang sử dụng một trình biên dịch GNU, trình biên dịch có thể lắp ráp . một danh sách phụ thuộc cho bạn Makefile đoạn:

depend: .depend 

.depend: $(SOURCES) 
     rm -f ./.depend 
     $(CC) $(CFLAGS) -MM $^>>./.depend; 

include .depend 

Ngoài ra còn có các công cụ makedepend, nhưng tôi không bao giờ thích nó càng nhiều càng tốt gcc -MM

+3

Tại sao bạn không đánh vần SOURCES? Không yêu cầu đặc biệt là nhiều nhân vật hơn và không được obfuscated là "SRCS" mà có thể trông giống như một từ viết tắt. – HelloGoodbye

-1

Tôi tin rằng lệnh mkdep là những gì bạn muốn. Nó thực sự quét các tệp .c cho các dòng #include và tạo một cây phụ thuộc cho chúng. Tôi tin rằng các dự án Automake/Autoconf sử dụng điều này theo mặc định.

19

Bạn có thể thêm một 'làm phụ thuộc' lệnh như những người khác đã tuyên bố nhưng tại sao không nhận được gcc để tạo ra phụ thuộc và biên dịch cùng một lúc:

DEPS := $(COBJS:.o=.d) 

-include $(DEPS) 

%.o: %.c 
    $(CC) -c $(CFLAGS) -MM -MF $(patsubst %.o,%.d,[email protected]) -o [email protected] $< 

tham số Các '-MF' xác định một tập tin để lưu trữ các phụ thuộc trong.

Dấu gạch ngang khi bắt đầu '-bao gồm' cho phép Tiếp tục khi tệp .d không tồn tại (ví dụ: trong lần biên dịch đầu tiên).

Lưu ý rằng dường như có lỗi trong gcc liên quan đến tùy chọn -o. Nếu bạn đặt tên tệp đối tượng để nói obj/_file__c.o thì số _file_.d được tạo sẽ vẫn chứa _file_.o, không phải obj/_file_c.o.

+13

Điều này không hiệu quả đối với tôi. Ví dụ. makefile được tạo ra và chạy lệnh này: 'g ++ -c -Wall -Werror -MM -MF main.d -o main.o main.cpp' Tôi nhận tệp main.d, nhưng main.o là 0 byte. Tuy nhiên cờ -MMD dường như làm chính xác những gì được yêu cầu. Vì vậy, quy tắc makefile làm việc của tôi đã trở thành: '$ (CC) -c $ (CFLAGS) -MMD -o $ @ $ <' –

0

Không có câu trả lời nào phù hợp với tôi. Ví dụ. Câu trả lời của Martin Fido cho thấy gcc có thể tạo tệp phụ thuộc, nhưng khi tôi thử rằng nó tạo ra các tệp đối tượng trống (không byte) cho tôi mà không có bất kỳ cảnh báo hoặc lỗi nào. Nó có thể là một lỗi gcc. Tôi đang trên

$ gcc --version gcc (GCC) 4.4.7 20.120.313 (Red Hat 4.4.7-16)

Vì vậy, đây là Makefile hoàn chỉnh của tôi làm việc cho tôi; đó là một sự kết hợp của các giải pháp + cái gì đó đã không được đề cập bởi bất cứ ai khác (ví dụ như "quy tắc thay thế hậu tố" quy định như .cc.o :):

CC = g++ 
CFLAGS = -Wall -g -std=c++0x 
INCLUDES = -I./includes/ 

# LFLAGS = -L../lib 
# LIBS = -lmylib -lm 

# List of all source files 
SRCS = main.cc cache.cc 

# Object files defined from source files 
OBJS = $(SRCS:.cc=.o) 

# # define the executable file 
MAIN = cache_test 

#List of non-file based targets: 
.PHONY: depend clean all 

## .DEFAULT_GOAL := all 

# List of dependencies defined from list of object files 
DEPS := $(OBJS:.o=.d) 

all: $(MAIN) 

-include $(DEPS) 

$(MAIN): $(OBJS) 
    $(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS) 

#suffix replacement rule for building .o's from .cc's 
#build dependency files first, second line actually compiles into .o 
.cc.o: 
    $(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,[email protected]) $< 
    $(CC) $(CFLAGS) $(INCLUDES) -c -o [email protected] $< 

clean: 
    $(RM) *.o *~ $(MAIN) *.d 

Thông báo tôi đã sử dụng .cc .. Các Makefile trên là dễ dàng để điều chỉnh cho các tệp .c.

Cũng quan trọng cần lưu ý tầm quan trọng của hai dòng sau:

$(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,[email protected]) $< 
$(CC) $(CFLAGS) $(INCLUDES) -c -o [email protected] $< 

để gcc được gọi là một lần để xây dựng một tập tin phụ thuộc đầu tiên, và sau đó thực sự biên dịch một file .cc. Và cứ thế cho mỗi tệp nguồn.

0

Giải pháp đơn giản: Chỉ cần sử dụng Makefile để có quy tắc biên dịch .c thành .o phụ thuộc vào (các) tệp tiêu đề và bất kỳ điều gì khác có liên quan trong dự án của bạn dưới dạng phụ thuộc.

Ví dụ:, trong Makefile ở đâu đó:

DEPENDENCIES=mydefs.h yourdefs.h Makefile GameOfThrones.S07E01.mkv 

::: (your other Makefile statements like rules 
::: for constructing executables or libraries) 

# Compile any .c to the corresponding .o file: 
%.o: %.c $(DEPENDENCIES) 
     $(CC) $(CFLAGS) -c -o [email protected] $< 
Các vấn đề liên quan