BASİT C ++ Makefile nasıl yapılır


303

Projemiz için her şeyi bir araya getirmek için bir Makefile kullanmamız gerekiyor, ancak profesörümüz bize nasıl yapılacağını asla göstermedi.

Sadece var bir tane , dosyayı a3driver.cpp. Sürücü bir yerden bir sınıf alır "/user/cse232/Examples/example32.sequence.cpp".

Bu kadar. Diğer her şey .cpp.

Adlı bir yürütülebilir dosya oluşturan basit bir Makefile yapmaya nasıl devam edebilirim a3a.exe?


9
.EXE kesinlikle Windows. İkinci düşüncede ... yol Unix tarzı. Muhtemelen Mingw-32 kullanıyor.
Nathan Osman

2
İç çekmek. Sanırım hiç kullanmasanız bile her ticaretin temellerini öğrenmek zorundasınız. Sadece işlerin nasıl çalıştığını anlamalısınız. Bununla birlikte, Eclipse gibi her zaman bir IDE'de gelişme şansınız yüksektir. Basit tek satırlık durumunuz için bir cevap alacaksınız ve çok sayıda web öğreticisi var, ancak dpth bilgisini istiyorsanız, O'reilly kitabını yenemezsiniz (çoğu s / w konusu için aynıdır). amazon.com/Managing-Projects-Make-Nutshell-Handbooks/dp/... amazon, half.com bir 2. el kopyasını al, eBay betterworldbooks
Mawg yeniden aktifleştirme Monica diyor

2
@Dennis tarafından gönderilen bağlantı artık öldü, ancak aynı materyal bu archive.org sayfasında bulunabilir .
Guilherme Salomé

Bu kişinin fikirlerini tercih ederim. ( hiltmon.com/blog/2013/07/03/… ) Proje yapısı kolayca uyacak şekilde değiştirilebilir. Ayrıca geliştirici zamanının automake / autoconf dışında başka şeylere harcanması gerektiğini de kabul ediyorum. Bu araçların yeri var, ama belki de iç projeler için değil. Böyle bir proje yapısı üretecek bir senaryo hazırlıyorum.
Daisuke Aramaki

@ GuilhermeSalomé Teşekkürler, bunun en basit ve eksiksiz öğretici olduğuna inanıyorum.
Hareen Laks

Yanıtlar:


560

Bu Unix için olduğundan, yürütülebilir dosyaların herhangi bir uzantısı yoktur.

Dikkat edilmesi gereken bir şey root-config, doğru derleme ve bağlantı bayraklarını sağlayan bir yardımcı programdır; ve root'a karşı uygulamalar oluşturmak için doğru kütüphaneler. Bu, yalnızca bu dokümanın orijinal kitlesi ile ilgili bir ayrıntı.

Beni bebeğim yap

ya da İlk Yaptığın Asla Unutmazsın

Make ve basit bir makefile yazma hakkında giriş

Marka Nedir? Neden Önemsemeliyim?

Make adlı araç derleme bağımlılığı yöneticisidir. Yani, yazılım projenizi kaynak dosyalar, nesne dosyaları, kütüphaneler, başlıklar vb. Bir koleksiyondan hangi sırayla almak için hangi komutların yürütülmesi gerektiğini bilmekle ilgilenir. - bazıları değişmiş olabilir Son zamanlarda --- ve programın doğru bir güncel sürümüne dönüştürmek.

Aslında, Make'ı başka şeyler için de kullanabilirsiniz, ama bunun hakkında konuşmayacağım.

Önemsiz Makefile

: Eğer içeren bir dizin olduğunu varsayalım tool tool.cc tool.o support.cc support.hhve support.ohangi bağlıdır rootve adı verilen bir programa derlenmiş gerekiyordu toolve siz (mevcut demektir kaynak dosyaları üzerinde hack ettik varsayalım toolartık güncel olan) ve istediğiniz programı derleyin.

