2017-09-17 158 views
6

Yani make lex çalıştırmak ve bana lex.yy.c dosyası oluşturur, tüm iyiMakefile neden yapmaması gerektiği şeyleri derlemekte ısrar ediyor?

sonra derleme içine scanner.c, sadece cc lex.yy.c scanner.c -o scanner çalışmalıdır denilen SourceFile alır make scanner, koşmak, ama bunun yerine yapar:

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

Neden lex -t scanner.l'u çalıştırmaya ve scanner.c kodumu etkin bir şekilde kodumun üzerine yazmaya karar veriyor? Lanet bir fikir yok ve beni delirtiyor.

benim 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 

Ne yanlış gidiyor?

cevap

8

Neden Lex -t scanner.l çalışmasına karar veriyor

ve çıkış benim kod overwritting etkili bir scanner.c için? Bu sizin inşa dizinde var durumla

bir scanner.c ve scanner.c

Eğer make scanner çalıştırın tarifi daha daha yeni bir scanner.l:

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

gerektirir Önkoşul scanner.c güncel olacaktır. , bunu yapan hiçbir reçete hazırlamamıştır, bu yüzden yerleşik reçeteler veritabanında geri çekilir.

make -p çalıştırarak bu yerleşik tarifleri inceleyin ve şunları bulacaksınız:

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

Bu yerleşik tarifi çalıştırarak eşleşen file.l bir file.c yapacaktır:

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

Yap desen sonucuna varmıştır Bu tarifi için kural - %.c: %.l - scanner.c tarafından memnun, scanner.l var ve daha güncel olan scanner.c.

lex -t scanner.l > scanner.c 

böylece scanner.c clobbering: Yani scanner.c UPTODATE yapmak için bu tarifi kullanır.

bu yerleşik tarifi uygulamak hiç yapmak istemiyorsanız

, açıkça sadece kural yazarak iptal edebilirsiniz:

%.c: %.l 

makefile herhangi tarifi olmadan.

Ayrıca yapmak komut satırında --no-builtin-rules geçirerek tüm yerleşik tarifleri devre dışı bırakabilir. Bir makefile davranışı hakkında beklentileriniz yerleşik tarifleri tarafından sabote verildiğinde

Ancak, bu beklentileriniz giriş dosyaları çıktı dosyalarını yapma zamanki gibi yanı bilgili değildir kuvvetli göstergesidir Makefile'nin çağırdığı araçlarla. Yap en Catalogue of Built-In Rules: Eğer sizin makefiles bu tarifi kendiniz yazmaya devam etmek zorunda kalmamak için

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

, marka ile <prereq-type> dosyadan <target-type> dosyası yapma kurallı yolu somutlaştırmak. onlar yol yapmak bunu biliyorum çünkü GNU yetkili örnek C ve C++ programcıları için otomatik normalde, köşe durumlar dışında, .c dosyaları veya .cpp dosyalarından .o dosyaları yapmak tarifleri yazmıyorum yapmak istedikleri şekilde. %.c: %.l kural için

yapmak en yerleşik tarifi bir file.l verilen file.c yapma kanonik yolu ifade eder. Eğer değilscanner.c scanner.l gelen böyle yapılmasını istiyoruz değilse ve için lex.yy.cscanner.l yapılabilir istemek yerine, eğer sen olmak scanner.l çağrıda dosya için gerekli veya yararlıdır: Yani kendinize sorun Ayrıca, scanner.c denen oldukça bağımsız bir kaynak dosya olduğunda, buna denir?

bu oyuncak örnekte olduğu gibi make 'yerleşik tarifleri yararlandı varsayalım:

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; 
} 

tarayıcı.yapmak tüm bu komutları çalıştırır

$ 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 

Not: gibi çalışır

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 

:

#ifndef SCANNER_H 
#define SCANNER_H 

extern int yylex(void); 

#endif 

saat Sonra makefile sadece olabilir

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

Eğer nasıl bunu söylemek herhangi tarifleri yazılı kalmadan lexer.c, lexer.o ve scanner.o yapmak. Sadece lexer.llexer.o noktasından hedefine bulunması gerekir bir oluşturulan dosyası - - Ayrıca otomatik lexer.c bir ara dosya olduğunu fark yüzden sonunda siler: söylenmişti olmadan

rm lexer.c 

.

Ve bu tarayıcı gibi çalışır: Eh

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

42 
Found an integer: [42] 

42.42 
Found a floating-point number: [42.42] 

^C 
5

make kesinlikle kullandığınız ile çakışan örtük kurallar tanımlayarak, varsayılan sonekleri tanımlar. Sonek kurallarını açıklayan bu howto örneğine bakın. senin makefiles başında

, bir satırı ekleyebilirsiniz:

.SUFFIXES: 

varsayılan eki kurallarını istemiyoruz make anlatmak için.

1

, adlandırılmış hedef yaratmaz aşağıdaki bağımlılık oluşturduk ve böylece o

yaratmaya çalışmak, her zaman denir
lex: scanner.l   <-- incorrect target name, not created from source. 
    lex scanner.l > lex.yy.c 

Bu bağımlılık lex adında bir dosya oluşturmaya çalışır, ancak aşağıdaki komut satırından hiçbiri oluşturulmaz. Bunu yerine,

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

hatta

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

(emin lex(1) standart çıktıya tarayıcıyı üretmez olarak bence arada., -o seçeneğini kullanın ama Lex bu istedik ,)

NOT 1

Sen h man sayfasına bakın seçenek -o için temas halinde doğrudan olmaya seçeneği bağımsız değişken gerektirir Aynı temel adın bir .l dosyasından bir .c dosyası oluşturmak için varsayılan bir kural ave. kural aynı adı taşıyan bir lex girişten kaynak C dosyasını üreten LFLAGS değişkeninde belirtilen bayraklarıyla değişken LEX komutunu çalıştırır, ancak .l uzantılı

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

gibi bir şeydir.