Dosyamı hata ayıklama ve sürüm derlemeleri için nasıl yapılandırabilirim?


175

Projem için aşağıdaki makefile var ve onu sürüm ve hata ayıklama yapıları için yapılandırmak istiyorum. #ifdef DEBUGKodumda, yerinde birçok makro var , bu yüzden bu makroyu ayarlamak -g3 -gdwarf2ve derleyicilere bayrakları eklemek meselesi . Bunu nasıl yapabilirim?

$(CC) = g++ -g3 -gdwarf2
$(cc) = gcc -g3 -gdwarf2

all: executable

executable: CommandParser.tab.o CommandParser.yy.o Command.o
    g++ -g -o output CommandParser.yy.o CommandParser.tab.o Command.o -lfl

CommandParser.yy.o: CommandParser.l 
    flex -o CommandParser.yy.c CommandParser.l
    gcc -g -c CommandParser.yy.c

CommandParser.tab.o: CommandParser.y
    bison -d CommandParser.y
    g++ -g -c CommandParser.tab.c

Command.o: Command.cpp
    g++ -g -c Command.cpp

clean:
    rm -f CommandParser.tab.* CommandParser.yy.* output *.o

Sadece açıklığa kavuşturmak için, bırak / hata ayıklama derlemeleri dediğimde, makefile'daki şeyleri elle yorumlamadan sadece makebir sürüm derlemesi yazabiliyorum ve make debugbir hata ayıklama derlemesi alabiliyorum .


12
Dikkat! $ (CC) = bir şey CC = bir şeyden farklı
levif

4
Yürütülebilir hedef, makefiles'ın altın kuralını ihlal eder: her hedef, "yürütülebilir" durumunuzda, hedefi adlandıran dosyayı güncelleştirmelidir.
JesperE

3
^ Ve eğer değilse, beyan edilmelidir.PHONY
underscore_d

Yanıtlar:


192

Sen kullanabilirsiniz Hedef özgü Değişken Değerlerini . Misal:

CXXFLAGS = -g3 -gdwarf2
CCFLAGS = -g3 -gdwarf2

all: executable

debug: CXXFLAGS += -DDEBUG -g
debug: CCFLAGS += -DDEBUG -g
debug: executable

executable: CommandParser.tab.o CommandParser.yy.o Command.o
    $(CXX) -o output CommandParser.yy.o CommandParser.tab.o Command.o -lfl

CommandParser.yy.o: CommandParser.l 
    flex -o CommandParser.yy.c CommandParser.l
    $(CC) -c CommandParser.yy.c

Tüm derleme komutlarınızda $ (CXX) veya $ (CC) kullanmayı unutmayın.

Daha sonra, 'make debug' -DDEBUG ve -g gibi ekstra bayraklara sahip olur ve burada 'make' gibi olmaz.

Bir yan notta, Makefile'nizi diğer yayınların önerdiği gibi çok daha özlü hale getirebilirsiniz.


42
Çalıştırılacak yürütülebilir dosyaların yolunu ve / veya adını içeren bir Makefile veya BadThingsMayHappen ™ içindeki CXX veya CC'yi asla değiştirmemelisiniz. CPPFLAGS, CXXFLAGS ve CFLAGS bu amaca hizmet eder.

11
Hata ayıklama ve hata ayıklama olmayan nesne dosyalarını karıştırdığı için bu öneri zayıftır, böylece biri bozuk bir derleme ile sonuçlanır.
Maxim Egorushkin

@MaximEgorushkin nasıl düzeltilir? Geçenlerde bu sorunla karşılaştım. Ben yayın nesne dosyaları ile bağlantılı bir hata ayıklama yürütülebilir yapı var. Şimdiye kadar tek çözüm hata ayıklama ilan etmek ve azgın sahte yayınlamak oldu
MauriceRandomNumber

3
@MauriceRandomNumber Hata ayıklama / bırakma işlemini kendi klasörlerinde yapın. Örnek: stackoverflow.com/a/48793058/412080
Maxim Egorushkin

43

Benzer bir sorun ararken bu soru sık sık ortaya çıktı, bu yüzden tam olarak uygulanan bir çözümün gerekli olduğunu hissediyorum. Özellikle de ben (ve başkalarını da varsayacağım) tüm çeşitli cevapları bir araya getirmekte zorlandım.

Aşağıda, ayrı dizinlerde birden çok derleme türünü destekleyen örnek bir Makefile bulunmaktadır. Gösterilen örnek, hata ayıklama ve bırakma yapılarını göstermektedir.