Bunu kendiniz yapmak için

  1. Bunlardan birini support.ccveya support.hhdaha yeni olup olmadığını kontrol edin support.ove eğer böyle bir komut çalıştırın

    g++ -g -c -pthread -I/sw/include/root support.cc
  2. Bunlardan birini support.hhveya tool.ccdaha yeni olup olmadığını kontrol edin tool.ove eğer böyle bir komut çalıştırın

    g++ -g  -c -pthread -I/sw/include/root tool.cc
  3. Bundan tool.odaha yeni olup olmadığını kontrol edin toolve eğer böyle bir komut çalıştırın

    g++ -g tool.o support.o -L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
    -lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz -Wl,-framework,CoreServices \
    -Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root -lm -ldl

Uf! Ne kadar zor! Hatırlanması gereken çok şey var ve hata yapma şansı var. (BTW-- burada gösterilen komut satırlarının ayrıntıları yazılım ortamımıza bağlıdır. Bunlar bilgisayarımda çalışır.)

Elbette, her seferinde üç komutu da çalıştırabilirsiniz. Bu işe yarar, ancak önemli bir yazılım parçasına iyi ölçeklenmez (MacBook'umda sıfırdan derlemek 15 dakikadan fazla süren DOGS gibi).

Bunun yerine şöyle bir dosya yazabilirsiniz makefile:

tool: tool.o support.o
    g++ -g -o tool tool.o support.o -L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
        -lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz -Wl,-framework,CoreServices \
        -Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root -lm -ldl

tool.o: tool.cc support.hh
    g++ -g  -c -pthread -I/sw/include/root tool.cc

support.o: support.hh support.cc
    g++ -g -c -pthread -I/sw/include/root support.cc

ve makekomut satırına yazmanız yeterlidir. Hangi yukarıda gösterilen üç adım otomatik olarak gerçekleştirecektir.

Buradaki girintisiz satırlar "target: bağımlılıklar" biçimine sahiptir ve bağımlılıklardan herhangi biri hedeften daha yeniyse ilişkili komutların (girintili satırlar) çalıştırılmasını sağlayın . Yani bağımlılık satırları, çeşitli dosyalarda değişikliklere uyum sağlamak için nelerin yeniden oluşturulması gerektiğinin mantığını tanımlar. support.ccDeğişiklik varsa bu support.oyeniden inşa edilmelidir, ancak tool.oyalnız bırakılabilir. Ne zaman support.odeğişiklikler toolyeniden inşa edilmelidir.

Her bağımlılık satırıyla ilişkili komutlar bir sekme ile ayarlanır (aşağıya bakın) hedefi değiştirmelidir (veya en azından değişiklik süresini güncellemek için ona dokunmalıdır).

Değişkenler, Yerleşik Kurallar ve Diğer Hediyeler

Bu noktada, makefile'ımız basitçe yapılması gereken işi hatırlamaktır, ancak yine de ihtiyaç duyulan her bir komutu tümüyle bulmamız ve yazmamız gerekiyordu. Bu şekilde olmak zorunda değil: Make, değişkenler, metin düzenleme işlevleri ve bunu bizim için çok daha kolaylaştırabilecek bir dizi yerleşik kural içeren güçlü bir dildir.

Değişken Yap

Bir make değişkenine erişim sözdizimi $(VAR).

Bir Make değişkenine atama sözdizimi: VAR = A text value of some kind (veya VAR := A different text value but ignore this for the moment).

Değişkenlerimizi, makefile'ımızın bu geliştirilmiş sürümü gibi kullanabilirsiniz:

CPPFLAGS=-g -pthread -I/sw/include/root
LDFLAGS=-g
LDLIBS=-L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
       -lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz \
       -Wl,-framework,CoreServices -Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root \
       -lm -ldl

tool: tool.o support.o
    g++ $(LDFLAGS) -o tool tool.o support.o $(LDLIBS)

tool.o: tool.cc support.hh
    g++ $(CPPFLAGS) -c tool.cc

support.o: support.hh support.cc
    g++ $(CPPFLAGS) -c support.cc

Bu biraz daha okunabilir, ancak yine de çok fazla yazmayı gerektirir

İşlev Yap

GNU make, dosya sisteminden veya sistemdeki diğer komutlardan bilgiye erişmek için çeşitli işlevleri destekler. Bu durumda biz ilgilenen edilir $(shell ...)argüman (lar) ın çıkışına genişler ki, ve $(subst opat,npat,text)tüm örneklerini değiştirir hangi opatile npatmetinde.

Bundan faydalanmak bize:

CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)

SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))

tool: $(OBJS)
    g++ $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)

tool.o: tool.cc support.hh
    g++ $(CPPFLAGS) -c tool.cc

support.o: support.hh support.cc
    g++ $(CPPFLAGS) -c support.cc

yazması daha kolay ve daha okunabilir.

Dikkat edin

  1. Her nesne dosyası ve son yürütülebilir dosya için bağımlılıkları açıkça belirtiyoruz
  2. Her iki kaynak dosya için de derleme kuralını açıkça yazmak zorunda kaldık

Örtük ve Örüntü Kuralları

Genellikle tüm C ++ kaynak dosyalarının aynı şekilde ele alınmasını bekleriz ve Make bunu belirtmek için üç yol sağlar:

  1. sonek kuralları (GNU markasında kullanılmayan kabul edilir, ancak geriye dönük uyumluluk için saklanır)
  2. örtük kurallar
  3. kalıp kuralları

Örtük kurallar yerleşiktir ve bunlardan birkaçı aşağıda ele alınacaktır. Desen kuralları aşağıdaki gibi belirtilir

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

yani, "otomatik" değişken $<ilk bağımlılığın adına genişlediğinde , komut dosyaları gösterilen komut çalıştırılarak C kaynak dosyalarından oluşturulur .

Yerleşik Kurallar

Make, bir projenin çok basit bir makefile tarafından derlenebileceği anlamına gelen bir dizi yerleşik kurala sahiptir.

C kaynak dosyaları için yerleşik GNU markası, yukarıda gösterilen dosyadır. Benzer şekilde, C ++ kaynak dosyalarından bir kurala sahip nesne dosyaları oluştururuz $(CXX) -c $(CPPFLAGS) $(CFLAGS).

Tek nesne dosyaları kullanılarak bağlanır $(LD) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS), ancak bizim durumumuzda çalışmaz, çünkü birden fazla nesne dosyasını bağlamak istiyoruz.

Yerleşik Kurallar Tarafından Kullanılan Değişkenler

Yerleşik kurallar, tüm kuralları yeniden yazmadan yerel ortam bilgilerini (ROOT dosyalarının nerede bulunacağı gibi) belirtmenize izin veren bir dizi standart değişken kullanır. Bizim için ilginç olma olasılığı en yüksek olanlar:

  • CC - kullanılacak C derleyicisi
  • CXX - kullanılacak C ++ derleyicisi
  • LD - kullanılacak bağlayıcı
  • CFLAGS - C kaynak dosyaları için derleme bayrağı
  • CXXFLAGS - C ++ kaynak dosyaları için derleme bayrakları
  • CPPFLAGS - C ve C ++ tarafından kullanılan c-önişlemcisinin bayrakları (genellikle komut satırında tanımlanan dosya yollarını ve sembolleri içerir)
  • LDFLAGS - bağlayıcı bayrakları
  • LDLIBS - bağlanacak kütüphaneler

Temel Makefile

Yerleşik kurallardan yararlanarak, makefile'ımızı aşağıdakileri basitleştirebiliriz:

CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)

SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))

all: tool

tool: $(OBJS)
    $(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)

tool.o: tool.cc support.hh

support.o: support.hh support.cc

clean:
    $(RM) $(OBJS)

distclean: clean
    $(RM) tool

Ayrıca, özel eylemleri gerçekleştiren birkaç standart hedef ekledik (kaynak dizini temizlemek gibi).

