İngilizceFransızcaİspanyolca

Ad


OnWorks favicon'u

makepp_cookbook - Bulutta Çevrimiçi

Makepp_cookbook'u Ubuntu Online, Fedora Online, Windows çevrimiçi emülatörü veya MAC OS çevrimiçi emülatörü üzerinden OnWorks ücretsiz barındırma sağlayıcısında çalıştırın

Bu, Ubuntu Online, Fedora Online, Windows çevrimiçi emülatörü veya MAC OS çevrimiçi emülatörü gibi birden fazla ücretsiz çevrimiçi iş istasyonumuzdan birini kullanarak OnWorks ücretsiz barındırma sağlayıcısında çalıştırılabilen makepp_cookbook komutudur.

Program:

ADI


makepp_cookbook -- Çeşitli durumlar için makefile oluşturmanın en iyi yolu

TANIM


Neredeyse hiç kimsenin bir yapım aleti kılavuzunu okumadığını keşfettim, çünkü açıkçası
hiç kimse yapım sürecinin kendisiyle gerçekten ilgilenmiyor - biz sadece sonuçlarla ilgileniyoruz.
Bu yemek kitabı, insanların ihtiyaç duydukları şeyi elde edebilecekleri umuduyla bir araya getirildi.
kılavuzda gezinmeden örneklerden hızlı bir şekilde. Bu, nasıl yazılacağını gösterir
sorular, kurulum talimatları ve engeller ise
sıkça Sorulan Sorular.

bina kütüphaneler
Do sen Gerçekten mi gerek a kütüphane?

Her biri çok sayıda modülden oluşan çok sayıda büyük program gördüm.
hangi kendi dizininde yaşıyor. Genellikle, her dizin kendi kitaplığına konur,
ve ardından son program tüm kitaplıklarla bağlantı kurar.

Çoğu durumda, bir kütüphane kullanmak yerine daha iyi bir yaklaşım olduğunu düşünüyorum. kütüphaneler
her modül başka bir modülde yeniden kullanılamıyorsa veya kullanılamayacaksa gerçekten doğru çözüm değildir.
programı, çünkü o zaman kitaplıkların tüm dezavantajlarını elde edersiniz ve bunların hiçbirini
avantajlar. Kitaplıklar aşağıdaki durumlarda yararlıdır:

1. Birkaç farklı programla ilişkilendirilmesi gereken bir grup alt rutininiz olduğunda
ve hiçbir program aslında alt rutinlerin %100'ünü kullanmaz; her program bir
farklı alt küme. Bu durumda, muhtemelen statik bir kitaplık kullanmak iyi bir fikirdir (bir
.a dosyası veya bir arşiv dosyası).

2. Birkaç farklı programa bağlanması gereken bir modülünüz olduğunda ve
dinamik olarak yüklemek istiyorsanız, her programın ayrı bir kopyasına sahip olması gerekmez.
kütüphane. Dinamik kitaplıklar yürütülebilir dosya alanından tasarruf edebilir ve bazen
sistem performansı, çünkü tüm dosyalar için yüklenen kitaplığın yalnızca bir kopyası vardır.
onu kullanan farklı programlar.

3. Bağlantı süreniz aşırı derecede uzun olduğunda, büyük parçalar için paylaşılan kitaplıkları kullanmak
program bağlantıyı önemli ölçüde hızlandırabilir.

Statik kitaplıkları kullanmanın bir ana dezavantajı vardır: bazı sistemlerde (örn. Linux), sıra
kütüphaneleri bağladığınız yer kritik derecede önemlidir. Bağlayıcı, kitaplıkları işler
komut satırında belirtilen sırada. İhtiyacı olduğunu düşündüğü her şeyi alır
her kitaplık, ardından bir sonraki kitaplığa geçer. Sonraki bazı kitaplıklar bir
Daha önceki bir kitaplıktan henüz dahil edilmemiş sembol, bağlayıcı
geri dönüp önceki kütüphaneden almayı bilin. Sonuç olarak, gerekli olabilir
kitaplığı linker komut satırında birden çok kez listelemek için. (bir proje üzerinde çalıştım
burada tüm kitaplık listesini üç kez tekrarlamamız gerekti. Bu proje ne yaptı
Ben aşağıda önerilen alternatif yaklaşımı, artımlı bağlamayı tercih ederim.)

Dinamik kitaplıkları kullanmanın birkaç dezavantajı vardır. İlk olarak, programınız biraz
kitaplık zaten başka bir program tarafından kullanılmıyorsa, başlatılması daha yavaştır, çünkü
bulunması ve yüklenmesi gerekir. İkincisi, tüm dinamikleri elde etmek gerçek bir güçlük olabilir.
doğru yerlere kurulmuş kütüphaneler; sadece yürütülebilir programı kopyalayamazsınız,
ayrıca tüm kitaplıklarını kopyaladığınızdan emin olmalısınız. Üçüncüsü, bazı sistemlerde,
hata ayıklayıcılar desteklemediğinden, paylaşılan kitaplıklar içinde kodun hatalarını ayıklamak zordur
onlar iyi.

Modülünüz başka bir programda asla kullanılmayacaksa, kullanmak için çok az neden vardır.
bir kitaplık: kitaplıkları kullanmanın tüm dezavantajlarını elde edersiniz ve hiçbir avantajınız olmaz.
Tercih ettiğim teknik, uygun olduğu yerde artımlı bağlantı kullanmaktır.

Bunu Linux'ta şu şekilde yapabilirsiniz:

my_module.o : $(filter_out my_module.o, $(joker karakter *.o))
ld -r -o $(çıktı) $(girdiler)

Bunun yapacağı şey, başka bir .o çağrılan dosya benim_modülüm.o, oluşacak
Tüm .o Bu alt dizindeki dosyalar. Bağlayıcı,
mümkün olduğunca referanslar ve kalan referansları çözülmeye bırakacaktır.
bağlamanın sonraki aşaması. En üst düzeyde, nihayet programınızı oluşturduğunuzda,
ile bağlantı kurmak yerine libmy_module.a or libmy_module.so, sadece ile bağlantı kurarsınız
benim_modülüm.o. bağlantı kurduğunda .o dosyalarında sipariş bağımlılığı ile ilgili sorunlarınız yok.
bağlayıcı komut satırı.

İzin vermek makep anlamaya dışarı hangi kütüphane modüller vardır gerekli

