Cara membuat Makefile SIMPLE C ++

303

Kita diharuskan menggunakan Makefile untuk mengumpulkan semuanya untuk proyek kita, tetapi profesor kita tidak pernah menunjukkan caranya.

Saya hanya punya satu file a3driver.cpp,. Pengemudi mengimpor kelas dari lokasi "/user/cse232/Examples/example32.sequence.cpp",.

Itu dia. Segala sesuatu yang lain terkandung dengan .cpp.

Bagaimana saya bisa membuat Makefile sederhana yang membuat executable disebut a3a.exe?

Menimpa
sumber
9
.EXE jadi pasti Windows. Setelah dipikir-pikir ... jalannya adalah gaya Unix. Mungkin menggunakan Mingw-32.
Nathan Osman
2
Mendesah. Saya kira Anda harus mempelajari dasar dari setiap perdagangan, bahkan jika Anda tidak akan pernah menggunakannya. Hanya harus memahami cara kerja barang. Kemungkinannya bagus, bahwa Anda akan selalu berkembang dalam IDE, seperti Eclipse. Anda akan mendapatkan jawaban di sini untuk kasing sederhana dan ada banyak tutorial web, tetapi jika Anda menginginkan pengetahuan dalam-dpth, Anda tidak dapat mengalahkan buku O'reilly (sama untuk sebagian besar topik s / w). amazon.com/Managing-Projects-Make-Nutshell-Handbooks/dp/… Pilih salinan tangan kedua dari amazon, half.com, betterworldbooks eBay
Mawg mengatakan mengembalikan Monica
2
Tautan yang diposting oleh @Dennis sekarang mati, tetapi materi yang sama dapat ditemukan di halaman archive.org ini .
Guilherme Salomé
Saya lebih suka ide orang ini. ( hiltmon.com/blog/2013/07/03/... ) Struktur proyek dapat dengan mudah dimodifikasi agar sesuai. Dan saya juga setuju bahwa waktu pengembang harus dihabiskan untuk hal-hal lain selain automake / autoconf. Alat-alat ini ada tempatnya, tetapi mungkin tidak untuk proyek internal. Saya sedang membangun skrip yang akan menghasilkan struktur proyek seperti itu.
Daisuke Aramaki
@ GuilhermeSalomé Terima kasih, saya percaya ini adalah tutorial terbaik yang sederhana dan lengkap.
Hareen Laks

Jawaban:

561

Karena ini untuk Unix, executable tidak memiliki ekstensi.

Satu hal yang perlu diperhatikan adalah root-configutilitas yang menyediakan kompilasi yang tepat dan menghubungkan bendera; dan pustaka yang tepat untuk membangun aplikasi terhadap root. Itu hanya detail yang terkait dengan audiens asli untuk dokumen ini.

Make Me Baby

atau Anda Tidak Pernah Lupa Saat Pertama Kali Dibuat

Diskusi pengantar make, dan cara menulis makefile sederhana

Apa itu Make? Dan Mengapa Saya Harus Peduli?

Alat yang disebut Make adalah pengelola dependensi build. Yaitu, perlu mengetahui perintah apa yang harus dijalankan dalam rangka untuk mengambil proyek perangkat lunak Anda dari kumpulan file sumber, file objek, perpustakaan, header, dll, dll .- beberapa di antaranya mungkin telah berubah baru-baru ini --- dan mengubahnya menjadi versi program yang benar dan terkini.

Sebenarnya, Anda dapat menggunakan Make untuk hal-hal lain juga, tetapi saya tidak akan membicarakan hal itu.

Makefile yang Sepele

Misalkan Anda memiliki direktori yang berisi:, tool tool.cc tool.o support.cc support.hhdan support.oyang bergantung pada rootdan seharusnya dikompilasi ke dalam program yang disebut tool, dan anggap bahwa Anda telah meretas file sumber (yang berarti yang ada toolsekarang sudah ketinggalan zaman) dan ingin kompilasi program.

