2008-11-18 82 views
80

我使用下面的makefile來構建我正在開發的程序(實際上是一個內核)。它從零開始,我正在學習這個過程,所以它並不完美,但我認爲它足夠強大,在這一點上我的經驗寫作makefile。如何讓Makefile自動重建包含修改過的頭文件的源文件? (在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 

我與此生成的文件主要問題是,當我修改頭文件中的一個或多個C文件包括的C文件不重建。我可以通過讓所有頭文件成爲所有C文件的依賴關係來很容易地解決這個問題,但是如果任何時候改變/添加頭文件,那麼這將有效地導致項目的完全重建,這不會很優雅。

我想要的只是包含包括的C文件,我更改的頭文件被重建,並且整個項目再次鏈接。我可以通過使所有頭文件成爲目標的依賴關係來進行鏈接,但我無法弄清楚如何在包含的頭文件更新時使C文件失效。

我聽說GCC有一些命令可以使這成爲可能(因此makefile可以以某種方式找出哪些文件需要重建),但我不能在我的生活中找到一個實際的實現示例來看看。有人可以發佈一個解決方案,將在makefile中啓用此行爲嗎?

編輯:我應該澄清,我熟悉將個別目標放入並具有每個target.o需要頭文件的概念。這要求我每次在某處添加頭文件時都要編輯makefile,這有點痛苦。我正在尋找一個解決方案,它可以自行獲取頭文件依賴項,我相當肯定我在其他項目中看到過。

回答

25

正如所指出的其他地方在這個網站,看到這個頁面: http://make.paulandlesley.org/autodep.html

總之,海灣合作委員會可以自動創建.D爲您相關文件,這是包含.c文件的依賴性小的makefile片段你編譯。 每次更改.c文件並對其進行編譯時,.d文件都將被更新。

除了向gcc添加-M標誌之外,還需要將.d文件包含在makefile中(如Chris上面所述)。 在使用sed解決的頁面中有一些更復雜的問題,但是您可以忽略它們並執行「make clean」來清除.d文件,只要抱怨無法生成不再生成頭文件存在。

+2

我可能會誤解,但我認爲GCC實際上增加了一項功能來嘗試解決sed問題。請特別注意http://gcc.gnu.org/onlinedocs/gcc-4.3.1/gcc/Preprocessor-Options.html。 – 2013-10-21 01:44:29

6

您必須爲每個C文件創建單獨的目標,然後將該頭文件列爲依賴項。你仍然可以使用你的通用指標,而只需將.h依賴事後,像這樣:

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

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

超出,超過了@mipadi說,你還可以探索利用「-M」選項生成一個記錄的依賴關係。你甚至可以將它們生成一個單獨的文件(可能是'depend.mk'),然後將它包含在makefile中。或者你可以找到一個'make depend'規則,它用正確的依賴關係編輯makefile(谷歌術語:「不要刪除該行」並依賴)。

3

基本上,您需要動態創建makefile規則以在頭文件更改時重建對象文件。如果你使用gcc和gnumake,這很容易;只是把這樣的東西:

$(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 

在你的生成文件。

+2

我有點明白這一點,除了(除了fromt他-MM和-MG標誌是新的),我不明白什麼是正則表達式看着神祕的文字行了。這不會讓我的隊友開心......^_ ^我會嘗試一下,看看我是否有任何結果。 – 2008-11-18 01:14:15

+0

sed是「流編輯器」的簡稱,它可以在不需要使用文件的情況下修改文本流。它是一個標準的Unix工具,體積更小,速度更快,因此比awk或perl更經常使用它。 – 2008-11-18 02:05:54

+0

啊,有這個問題:我在Windows下這樣做。 – 2008-11-20 18:47:50

16

這相當於Chris Dodd's answer,但使用不同的命名約定(巧合的不需要sed神奇。從a later duplicate複製。


如果您使用的是GNU編譯器,編譯器可以組裝。對你的依賴列表Makefile片段中:

depend: .depend 

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

include .depend 

也有工具makedepend,但我從來不喜歡它,就像gcc -MM

-1

我相信mkdep命令是你想要的。它實際上掃描#include行的.c文件併爲它們創建依賴關係樹。我相信Automake/Autoconf項目默認使用它。

19

你可以添加一個「讓依賴」命令,正如其他人說,但爲什麼不GCC創建的依賴,並在同一時間編譯:

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

-include $(DEPS) 

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

的「-MF」參數指定一個文件來存儲

'-include'開始處的破折號表示在.d文件不存在時(例如在第一次編譯時),Make會繼續。

請注意,在-o選項中似乎存在gcc中的錯誤。如果將對象文件名設置爲obj/_file__c.o,則生成的_file_.d將仍包含_file_.o而不是obj/_file_c.o

0

沒有答案爲我工作。例如。 Martin Fido的回答表明gcc可以創建依賴文件,但是當我試圖爲我生成空的(零字節)目標文件時,沒有任何警告或錯誤。這可能是一個gcc的錯誤。我對

$ GCC --version海合會(GCC)4.4.7 20120313(紅帽4.4.7-16)

因此,這裏是我的完整的Makefile爲我的作品;它的解決方案+東西不是由其他任何人(例如,「後綴替換規則」提到指定爲.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 

通知我使用.CC。以上的Makefile容易調整.c文件。

另外需要注意以下兩行的重要性:

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

所以GCC被調用一次以先建一個依賴文件,然後實際上編譯一個.cc文件。等等每個源文件。

0

更簡單的解決方案:只需使用Makefile將.c編譯爲.o編譯規則就會依賴於頭文件和任何與項目相關的依賴項。

E.g.,在Makefile的地方:

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] $< 
相關問題