मैं डिबग और रिलीज़ बिल्ड के लिए अपने मेकफाइल को कैसे कॉन्फ़िगर कर सकता हूं?


175

मेरे पास अपनी परियोजना के लिए निम्नलिखित मेकफाइल है, और मैं इसे रिलीज़ और डीबग बिल्ड के लिए कॉन्फ़िगर करना चाहूंगा। मेरे कोड में, मेरे पास बहुत सारे #ifdef DEBUGमैक्रोज़ हैं, इसलिए यह केवल इस मैक्रो को सेट -g3 -gdwarf2करने और संकलक में झंडे जोड़ने की बात है । मैं यह कैसे कर सकता हूँ?

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

बस स्पष्ट करने के लिए, जब मैं कहता हूं कि रिलीज़ / डिबग बनाता है, तो मैं चाहता हूं कि मैं केवल टाइप करूं makeऔर एक रिलीज बिल्ड प्राप्त करूं या make debugएक डिबग बिल्ड प्राप्त करूं , बिना मेनुफाइल में चीजों को मैन्युअल रूप से टिप्पणी किए।


12
ध्यान! $ (CC) = CC से कुछ अलग है = something
levif

4
निष्पादन योग्य लक्ष्य, मेकफ़ाइल्स के सुनहरे नियम का उल्लंघन करता है: प्रत्येक लक्ष्य को आपके निष्पादन के मामले में लक्ष्य नामकरण फ़ाइल को अद्यतन करना चाहिए।
जेस्पर

3
^ और यदि ऐसा नहीं है, तो इसे घोषित किया जाना चाहिए.PHONY
अंडरस्कोर_ड

जवाबों:


192

आप लक्ष्य-विशिष्ट चर मानों का उपयोग कर सकते हैं । उदाहरण:

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

अपने सभी संकलित आदेशों में $ (CXX) या $ (CC) का उपयोग करना याद रखें।

फिर, 'डीबग करें' में अतिरिक्त झंडे होंगे जैसे -DDEBUG और -g जहाँ 'मेक' नहीं होगा।

एक साइड नोट पर, आप अपने मेकफाइल को और अधिक संक्षिप्त बना सकते हैं जैसे अन्य पदों का सुझाव दिया था।


42
आपको किसी मेकफाइल या बैडहिंग्स मयप्पन (टीएम) के भीतर कभी भी CXX या CC को नहीं बदलना चाहिए, जिसमें चलाने के लिए निष्पादन योग्य का पथ और / या नाम होता है। CPPFLAGS, CXXFLAGS और CFLAGS इस उद्देश्य की पूर्ति करते हैं।

11
यह सलाह खराब है क्योंकि यह डीबग और गैर-डीबग ऑब्जेक्ट फ़ाइलों को मिलाता है, ताकि कोई दूषित बिल्ड के साथ समाप्त हो जाए।
मैक्सिम एगोरुस्किन

@MaximEgorushkin कैसे तय करें? मुझे हाल ही में यह समस्या आई। मेरे पास एक डीबग निष्पादन योग्य बिल्ड है, जो रिलीज़ ऑब्जेक्ट फ़ाइलों के साथ जुड़ा हुआ था। अब तक केवल समाधान डिबग घोषित करने और सबसे खराब टोने
टोटके

3
@MauriceRandomNumber अपने ही फ़ोल्डरों में डिबग / रिलीज़ बनाएँ। उदाहरण: stackoverflow.com/a/48793058/412080
मैक्सिम एगोरुस्किन

43

इसी तरह की समस्या के लिए खोज करते समय यह सवाल अक्सर सामने आया है, इसलिए मुझे लगता है कि एक पूरी तरह से लागू समाधान का वारंट है। खासकर जब से मैंने (और मैं दूसरों को मानूंगा) सभी विभिन्न उत्तरों को एक साथ जोड़कर संघर्ष किया है।

नीचे एक नमूना मेकफाइल है जो अलग-अलग निर्देशिकाओं में कई बिल्ड प्रकारों का समर्थन करता है। सचित्र उदाहरण डिबग और रिलीज़ बिल्ड दिखाता है।

समर्थन करता है ...

  • विशिष्ट बिल्ड के लिए अलग प्रोजेक्ट निर्देशिका
  • डिफ़ॉल्ट लक्ष्य निर्माण का आसान चयन
  • परियोजना के निर्माण के लिए आवश्यक निर्देशिका बनाने के लिए मूक प्रस्तुतिकरण का लक्ष्य
  • निर्माण-विशिष्ट संकलक विन्यास झंडे
  • यदि परियोजना के पुनर्निर्माण की आवश्यकता है तो GNU मेकिंग की प्राकृतिक विधि
  • अप्रचलित प्रत्यय नियमों के बजाय पैटर्न नियम

#
# 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)

मेकफाइल में रहने वाले के अलावा किसी निर्देशिका में स्रोत फ़ाइलों के निर्माण की अनुमति देने के लिए आप इसे कैसे संशोधित करते हैं?
जेफरसन हडसन

@JeffersonHudson यदि स्रोत फाइलें नाम की निर्देशिका में हैं src, तो SRCS = file1.c file2.c file3.c file4.cपढ़ने के लिए लाइन को संशोधित करें SRCS = src/file1.c src/file2.c src/file3.c src/file4.c
जीरो

3
मुझे जो बात पसंद नहीं है, वह डिबग और रिलीज़ के लिए सभी नियमों और चर का दोहराव है। मेरे पास एक समान मेकफिल है लेकिन इसे विस्तारित करते समय मुझे डिबग और रिलीज़ के लिए प्रत्येक नई चीज़ को सावधानीपूर्वक कॉपी करने की आवश्यकता है और इसे सावधानीपूर्वक रूपांतरित करें।
BeeOnRope