Destekler ...

  • belirli yapılar için ayrı proje dizinleri
  • varsayılan hedef oluşturmanın kolay seçilmesi
  • projeyi oluşturmak için gerekli dizinleri oluşturmak için sessiz hazırlık hedefi
  • derlemeye özgü derleyici yapılandırma bayrakları
  • GNU Make'ın projenin yeniden inşasını gerektirip gerektirmediğini belirlemenin doğal yöntemi
  • eski sonek kuralları yerine kalıp kuralları

#
# Compiler flags
#
CC     = gcc
CFLAGS = -Wall -Werror -Wextra

#
# Project files
#
SRCS = file1.c file2.c file3.c file4.c
OBJS = $(SRCS:.c=.o)
EXE  = exefile

#
# Debug build settings
#
DBGDIR = debug
DBGEXE = $(DBGDIR)/$(EXE)
DBGOBJS = $(addprefix $(DBGDIR)/, $(OBJS))
DBGCFLAGS = -g -O0 -DDEBUG

#
# Release build settings
#
RELDIR = release
RELEXE = $(RELDIR)/$(EXE)
RELOBJS = $(addprefix $(RELDIR)/, $(OBJS))
RELCFLAGS = -O3 -DNDEBUG

.PHONY: all clean debug prep release remake

# Default build
all: prep release

#
# Debug rules
#
debug: $(DBGEXE)

$(DBGEXE): $(DBGOBJS)
    $(CC) $(CFLAGS) $(DBGCFLAGS) -o $(DBGEXE) $^

$(DBGDIR)/%.o: %.c
    $(CC) -c $(CFLAGS) $(DBGCFLAGS) -o $@ $<

#
# Release rules
#
release: $(RELEXE)

$(RELEXE): $(RELOBJS)
    $(CC) $(CFLAGS) $(RELCFLAGS) -o $(RELEXE) $^

$(RELDIR)/%.o: %.c
    $(CC) -c $(CFLAGS) $(RELCFLAGS) -o $@ $<

#
# Other rules
#
prep:
    @mkdir -p $(DBGDIR) $(RELDIR)

remake: clean all

clean:
    rm -f $(RELEXE) $(RELOBJS) $(DBGEXE) $(DBGOBJS)

Makefile'nin bulunduğu dizinden başka bir dizinde kaynak dosyalarının oluşturulmasına izin vermek için bunu nasıl değiştirirsiniz?
Jefferson Hudson

@JeffersonHudson Kaynak dosyalar adlı bir dizindeyse src, SRCS = file1.c file2.c file3.c file4.cokunacak satırı değiştirin SRCS = src/file1.c src/file2.c src/file3.c src/file4.c.
zero2cx

3
Sevmediğim şey, hata ayıklama ve serbest bırakma için tüm kuralların ve değişkenlerin çoğaltılmasıdır. Ben de benzer bir Makefile var ama uzatırken dikkatle her yeni şey hata ayıklama ve serbest bırakmak ve dikkatle dönüştürmek yapıştırmak gerekir.
BeeOnRope

Bu kabul edilen cevap olmalı. Keşke bunu uzun zaman önce görseydim.
Michael Dorst

42

Release / build'i yapılandırarak, makefile başına yalnızca bir yapılandırmaya ihtiyacınız varsa, bu sadece bir konudur ve CC ve CFLAGS'ı ayırır:

CFLAGS=-DDEBUG
#CFLAGS=-O2 -DNDEBUG
CC=g++ -g3 -gdwarf2 $(CFLAGS)

Gnu makefile kullanıp kullanamayacağınıza bağlı olarak, bunu biraz daha meraklı hale getirmek için koşullu kullanabilir ve komut satırından kontrol edebilirsiniz:

DEBUG ?= 1
ifeq ($(DEBUG), 1)
    CFLAGS =-DDEBUG
else
    CFLAGS=-DNDEBUG
endif

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

ve sonra şunu kullanın:

make DEBUG=0
make DEBUG=1

Her iki yapılandırmayı aynı anda denetlemeniz gerekiyorsa, derleme dizinleri ve bir derleme / yapılandırma oluşturmanın daha iyi olduğunu düşünüyorum.


18
Ben garip bir şey yapıyorum bilmiyorum ama çalışmaya (deyimi ise hata ayıklama almak ifeq (DEBUG, 1)benim için), DEBUGdeğişken parantez sarılı gerekli böylece Seviyorum: ifeq ($(DEBUG), 1).
shanet

25

Makefile'inizi aynı anda daha basit hale getirebileceğinizi de unutmayın:

DEBUG ?= 1
ifeq (DEBUG, 1)
    CFLAGS =-g3 -gdwarf2 -DDEBUG
else
    CFLAGS=-DNDEBUG
endif

CXX = g++ $(CFLAGS)
CC = gcc $(CFLAGS)