Untuk melakukan ini sendiri, Anda bisa

  1. Periksa apakah salah satu support.ccatau support.hhlebih baru dari support.o, dan jika demikian jalankan perintah suka

    g++ -g -c -pthread -I/sw/include/root support.cc
  2. Periksa apakah salah satu support.hhatau tool.cclebih baru dari tool.o, dan jika demikian jalankan perintah suka

    g++ -g  -c -pthread -I/sw/include/root tool.cc
  3. Periksa apakah tool.olebih baru dari tool, dan jika demikian jalankan perintah seperti

    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

Fiuh! Sungguh merepotkan! Ada banyak yang harus diingat dan beberapa peluang untuk melakukan kesalahan. (BTW-- rincian baris perintah yang ditampilkan di sini tergantung pada lingkungan perangkat lunak kami. Yang ini berfungsi di komputer saya.)

Tentu saja, Anda bisa menjalankan ketiga perintah setiap waktu. Itu akan berhasil, tetapi itu tidak skala baik ke bagian besar perangkat lunak (seperti DOGS yang membutuhkan lebih dari 15 menit untuk dikompilasi dari bawah ke atas di MacBook saya).

Alih-alih, Anda dapat menulis file bernama makefileseperti ini:

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

dan cukup ketik makedi baris perintah. Yang akan melakukan tiga langkah yang ditunjukkan di atas secara otomatis.

Baris yang tidak diindentifikasi di sini memiliki bentuk "target: dependencies" dan beri tahu Make bahwa perintah yang terkait (indents lines) harus dijalankan jika ada dependensi yang lebih baru daripada target. Yaitu, garis ketergantungan menggambarkan logika apa yang perlu dibangun kembali untuk mengakomodasi perubahan dalam berbagai file. Jika support.ccperubahan itu berarti support.oharus dibangun kembali, tetapi tool.odapat dibiarkan sendiri. Kapan support.operubahan toolharus dibangun kembali.

Perintah-perintah yang terkait dengan setiap baris dependensi dimatikan dengan sebuah tab (lihat di bawah) harus memodifikasi target (atau setidaknya menyentuhnya untuk memperbarui waktu modifikasi).

Variabel, Aturan yang Terpasang, dan Barang Lainnya

Pada titik ini, makefile kami hanya mengingat pekerjaan yang perlu dilakukan, tetapi kami masih harus mencari tahu dan mengetik setiap perintah yang diperlukan secara keseluruhan. Tidak harus seperti itu: Make adalah bahasa yang kuat dengan variabel, fungsi manipulasi teks, dan banyak aturan bawaan yang bisa membuat ini lebih mudah bagi kita.

Buat Variabel

Sintaks untuk mengakses variabel make adalah $(VAR).

Sintaks untuk menetapkan ke variabel Make adalah: VAR = A text value of some kind (atau VAR := A different text value but ignore this for the moment).

Anda dapat menggunakan variabel dalam aturan seperti versi perbaikan dari makefile kami:

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

yang sedikit lebih mudah dibaca, tetapi masih membutuhkan banyak pengetikan

Buat Fungsi

GNU make mendukung berbagai fungsi untuk mengakses informasi dari sistem file atau perintah lain pada sistem. Dalam hal ini kami tertarik untuk $(shell ...)memperluas ke output dari argumen, dan $(subst opat,npat,text)yang menggantikan semua contoh opatdengan npatdalam teks.

Mengambil keuntungan dari ini memberi kita:

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

yang lebih mudah diketik dan lebih mudah dibaca.

Perhatikan itu

  1. Kami masih menyatakan secara eksplisit dependensi untuk setiap file objek dan yang dapat dieksekusi akhir
  2. Kami harus secara eksplisit mengetik aturan kompilasi untuk kedua file sumber

Aturan Implisit dan Pola

