Bir Makefile'ın değiştirilmiş bir başlık dosyası içeren kaynak dosyalarını otomatik olarak yeniden oluşturmasını nasıl sağlayabilirim? (C / C ++ ile)


92

Üzerinde çalıştığım bir programı (aslında bir çekirdek) oluşturmak için kullandığım aşağıdaki makefile var. Sıfırdan ve süreci öğreniyorum, bu yüzden mükemmel değil, ancak bu noktada makefile yazma deneyimim için yeterince güçlü olduğunu düşünüyorum.

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 $@ $^

$(SOBJS) : $(SFILES)
    $(AS) $(ASFLAGS) $< -o $@

%.o: %.c
    @echo Compiling $<...
    $(CC) $(CFLAGS) -c -o $@ $<

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

Bu makefile ile ilgili temel sorunum, bir veya daha fazla C dosyasının içerdiği bir başlık dosyasını değiştirdiğimde, C dosyalarının yeniden oluşturulmamasıdır. Tüm üstbilgi dosyalarımın tüm C dosyalarım için bağımlılıklar olmasını sağlayarak bunu oldukça kolay bir şekilde düzeltebilirim, ancak bu, bir başlık dosyasını değiştirdiğim / eklediğim her seferinde projenin tamamen yeniden oluşturulmasına neden olur ki bu çok zarif olmaz.

İstediğim, yalnızca değiştirdiğim başlık dosyasını içeren C dosyalarının yeniden oluşturulması ve tüm projenin yeniden bağlanması. Bağlamayı, tüm başlık dosyalarının hedefin bağımlılıkları olmasına neden olarak yapabilirim, ancak C dosyalarının dahil edilen başlık dosyaları daha yeni olduğunda nasıl geçersiz kılınacağını çözemiyorum.

GCC'nin bunu mümkün kılmak için bazı komutları olduğunu duydum (böylece makefile bir şekilde hangi dosyaların yeniden oluşturulması gerektiğini anlayabilir) ama hayatım boyunca bakacak gerçek bir uygulama örneği bulamıyorum. Birisi bir makefile bu davranışı sağlayacak bir çözüm gönderebilir mi?

DÜZENLEME: Açıklığa kavuşturmalıyım, bireysel hedefleri yerleştirme ve her bir hedefe sahip olma kavramına aşinayım. Başlık dosyalarını gerektiriyor. Bu, bir yere bir üstbilgi dosyası eklediğim her seferinde makefile'ı düzenlememi gerektiriyor, bu biraz acı verici. Başlık dosyası bağımlılıklarını kendi başına türetebilen bir çözüm arıyorum, diğer projelerde gördüğümden oldukça eminim.

Yanıtlar:


30

Bu sitede başka yerlerde de belirtildiği gibi, şu sayfaya bakın: Otomatik Bağımlılık Oluşturma

Kısacası, gcc sizin için otomatik olarak .d bağımlılık dosyaları oluşturabilir, bunlar derlediğiniz .c dosyasının bağımlılıklarını içeren mini makefile parçalarıdır. .C dosyasını her değiştirdiğinizde ve derlediğinizde, .d dosyası güncellenecektir.