EXECUTABLE = output
OBJECTS = CommandParser.tab.o CommandParser.yy.o Command.o
LIBRARIES = -lfl

all: $(EXECUTABLE)

$(EXECUTABLE): $(OBJECTS)
    $(CXX) -o $@ $^ $(LIBRARIES)

%.yy.o: %.l 
    flex -o $*.yy.c $<
    $(CC) -c $*.yy.c

%.tab.o: %.y
    bison -d $<
    $(CXX) -c $*.tab.c

%.o: %.cpp
    $(CXX) -c $<

clean:
    rm -f $(EXECUTABLE) $(OBJECTS) *.yy.c *.tab.c

Artık dosya adlarını her yerde tekrarlamak zorunda değilsiniz. Herhangi bir .l dosyası flex ve gcc'den, herhangi bir .y dosyası bizon ve g ++ 'dan ve herhangi bir .cpp dosyası sadece g ++' dan geçecektir.

Sonunda beklediğiniz .o dosyalarını listeleyin ve Make, hangi kuralların ihtiyaçları karşılayabileceğini bulma işini yapacaktır ...

kayıt için:

  • $@ Hedef dosyanın adı (iki nokta üst üste işaretinden önceki dosya)

  • $< İlk (veya yalnızca) önkoşul dosyasının adı (iki nokta üst üste işaretinden sonraki ilk dosya)

  • $^ Tüm önkoşul dosyalarının adları (boşlukla ayrılmış)

  • $*Kök ( %kural tanımındaki joker karakterle eşleşen bit .


"Kayıt için" bölümünde, farklı açıklamalarla iki kez tanımlanan bir öğe var. Göre gnu.org/software/make/manual/make.html#Automatic-Variables , $^önkoşul tüm dosyaları içindir.
Grant Peters

Grant için teşekkürler - yazım hatası düzeltildi! (Makefile'yi kontrol ettim ve orada doğru kullandım, ancak açıklamayı yazdım.)
Stobor

2
Otomatik değişkenler de dahil olmak üzere, oldukça küçük bir Makefile yazmak için bu kısa kılavuzlardan daha fazlası olmasını isterdim.
AzP

Makefile'i değiştirmek zorunda kalmadan hem hata ayıklama hem de bırakma hedefine sahip olmak ve kendi tercihinize göre varsayılanı seçme yeteneği iyidir.

1
Bu çözümde, hata ayıklama ve bırakma çıktı dosyalarının aynı dizinde karıştırılması sorunu vardır. Eğer uyumlu değilse, hata ayıklama arasında her geçiş yaptığınızda bir temizlik yapmaya dikkat etmedikçe bu garip ve harika yollarla patlar. Uyumlu olsalar bile, temiz olmadan beklediğiniz şeyi yapmazlar: projeyi sürüm olarak oluşturduysanız ve sonra DEBUG = 1 yaparsanız, yalnızca kaynağı değişmiş dosyaları yeniden oluşturur, böylece genellikle bu şekilde bir "hata ayıklama" derlemesi alın.
BeeOnRope

3

bir değişkenin olabilir

DEBUG = 0

koşullu bir ifade kullanabilirsiniz

  ifeq ($(DEBUG),1)

  else

  endif

2

Cevapları daha önce tamamlıyoruz ... Komutlarınızda tanımladığınız değişkenlere başvurmanız gerekir ...

DEBUG ?= 1
ifeq (DEBUG, 1)
    CFLAGS =-g3 -gdwarf2 -DDEBUG
else
    CFLAGS=-DNDEBUG
endif

CXX = g++ $(CFLAGS)
CC = gcc $(CFLAGS)

all: executable

executable: CommandParser.tab.o CommandParser.yy.o Command.o
    $(CXX) -o output CommandParser.yy.o CommandParser.tab.o Command.o -lfl

CommandParser.yy.o: CommandParser.l 
    flex -o CommandParser.yy.c CommandParser.l
    $(CC) -c CommandParser.yy.c

CommandParser.tab.o: CommandParser.y
    bison -d CommandParser.y
    $(CXX) -c CommandParser.tab.c

Command.o: Command.cpp
    $(CXX) -c Command.cpp

clean:
    rm -f CommandParser.tab.* CommandParser.yy.* output *.o

1
Olması gereken (şimdi bir Silinmiş?) Yanıtı var (bir Yanıtı Yorum Yapmış ifeq (DEBUG, 1)olmalı ) ifeq ($(DEBUG), 1). Sanırım burada cevabınıza atıfta bulunmuş olabilir.
Keith M

0

Ayrıca Makefile'nize basit bir şey ekleyebilirsiniz.

ifeq ($(DEBUG),1)
   OPTS = -g
endif

Sonra hata ayıklamak için derleyin

make DEBUG=1

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.