Kami biasanya berharap bahwa semua file sumber C ++ harus diperlakukan dengan cara yang sama, dan Make menyediakan tiga cara untuk menyatakan ini:

  1. aturan suffix (dianggap usang dalam pembuatan GNU, tetapi disimpan untuk kompatibilitas mundur)
  2. aturan implisit
  3. aturan pola

Aturan implisit sudah ada, dan beberapa akan dibahas di bawah ini. Aturan pola ditentukan dalam bentuk seperti

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

yang berarti bahwa file objek dihasilkan dari file sumber C dengan menjalankan perintah yang ditunjukkan, di mana variabel "otomatis" $<meluas ke nama dependensi pertama.

Aturan bawaan

Make memiliki seluruh aturan bawaan yang berarti bahwa seringkali, sebuah proyek dapat dikompilasi oleh makefile yang sangat sederhana.

GNU make built in rule untuk file sumber C adalah yang ditunjukkan di atas. Demikian pula kita membuat file objek dari file sumber C ++ dengan aturan seperti $(CXX) -c $(CPPFLAGS) $(CFLAGS).

File objek tunggal ditautkan menggunakan $(LD) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS), tetapi ini tidak akan berfungsi dalam kasus kami, karena kami ingin menautkan banyak file objek.

Variabel Digunakan Dengan Aturan Built-in

Aturan bawaan menggunakan seperangkat variabel standar yang memungkinkan Anda menentukan informasi lingkungan lokal (seperti tempat menemukan ROOT termasuk file) tanpa menulis ulang semua aturan. Yang paling mungkin menarik bagi kami adalah:

  • CC - kompiler C untuk digunakan
  • CXX - kompiler C ++ untuk digunakan
  • LD - penghubung untuk digunakan
  • CFLAGS - flag kompilasi untuk file sumber C
  • CXXFLAGS - flag kompilasi untuk file sumber C ++
  • CPPFLAGS - flag untuk c-preprocessor (biasanya menyertakan path file dan simbol yang didefinisikan pada baris perintah), digunakan oleh C dan C ++
  • LDFLAGS - bendera tautan
  • LDLIBS - perpustakaan untuk ditautkan

Makefile Dasar

Dengan memanfaatkan aturan bawaan kami dapat menyederhanakan makefile kami menjadi:

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

Kami juga telah menambahkan beberapa target standar yang melakukan tindakan khusus (seperti membersihkan direktori sumber).

Perhatikan bahwa ketika make dipanggil tanpa argumen, ia menggunakan target pertama yang ditemukan dalam file (dalam hal ini semua), tetapi Anda juga dapat memberi nama target untuk mendapatkan apa yang membuat make cleanmenghapus file objek dalam kasus ini.

Kami masih memiliki semua dependensi yang dikodekan.

Beberapa Perbaikan Misterius

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

Perhatikan itu

  1. Tidak ada lagi garis ketergantungan untuk file sumber!?!
  2. Ada beberapa sihir aneh yang terkait dengan .depend dan depend
  3. Jika Anda melakukannya makemaka ls -AAnda melihat file bernama .dependyang berisi hal-hal yang terlihat seperti membuat garis ketergantungan

Bacaan Lainnya

Tahu Bug dan Catatan Sejarah

Bahasa input untuk Make adalah spasi putih. Secara khusus, garis tindakan dependensi harus dimulai dengan tab . Tetapi serangkaian ruang bisa terlihat sama (dan memang ada editor yang akan secara diam-diam mengubah tab menjadi spasi atau sebaliknya), yang menghasilkan file Make yang terlihat benar dan masih tidak berfungsi. Ini diidentifikasi sebagai bug sejak awal, tetapi ( ceritanya ) itu tidak diperbaiki, karena sudah ada 10 pengguna.

(Ini disalin dari pos wiki yang saya tulis untuk mahasiswa pascasarjana fisika.)