यह स्वीकृत उत्तर होना चाहिए। काश, मैं इसे बहुत पहले देख चुका होता।
माइकल डोरस्ट

42

यदि रिलीज़ रिलीज़ / बिल्ड द्वारा कॉन्फ़िगर किया गया है, तो इसका मतलब है कि आपको केवल मेकफाइल के लिए एक ही कॉन्फिगर की जरूरत है, तो यह केवल एक मामला है और CC और CFLAGS को डिकम्पोज करना है:

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

इस बात पर निर्भर करता है कि क्या आप ग्नू मेफाइल का उपयोग कर सकते हैं, आप सशर्त का उपयोग कर इसे थोड़ा कट्टर बना सकते हैं, और इसे कमांड लाइन से नियंत्रित कर सकते हैं:

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

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

और फिर उपयोग करें:

make DEBUG=0
make DEBUG=1

यदि आपको एक ही समय में दोनों कॉन्फ़िगरेशन को नियंत्रित करने की आवश्यकता है, तो मुझे लगता है कि बिल्ड निर्देशिकाओं का होना बेहतर है, और एक निर्माण निर्देशिका / कॉन्फ़िगरेशन।


18
मुझे नहीं पता कि मैं कुछ अजीब कर रहा हूं, लेकिन डिबग पाने के लिए अगर ifeq (DEBUG, 1)मेरे लिए काम ( ) के लिए वक्तव्य , तो इस DEBUGतरह से कोष्ठक में लिपटे चर की आवश्यकता है ifeq ($(DEBUG), 1):।
शानेट

25

ध्यान दें कि आप अपना मेकफाइल सरल भी बना सकते हैं:

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

अब आपको हर जगह फ़ाइल नाम दोहराना नहीं है। कोई भी .l फाइलें फ्लेक्स और gcc से होकर गुजरेगी, कोई भी .y फाइलें बायसन और g ++ से गुजरेंगी, और कोई भी .cpp फाइलें सिर्फ g ++ से होकर गुजरेंगी।

बस उन .o फ़ाइलों को सूचीबद्ध करें जिनसे आप समाप्त होने की उम्मीद करते हैं, और मेक यह पता लगाने का काम करेगा कि कौन से नियम जरूरतों को पूरा कर सकते हैं ...

रिकार्ड के लिए:

  • $@ लक्ष्य फ़ाइल का नाम (बृहदान्त्र से पहले वाला)

  • $< पहली (या केवल) पूर्वापेक्षा फ़ाइल का नाम (बृहदान्त्र के बाद पहला)

  • $^ सभी आवश्यक फाइलों के नाम (अंतरिक्ष अलग)

  • $*तना (थोड़ा जो %नियम की परिभाषा में वाइल्डकार्ड से मेल खाता है ।


आप "रिकॉर्ड के लिए" अनुभाग में एक आइटम को विभिन्न विवरणों के साथ दो बार परिभाषित किया गया है। Gnu.org/software/make/manual/make.html#Automatic-Variables के अनुसार , $^सभी आवश्यक फ़ाइलों के लिए है।
ग्रेटर पीटर्स

उस अनुदान के लिए धन्यवाद - टाइपो तय! (मैं मेकफाइल पर जाँच की, और ऐसा लगता है कि मैं इसे सही ढंग से वहाँ इस्तेमाल किया, लेकिन स्पष्टीकरण टाइप किया।)
Stobor

2
काश, इन छोटे गाइडों में ऑटोमैटिक वैरिएबल सहित एक छोटे से मेकफाइल्स को लिखने की अधिक संभावना होती।
अज़प

Makefile को बदले बिना डिबग और रिलीज़ दोनों लक्ष्य रखना अच्छा है, और डिफ़ॉल्ट को अपनी पसंद के आधार पर चुनने की क्षमता।

1
इस समाधान में समस्या है कि डिबग और रिलीज़ आउटपुट फ़ाइलों को एक ही निर्देशिका में एक साथ मिलाया जाता है। यदि वे संगत नहीं हैं, तो यह अजीब और अद्भुत तरीके से उड़ाएगा जब तक कि आप हर बार डिबग और न के बीच में बदलाव करने के लिए साफ-सफाई करने के लिए सावधान रहें। यहां तक ​​कि अगर वे संगत हैं, तो यह वह नहीं करेगा जो आप बिना साफ किए उम्मीद करते हैं: यदि आपके पास रिलीज के रूप में बनाया गया प्रोजेक्ट है, और फिर DEBUG = 1 बनाते हैं, तो यह केवल उन फ़ाइलों का पुनर्निर्माण करेगा जिनके स्रोत बदल गए हैं, इसलिए आप आम तौर पर नहीं करेंगे उस तरह से एक "डिबग" का निर्माण करें।
BeeOnRope

3

आपके पास एक चर हो सकता है

DEBUG = 0

तो आप एक सशर्त बयान का उपयोग कर सकते हैं

  ifeq ($(DEBUG),1)

  else

  endif

2

पहले से जवाबों को पूरा करना ... आपको अपने आदेशों में जानकारी को परिभाषित करने वाले चर को संदर्भित करने की आवश्यकता है ...

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
वहाँ एक (अब हटा दिया गया है?) उत्तर (जो एक उत्तर पर एक टिप्पणी ifeq (DEBUG, 1)होना चाहिए था ) जो नोट किया जाना चाहिए ifeq ($(DEBUG), 1)। मैं यह अनुमान लगा रहा हूँ कि यह आपके उत्तर की बात कर रहा होगा।
कीथ एम

0

आप अपने Makefile में कुछ सरल जोड़ सकते हैं जैसे कि

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

फिर इसे डिबगिंग के लिए संकलित करें

make DEBUG=1

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.