Make argümanı olmadan çağrıldığında, dosyada bulunan ilk hedefi (bu durumda tümü) kullandığını, ancak make cleanbu durumda nesne dosyalarını kaldırmayı sağlayan hedefi de adlandırabileceğinizi unutmayın .

Hala bağımlılıkları kodlanmış.

Bazı Gizemli Gelişmeler

CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)

SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))

all: tool

tool: $(OBJS)
    $(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)

depend: .depend

.depend: $(SRCS)
    $(RM) ./.depend
    $(CXX) $(CPPFLAGS) -MM $^>>./.depend;

clean:
    $(RM) $(OBJS)

distclean: clean
    $(RM) *~ .depend

include .depend

Dikkat edin

  1. Artık kaynak dosyalar için bağımlılık satırları yok!?!
  2. .Depend ve depends ile ilgili garip bir sihir var
  3. Bunu yaparsanız makeo zaman ls -Asize adlı bir dosya göreceksiniz .dependyapmak bağımlılık hatları gibi bakmak şeyleri içerir

Diğer Okumalar

Hataları ve Tarihsel Notları Tanıyın

Make için giriş dili boşluklara duyarlıdır. Özellikle, bağımlılıkları izleyen eylem çizgileri bir sekme ile başlamalıdır . Ancak bir dizi boşluk aynı görünebilir (ve sekmeleri sessizce boşluklara dönüştürecek veya tam tersi olan editörler vardır), bu da doğru görünen ve hala çalışmayan bir Make dosyasıyla sonuçlanır. Bu, erken bir hata olarak tanımlandı, ancak ( hikaye gidiyor ) düzeltilmedi, çünkü zaten 10 kullanıcı vardı.

(Bu, fizik lisansüstü öğrencileri için yazdığım bir wiki yayınından kopyalandı.)


9
Bağımlılık yaratmanın bu yöntemi eski ve aslında zararlıdır. Bkz. Gelişmiş Otomatik Bağımlılık Üretimi .
Maxim Egorushkin

5
-pthreadbayrak gccgerekli makroları tanımlamaya neden olur -D_REENTRANT, gereksizdir.
Maxim Egorushkin

8
@jcoe Bağımlılıklar oluşturmak için gereksiz bir ekstra önişlemci geçişi yapar. Gereksiz işler yapmak, sadece buz kutuplarını eriten ısıyı dağıtır ve daha büyük ölçekte, evrenimizin ısı ölümüne yaklaşmaktadır.
Maxim Egorushkin

2
Muhtemelen "zararlı" biraz fazladır, ancak açık bağımlılık üretme aşamalarının veya hedeflerinin modası geçmiş olduğu göz önüne alındığında, en azından GCC 3'te, gerçekten hepimizin onları geçmesi gerektiğini düşünüyorum. bruno.defraine.net/techtips/makefile-auto-dependencies-with-gcc/...
hmijail Yasta resignees

2
Gerçekten, kabul edilen cevap çok özel bir yazılıma ( root-config) bağlı olmamalıdır . Aynı kapasiteye sahip daha genel bir alternatif varsa ya da dışarıda bırakılmalıdır. En sık kullanılan markaların listesi ve açıklaması nedeniyle düşüş yapmadım.
yeşil diod

56

Bunun ayrıntılı bir örnekle öğrenmenin daha kolay olduğunu her zaman düşündüm, bu yüzden makefiles'i düşünüyorum. Her bölüm için girintili olmayan bir satır vardır ve bölümün adını ve ardından bağımlılıkları gösterir. Bağımlılıklar ya diğer bölümler (geçerli bölümden önce çalıştırılacak) ya da dosyalar (güncelleştirilirse bir sonraki çalıştırmanızda geçerli bölümün tekrar çalıştırılmasına neden olur make) olabilir.

İşte hızlı bir örnek (bir sekme kullanmam gereken 4 boşluk kullandığımı unutmayın, Stack Overflow sekmeleri kullanmama izin vermiyor):

a3driver: a3driver.o
    g++ -o a3driver a3driver.o

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