dmckee --- mantan kucing moderator
sumber
9
Metode ini untuk menghasilkan dependensi sudah usang dan sebenarnya berbahaya. Lihat Generasi Ketergantungan Otomatis Lanjut .
Maxim Egorushkin
5
-pthreadflag menyebabkan gccuntuk mendefinisikan macro yang diperlukan, -D_REENTRANTtidak perlu.
Maxim Egorushkin
8
@ jcoe Ini melakukan pass preprocessor tambahan yang tidak perlu untuk menghasilkan dependensi. Melakukan pekerjaan yang tidak perlu itu hanya menghilangkan panas yang melelehkan kutub es dan, dalam skala yang lebih besar, mendekati kematian panas alam semesta kita.
Maxim Egorushkin
2
Mungkin "berbahaya" sedikit berlebihan, tetapi mengingat fase atau target generasi ketergantungan secara eksplisit sudah ketinggalan jaman karena setidaknya GCC 3, saya benar-benar berpikir bahwa kita semua harus bergerak melewatinya. bruno.defraine.net/techtips/makefile-auto-dependencies-with-gcc/…
hmijail meratapi orang-orang yang mengundurkan diri
2
Sungguh, jawaban yang diterima seharusnya tidak tergantung pada perangkat lunak yang sangat spesifik ( root-config). Alternatif yang lebih umum dengan kemampuan yang sama harus diusulkan jika ada atau harus ditinggalkan begitu saja. Saya tidak downvote karena daftar dan penjelasan tentang makro make paling sering digunakan.
green diod
56

Saya selalu berpikir ini lebih mudah untuk dipelajari dengan contoh terperinci, jadi inilah cara saya memikirkan makefile. Untuk setiap bagian Anda memiliki satu baris yang tidak berlekuk dan itu menunjukkan nama bagian diikuti oleh dependensi. Ketergantungan dapat berupa bagian lain (yang akan dijalankan sebelum bagian saat ini) atau file (yang jika diperbarui akan menyebabkan bagian saat ini dijalankan lagi di lain waktu Anda menjalankan make).

Berikut ini adalah contoh cepat (perlu diingat bahwa saya menggunakan 4 spasi di mana saya harus menggunakan tab, Stack Overflow tidak akan membiarkan saya menggunakan tab):

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

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

Saat Anda mengetik make, ia akan memilih bagian pertama (a3driver). a3driver tergantung pada a3driver.o, jadi itu akan masuk ke bagian itu. a3driver.o tergantung pada a3driver.cpp, jadi itu hanya akan berjalan jika a3driver.cpp telah berubah sejak dijalankan terakhir. Dengan asumsi itu telah (atau belum pernah dijalankan), ia akan mengkompilasi a3driver.cpp ke file .o, kemudian kembali ke a3driver dan kompilasi executable akhir.

Karena hanya ada satu file, bahkan dapat dikurangi menjadi:

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

Alasan saya menunjukkan contoh pertama adalah karena ia menunjukkan kekuatan makefile. Jika Anda perlu mengkompilasi file lain, Anda bisa menambahkan bagian lain. Berikut ini contoh dengan secondFile.cpp (yang memuat dalam header bernama secondFile.h):

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

Dengan cara ini jika Anda mengubah sesuatu di secondFile.cpp atau secondFile.h dan mengkompilasi ulang, itu hanya akan mengkompilasi ulang secondFile.cpp (bukan a3driver.cpp). Atau secara bergantian, jika Anda mengubah sesuatu di a3driver.cpp, itu tidak akan mengkompilasi ulang secondFile.cpp.

Beri tahu saya jika Anda memiliki pertanyaan tentangnya.

Ini juga tradisional untuk memasukkan bagian bernama "semua" dan bagian bernama "bersih". "all" biasanya akan membangun semua executable, dan "clean" akan menghapus "build artefacts" seperti file .o dan executable:

all: a3driver ;

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