Belirli bir programın ondan yalnızca birkaç dosyaya ihtiyaç duyduğu gerçek bir kitaplığınız olsa bile
(her bir modül yerine), makepp hangi modüllerin olduğunu anlayabilir.
kütüphaneden ihtiyaç duyulur ve yalnızca derlemedekileri içerir. Bu derlemeyi kaydedebilir
zaman, kütüphaneyi bir programla birlikte geliştiriyorsanız, çünkü zahmete girmezsiniz.
Üzerinde çalıştığınız belirli program için gerekli olmayan kitaplık modüllerini derleyin.

Kitaplığınız, içinde bildirilen tüm işlevlerin veya sınıfların kuralına kesinlikle uyuyorsa,
bir dosya xyz.h tamamen derlenen bir kaynak dosyada uygulanır. xyz.o (yani sen
uygulamayı bölmeyin xyz1.o ve xyz2.o), sonra kullanabilirsiniz
"$(infer_objects)" işlevi, makepp'e yalnızca ilgili modülleri
kütüphane. Bu, düzinelerce içerme dosyası içeren kitaplıklar için şaşırtıcı derecede iyi çalışabilir.
Temel olarak, "$(infer_objects)" aşağıdakilerin listesini inceler. .h dahil edilen ve görünen dosyalar
karşılık gelen için .o Dosyalar. Hızla bir kitaplık ve program geliştiriyorsanız
birlikte, bu derleme zamanından tasarruf sağlayabilir, çünkü asla modülleri derlemekle uğraşmazsınız.
programın kullanmadığı kitaplık.

İşte bunu kullanma şeklime bir örnek:

programım: $(infer_objects *.o, $(LIB1)/*.o $(LIB2)/*.o)
$(CXX) $(girdiler) -o $(çıktı) $(SYSTEM_LIBRARIES)

"$(infer_objects )" işlevi ilk argümanını döndürür (joker karakter yaptıktan sonra
genişletme) ve ayrıca ikinci argümanındaki dosya listesine bakar,
adı herhangi bir dosyanın adıyla aynı olan dosyalar .h herhangi bir dosyanın içerdiği dosyalar ilk
argüman. Bu tür dosyalar bulunursa, bunlar listeye eklenir.

bina a statik kütüphane

Gerçekten bir kitaplığa ihtiyacınız olduğundan eminseniz ve artımlı bağlantı mevcut değilse veya
yapmak istediğin bu değil, bunu yapmanın birkaç yolu var. İlk olarak, işte bir örnek
tüm dosyaların açıkça listelendiği yer:

LIBRARY_FILES = abcde

libmine.a: $(KÜTÜPHANE_DOSYALARI).o
&rm -f $(çıktı)
$(AR) cr $(çıktı) $(girdiler)
ranlib $(output) # İşletim sisteminize bağlı olarak gerekli olmayabilir.

&rm, makepp'in yerleşik "rm" komutudur. Makefile yazmaya alışkınsanız,
bu komuta biraz şaşırdım; bunun gibi bir şeye daha alışmış olabilirsiniz:

libmine.a: $(KÜTÜPHANE_DOSYALARI).o
$(AR) ru $@ $? # Tavsiye edilmez!!!!!!!
ranlib $(çıktı)

nerede $? ("$(changed_inputs)" olarak da bilinir) herhangi bir dosya anlamına gelen otomatik bir değişkendir.
kütüphanenin son inşasından bu yana değişti ve $@ kabaca aynı
"$(çıktı)" olarak.

Bu yaklaşım birkaç nedenden dolayı önerilmez:

· Geçerli dizinden bir kaynak dosyayı kaldırdığınızı varsayalım. hala içinde
kütüphane, çünkü kütüphaneyi sıfırdan yeniden oluşturmadınız. Sonuç olarak, herhangi bir şey
bu kütüphaneyle bağlantıların eski olması .o dosya ve bu, işinizi mahvedebilir
inşa eder. (Bir keresinde ölü kodu kaldırmaya çalışırken bununla iyice kafam karıştı
bir projeden: Dosyaları silmeye devam ettim ve hala bağlantılıydı, bu yüzden kodun olduğunu düşündüm
ölü. Ancak, bir başkası projeyi sıfırdan yeniden oluşturduğunda, herhangi bir bağlantı oluşturmadı.
daha fazla! Sorun şuydu ki, eski .o dosyalar hala arşivdeydi.)

Ayrıca, "ar" seçeneklerinize ve "ar" uygulamanıza bağlı olarak (örn.
"r" yerine "q" seçeneğini kullanın, birden fazla sürümüne sahip olabilirsiniz.
aynı .o içinde .a dosya. Farklı sürümler farklı globaller tanımlıyorsa,
linker ikisini de çekmeye çalışabilir. Bu muhtemelen kötü bir şey.

Bu yüzden önce kütüphane dosyasını kaldırıyoruz ve sıfırdan oluşturuyoruz. Bu irade
bir kitaplıktaki modülleri güncellemekten biraz daha uzun sürer, ancak çok daha uzun sürmez; üzerinde
modern bir bilgisayar tarafından tüketilen zaman miktarı ar program çok küçük
C derleyicisinin tipik bir yapıda ne aldığına, bu yüzden endişelenmeye değmez
hakkında.

· makepp'in doğru yapıları garanti etmeye çalışmasının yollarından biri,
belirli bir hedefi oluşturmak için komut satırı değiştiyse otomatik olarak yeniden oluşturun. Fakat
$ kullanarak? değişken sorunlara neden olabilir, çünkü kitaplık her güncellendiğinde,
build komutu farklıdır. (Bunu kullanarak bastırabilirsiniz.
":build_check görmezden_eylem"; ayrıntılar için makepp_build_check'e bakın.)

· Arşivi yeniden oluşturmak yerine güncellemek makepp'i imkansız hale getirecektir.
dosyayı düzgün bir şekilde derleme önbelleğine koyun (ayrıntılar için makepp_build_cache'ye bakın).

Bazen tüm dosyaları listelemenin bir acı varsa, özellikle de bir sorun varsa, biraz olduğunu görebilirsiniz.
proje hızlı bir gelişim sürecinden geçiyor ve dosya listesi sürekli değişiyor. o
kitaplığı aşağıdaki gibi joker karakterler kullanarak oluşturmak daha kolay olabilir:

libmine.a: $(only_targets *.o)
&rm $(çıktı)
$(AR) cr $(çıktı) $(girdiler)

Bu tüm koyar .o Geçerli dizindeki dosyalar kitaplığa. joker karakter
herhangi biriyle eşleşir .o var olan veya oluşturulabilen dosya, bu nedenle dosyalar çalışmasa bile çalışır
henüz var.

"only_targets" işlevi hariç tutmak için kullanılır .o karşılık gelen olmayan dosyalar
kaynak dosyaları artık. adlı bir dosyanız olduğunu varsayalım. xyz.c içine koyduğun
kütüphane. Bu, bir xyz.o ortalıkta dolanan dosya. şimdi siliyorsun xyz.c
çünkü eski, ama silmeyi unutuyorsun xyz.o. "only_targets" olmadan
fonksiyonu, xyz.o yine de listeye dahil edilecek .o kütüphanede bulunan dosyalar.

bina a dinamik kütüphane

Dinamik kitaplıklar oluşturma süreci tamamen sisteme bağlıdır. çok isterim
dinamik bir kitaplık oluşturmak için libtool kullanmanızı öneririz (bkz.
<http://www.gnu.org/software/libtool/>), böylece nasıl yapacağınızı bulmak zorunda değilsiniz.
platformunuz ve böylece makefile'niz bir platforma geçtiğinizde bile çalışmaya devam edecek.
farklı işletim sistemi Ayrıntılar için libtool belgelerine bakın. İşte örnek bir Makefile:

LIBTOOL := lib aracı

libflick.la : $(only_targets *.lo)
$(LIBTOOL) --mode=bağ $(CC) $(girdiler) -o $(çıktı)

%.lo : %.c
$(LIBTOOL) --mode=derleme $(CC) $(CFLAGS) $(INCLUDES) -c $(girdi) -o $(çıktı)

bina on birkaç farklı makineler or ağlar
Makefile dosyalarıyla ilgili en can sıkıcı sorunlardan biri, siz yaptığınızda neredeyse hiç çalışmamasıdır.
farklı bir makineye veya farklı bir ağa geçin. Makefile dosyalarınız üzerinde çalışmak zorundaysa
gezegendeki her olası makine, o zaman muhtemelen bir çeşit yapılandırmaya ihtiyacınız var
senaryo. Ancak yalnızca birkaç farklı makinede çalışmanız gerekiyorsa, bunun birkaç yolu vardır.
bu soruna yaklaşabilirsiniz:

kullanım a farklı dahil dosya in herşey the ortamları

Her makefile dosyasının başına şunun gibi bir satır ekleyebilirsiniz:

system_defs.mk'yi dahil et

Dosya system_defs.mk normalde her biri için farklı bir yerde bulunurdu
Çevre. Derleme dizinlerinizin tüm makinelerde aynı olmasını istiyorsanız,
system_defs.mk yapı dizinlerinin üzerindeki bir dizinde veya başka bir içerme yolu sağlayın
"-I" komut satırı seçeneğini kullanarak makepp için.

Bu genellikle yapmak biraz acı vericidir, ancak çok sayıda varsa iyi çalışır.
farklılıklar.

kullanım if ifadeleri

Bunu yapmanın en çirkin yolu budur, ancak genellikle işe yarayacaktır.

ifsys i386
cc := gcc
başka ifsys sun4u
cc := cc
başka ifsys hpux11
CC = c89
endif

Tek yapmanız gereken birkaç program veya kitaplık bulmak veya farklı
yerlerde, daha iyi yollar olabilir (aşağıya bakın).

bul_program, ilk_uygun, dosyayı bul

Bu işlevler, sisteminizdeki çeşitli farklı dizinleri arayabilir.
uygun dosyalar. Bu, elbette, bir yapılandırma komut dosyası kadar güçlü değil, ama buluyorum
kullanışlı. Örneğin, aşağıdakileri yapıyorum:

CXX ;= $(find_program g++ c++ pg++ cxx CC aCC)
# PATH'de bulunan ilk C++ derleyicisini seçin.
# (Bu arada, CXX'i hiç tanımlamazsanız, bu
# tanımlanma şeklidir.)
TCL_INCLUDE ;= -I$(dir_noslash $(findfile tcl.h, \
/usr/local/stow/tcl-8.4.5-nothread/include \
/usr/include/tcl8.4 /usr/include/tcl \
/net/na1/tcl8.4a3/include /net/na1/tcl8.4a3/include))
# $(findfile ) belirtilenlerin her birinde tcl.h'yi arar
# dizin ve tam yolu döndürür. Bu o zaman
# çıkarılarak bir derleme seçeneğine dönüştürülür
# dosya adı (dizinden ayrılırken) ve -I ile önek.
%.o : %.cpp
$(CXX) $(CXXFLAGS) $(TCL_INCLUDE) $(giriş) -o $(çıktı)

TCL_LIB ;= $((ilk_kullanılabilir
/usr/local/stow/tcl-8.4.5-nothread/lib/libtcl8.4.so
/usr/lib/libtcl8.4.so /usr/lib/libtcl.so
/net/na1/tcl8.4a3/lib/libtcl8.4.a
/net/na1/tcl8.4a3/lib/libtcl8.4.sl))
# Tcl kütüphanesinin nerede olduğunu bulun. Bu daha sonra açıkça
# link komutunda listelenir:
programım : *.o
$(CXX) $(CXXFLAGS) $(girdiler) -o $(çıktı) $(TCL_LIB)

Bizi daha iyi tanımak için avantaj of Perl en yapılandırma bilgi

hakkında bazı ek bilgilere ihtiyacınız varsa yukarıdaki teknikler yeterli olmayabilir.
sisteminiz, örneğin uzun bir çiftin var olup olmadığı veya bayt sırasının ne olduğu gibi. Ancak,
Perl bunları zaten hesapladı, yani yanıtlarını kullanabilirsiniz.

Perl'in otomatik yapılandırma betiği, tüm yapılandırma bilgilerini aşağıdakiler aracılığıyla kullanılabilir hale getirir:
%Config karması. Makepp'te bir Perl karma değerine doğrudan erişmek için bir sözdizimi yoktur, ancak şunları yapabilirsiniz:
Perl'e bırakın ve makepp'ten doğrudan erişilebilen skaler değişkenleri ayarlayın:

perl_begin
# Yapılandırma karmasından değerleri getir.
Config'i kullanın;
$CC = $Yapılandırma{'cc'}; # Perl'in kullandığı C derleyicisi;
$byteorder_flags = "-DBYTEORDER=$Config{'byteorder'}";
$longdouble_defined = $Config{'d_longdbl'} eq 'tanımla';
$CFLAGS_for_shared_libs = $Config{'cccdlflags'};
$LDFLAGS_for_shared_libs = $Config{'ccdlflags'};
perl_end

Ayrıca, 'config'i kullan' işlemini yaptıktan sonra, "$(Perl )" ifadesini aşağıdaki gibi kullanabilirsiniz.
bu:

SHARED_LIB_EXTENSION := $(perl $Config{'dlext'})

%Config hash aracılığıyla hangi bilgilerin mevcut olduğunu görmek için "perldoc Config" yazın.

Perl'in yapılandırması, tamsayı türleri, baytlar hakkında bilgi almak için iyi bir yerdir.
sipariş ve genellikle bulmak için ayrı bir yapılandırma komut dosyası gerektiren diğer şeyler. Bazı
dosya sistemindeki şeylerin varlığıyla ilgili bilgileri,
geçerli. Örneğin, $Config{'cc'}, Perl'in oluşturulduğu C derleyicisine atıfta bulunur,
kullanmak istediğiniz aynı C derleyicisi olmayabilir. Aslında, var olmayabilir bile
Perl'i muhtemelen bir ikili paket aracılığıyla kurduğunuz için sisteminizde.

İpuçları için kullanma joker
Uygun herşey Dosyaları dışında a belli alt küme

Makepp'in joker karakterlerinin şu anda tüm dosyaları eşleştirmenin bir yolu yok dışında kesin
ayarlayın, ancak bunu bir işlev kombinasyonu ile yapabilirsiniz.

Örneğin, bir kitaplıktaki her modül için bir test programınız olduğunu, ancak
test programlarını kütüphaneye dahil etmek istiyorum. Tüm test programları ile başlarsa
test, ardından bunları şu şekilde hariç tutabilirsiniz:

libproduction.a: $(filter_out testi*, $(joker karakter *.o))

"$(filter )" ve "$(filter_out )" işlevleri, yapılacak çok güçlü bir dizi filtredir.
her türlü küme kesişim ve fark işlemleri. Örneğin,

SUBDIRS ;= $(filter_out *test* *$(ARCH)*, $(kabuk bulma . -type d -print))
# Sahip olmayan tüm alt dizinleri döndürür
# "test" veya içlerinde $(ARCH).

$(filtre $(patsubst test_dir/test_%.o, %.o, $(wildcard test_dir/*.o)), \
$(joker karakter *.o))
# Geçerli dizindeki .o dosyalarının bir listesini döndürür
# karşılık gelen bir dizin
# test_*.o dosyası test_dir alt dizininde.
$(filter_out $(patsubst man/man3/%.3, %.o, $(wildcard adam/man3/*.3)), \
$(joker karakter *.o))
# Geçerli dizindeki .o dosyalarının bir listesini döndürür
# kılavuz sayfası olmayan dizin
# man/man3 alt dizininde aynı dosya adıyla.

kullanma the "$(only_targets )" işlev için gidermek bayat .o Dosyaları

Bunun gibi bir build komutuyla bir program veya kitaplık oluşturduğunuzu varsayalım:

programı: *.o
$(CC) $(girdiler) -o $(çıktı)

Şimdi bir kaynak dosyayı sildiğinizi varsayalım. İlgili dosyayı silmeyi unutursanız .o dosyası,
daha fazla inşa etmenin bir yolu olmasa da yine de bağlantılı olacaktır. İçinde
gelecekte makepp muhtemelen bu durumu otomatik olarak tanıyacak ve
joker karakter listesi, ancak şu anda manuel olarak hariç tutmasını söylemelisiniz:

program: $(only_targets *.o)
$(CC) $(girdiler) -o $(çıktılar)

Makepp bayatlama yapmanın bir yolunu bilmiyor .o kaynak dosyası olduğundan artık dosya
gitti, bu nedenle "$(only_targets )" işlevi onu bağımlılık listesinden hariç tutacaktır.

İpuçları için çoklu dizinleri
Makepp yazmanın ana nedenlerinden biri, birden çok öğenin işlenmesini basitleştirmekti.
dizinler. Makepp, birden çok makefile'den derleme komutlarını birleştirebilir, böylece
tarafından oluşturulan bir dosyaya bağlı olan bir makefile içindeki bir kuralla düzgün bir şekilde ilgilenin.
farklı makefile

Ne için do in yer of özyineli yapmak

Makepp, geriye dönük uyumluluk için özyinelemeli oluşturmayı destekler, ancak şiddetle tavsiye edilir
O Sen değil onu kullan. Ne olduğunu bilmiyorsan, iyi.

Neden istemediğinize ilişkin ayrıntılar için makepp'deki "Hiyerarşik yapılar için daha iyi sistem" konusuna bakın.
özyinelemeli make kullanın veya web'de "özyinelemeli make zararlı olarak kabul edilir" için arama yapın.

Her makefile'de "all" hedefini yapmak için özyinelemeli bir make yapmak yerine,
makepp'in hangi hedeflerin gerçekten oluşturulması gerektiğini bulmasına izin vermek genellikle daha kolaydır.
Ayrıca, tüm bilgilerinizi koyarsanız .o ve kütüphane dosyaları ile aynı dizinde
makefiles varsa, makepp otomatik olarak hangi makefile'ların da gerekli olduğunu bulur.
gereken tek şey, en üst seviyenizin gerekli dosyaları listelemesidir.
son bağlantı adımı için. Aşağıdaki örneklere bakın.

Bir makefile için her dizin: ile dolaylı olarak yükleme

Birden çok dizini işlemenin en yaygın yolu, her dizine bir makefile koymaktır.
bu, her şeyin o dizinde veya bu dizinden nasıl oluşturulacağını açıklar. Eğer koyarsan .o dosyalar
kaynak dosyalarla aynı dizinde, ardından örtük yükleme (bkz.
makepp_build_algorithm) tüm makefile dosyalarını otomatik olarak bulacaktır. eğer seninkini koyarsan .o
dosyaları farklı bir dizinde (örneğin, mimariye bağlı bir alt dizinde), ardından
muhtemelen "load_makefile" ifadesini kullanarak ilgili tüm makefile dosyalarını yüklemeniz gerekecektir.

Örtük yükleme kullanan bir dizin hiyerarşisi için örnek bir üst düzey makefile burada
birçok paylaşılan kitaplıktan oluşan bir program oluşturmak için (ancak bkz.
kütüphane?" makepp_cookbook'ta, çünkü bir grup paylaşılan kütüphaneden bir program yapmak
mutlaka iyi bir fikir değildir):

# Üst düzey makefile:
program : main.o **/*.la # Tüm alt dizinlerden paylaşılan kitaplıklarda bağlantı.
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(girdiler) -o $(çıktı) $(LIBS)

Üst düzey makefile'de ihtiyacınız olan hemen hemen hepsi bu. Her alt dizinde,
muhtemelen böyle bir şey yapardı:

# Her alt dizinde Makefile:
standard_defs.mk içerir # Aramalar ., .., ../ .., vb. o kadar
# belirtilen içerme dosyasını bulur.
# burada bazı değişken tanımlarını geçersiz kıl
ÖZEL_FLAGS := -do_something_farklı

Hedefleri oluşturmak için komutlar varsa, her makefile muhtemelen hemen hemen aynı olabilir.
oldukça benzerler.

Son olarak, aşağıdakileri standart_defs.mk dosya (muhtemelen
üst düzey dizinde bulunmalıdır):

# Tüm dizinler için ortak değişken ayarları ve oluşturma kuralları.
CFLAGS := -g -O2
INCLUDE_DIR := $(find_upwards içerir)
# Aramalar ., .., ../ .., vb. bir dosya için veya
# dizin içerir, yani koyarsanız
# tüm içerme dosyalarınız orada, bu
# bul onları.
DAHİLDİR := -I$(INCLUDE_DIR)

%.lo : %.c
$(LIBTOOL) --mode=derleme $(CC) $(CFLAGS) $(INCLUDES) -c $(girdi) -o $(çıktı)

lib$(relative_to ., ..).la: $(only_targets *.lo)
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(çıktı) $(girdiler)
# $(relative_to ., ..) geçerli olanın adını döndürür
# üst seviyeye göre alt dizin
# alt dizin. Yani bu makefile xyz/Makefile ise,
# bu kural xyz/libxyz.la'yı oluşturacak.

# Genel içerme dosyalarını en üst düzey içerme dizinine yayınlayın:
$(INCLUDE_DIR)/public_%.h : public_%.h
:build_check symlnk
&ln -fr $(girdi) $(çıktı)

Bir makefile için her dizin: açık yükleme

hepsini koymak istersen .o dosyaları mimariye bağlı bir alt dizine, ardından
yukarıdaki örnek şöyle bir şey olacak şekilde değiştirilmelidir:

# Üst düzey makefile:
MAKEFILES := $(wildcard **/Makeppfile) # Tüm alt dizinlerin listesi
# makefile'leri alın.

load_makefile $(MAKEFILES) # Hepsini yükle.

standard_defs.mk dahil # main.o için derleme komutu alın.

program : $(ARCH)/main.o */**/$(ARCH)/*.la
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(girdiler) -o $(çıktı) $(LIBS)
# */**/$(ARCH) alt dizini hariç tutar
# $(ARCH), inşa etmek istemediğimiz yer
# paylaşılan bir kitaplık.

Her makefile öncekiyle tamamen aynı olacaktır:

# Her alt dizinde Makefile:
standard_defs.mk'yi dahil et
# ... burada değişken geçersiz kılar

Ve nihayet, standart_defs.mk aşağıdaki gibi bir şey içerecektir:

# Tüm dizinler için ortak değişken ayarları ve oluşturma kuralları.
ARCH ;= $(kabuk uname -s)-$(kabuk uname -m)-$(kabuk uname -r)
# Bazen insanlar sadece $(shell uname -m) kullanır, fakat
# bu FreeBSD ve Linux üzerinde aynı olacak
# bir x86. -r, Linux'ta gerçekten kullanışlı değildir,
# ancak diğer işletim sistemleri için önemlidir: için ikili dosyalar
# SunOS 5.8, genellikle SunOS 5.7'de çalışmaz.
&mkdir -p $(ARCH) # Çıktı dizininin var olduğundan emin olun.
CFLAGS := -g -O2
INCLUDE_DIR := $(find_upwards içerir)
# Aramalar ., .., ../ .., vb. bir dosya için veya
# dizin içerir, yani koyarsanız
# tüm içerme dosyalarınız orada, bu
# bul onları.
DAHİLDİR := -I$(INCLUDE_DIR)

$(ARCH)/%.lo : %.c
$(LIBTOOL) --mode=derleme $(CC) $(CFLAGS) $(INCLUDES) -c $(girdi) -o $(çıktı)

$(ARK)/ lib$(relative_to ., ..).la: $(only_targets *.lo)
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(çıktı) $(girdiler)
# $(relative_to ., ..) geçerli olanın adını döndürür
# üst seviyeye göre alt dizin
# alt dizin. Yani bu makefile xyz/Makefile ise,
# bu kural xyz/$(ARCH)/libxyz.la'yı oluşturacak.

# Genel içerme dosyalarını üst düzey içerme dizinine kopyalayın:
$(INCLUDE_DIR)/public_%.h : public_%.h
&cp $(girdi) $(çıktı)

Otomatik olarak yapma the Makefile'lar

Makefile dosyalarınız birbirine çok benziyorsa (yukarıdaki örnekte olduğu gibi), Makepp'e şunu söyleyebilirsiniz:
yoksa bunları otomatik olarak oluşturmak için. Aşağıdakileri üst seviyenize eklemeniz yeterli
makefile:

SUBDIRS := $(filter_out istenmeyen_dir1 istenmeyen_dir2, $(joker karakter */**))
$(foreach)/Makeppfile: : foreach $(SUBDIRS)
&echo "standart_defs.mk dahil" -o $(çıktı)
&echo "_include ek_defs.mk" -o >>$(çıktı)
# Ek_defs.mk dosyası varsa, o zaman
# dahil edilecek, ancak mevcut değilse,
# _include ifadesi yoksayılacak.

Artık makefile dosyaları otomatik olarak oluşturulacak.

Bir makefile bir tek at the üst seviye

Tüm makefile dosyalarınız aynıysa, şunu sorabilirsiniz: neden her birinde bir makefile olmalı?
seviye? Neden hepsini en üst düzey makefile'e koymuyorsunuz?

Evet, bu yapılabilir. Başlıca dezavantajı, belirlemenin zorlaşmasıdır.
her alt dizin için farklı yapı seçenekleri. İkinci bir dezavantaj, sizin
makefile muhtemelen okunması biraz zorlaşacaktır.

İşte tam da bunu yapmanın bir örneği:

# Dizin hiyerarşisi için üst düzey makefile. Programı oluşturur
# örnek olarak bir dizi paylaşılan kitaplıktan. (Yukarıdaki uyarılara bakın
# neden artımlı bağlantı veya başka bir şey kullanmak isteyebileceğinize dair
# paylaşılan kitaplıklar yerine yaklaşım.)
makepp_percent_subdirs := 1 # %'nin birden çok dizinle eşleşmesine izin verin.
SUBDIRS := $(filter_out *CVS* other-unwanted_dirs $(joker karakter **))
CFLAGS := -g -O2
DAHİLDİR := -İçerir

%.lo: %.c
$(LIBTOOL) --mode=derleme $(CC) $(INCLUDES) $(CFLAGS) -c $(girdi) -o $(çıktı)

$(her biri için)/ lib$(notdir $(foreach))).la: $(foreach)/*.lo : foreach $(SUBDIRS)
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(çıktı) $(girdiler)
# Tüm kütüphaneleri yapma kuralı.

program : main.o **/*.la
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(çıktı) $(girdiler)

içerir/$(notdir $(foreach)) : $(foreach) : foreach **/public_*.h
&cp $(girdi) $(çıktı)
# Genel olarak kopyalamak için örnek kural
# erişilebilir .h dosyaları doğru yere.

A çamça hedef

Geleneksel makefile'ler temiz bir hedef içerir, bu da eski olan her şeyi kaldırmaya izin verir.
inşa edilmiş. Bunu makepp ile yapmamanız için üç neden var:

1. Makepp, doğru bir yapı sağlamak için büyük çaba harcıyor. Yani çaresiz "Yapmıyorum
Neyin yanlış olduğunu biliyorum", sıfırdan başlamak istemeniz geçmişte kaldı.

2. İnsanlar bazen iki çelişkili şeyi aynı anda yaparak zamandan tasarruf etmeye çalışacaklardır:
"hepsini temizle". Bu, makepp'in akıllı joker karakter sistemini karıştırabilir, çünkü
bir şey yapmadan önce gerçekleri öğren. Sonra temiz eylem gelir, ki bu
makepp'e ne yaptığını söyleme (aslında yapamaz, çünkü bir şeyi geri alır --
bir yapı aracının ne için olduğunun aksine). Sonra "hepsi" gelir, ancak güncel dosyalar,
hangi orada, gizemli bir şekilde gitti.

3. Aynı şeyi daha verimli yapan "makeppclean" komutu var.

Bununla birlikte, bu tarihsel bölümü koruyoruz, çünkü size tarihi hakkında bir şeyler anlatıyor.
makepp'in çalışma şekli: "Temiz" adlı sahte bir hedef, yalnızca bir dizi komutun adıdır.
make işleminden kaynaklanan tüm dosyaları kaldırın. Genellikle temiz bir hedef görünür
böyle bir şey:

$(sahte temizlik):
&rm -fm $(joker karakter *.o .makepp_log)
# -m ve .makepp_log makepp'in tüm gereksizlerinden kurtulur.

Silmek istediğiniz dosyaları açıkça listelemek yerine makepp'e şunu da söyleyebilirsiniz.
nasıl inşa edileceğini bildiği her şeyi kaldırın, şöyle:

$(sahte temizlik):
&rm -fm .makepp_log $(only_targets *)

Bunun avantajı, kaynak dosyalarınızdan herhangi birinin diğer dosyalardan oluşturulabilmesi durumunda,
onlar da silinecek; öte yandan bayat .o dosyalar (eskiden dosyalar
oluşturulabilir ancak kaynak dosyası o zamandan beri kaldırılmış olan) silinmeyecektir.

Birkaç farklı dizinde makefile içeren bir yapınız varsa,
level makefile, "temiz" hedefe (veya başka herhangi bir sahte hedefe) farklı bir şekilde başvurabilir.
makefile:

# Üst düzey makefile
SUBDIRS := alt1 alt2

# burada kurallar oluşturun

# Derlemeden sonra temizleyin:
$(sahte temizlik): $(SUBDIRS)/temiz
&rm -fm .makepp_log $(only_targets *)

Alternatif olarak, "temiz" hedefinizi yalnızca üst düzey makefile'e koyabilir ve sahip olabilirsiniz.
tüm dizinleri şu şekilde işleyin:

$(sahte temizlik):
&rm -fm $(only_targets **/*)

kullanma Qt'ler güç önişlemci
Bu örnek, Nokia'nın Qt GUI kitaplığını kullanan bir yardımcı program için bir makefile gösterir (bkz.
<http://qt.nokia.com>). Bu konuda biraz sıra dışı olan tek şey, siz
widget tanımları içeren çoğu ".h" dosyasında "moc" adlı bir önişlemci çalıştırmalıdır,
ancak "Q_OBJECT" makrosunu kullanmayan herhangi bir ".h" dosyasında "moc" çalıştırmak istemezsiniz.

Otomatik olarak belirlenmesi hangi Dosyaları gerek güç Dosyaları

Elbette, üzerlerinde "moc" çalıştırılması gereken tüm ".h" dosyalarını listeleyebilirsiniz.
Bununla birlikte, hızla yeni widget'lar geliştiriyorsanız, bu biraz can sıkıcı olabilir.
makefile'deki listeyi güncellemeye devam edin. Moc'u listeleme ihtiyacının üstesinden gelebilirsin
modüller açıkça bunun gibi bir şeyle:

MOC := $(QTDIR)/bin/moc
MODÜLLER := programınızda bulunan modüller ne olursa olsun
MOC_MODULES := $(patsubst %.h, moc_%, $(&grep -l /Q_OBJECT/ *.h))
# Q_OBJECT makrosu için tüm .h dosyalarını tarar.

programım: $(MODULES).o $(MOC_MODULES).o
$(CXX) $(girdiler) -o $(çıktı)

moc_%.cxx: %.h # .h dosyalarından moc dosyalarını yapar.
$(MOC) $(girdi) -o $(çıktı)

%.o: %.cxx
$(CXX) $(CXXFLAGS) -c $(girdi) -o $(çıktı)

Bu yaklaşım, her bir dosyanızı tarar. .h makepp her çalıştırıldığında dosyalar
"Q_OBJECT" makrosu. Bu pahalı geliyor, ancak muhtemelen hiç uzun sürmeyecek. ( .h
dosyaların tümünün derleme işlemiyle yine de diskten yüklenmesi gerekecek, bu yüzden
önbelleğe alınır.)

#Dahil etmek the .moc dosya

Başka bir yaklaşım, widget'ınızdaki "moc" ön işlemcisinden gelen çıktıyı "#include" etmektir.
uygulama dosyası Bu, "#include" yazmayı hatırlamanız gerektiği anlamına gelir, ancak
derlenecek daha az modül olması ve dolayısıyla derlemenin daha hızlı olması avantajı.
(Çoğu C++ derlemesi için, zamanın çoğu başlık dosyalarını okumakla geçer ve
önişlemciden gelen çıktının, neredeyse widget'ınız kadar dosya içermesi gerekir
neyse.) Örneğin:

// benim_widget'ım.h
class MyWidget : genel QWidget {
Q_OBJECT
/ / ...
}

// benim_widget.cpp

#include "my_widget.h"
#include "my_widget.moc" // my_widget.moc,
// moc önişlemcisi.
// Diğer uygulama işleri burada.
MyWidget::MyWidget(QWidget * ebeveyn, const char * isim) :
QWidget(ebeveyn, isim)
{
/ / ...
}

Şimdi, tüm ".moc" dosyalarını yapmak için makefile'nizde aşağıdaki gibi bir kurala ihtiyacınız var:

MOC := $(QTDIR)/bin/moc
# .moc dosyaları oluşturma kuralı:
%.moc: %.h
$(MOC) $(girdi) -o $(çıktı)

Makepp, olmazsa "my_widget.moc" yapması gerektiğini anlayacak kadar akıllıdır.
zaten mevcutsa veya güncel değilse.

Bu ikinci yaklaşım, derlemeyi hızlandırdığı için genellikle kullandığım yaklaşımdır.

Yedek için önerilmiyor yapmak deyimler
MAKECMDHEDEFLER

Bazen insanların makefile'lerinde hangi hedefi oluşturduklarına bağlı olarak kurallar vardır.
"MAKECMDGOALS" özel değişkenini kullanarak. Örneğin, bazen şöyle şeyler görür:
bu:

ifneq ($(filtre üretimi, $(MAKECMDGOALS)))
FLAGLAR := -O2
başka
FLAGLAR := -g
endif

Bu makepp ile iyi çalışacaktır. Ancak bunun için "MAKECMDGOALS" kullanmamanızı tavsiye ederim.
durumlar (ve GNU da el kitabı yapar). Optimize edilmiş halinizi koymaktan daha iyisiniz ve
hata ayıklamayla derlenmiş .o dosyaları ayrı dizinlerde tutmak veya onlara farklı önekler vermek veya
son ekler veya bunları ayrı tutmak için depoları kullanma.

Muhtemelen "MAKECMDGOALS" a başvurmak isteyebileceğiniz tek zaman,
makefile dosyalarınızı yüklemek uzun zaman alıyor ve "temiz" hedefiniz için buna ihtiyacınız yok
(ama temiz bir hedefe ihtiyacınız yok). Örneğin,

ifneq ($(MAKECMDGOALS),temiz)
load_makefile $(joker karakter **/Makeppfile)
başka
no_implicit_load . # Diğer makefile dosyalarının otomatik yüklenmesini engelle.
endif

$(sahte temizlik):
&rm -f $(joker karakter **/*.o)

Recursive yapmak için inşa etmek in farklı dizinleri

makepp_cookbook'ta "Birden çok dizin için ipuçları" konusuna bakın.

Recursive yapmak için değişiklik değer of a değişken

Bazı makefile'ler kendilerini farklı bir değişken değeriyle yeniden çağırır, örneğin hata ayıklama
aşağıdaki makefile parçasında hedef

.PHONY: tüm hata ayıklama

optimize edilmiş:
$(MAKE) programı CFLAGS=-O2

hata ayıklama:
$(MAKE) programı CFLAGS=-g

program: ao bo
$(CC) $(CFLAGS) $^ -o $@

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

Kullanıcı "make debug" yazarsa, programı hata ayıklama etkinken varsayılan modda oluşturur.
optimizasyon yerine.

Bunu yapmanın daha iyi bir yolu, iki farklı program seti ile iki farklı program oluşturmaktır.
nesne dosyaları, bunun gibi:

FLAGLAR := -O2
HATA AYIKLAMA_BAYRAKLARI := -g
MODÜLLER := ab

program: $(MODÜLLER).o
$(CC) $(CFLAGS) $(girdiler) -o $(çıktı)

hata ayıklama/program: hata ayıklama/$(MODULES).o
$(CC) $(DEBUG_FLAGS) $(girdiler) -o $(çıktı)

%.o : %.c
$(CC) $(CFLAGS) -c $(girdi) -o $(çıktı)

hata ayıklama/%.o : %.c
$(CC) $(DEBUG_FLAGS) -c $(girdi) -o $(çıktı)

$(sahte hata ayıklama): hata ayıklama/program

Bunu bu şekilde yapmanın avantajı şudur: (a)
hata ayıklamadan optimize edilmiş duruma ve tekrar geri dönün; (B)

Yukarıdakiler, depolar kullanılarak biraz daha özlü yazılabilir. Devamındaki
makefile tam olarak eşdeğerdir:

depo hata ayıklama=. # Hata ayıklama alt dizininin bir kopyası gibi görünmesini sağlar
# geçerli alt dizin.
load_makefile hata ayıklama CFLAGS=-g
# Hata ayıklama alt dizininde çağrıldığında CFLAGS'ı geçersiz kıl
CFLAGS := -O2 # Bu alt dizinde çağrıldığında CFLAGS'ın değeri

program: ao bo
$(CC) $(CFLAGS) $^ -o $@

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

$(sahte hata ayıklama): hata ayıklama/program
# Kullanıcı "makepp debug" yazarsa, derler
# program yerine hata ayıklama/program.

Diğer ipuçları
Ne kadar do I inşa etmek bir Bölüm farklı olarak sadece bir Zamanlar?

Makepp bunu yapmayı zorlaştırıyor çünkü sonuç kurallar açısından tutarsız.
Ancak buna ihtiyaç duyabileceğiniz durumlar vardır, örneğin sadece bir modül ile derlemek için.
ağır hata ayıklama bilgileri. Bunu, önce aşağıdakileri oluşturarak iki adımda başarabilirsiniz:
bağımlılığı ayrı ayrı ve ardından bağlantı aşamasından hariç tutma:

makepp DEBUG=3 buggy.o # Diğer seçenekle oluşturun.
makepp --dont-build=buggy.o buggy # "Yanlış" derleme seçeneğine rağmen kullanın.

Ne kadar do I yapmak elbette my çıktı dizinleri var olmak?

Çıktı dizini oluşturmak için bir kural belirleyebilir, ardından her dosyanın
çıktı dizinine gider, buna bağlıdır. Ama genellikle böyle bir şey yapmak daha kolaydır
bu:

# Klasik yol
kukla := $(kabuk testi -d $(OUTPUT_DIRECTORY) || mkdir -p $(OUTPUT_DIRECTORY))
# Bu genellikle tüm dosyaları bağımlı kılmaktan daha kolaydır.
# $(OUTPUT_DIRECTORY) ve bunu yapmak için bir kuralın olması.
# Zorlamak için = yerine := kullanmanız gerektiğini unutmayın.
#hemen yürütün.
# Alternatif bir yaklaşım: Perl kodunu kullanarak, OUTPUT_DIRECTORY local var
perl_begin
-d $OUTPUT_DIRECTORY veya mkdir $OUTPUT_DIRECTORY;
perl_end
# Modern yol, mevcut dizinler için hiçbir şey yapmaz
&mkdir -p $(OUTPUT_DIRECTORY)

Bu ifadelerden biri makefile dosyanızın en üstüne yakın olmalıdır, bu nedenle yürütülürler.
dizine ihtiyaç duyabilecek herhangi bir şeyden önce.

Ne kadar do I anabolik etkileri de mevcuttur a komuta için yürütmek on her yapı?

En kolay yol, kural mekanizmasını hiç kullanmak değil, basitçe yürütmektir.
bu:

kukla := $(kabuk tarihi > last_build_timestamp)

Veya şöyle bir Perl bloğuna koyun:

perl_begin
system("yürütülecek komut");
perl_end

Bu yaklaşımın dezavantajı, alakasız bir hedef olsa bile yürütülecek olmasıdır.
çalıştırılıyor.

İkinci bir yaklaşım, dosyayı gerçek bir dosya olsa bile sahte hedef olarak ilan etmektir.
Bu, makepp'i her seferinde onu oluşturmak için komutu yeniden yürütmeye zorlar, ancak yalnızca
bazı kuralların bağımlılık listesinde görünür.

Ne kadar do I kısaltmak the görüntülenen inşa etmek komutlar?

Genellikle derleme komutları için o kadar çok seçenek vardır ki, ekranda görüntülenenler
ekran okunamıyor. görüntülenmesini engelleyerek görüntülenenleri değiştirebilirsiniz.
komutun tamamını ve ardından komutun ilginç kısmını açıkça yazdırın. Onun
"$(filter_out )" kullanarak komutun yalnızca ilgili bölümünü yazdırmak kolaydır, örneğin
bu:

ALL_CFLAGS = $(CFLAGS) $(DAHİL) $(ADDL_CXX_FLAGS) $(DEBUG_FLAGS)

%.o : %.c
@&echo $(notdir $(CC)) ... \
$(filter_out -I* $(ADDL_CXX_FLAGS), $(ALL_CFLAGS)) \
-c $(girdi)
@$(CC) $(ALL_CFLAGS) -c $(girdi) -o $(çıktı)

(Komutun önündeki "@", komutun yazdırılmasını engeller.)

Bu, ilginç seçeneklerin çoğunu görmenizi sağlar ancak tüm seçenekleri görüntülemez.
dizinleri içerir (ki çoğu zaman çoktur!). ilgilendiğiniz kısım ise
Komutunuzda bitişik ise, "yazdır" işlevini de kullanabilirsiniz (bu,
newline, bu yüzden birkaçını istemiyorsunuz):

hedef:
@... $(ilginç kısmı yazdır) ...

Ne kadar do I dönüştürmek a dosya içine bağımlılıklar?

Bazı belirsiz dosya biçimleri için bir tarayıcı uygulamaya değmez. Bir projede
xml dosyamız var, diyelim foobar.xml için bağımlılıkları içeren foobar.out:


a
B
C


Bu basit düzene bağlı kalmaya karar verdik, bu yüzden xml'yi ayrıştırmamıza gerek yok. İle
Yerleşik &sed, üç tür için üç basit ikame ile yaptığımız şey:
hatları:

%.d: %.xml
&sed'ler! !$(stem).out: \\! || s! (.+) !$$1 \\! || s! !# Boş!' \
$(girdi) -o $(çıktı)

foobar.d'yi dahil et

Bunu dahil etmeye çalışmak, önce "foobar.d" dosyasını üretir:

foobar.out: \
A \
B \
C \
# Boş

Boş (sadece bir yorum veya gerçekten boş) satır, sondaki hakkında endişelenmenize gerek kalmaz
ters eğik çizgi. Çok satırlı bir liste üreten bir alternatif:

%.d: %.xml
&sed'ler! !$(stem).out: \$$((! || s! !))! || s!<.+?>!!g' \
$(girdi) -o $(çıktı)

foobar.d'yi dahil et

Bu bir eşdeğer üretir:

foobar.out: $((
a
b
c
))

Yapmanız gereken daha karmaşık bir yeniden yazma işleminiz varsa, makefile içinde veya bir
dahil ettiğiniz modül. Örneğin, $_ tanımını kaldırmak, giriş satırlarını atlayacaktır:

alt filtrem {
/ if undef $_ döndür
benim $stem = f_stem;
s! !$stem.out: \$((! || s! !))! || s!<.+?>!!g;
}

%.d: %.xml
&sed'ler! !$(stem).out: \$$((! || s! !))! || s!<.+?>!!g' \
$(girdi) -o $(çıktı)

foobar.d'yi dahil et

onworks.net hizmetlerini kullanarak makepp_cookbook'u çevrimiçi kullanın


Ücretsiz Sunucular ve İş İstasyonları

Windows ve Linux uygulamalarını indirin

Linux komutları

Ad