Yazdığınızda make, ilk bölümü seçecektir (a3driver). a3driver a3driver.o'ya bağlıdır, bu yüzden o bölüme gidecektir. a3driver.o a3driver.cpp dosyasına bağlıdır, bu nedenle yalnızca son çalıştırılmasından bu yana a3driver.cpp değiştiyse çalışır. A3driver.cpp dosyasının bir .o dosyasına derlendiğini (veya hiç çalıştırılmadığını) varsayarsak, a3driver'a geri dönecek ve son yürütülebilir dosyayı derleyecektir.

Yalnızca bir dosya olduğundan, aşağıdakilere indirgenebilir:

a3driver: a3driver.cpp
    g++ -o a3driver a3driver.cpp

İlk örneği göstermemizin nedeni, markaların gücünü göstermesidir. Başka bir dosya derlemeniz gerekiyorsa, başka bir bölüm ekleyebilirsiniz. Burada, secondFile.cpp (secondFile.h adlı bir üstbilgiye yüklenen) içeren bir örnek verilmiştir:

a3driver: a3driver.o secondFile.o
    g++ -o a3driver a3driver.o secondFile.o

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

secondFile.o: secondFile.cpp secondFile.h
    g++ -c secondFile.cpp

Bu şekilde secondFile.cpp veya secondFile.h dosyasında bir şeyi değiştirir ve yeniden derlerseniz, yalnızca secondFile.cpp (a3driver.cpp değil) yeniden derlenir. Alternatif olarak, a3driver.cpp dosyasında bir şeyi değiştirirseniz, secondFile.cpp dosyasını yeniden derlemez.

Bu konuda herhangi bir sorunuz olursa bize bildirin.

"All" adlı bir bölümü ve "clean" adlı bir bölümü eklemek de gelenekseldir. "tümü" genellikle tüm yürütülebilir dosyaları oluşturur ve "temiz", .o dosyaları ve yürütülebilir dosyalar gibi "yapı yapılarını" kaldırır:

all: a3driver ;

clean:
    # -f so this will succeed even if the files don't exist
    rm -f a3driver a3driver.o

EDIT: Windows'da olduğunuzu fark etmedim. Ben tek fark değişiyor düşünüyorum -o a3driveriçin -o a3driver.exe.


Kullanmaya çalıştığım mutlak kod: p4a.exe: p4driver.cpp g ++ -o p4a p4driver.cpp AMA, bana "eksik ayırıcı" diyor. SEKME kullanıyorum, ama yine de bunu söylüyor. Herhangi bir fikir?
Mart'ta Beight, 0:25

2
Anlayabildiğim kadarıyla, bu hata mesajı sadece boşluklarınız varsa ortaya çıkar. Boşluklarla başlayan herhangi bir satırınız olmadığından emin olun (boşluk + sekmesi bu hatayı verecektir). Aklıma gelen tek şey bu ..
Brendan Long

Gelecekteki editörlere not: StackOverflow, yanıtta düzenleseniz bile sekmeleri oluşturamaz, bu yüzden lütfen bu konuda notumu "düzeltmeye" çalışmayın.
Brendan Uzun

35

Neden herkes kaynak dosyaları listelemeyi sever? Basit bir bulma komutu bunu kolayca halledebilir.

İşte basit bir C ++ Makefile kir örneği. Sadece .Cdosyaları içeren bir dizine bırakın ve yazın make...

appname := myapp

CXX := clang++
CXXFLAGS := -std=c++11

srcfiles := $(shell find . -name "*.C")
objects  := $(patsubst %.C, %.o, $(srcfiles))

all: $(appname)

$(appname): $(objects)
    $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(appname) $(objects) $(LDLIBS)

depend: .depend

.depend: $(srcfiles)
    rm -f ./.depend
    $(CXX) $(CXXFLAGS) -MM $^>>./.depend;

clean:
    rm -f $(objects)

dist-clean: clean
    rm -f *~ .depend

include .depend