EDIT: Saya tidak melihat Anda menggunakan Windows. Saya pikir satu-satunya perbedaan adalah mengubah -o a3driverke -o a3driver.exe.

Brendan Long
sumber
Kode absolut yang saya coba gunakan adalah: p4a.exe: p4driver.cpp g ++ -o p4a p4driver.cpp NAMUN, itu memberitahu saya "pemisah yang hilang". Saya menggunakan TAB, tetapi masih mengatakan itu. Ada ide?
Befall
2
Sejauh yang saya tahu, pesan kesalahan itu hanya muncul jika Anda memiliki spasi. Pastikan Anda tidak memiliki garis yang dimulai dengan spasi (spasi + tab akan memberikan kesalahan itu). Itulah satu-satunya hal yang dapat saya pikirkan ..
Brendan Long
Catatan untuk editor mendatang: StackOverflow tidak dapat membuat tab bahkan jika Anda mengeditnya menjadi jawaban, jadi tolong jangan mencoba untuk "memperbaiki" catatan saya tentang itu.
Brendan Long
35

Mengapa semua orang suka mencantumkan file sumber? Perintah find sederhana dapat menangani itu dengan mudah.

Berikut adalah contoh dari C ++ Makefile yang sederhana. Cukup taruh di direktori yang berisi .Cfile dan kemudian ketik 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
friedmud
sumber
2
Alasan untuk tidak mencari file sumber secara otomatis adalah karena seseorang dapat memiliki target pembangunan yang berbeda yang membutuhkan file yang berbeda.
hmijail meratapi orang-orang yang mengundurkan diri
Setuju @hmijail, serta submodul yang berisi satu ton sumber / header yang tidak ingin dikompilasi / ditautkan ... dan tidak diragukan lagi banyak keadaan lain di mana pencarian / penggunaan lengkap tidak cocok.
Insinyur
Mengapa menggunakan "shell find" dan bukan "wildcard"?
Nolan
1
@Nolan untuk menemukan file sumber di pohon direktori sumber
AlejandroVD
13

Anda memiliki dua opsi.

Opsi 1: makefile paling sederhana = NO MAKEFILE.

Ganti nama "a3driver.cpp" menjadi "a3a.cpp", dan kemudian pada baris perintah tulis:

nmake a3a.exe

Dan itu saja. Jika Anda menggunakan GNU Make, gunakan "make" atau "gmake" atau apa pun.

Opsi 2: makefile 2-baris.

a3a.exe: a3driver.obj
    link /out:a3a.exe a3driver.obj
Tidak ada
sumber
3
Ini akan menjadi jawaban yang sangat baik jika tidak mengandaikan begitu banyak hal tentang detail lingkungan OP. Ya, mereka ada di Windows, tetapi itu tidak berarti mereka menggunakan nmake. Baris linkperintah juga terlihat sangat spesifik untuk kompiler tertentu, dan paling tidak harus mendokumentasikan yang mana.
tripleee
6

File Make Anda akan memiliki satu atau dua aturan ketergantungan tergantung pada apakah Anda mengkompilasi dan menautkan dengan satu perintah, atau dengan satu perintah untuk kompilasi dan satu untuk tautan.

Ketergantungan adalah pohon aturan yang terlihat seperti ini (perhatikan bahwa indentasi harus TAB):

main_target : source1 source2 etc
    command to build main_target from sources

source1 : dependents for source1
    command to build source1

Ada harus menjadi baris kosong setelah perintah untuk target, dan harus ada tidak ada garis kosong sebelum perintah. Target pertama dalam makefile adalah tujuan keseluruhan, dan target lain dibangun hanya jika target pertama bergantung padanya.

Jadi makefile Anda akan terlihat seperti ini.

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

a3driver.obj : a3driver.cpp
    cc a3driver.cpp
John Knoeller
sumber
6

Saya sarankan (perhatikan bahwa indentasi adalah TAB):

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

