2017-09-17 15 views
6

तो मैं make lex चलाने के लिए और यह मेरे lex.yy.c फ़ाइल उत्पन्न करता है, सब अच्छामेकफ़ाइल उन चीजों को संकलित करने का आग्रह क्यों करता है जो इसे नहीं करना चाहिए?

तो मैं make scanner है, जो एक sourcefile संकलन में scanner.c, यह बस cc lex.yy.c scanner.c -o scanner चलाना चाहिए बुलाया लेता है चलाने के लिए, लेकिन इसके बजाय यह इस करता है:

lex -t scanner.l > scanner.c 
cc lex.yy.c scanner.c -o scanner 

lex -t scanner.l को चलाने का निर्णय क्यों लेता है और इसे scanner.c पर प्रभावी रूप से मेरे कोड को ओवरराइट करने का निर्णय क्यों देता है? कोई शापित विचार नहीं है, और यह मुझे पागल कर रहा है।

मेरी makefile:

scanner: scanner.h scanner.c lex.yy.c 
    cc lex.yy.c scanner.c -o scanner 

lex: scanner.l 
    lex scanner.l > lex.yy.c 

clean: 
    rm lex.yy.c 
    rm scanner 

क्या गलत हो रहा है?

उत्तर

8

यह lex -t scanner.l को चलाने का निर्णय क्यों लेता है और स्कैनर.c को आउटपुट को प्रभावी ढंग से मेरे कोड को ओवरराइट करने का निर्णय लेता है?

जब भी ऐसा होता है कि आप अपने निर्माण निर्देशिका में एक scanner.c और एक scanner.l कि अधिक नवीनतम scanner.c

जब आप चलाने make scanner, नुस्खा से है:

scanner: scanner.h scanner.c lex.yy.c 
    cc lex.yy.c scanner.c -o scanner 

कि आवश्यकता है इसकी पूर्व शर्त scanner.c अपतटीय हो जाएगी। आप ने कोई नुस्खा नहीं दिया है जो ऐसा करता है, इसलिए बिल्टिन व्यंजनों के डेटाबेस पर वापस आते हैं।

make -p चलाकर उन builtin व्यंजनों की जांच करना और आपको:

%.c: %.l 
# recipe to execute (built-in): 
    @$(RM) [email protected] 
    $(LEX.l) $< > [email protected] 

यह अंतर्निहित नुस्खा चलाकर मिलान file.l से एक file.c कर देगा:

rm file.c # Not echoed 
lex -t file.l > file.c 

मेक पाता पैटर्न है कि इस नुस्खा के लिए नियम - %.c: %.l - scanner.c से संतुष्ट है, क्योंकि scanner.l मौजूद है और हाल ही मेंसे अधिक है। तो यह यह नुस्खा का उपयोग करता scanner.c uptodate बनाने के लिए:

lex -t scanner.l > scanner.c 

जिससे आपके scanner.c clobbering।अपने makefile में किसी भी नुस्खा के बिना

%.c: %.l 

:

आप इस builtin नुस्खा लागू करने के लिए कभी नहीं करना चाहते, तो आप स्पष्ट रूप से यह सिर्फ नियम लिख कर रद्द कर सकते हैं।

तुम भी मेकअप कमांडलाइन पर --no-builtin-rules पास करके सभी builtin व्यंजनों निष्क्रिय कर सकते हैं।

हालांकि, जब भी एक makefile के व्यवहार के बारे अपनी उम्मीदों builtin व्यंजनों से नाकाम कर रहे हैं यह मजबूत संकेत है कि अपनी अपेक्षाओं नहीं इनपुट फ़ाइलें से उत्पादन फ़ाइलें बनाने का हमेशा की तरह के रूप में अच्छी तरह से वाकिफ रहे हैं आपके मेकफ़ाइल का उपयोग करने वाले टूल के साथ। मेक के Catalogue of Built-In Rules:

%.<target-type>: %.<prereq-type> 
    <command> 
    ... 

मेकअप के साथ एक <prereq-type> फ़ाइल से एक <target-type> फ़ाइल बनाने का विहित रास्ता प्रतीक है, ताकि आप अपने makefiles में यह नुस्खा खुद के लेखन रखने के लिए नहीं है। उदाहरण C और C++ प्रोग्रामर जो जीएनयू के साथ सक्षम हैं बनाने .c फाइल या .cpp फाइलों से .o फ़ाइलें बनाने के लिए, कोने मामलों को छोड़कर व्यंजनों बारे में नहीं है, क्योंकि वे जानते हैं कि इस तरह से बना यह करना होगा स्वचालित रूप से सामान्य रूप से है जिस तरह से वे चाहते हैं। %.c: %.l शासन के लिए

मेक के builtin नुस्खा बनाने file.c एक file.l दिया के विहित रास्ता व्यक्त करता है। तो अपने आप से पूछना: आप नहीं चाहते scanner.c scanner.l से ऐसा किए जाने के लिए करते हैं, और अगर आप चाहते हैं बजाय lex.yy.c को scanner.l से बनाया जा, यह आवश्यक या फ़ाइल आप scanner.l कहा जाता है होना करने के लिए के लिए उपयोगी है कहा जाता है कि, जब आपके पास एक बहुत ही स्वतंत्र स्रोत फ़ाइल है जिसे scanner.c कहा जाता है?