2
Kaynak dosyaları otomatik olarak bulmamanın bir nedeni, farklı dosyalara ihtiyaç duyan farklı oluşturma hedeflerine sahip olabilmesidir.
hmijail resignees

@Hmijail üzerinde hem de derlenmiş / bağlantılı olmasını istemediğiniz tonlarca kaynak / başlık içeren alt modüller ve kuşkusuz ayrıntılı arama / kullanımın uygun olmadığı birçok koşul vardır.
Mühendis

Bunun yerine neden "joker" değil "kabuk bulma" kullanılır?
Nolan

1
@Nolan bir kaynak dizin ağacındaki kaynak dosyaları bulmak için
AlejandroVD

13

İki seçeneğiniz vardı.

Seçenek 1: en basit marka = MAKEFILE YOK.

"A3driver.cpp" dosyasını "a3a.cpp" olarak yeniden adlandırın ve komut satırına şunu yazın:

nmake a3a.exe

Ve bu kadar. GNU Make kullanıyorsanız, "make" veya "gmake" veya başka bir yöntem kullanın.

Seçenek 2: 2 satırlı bir dosya.

a3a.exe: a3driver.obj
    link /out:a3a.exe a3driver.obj

3
OP ortamının ayrıntıları hakkında çok fazla şey varsaymasaydı bu mükemmel bir cevap olurdu. Evet, Windows'talar, ancak bu kullandıkları anlamına gelmiyor nmake. linkKomut satırı da çok az belgenin bir anda belirli bir derleyici çok özel görünüyor ve gerektiği.
üçlü

6

Make dosyanızda, tek bir komutla veya derleme için bir komutla veya bağlantı için bir komutla bağlantı kurmanıza ve bağlantı kurmanıza bağlı olarak bir veya iki bağımlılık kuralı olacaktır.

Bağımlılık, şuna benzeyen bir kurallar ağacıdır (girintinin bir SEKME olması gerektiğini unutmayın ):

main_target : source1 source2 etc
    command to build main_target from sources

source1 : dependents for source1
    command to build source1

Orada gereken bir hedef için komutlar sonra boş bir satır olacak ve orada olmalı değil komutlar önce boş bir satır olacak. Marka dosyasındaki ilk hedef genel hedeftir ve diğer hedefler yalnızca ilk hedef onlara bağlıysa oluşturulur.

Yani makyajınız böyle bir şeye benzeyecek.

a3a.exe : a3driver.obj 
    link /out:a3a.exe a3driver.obj

a3driver.obj : a3driver.cpp
    cc a3driver.cpp

6

Ben öneririm (girintinin SEKME olduğunu unutmayın):