Gcc'ye -M işaretini eklemenin yanı sıra .d dosyalarını makefile'a eklemeniz gerekir (Chris'in yukarıda yazdığı gibi). Sayfada sed kullanılarak çözülen bazı daha karmaşık sorunlar var, ancak artık mevcut olmayan bir üstbilgi dosyası oluşturamamakla ilgili şikayette bulunduğunuzda bunları görmezden gelebilir ve .d dosyalarını temizlemek için "temizlemeyi" yapabilirsiniz. .


2
Yanılıyor olabilirim, ancak GCC'nin aslında bu sed sorununu aşmak için bir özellik eklediğini düşünüyorum. Check out gcc.gnu.org/onlinedocs/gcc-4.3.1/gcc/Preprocessor-Options.html özellikle -MP.
Eugene Marcotte

Evet, -MP, GCC 3'ten beri var, clang ve icc'de var ve sed ihtiyacını ortadan kaldırıyor. bruno.defraine.net/techtips/makefile-auto-dependencies-with-gcc/…
hmijail mourns resignees

Yanıttaki bağlantının en son sürümü, GCC bayraklarının kullanıldığı örnekler içerir.
MadScientist

21

Başkalarının da belirttiği gibi bir 'bağımlı yap' komutu ekleyebilirsiniz, ancak neden aynı anda bağımlılıklar oluşturmak ve derlemek için gcc almıyorsunuz:

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

-include $(DEPS)

%.o: %.c
    $(CC) -c $(CFLAGS) -MM -MF $(patsubst %.o,%.d,$@) -o $@ $<

'-MF' parametresi, bağımlılıkların saklanacağı bir dosyayı belirtir.

'-İnclude' başındaki tire, Make'e .d dosyası yokken devam etmesini söyler (örn. İlk derlemede).

Gcc'de -o seçeneğiyle ilgili bir hata olduğunu unutmayın. Nesne dosya adını söyleyecek şekilde ayarlarsanız, obj/_file__c.ooluşturulan dosya _file_.diçermez _file_.o, içermez obj/_file_c.o.


19
Bu benim için işe yaramadı. Örneğin makefile bunu oluşturdu ve çalıştırdı: g++ -c -Wall -Werror -MM -MF main.d -o main.o main.cpp main.d dosyasını aldım, ancak main.o 0 bayttı. Ancak -MMD bayrağı tam olarak gerekeni yapıyor gibi görünüyor. Böylece çalışma makefile $(CC) -c $(CFLAGS) -MMD -o $@ $<
Darren Cook

17

Bu, Chris Dodd'un cevabına eşdeğerdir , ancak farklı bir adlandırma kuralı kullanır (ve tesadüfen sedsihir gerektirmez . Daha sonraki bir kopyadan kopyalandı .


Bir GNU derleyicisi kullanıyorsanız, derleyici sizin için bir bağımlılıklar listesi oluşturabilir. Makefile parçası:

depend: .depend

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

include .depend

Araç da var makedepend, ama onu hiç bu kadar sevmedimgcc -MM


4
KAYNAKLAR'ı neden hecelemiyorsun? Özellikle çok daha fazla karakter gerektirmez ve kısaltma gibi görünebilecek "SRCS" kadar karmaşık değildir.
HelloGoodbye

@HelloGoodbye Biraz tarz. Her zaman kullandım ve her zaman gördüm SRCSve OBJS. Çoğu zaman aynı fikirdeyim ama herkes bunların ne olduğunu bilmeli.
sherrellbc

@sherrellbc İnsanların "bilmesi gereken" ve gerçekte ne bildiği genellikle iki farklı şeydir: P
HelloGoodbye

7

Her bir C dosyası için ayrı hedefler oluşturmanız ve ardından başlık dosyasını bağımlılık olarak listelemeniz gerekir. Yine de genel hedeflerinizi kullanabilir ve .hbağımlılıkları sonradan yerleştirebilirsiniz, örneğin:

%.o: %.c
        @echo Compiling $<...
        $(CC) $(CFLAGS) -c -o $@ $<

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

4

Temel olarak, başlık dosyaları değiştiğinde nesne dosyalarını yeniden oluşturmak için makefile kurallarını dinamik olarak oluşturmanız gerekir. Gcc ve gnumake kullanıyorsanız, bu oldukça kolaydır; sadece şöyle bir şey koyun:

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

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

makefile dosyanızda.


2
Bunu anlıyorum, ancak (he -MM ve -MG bayraklarının yeni olması dışında) şifreli metnin normal ifadesinin ne için olduğunu anlamıyorum. Bu beni takım arkadaşlarımı mutlu etmeyecek ... ^ _ ^ Yine de deneyeceğim ve herhangi bir sonucum olup olmadığına bakacağım.
Nicholas Flynt

sed, bir dosya kullanmaya gerek kalmadan bir metin akışını değiştirebilen "akış düzenleyici" nin kısaltmasıdır. Standart bir Unix aracıdır ve daha küçük ve daha hızlıdır, bu nedenle awk veya perl'den daha sık kullanılır.
Zan Lynx

Ah, sorun var: Bunu Windows altında yapıyorum.
Nicholas Flynt

3

@ Mipadi'nin söylediklerinin yanı sıra -M, bağımlılıkların bir kaydını oluşturmak için ' ' seçeneğinin kullanımını da keşfedebilirsiniz . Bunları, daha sonra makefile'a ekleyeceğiniz ayrı bir dosyada (belki 'bağımlı.mk') bile oluşturabilirsiniz. Veya make dependmakefile'ı doğru bağımlılıklar ile düzenleyen bir ' ' kuralı bulabilirsiniz (Google terimleri: "bu satırı kaldırma" ve buna bağlıdır).


1

Cevapların hiçbiri benim için işe yaramadı. Örneğin, Martin Fido'nun cevabı gcc'nin bağımlılık dosyası oluşturabileceğini, ancak bunun benim için herhangi bir uyarı veya hata olmadan boş (sıfır bayt) nesne dosyaları oluşturduğunu söyledi. Bir gcc hatası olabilir. Ben varım

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

İşte benim için çalışan tam Makefile'ım; bu, çözümlerin + başka hiç kimsenin bahsetmediği bir şeyin birleşimidir (örn. .cc.o olarak belirtilen "sonek değiştirme kuralı" :)

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,$@) $<
    $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<

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

Dikkat. .Cc kullandım .. Yukarıdaki Makefile'ı .c dosyaları için ayarlamak kolaydır.

Ayrıca bu iki satırın önemine dikkat edin:

$(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,$@) $<
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<

bu nedenle gcc, önce bir bağımlılık dosyası oluşturmak için bir kez çağrılır ve ardından aslında bir .cc dosyası derler. Ve her kaynak dosyası için böyle devam eder.


0

Daha basit çözüm: .c'den .o'ya derleme kuralının başlık dosyalarına ve projenizle ilgili diğer her şeye bağımlı olması için Makefile'ı kullanın.

Örneğin Makefile'da bir yerde:

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

-1

İstediğin mkdepşeyin komut olduğuna inanıyorum . Aslında .c dosyalarında #includesatırları tarar ve onlar için bir bağımlılık ağacı oluşturur. Automake / Autoconf projelerinin bunu varsayılan olarak kullandığına inanıyorum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.