मान लीजिए आप इस खिलौने उदाहरण के रूप में कर के builtin व्यंजनों का फायदा उठाया:

lexer.l

%{ 
#include <stdio.h> 
%} 
%% 
[ \t] ; 
[0-9]+\.[0-9]+ { printf("Found a floating-point number: [%s]\n",yytext); } 
[0-9]+ { printf("Found an integer: [%s]\n",yytext); } 
[a-zA-Z0-9]+ { printf("Found a string: [%s]\n",yytext); } 
%% 

scanner.c

#include "scanner.h" 

int main(void) { 
    yylex(); 
    return 0; 
} 

स्कैनर।ज

#ifndef SCANNER_H 
#define SCANNER_H 

extern int yylex(void); 

#endif 

फिर अपने makefile हो सकता है बस:

Makefile

SRCS := scanner.c lexer.c 
OBJS := $(SRCS:.c=.o) 
LDLIBS := -lfl 

.PHONY: all clean 

all: scanner 

scanner: $(OBJS) 
    $(LINK.o) -o [email protected] $^ $(LDLIBS) 

scanner.o: scanner.h 

clean: 
    rm -f scanner *.o 

जो की तरह चलाता है:

$ make 
cc -c -o scanner.o scanner.c 
lex -t lexer.l > lexer.c 
cc -c -o lexer.o lexer.c 
cc -o scanner scanner.o lexer.o -lfl 
rm lexer.c 

ध्यान दें कि बनाने के लिए इन सभी आदेशों चलाता है:

012,
cc -c -o scanner.o scanner.c 
    lex -t lexer.l > lexer.c 
    cc -c -o lexer.o lexer.c 

आप किसी भी व्यंजनों है कि यह बताने के लिए ऐसा करने के लिए लिखा बिना lexer.c, lexer.o और scanner.o बनाने के लिए। यह भी स्वचालित रूप से देखती है कि lexer.c एक मध्यवर्ती फ़ाइल है - कि केवल lexer.llexer.o करने से प्राप्त करने के लिए मौजूद करने की जरूरत है एक उत्पन्न फ़ाइल - तो यह यह अंत में हटाता है:

rm lexer.c 

करने के लिए कहा जा रहा है बिना ।

और यह स्कैनर की तरह चलाता है: ठीक है

$ ./scanner 
hello 
Found a string: [hello] 

42 
Found an integer: [42] 

42.42 
Found a floating-point number: [42.42] 

^C 
5

make आप निश्चित रूप से डिफ़ॉल्ट प्रत्यय को परिभाषित करते हैं, जो निहित नियमों को परिभाषित करते हैं जो आपके द्वारा परिभाषित किए गए कार्यों के साथ संघर्ष करते हैं।

उदाहरण के लिए यह howto देखें, जो प्रत्यय नियमों को बताता है।

अपने makefiles की शुरुआत में, आप एक लाइन जोड़ सकते हैं:

.SUFFIXES: 

make बताने के लिए आप डिफ़ॉल्ट प्रत्यय नियम नहीं करना चाहती।

1

, तो आपको निम्न निर्भरता, जो नामित लक्ष्य का निर्माण नहीं करता बनाया है, और इसलिए हमेशा कहा जाता है, यह

बनाने की कोशिश करने के लिए
lex: scanner.l   <-- incorrect target name, not created from source. 
    lex scanner.l > lex.yy.c 

यह निर्भरता lex नाम की एक फ़ाइल बनाने का प्रयास करती है, लेकिन नीचे दिए गए कमांड लाइन से कोई भी नहीं बनाया गया है। शायद आप इस बजाय

lex.yy.c: scanner.l 
    lex scanner.l -olex.yy.c 

या यहाँ तक कि

lex.yy.c: scanner.l 
    lex scanner.l [email protected] 

(, -o विकल्प का उपयोग के रूप में lex(1) मानक आउटपुट पर स्कैनर का उत्पादन नहीं करता। जिस तरह से मुझे लगता है कि करके, लेकिन नहीं जानते कि, लेक्स चाहता था, विकल्प तर्क की आवश्यकता विकल्प -o के संपर्क में सीधे हो सकता है, आदमी पेज)

नोट 1

आप ज देखना एक ही बेसनाम नाम की .l फ़ाइल से .c फ़ाइल बनाने के लिए एक डिफ़ॉल्ट नियम है। नियम की तरह

.l.c: 
    $(LEX) $(LFLAGS) [email protected] $< 

कि LFLAGS चर में संकेत झंडे के साथ चर LEX में आदेश निष्पादित करता है, एक ही नाम के एक लेक्स इनपुट से स्रोत सी फ़ाइल पैदा करने के लिए, लेकिन .l विस्तार के साथ कुछ न कुछ है।

संबंधित मुद्दे