tool: tool.o file1.o file2.o
    $(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@

veya

LINK.o = $(CXX) $(LDFLAGS) $(TARGET_ARCH)
tool: tool.o file1.o file2.o

İkinci öneri GNU'yu yeniden kullandığından biraz daha iyidir. Ancak, çalışmak için bir kaynak dosyanın son yürütülebilir dosya ile aynı ada sahip olması gerekir (yani: tool.cve tool).

Dikkat edin, kaynakları beyan etmek gerekli değildir. Ara nesne dosyaları, örtük kural kullanılarak oluşturulur. Sonuç olarak, bu Makefileçalışma C ve C ++ için (ve ayrıca Fortran, vb için).

Ayrıca, varsayılan $(CC)olarak, bağlayıcı olarak Makefile kullanıldığına dikkat edin. $(CC)C ++ nesne dosyalarını bağlamak için çalışmaz. LINK.oSadece bundan dolayı değişiklik yapıyoruz . C kodunu derlemek istiyorsanız, LINK.odeğeri zorlamanız gerekmez .

Elbette, derleme bayraklarınızı değişkenle CFLAGSve kütüphanelerinizi de ekleyebilirsiniz LDLIBS. Örneğin:

CFLAGS = -Wall
LDLIBS = -lm

Bir yan not: harici kitaplıklar kullanmanız gerekiyorsa, doğru bir şekilde ayarlamak için pkg-config kullanmanızıCFLAGS ve LDLIBS:

CFLAGS += $(shell pkg-config --cflags libssl)
LDLIBS += $(shell pkg-config --libs libssl)

Dikkatli okuyucu, Makefilebir başlık değiştirilirse bunun düzgün bir şekilde yeniden oluşturulmadığını fark edecektir . Sorunu çözmek için şu satırları ekleyin:

override CPPFLAGS += -MMD
include $(wildcard *.d)

-MMDbaşlık bağımlılıkları hakkında Makefile parçaları içeren .d dosyaları oluşturmanıza olanak sağlar. İkinci satır sadece onları kullanır.

Elbette, iyi yazılmış bir Makefile de şunları içermeli cleanve distcleankurallara uymalıdır:

clean:
    $(RM) *.o *.d

distclean: clean
    $(RM) tool

Dikkat, $(RM)eşdeğerdir rm -f, ancak rmdoğrudan aramamak iyi bir uygulamadır .

allKural takdir edilmektedir. Çalışmak için dosyanızın ilk kuralı olmalıdır:

all: tool

Ayrıca bir installkural ekleyebilirsiniz :

PREFIX = /usr/local
install:
    install -m 755 tool $(DESTDIR)$(PREFIX)/bin

DESTDIRvarsayılan olarak boştur. Kullanıcı, programınızı alternatif bir sisteme kurmak için ayarlayabilir (çapraz derleme işlemi için zorunlu). Paketinizi PREFIXkurmak için çoklu dağıtım için paket koruyucular da değişebilir /usr.

Son bir sözcük: Kaynak dosyaları alt dizinlere yerleştirmeyin. Bunu gerçekten yapmak istiyorsanız, bunu Makefilekök dizinde tutun ve dosyalarınızı tanımlamak için tam yolları kullanın (örn. subdir/file.o).

Özetlemek gerekirse, tam Makefile'niz şöyle görünmelidir:

LINK.o = $(CXX) $(LDFLAGS) $(TARGET_ARCH)
PREFIX = /usr/local
override CPPFLAGS += -MMD
include $(wildcard *.d)

all: tool
tool: tool.o file1.o file2.o
clean:
    $(RM) *.o *.d
distclean: clean
    $(RM) tool
install:
    install -m 755 tool $(DESTDIR)$(PREFIX)/bin

Sonlara doğru: Kurallar arasında boş satır olmamalı mı? John Knoeller'ın cevabı iddia etti.
Peter Mortensen

makeBildiğim hiçbir uygulamanın (GNU Make ve BSD Make) kurallar arasında boş satırlara ihtiyacı yoktur. Bununla birlikte, makekendi hataları ile tonlarca uygulama var ^ Wspecificities.
Jérôme Pouiller

5

Kullandığım friedmud cevabını . Bir süre buna baktım ve başlamak için iyi bir yol gibi görünüyor. Bu çözüm ayrıca derleyici bayrakları eklemek için iyi tanımlanmış bir yönteme sahiptir. Tekrar cevapladım, çünkü çevremde, Ubuntu ve g ++ 'da çalışmasını sağlamak için değişiklikler yaptım. Bazen daha iyi çalışan örnekler en iyi öğretmendir.

appname := myapp

CXX := g++
CXXFLAGS := -Wall -g

srcfiles := $(shell find . -maxdepth 1 -name "*.cpp")
objects  := $(patsubst %.cpp, %.o, $(srcfiles))

all: $(appname)

$(appname): $(objects)
    $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(appname) $(objects) $(LDLIBS)

depend: .depend

.depend: $(srcfiles)
    rm -f ./.depend
    $(CXX) $(CXXFLAGS) -MM $^>>./.depend;

clean:
    rm -f $(objects)

dist-clean: clean
    rm -f *~ .depend

include .depend

Makefiles çok karmaşık görünüyor. Birini kullanıyordum, ancak g ++ kitaplıklarında bağlantı oluşturma ile ilgili bir hata oluşturuyordu. Bu yapılandırma bu sorunu çözdü.

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.