atau

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

Saran terakhir sedikit lebih baik karena menggunakan kembali GNU Membuat aturan implisit. Namun, agar dapat berfungsi, file sumber harus memiliki nama yang sama dengan yang dapat dieksekusi akhir (yaitu: tool.cdan tool).

Perhatikan, tidak perlu mendeklarasikan sumber. File objek menengah dihasilkan menggunakan aturan implisit. Akibatnya, ini Makefileberfungsi untuk C dan C ++ (dan juga untuk Fortran, dll ...).

Perhatikan juga, secara default, Makefile menggunakan $(CC)sebagai tautan. $(CC)tidak berfungsi untuk menautkan file objek C ++. Kami memodifikasi LINK.ohanya karena itu. Jika Anda ingin mengkompilasi kode C, Anda tidak perlu memaksakan LINK.onilainya.

Tentu, Anda juga dapat menambahkan flag kompilasi Anda dengan variabel CFLAGSdan menambahkan pustaka Anda LDLIBS. Sebagai contoh:

CFLAGS = -Wall
LDLIBS = -lm

Catatan satu sisi: jika Anda harus menggunakan perpustakaan eksternal, saya sarankan untuk menggunakan pkg-config untuk mengatur CFLAGSdan LDLIBS:

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

Pembaca yang penuh perhatian akan melihat bahwa ini Makefiletidak membangun kembali dengan benar jika satu header diubah. Tambahkan baris ini untuk memperbaiki masalah:

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

-MMDmemungkinkan untuk membangun file .d yang berisi fragmen Makefile tentang dependensi header. Baris kedua hanya menggunakannya.

Yang pasti, Makefile yang ditulis dengan baik juga harus mencakup cleandan distcleanaturan:

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

distclean: clean
    $(RM) tool

Perhatikan, $(RM)sama dengan rm -f, tetapi praktik yang baik untuk tidak menelepon rmlangsung.

The allrule juga dihargai. Agar berfungsi, itu harus menjadi aturan pertama dari file Anda:

all: tool

Anda juga dapat menambahkan installaturan:

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

DESTDIRkosong secara default. Pengguna dapat mengaturnya untuk menginstal program Anda di sistem alternatif (wajib untuk proses cross-kompilasi). Pengelola paket untuk beberapa distribusi juga dapat berubah PREFIXuntuk menginstal paket Anda/usr .

Satu kata terakhir: Jangan letakkan file sumber di dalam sub-direktori. Jika Anda benar-benar ingin melakukannya, simpan ini Makefiledi direktori root dan gunakan path lengkap untuk mengidentifikasi file Anda (yaitu subdir/file.o).

Jadi untuk meringkas, Makefile lengkap Anda akan terlihat seperti:

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
Jérôme Pouiller
sumber
Menjelang akhir: Bukankah seharusnya ada garis kosong di antara aturan? Jawaban John Knoeller mengklaim hal itu.
Peter Mortensen
Tidak ada implementasi makeyang saya tahu (GNU Make dan BSD Make) membutuhkan baris kosong antara aturan. Namun, ada banyak makeimplementasi dengan bug mereka sendiri ^ Spesifikasi khusus.
Jérôme Pouiller
5

Saya menggunakan jawaban friedmud . Saya melihat ini sebentar, dan sepertinya ini cara yang baik untuk memulai. Solusi ini juga memiliki metode yang jelas untuk menambahkan flag compiler. Saya menjawab lagi, karena saya membuat perubahan agar berfungsi di lingkungan saya, Ubuntu dan g ++. Lebih banyak contoh kerja adalah guru terbaik, kadang-kadang.

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 tampaknya sangat kompleks. Saya menggunakan satu, tapi itu menghasilkan kesalahan yang terkait dengan tidak menautkan di pustaka g ++. Konfigurasi ini menyelesaikan masalah itu.

VectorVortec
sumber