Saya memiliki makefile berikut yang saya gunakan untuk membangun program (sebenarnya kernel) yang sedang saya kerjakan. Ini dari awal dan saya belajar tentang prosesnya, jadi ini tidak sempurna, tapi saya pikir ini cukup kuat pada titik ini untuk tingkat pengalaman saya menulis makefiles.
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
Masalah utama saya dengan makefile ini adalah bahwa ketika saya memodifikasi file header yang disertakan satu atau lebih file C, file C tidak dibangun kembali. Saya dapat memperbaikinya dengan cukup mudah dengan membuat semua file header saya menjadi dependensi untuk semua file C saya, tetapi itu secara efektif akan menyebabkan pembangunan kembali proyek secara lengkap setiap kali saya mengubah / menambahkan file header, yang tidak akan terlalu anggun.
Yang saya inginkan hanya untuk file C itu menyertakan file header yang saya ubah untuk dibangun kembali, dan untuk seluruh proyek untuk ditautkan lagi. Saya dapat melakukan penautan dengan membuat semua file header menjadi dependensi dari target, tetapi saya tidak dapat menemukan cara membuat file C menjadi tidak valid ketika file header yang disertakan lebih baru.
Saya pernah mendengar bahwa GCC memiliki beberapa perintah untuk memungkinkan hal ini (sehingga makefile entah bagaimana dapat mengetahui file mana yang perlu dibangun kembali) tetapi saya tidak dapat seumur hidup saya menemukan contoh implementasi yang sebenarnya untuk dilihat. Dapatkah seseorang memposting solusi yang akan mengaktifkan perilaku ini di makefile?
EDIT: Saya harus mengklarifikasi, saya akrab dengan konsep menempatkan target individu dan memiliki setiap target.o memerlukan file header. Itu mengharuskan saya untuk mengedit makefile setiap kali saya menyertakan file header di suatu tempat, yang agak merepotkan. Saya mencari solusi yang dapat memperoleh dependensi file header sendiri, yang saya cukup yakin pernah saya lihat di proyek lain.
sumber
Anda dapat menambahkan perintah 'make depend' seperti yang dinyatakan orang lain tetapi mengapa tidak mendapatkan gcc untuk membuat dependensi dan mengompilasi pada saat yang sama:
Parameter '-MF' menentukan file untuk menyimpan dependensi.
Tanda hubung di awal '-include' memberitahu Make untuk melanjutkan ketika file .d tidak ada (misalnya pada kompilasi pertama).
Perhatikan bahwa tampaknya ada bug di gcc terkait opsi -o. Jika Anda menyetel nama file objek menjadi mengatakan
obj/_file__c.o
maka yang dihasilkan_file_.d
akan tetap berisi_file_.o
, bukanobj/_file_c.o
.sumber
g++ -c -Wall -Werror -MM -MF main.d -o main.o main.cpp
Saya mendapat file main.d, tetapi main.o adalah 0 byte. Namun flag -MMD sepertinya melakukan apa yang diperlukan. Jadi aturan makefile kerja saya menjadi:$(CC) -c $(CFLAGS) -MMD -o $@ $<
Ini sama dengan jawaban Chris Dodd , tetapi menggunakan konvensi penamaan yang berbeda (dan secara kebetulan tidak memerlukan
sed
keajaiban. Disalin dari duplikat selanjutnya .Jika Anda menggunakan kompiler GNU, kompilator dapat menyusun daftar dependensi untuk Anda. Fragmen makefile:
Ada juga alatnya
makedepend
, tapi saya tidak pernah menyukainyagcc -MM
sumber
SRCS
danOBJS
. Saya setuju sebagian besar waktu, tetapi setiap orang harus tahu apa itu.Anda harus membuat target individual untuk setiap file C, lalu mencantumkan file header sebagai dependensi. Anda masih dapat menggunakan target umum Anda, dan hanya menempatkan
.h
dependensi setelahnya, seperti:sumber
Pada dasarnya, Anda perlu membuat aturan makefile secara dinamis untuk membangun kembali file objek saat file header berubah. Jika Anda menggunakan gcc dan gnumake, ini cukup mudah; taruh saja sesuatu seperti:
$(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
di makefile Anda.
sumber
Selain dan di atas apa yang dikatakan @mipadi, Anda juga dapat menjelajahi penggunaan opsi '
-M
' untuk menghasilkan catatan dependensi. Anda bahkan dapat membuatnya menjadi file terpisah (mungkin 'depend.mk') yang kemudian Anda masukkan ke dalam makefile. Atau Anda dapat menemukanmake depend
aturan ' ' yang mengedit makefile dengan dependensi yang benar (istilah Google: "jangan hapus baris ini" dan bergantung).sumber
Tidak ada jawaban yang berhasil untuk saya. Misalnya jawaban Martin Fido menyarankan gcc dapat membuat file dependensi, tetapi ketika saya mencoba itu menghasilkan file objek kosong (nol byte) untuk saya tanpa peringatan atau kesalahan apa pun. Ini mungkin bug gcc. aku berada
Jadi, inilah Makefile lengkap saya yang cocok untuk saya; ini adalah kombinasi dari solusi + sesuatu yang tidak disebutkan oleh orang lain (misalnya, "aturan penggantian sufiks" ditetapkan sebagai .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,$@) $< $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< clean: $(RM) *.o *~ $(MAIN) *.d
Perhatikan saya menggunakan .cc .. Makefile di atas mudah disesuaikan untuk file .c.
Perhatikan juga pentingnya dua baris ini:
jadi gcc dipanggil sekali untuk membuat file dependensi terlebih dahulu, lalu mengompilasi file .cc. Begitu seterusnya untuk setiap file sumber.
sumber
Solusi yang lebih sederhana: Cukup gunakan Makefile agar aturan kompilasi .c ke .o bergantung pada file header dan apa pun yang relevan dalam proyek Anda sebagai dependensi.
Misalnya, di Makefile di suatu tempat:
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 $@ $<
sumber
Saya percaya
mkdep
perintah itu adalah apa yang Anda inginkan. Ini sebenarnya memindai file .c untuk#include
baris dan membuat pohon ketergantungan untuk mereka. Saya yakin proyek Automake / Autoconf menggunakan ini secara default.sumber