InggrisPerancisSpanyol

Ad


favorit OnWorks

makepp_cookbook - Online di Awan

Jalankan makepp_cookbook di penyedia hosting gratis OnWorks melalui Ubuntu Online, Fedora Online, emulator online Windows, atau emulator online MAC OS

Ini adalah perintah makepp_cookbook yang dapat dijalankan di penyedia hosting gratis OnWorks menggunakan salah satu dari beberapa workstation online gratis kami seperti Ubuntu Online, Fedora Online, emulator online Windows atau emulator online MAC OS

PROGRAM:

NAMA


makepp_cookbook -- Cara terbaik untuk mengatur makefile untuk berbagai situasi

DESKRIPSI


Saya menemukan bahwa praktis tidak ada yang pernah membaca manual untuk alat make, karena terus terang
tidak ada yang benar-benar tertarik pada proses pembuatan itu sendiri--kami hanya tertarik pada hasil.
Maka buku masak ini disusun dengan harapan masyarakat bisa mendapatkan apa yang mereka butuhkan
cepat dari contoh tanpa mengarungi manual. Ini menunjukkan cara mengetik
pertanyaan, sedangkan petunjuk pemasangan dan batu sandungan akan ditemukan di
pertanyaan yang sering diajukan.

Bangunan perpustakaan
Do kamu benar-benar perlu a Perpustakaan?

Saya telah melihat sejumlah program besar yang terdiri dari sejumlah besar modul, masing-masing dari
yang tinggal di direktori sendiri. Umumnya, setiap direktori dimasukkan ke dalam perpustakaannya sendiri,
dan kemudian program terakhir terhubung dengan semua perpustakaan.

Dalam banyak kasus, saya pikir daripada menggunakan perpustakaan, ada pendekatan yang lebih baik. Perpustakaan
bukanlah solusi yang tepat jika setiap modul tidak dapat atau tidak akan digunakan kembali di modul lain
program, karena dengan demikian Anda mendapatkan semua kekurangan perpustakaan dan tidak ada satu pun dari
keuntungan. Perpustakaan berguna dalam kasus berikut:

1. Ketika Anda memiliki banyak subrutin yang harus dihubungkan dengan beberapa subrutin yang berbeda
program, dan tidak ada program yang benar-benar menggunakan 100% subrutin--setiap program menggunakan a
subset yang berbeda. Dalam hal ini, mungkin ide yang baik untuk menggunakan perpustakaan statis (a
.a file, atau file arsip).

2. Ketika Anda memiliki modul yang harus ditautkan ke beberapa program berbeda, dan Anda
ingin memuatnya secara dinamis sehingga setiap program tidak harus memiliki salinan terpisah dari
Perpustakaan. Pustaka dinamis dapat menghemat ruang file yang dapat dieksekusi dan terkadang meningkatkan
kinerja sistem karena hanya ada satu salinan perpustakaan yang dimuat untuk semua
berbagai program yang menggunakannya.

3. Ketika waktu tautan Anda sangat panjang, gunakan perpustakaan bersama untuk sebagian besar
program dapat secara signifikan mempercepat tautan.

Menggunakan perpustakaan statis memiliki satu kelemahan utama: pada beberapa sistem (misalnya Linux), urutannya
di mana Anda menautkan perpustakaan sangat penting. Linker memproses perpustakaan
dalam urutan yang ditentukan pada baris perintahnya. Ia mengambil semua yang menurutnya dibutuhkan dari
setiap perpustakaan, kemudian pindah ke perpustakaan berikutnya. Jika beberapa perpustakaan berikutnya mengacu pada
simbol yang belum dimasukkan dari perpustakaan sebelumnya, tautannya tidak
tahu untuk kembali dan mengambilnya dari perpustakaan sebelumnya. Akibatnya, itu mungkin diperlukan
untuk membuat daftar pustaka beberapa kali di baris perintah tautan. (Saya mengerjakan sebuah proyek
di mana kami harus mengulang seluruh daftar perpustakaan tiga kali. Proyek inilah yang membuat
saya lebih suka pendekatan alternatif yang disarankan di bawah ini, yaitu penautan tambahan.)

Menggunakan perpustakaan dinamis memiliki beberapa kelemahan. Pertama, program Anda bisa sedikit
lebih lambat untuk memulai jika perpustakaan belum digunakan oleh beberapa program lain, karena
itu harus ditemukan dan dimuat. Kedua, itu bisa sangat merepotkan untuk mendapatkan semua dinamika
perpustakaan dipasang di lokasi yang benar; Anda tidak bisa hanya menyalin program yang dapat dieksekusi,
Anda juga harus memastikan bahwa Anda menyalin semua perpustakaannya. Ketiga, pada beberapa sistem, itu
sulit untuk men-debug kode di dalam pustaka bersama karena debugger tidak mendukung
mereka dengan baik.

Jika modul Anda tidak akan pernah digunakan di program lain, maka ada sedikit alasan untuk menggunakannya
perpustakaan: Anda mendapatkan semua kerugian menggunakan perpustakaan dan tidak ada satu pun keuntungan.
Teknik yang saya sukai adalah menggunakan penautan tambahan, jika tersedia.

Inilah cara Anda dapat melakukan ini di Linux:

my_module.o : $(filter_out my_module.o, $(wildcard *.o))
ld -r -o $(keluaran) $(masukan)

Apa yang akan dilakukan adalah membuat yang lain .o file bernama modul_saya.o, yang terdiri dari
semua .o file dalam subdirektori ini. Linker akan menyelesaikan sebanyak
referensi sebanyak mungkin, dan akan meninggalkan referensi yang tersisa untuk diselesaikan dalam a
tahap penyambungan selanjutnya. Di tingkat atas, ketika Anda akhirnya membangun program Anda,
alih-alih menghubungkan dengan libmy_module.a or libmy_module.so, Anda cukup menautkan dengan
modul_saya.o. Saat Anda menautkan .o file, Anda tidak memiliki masalah dengan ketergantungan pesanan di
baris perintah penghubung.

Membiarkan makepp mencari di luar yang perpustakaan modul adalah dibutuhkan

Bahkan jika Anda memiliki perpustakaan yang sebenarnya, di mana program tertentu hanya membutuhkan beberapa file darinya
(daripada setiap modul tunggal), makepp mungkin dapat mengetahui modul mana yang
diperlukan dari perpustakaan dan hanya menyertakan yang ada di build. Ini dapat menyimpan kompilasi
waktu jika Anda mengembangkan perpustakaan bersama dengan sebuah program, karena Anda tidak repot-repot
kompilasi modul perpustakaan yang tidak diperlukan untuk program tertentu yang sedang Anda kerjakan.

Jika perpustakaan Anda secara ketat mematuhi konvensi bahwa semua fungsi atau kelas dideklarasikan dalam
file xyz.h sepenuhnya diimplementasikan dalam file sumber yang dikompilasi ke xyz.o (yaitu, kamu
jangan pisahkan implementasinya menjadi xyz1.o dan xyz2.o), maka Anda dapat menggunakan
"$(infer_objects)" berfungsi untuk memberi tahu makepp agar hanya mengeluarkan modul yang relevan dari
Perpustakaan. Ini dapat bekerja dengan sangat baik untuk perpustakaan bahkan dengan lusinan file yang disertakan.
Pada dasarnya, "$(infer_objects)" memeriksa daftar .h file yang disertakan, dan terlihat
untuk yang sesuai .o file. Jika Anda dengan cepat mengembangkan perpustakaan dan program
bersama-sama, ini dapat menghemat waktu kompilasi, karena Anda tidak perlu repot-repot mengkompilasi modul
perpustakaan yang tidak digunakan oleh program.

Berikut adalah contoh cara saya menggunakannya:

program_saya: $(infer_objects *.o, $(LIB1)/*.o $(LIB2)/*.o)
$(CXX) $(masukan) -o $(keluaran) $(SYSTEM_LIBRARY)

Fungsi "$(infer_objects )" mengembalikan argumen pertamanya (setelah melakukan wildcard
ekspansi di atasnya), dan juga melihat daftar file dalam argumen kedua, untuk
file yang namanya sama dengan nama apapun .h file yang disertakan oleh file apa pun dalam yang pertama
argumen. Jika file tersebut ditemukan, ini akan ditambahkan ke daftar.

Bangunan a statis perpustakaan

Jika Anda yakin benar-benar membutuhkan perpustakaan dan penautan tambahan tidak tersedia atau
bukan apa yang ingin Anda lakukan, ada beberapa cara untuk melakukannya. Pertama, ini contohnya
di mana semua file secara eksplisit terdaftar:

LIBRARY_FILES = abcde

libmine.a: $(LIBRARY_FILES).o
&rm -f $(keluaran)
$(AR) cr $(keluaran) $(masukan)
ranlib $(output) # Mungkin tidak diperlukan, tergantung pada OS Anda.

&rm adalah perintah "rm" bawaan makepp. Jika Anda terbiasa menulis makefile, Anda mungkin
sedikit terkejut dengan perintah ini; Anda mungkin terbiasa dengan sesuatu yang lebih seperti ini:

libmine.a: $(LIBRARY_FILES).o
$(AR) ru $@ $? # Tidak direkomendasikan!!!!!!!
ranlib $(keluaran)

dimana $? (juga dikenal sebagai "$(changed_inputs)") adalah variabel otomatis yang berarti file apa pun
yang telah berubah sejak terakhir kali perpustakaan dibangun, dan $@ kira-kira sama
sebagai "$(keluaran)".

Pendekatan ini tidak disarankan karena beberapa alasan:

· Misalkan Anda menghapus file sumber dari direktori saat ini. Itu masih di
perpustakaan, karena Anda tidak membangun kembali perpustakaan dari awal. Akibatnya, apapun
bahwa tautan dengan perpustakaan ini akan menjadi basi .o file, dan itu dapat mengacaukan
membangun. (Saya pernah benar-benar bingung dengan ini ketika saya mencoba menghapus kode mati
dari sebuah proyek: Saya terus menghapus file dan masih tertaut, jadi saya pikir kodenya adalah
mati. Namun, ketika orang lain membangun kembali proyek dari awal, itu tidak menghubungkan apa pun
lagi! Masalahnya adalah yang lama .o file masih dalam arsip.)

Juga, tergantung pada opsi Anda untuk "ar" dan implementasi "ar" Anda (misalnya, jika Anda
gunakan opsi "q" alih-alih "r"), Anda dapat memiliki beberapa versi
sama .o dalam .a mengajukan. Jika versi yang berbeda mendefinisikan global yang berbeda,
linker mungkin mencoba menarik keduanya. Ini mungkin hal yang buruk.

Inilah mengapa pertama-tama kami menghapus file perpustakaan, dan membuatnya dari awal. Ini akan
membutuhkan waktu sedikit lebih lama dari sekadar memperbarui modul di perpustakaan, tetapi tidak lebih lama; pada
komputer modern, jumlah waktu yang dihabiskan oleh ar program sangat kecil dibandingkan
dengan apa yang dibutuhkan oleh kompiler C dalam bangunan biasa, jadi tidak perlu khawatir
tentang.

· Salah satu cara makepp mencoba untuk menjamin build yang benar adalah bahwa itu akan
secara otomatis membangun kembali jika baris perintah untuk membangun target tertentu telah berubah. Tetapi
menggunakan $? variabel dapat menyebabkan masalah, karena setiap kali perpustakaan diperbarui,
perintah build berbeda. (Anda dapat menekan ini menggunakan
":build_check abaikan_action"; lihat makepp_build_check untuk detailnya.)

· Memperbarui arsip daripada membangunnya kembali akan membuat makepp tidak mungkin
letakkan file dengan benar ke dalam cache build (lihat makepp_build_cache untuk detailnya).

Kadang-kadang Anda mungkin menemukan bahwa mendaftar semua file agak merepotkan, terutama jika a
proyek sedang mengalami perkembangan pesat dan daftar file terus berubah. Dia
mungkin lebih mudah untuk membangun perpustakaan menggunakan wildcard, seperti ini:

libmine.a: $(only_targets *.o)
&rm $(keluaran)
$(AR) cr $(keluaran) $(masukan)

Ini menempatkan semua .o file dalam direktori saat ini ke perpustakaan. Kartu liar
cocok dengan apa saja .o file yang ada atau dapat dibangun, sehingga akan berfungsi bahkan jika file tidak
belum ada.

Fungsi "only_targets" digunakan untuk mengecualikan .o file yang tidak memiliki korespondensi
file sumber lagi. Misalkan Anda memiliki file bernama xyz.c yang biasa Anda masukkan ke dalam
Perpustakaan. Artinya ada xyz.o file tergeletak di sekitar. Sekarang kamu hapus xyz.c
karena sudah usang, tapi kamu lupa menghapusnya xyz.o. Tanpa "only_targets"
fungsi, xyz.o masih akan dimasukkan dalam daftar .o file yang termasuk dalam perpustakaan.

Bangunan a dinamis perpustakaan

Proses membangun perpustakaan dinamis sepenuhnya bergantung pada sistem. Saya akan sangat
merekomendasikan menggunakan libtool untuk membangun perpustakaan dinamis (lihat
<http://www.gnu.org/software/libtool/>), jadi Anda tidak perlu mencari cara untuk melakukannya di
platform Anda, dan agar makefile Anda akan terus berfungsi bahkan saat Anda beralih ke a
berbeda OS. Lihat dokumentasi libtool untuk detailnya. Berikut ini contoh Makefile:

LIBTOOL := libtool

libflick.la : $(only_targets *.lo)
$(LIBTOOL) --mode=link $(CC) $(masukan) -o $(keluaran)

%.lo : %.c
$(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(TERMASUK) -c $(input) -o $(output)

Bangunan on beberapa berbeda mesin or jaringan
Salah satu masalah yang paling mengganggu dengan makefile adalah mereka hampir tidak pernah berfungsi saat Anda
beralih ke mesin yang berbeda atau jaringan yang berbeda. Jika makefile Anda harus dikerjakan
setiap mesin yang mungkin di planet ini, maka Anda mungkin memerlukan semacam konfigurasi
naskah. Tetapi jika Anda hanya harus bekerja pada beberapa mesin yang berbeda, ada beberapa cara
anda dapat mendekati masalah ini:

penggunaan a berbeda memasukkan fillet in semua itu lingkungan

Di awal setiap makefile, Anda dapat menyertakan baris seperti ini:

sertakan system_defs.mk

File sistem_defs.mk biasanya akan ditempatkan di tempat yang berbeda untuk masing-masing
lingkungan. Jika Anda ingin direktori build Anda identik di semua mesin, maka masukkan
sistem_defs.mk di direktori di atas direktori build, atau sediakan jalur sertakan
untuk makepp menggunakan opsi baris perintah "-I".

Ini biasanya agak menyakitkan untuk dilakukan, tetapi bekerja dengan baik jika ada banyak
perbedaan.

penggunaan if Laporan

Ini adalah cara paling jelek untuk melakukannya, tetapi biasanya akan berhasil.

ifsys i386
CC := gcc
lain ifsys sun4u
CC := CC
lain jika hpux11
CC = c89
endif

Jika semua yang perlu Anda lakukan adalah menemukan beberapa program atau perpustakaan atau memasukkan file dalam format yang berbeda
tempat, mungkin ada cara yang lebih baik (lihat di bawah).

temukan_program, pertama_tersedia, Mencari berkas

Fungsi-fungsi ini dapat mencari berbagai direktori berbeda di sistem Anda untuk menemukan
file yang sesuai. Ini tidak sekuat skrip konfigurasi, tentu saja, tetapi saya menemukannya
berguna. Misalnya, saya melakukan hal berikut:

CXX ;= $(find_program g++ c++ pg++ cxx CC aCC)
# Pilih compiler C++ pertama yang tersedia di PATH.
# (Kebetulan, jika Anda tidak mendefinisikan CXX sama sekali, ini
# adalah cara itu didefinisikan.)
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 ) mencari tcl.h di setiap yang ditunjukkan
# direktori dan mengembalikan path lengkap. Ini kemudian
# diubah menjadi opsi kompilasi dengan menghapus
# nama file (meninggalkan direktori) dan diawali dengan -I.
%.o : %.cpp
$(CXX) $(CXXFLAGS) $(TCL_INCLUDE) $(masukan) -o $(keluaran)

TCL_LIB ;= $((tersedia_pertama
/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))
# Temukan di mana perpustakaan Tcl berada. Hal ini kemudian secara eksplisit
# tercantum pada perintah tautan:
program_saya : *.o
$(CXX) $(CXXFLAGS) $(masukan) -o $(keluaran) $(TCL_LIB)

Mengambil keuntungan of Perl's config informasi

Teknik di atas mungkin tidak cukup jika Anda memerlukan beberapa informasi tambahan tentang
sistem Anda, seperti apakah ada long double, atau apa urutan bytenya. Namun,
Perl telah menghitung hal-hal ini, jadi Anda bisa menggunakan jawabannya.

Skrip konfigurasi otomatis Perl membuat semua informasi konfigurasinya tersedia melalui
hash %Config. Tidak ada sintaks untuk mengakses hash Perl secara langsung di makepp, tetapi Anda bisa
masuk ke Perl dan atur variabel skalar, yang dapat diakses langsung dari makepp:

perl_begin
# Ambil nilai dari hash konfigurasi.
gunakan Konfigurasi;
$CC = $Konfigurasi{'cc'}; # C compiler yang perl digunakan;
$byteorder_flags = "-DBYTEORDER=$Config{'byteorder'}";
$longdouble_defined = $Config{'d_longdbl'} eq 'define';
$CFLAGS_for_shared_libs = $Config{'cccdlflags'};
$LDFLAGS_for_shared_libs = $Config{'ccdlflags'};
perl_end

Juga, setelah Anda melakukan 'use Config', Anda dapat menggunakan pernyataan "$(perl )", seperti
ini:

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

Ketik "perldoc Config" untuk melihat informasi apa yang tersedia melalui hash %Config.

Konfigurasi Perl adalah tempat yang baik untuk mendapatkan hal-hal seperti informasi tentang tipe integer, byte
order, dan hal-hal lain yang biasanya memerlukan skrip konfigurasi terpisah untuk menemukannya. Beberapa
informasinya yang berkaitan dengan keberadaan hal-hal di sistem file mungkin tidak
sah. Misalnya, $Config{'cc'} merujuk ke kompiler C yang digunakan untuk membuat Perl,
yang mungkin bukan kompiler C yang sama yang ingin Anda gunakan. Bahkan, itu mungkin tidak ada
di sistem Anda, karena Anda mungkin menginstal Perl melalui paket biner.

Tips untuk menggunakan wildcard
Sesuai semua arsip kecuali a tertentu bagian

Wildcard Makepp saat ini tidak memiliki cara untuk mencocokkan semua file kecuali tertentu
set, tetapi Anda dapat melakukannya dengan kombinasi fungsi.

Misalnya, Anda memiliki program pengujian untuk setiap modul di perpustakaan, tetapi Anda tidak memilikinya
ingin memasukkan program uji di perpustakaan. Jika semua program pengujian dimulai dengan
uji, maka Anda dapat mengecualikannya seperti ini:

libproduction.a: $(filter_out test*, $(wildcard *.o))

Fungsi "$(filter )" dan "$(filter_out )" adalah kumpulan filter yang sangat kuat untuk dilakukan
semua jenis operasi simpang dan selisih himpunan. Sebagai contoh,

SUBDIRS ;= $(filter_out *test* *$(ARCH)*, $(Shell find . -type d -print))
# Mengembalikan semua subdirektori yang tidak memiliki
# "test" atau $(ARCH) di dalamnya.

$(filter $(patsubst test_dir/test_%.o, %.o, $(wildcard test_dir/*.o)), \
$(karakter pengganti *.o))
# Mengembalikan daftar file .o saat ini
# direktori yang sesuai
# file test_*.o di subdirektori test_dir.
$(filter_out $(patsubst man/man3/%.3, %.o, $(wildcard man/man3/*.3)), \
$(karakter pengganti *.o))
# Mengembalikan daftar file .o saat ini
# direktori yang tidak ada halaman manualnya
# dengan nama file yang sama di subdirektori man/man3.

Menggunakan itu "$(only_targets )" fungsi untuk menghapuskan basi .o arsip

Misalkan Anda sedang membangun program atau perpustakaan dengan perintah build seperti ini:

program: *.o
$(CC) $(masukan) -o $(keluaran)

Misalkan Anda sekarang menghapus file sumber. Jika Anda lupa untuk menghapus yang sesuai .o file,
itu akan tetap terhubung meskipun tidak ada cara untuk membangunnya lagi. Dalam
masa depan, makepp mungkin akan mengenali situasi ini secara otomatis dan mengecualikannya dari
daftar wildcard, tetapi saat ini, Anda harus memberi tahunya untuk mengecualikannya secara manual:

program: $(hanya_target *.o)
$(CC) $(masukan) -o $(keluaran)

Makepp tidak tahu cara apa pun untuk membangun basi .o file lagi karena file sumbernya adalah
hilang, jadi fungsi "$(only_targets )" akan mengecualikannya dari daftar ketergantungan.

Tips untuk beberapa direktori
Salah satu alasan utama untuk menulis makepp adalah untuk menyederhanakan penanganan multiple
direktori. Makepp dapat menggabungkan perintah build dari beberapa makefile, sehingga dapat
menangani aturan dengan benar dalam satu makefile yang bergantung pada file yang dibuat oleh a
makefile yang berbeda.

Apa untuk do in tempat of rekursif membuat

Makepp mendukung pembuatan rekursif untuk kompatibilitas mundur, tetapi sangat disarankan
bahwa Anda tidak Gunakan. Jika Anda tidak tahu apa itu, bagus.

Lihat "Sistem yang lebih baik untuk pembuatan hierarkis" di makepp untuk detail tentang mengapa Anda tidak mau
gunakan merek rekursif, atau cari di web untuk "pembuatan rekursif dianggap berbahaya".

Alih-alih melakukan make rekursif untuk membuat target "semua" di setiap makefile, itu adalah
biasanya lebih mudah untuk membiarkan makepp mencari tahu target mana yang benar-benar perlu dibangun.
Selanjutnya, jika Anda memasukkan semua .o dan file perpustakaan di direktori yang sama dengan
makefiles, maka makepp akan secara otomatis mencari tahu makefile mana yang juga diperlukan--the
satu-satunya hal yang diperlukan adalah membuat daftar file yang diperlukan tingkat atas Anda
untuk langkah penyambungan terakhir. Lihat contoh di bawah ini.

Satu makefile untuk setiap direktori: dengan implisit pemuatan

Cara paling umum untuk menangani banyak direktori adalah dengan meletakkan makefile di setiap direktori
yang menjelaskan cara membangun semuanya di atau dari direktori itu. Jika Anda menempatkan .o file dalam
direktori yang sama dengan file sumber, lalu pemuatan implisit (lihat "Pemuatan implisit" di
makepp_build_algorithm) secara otomatis akan menemukan semua makefile. Jika Anda menempatkan Anda .o
file dalam direktori yang berbeda (misalnya, dalam subdirektori yang bergantung pada arsitektur), maka Anda
mungkin harus memuat semua makefile yang relevan menggunakan pernyataan "load_makefile".

Berikut adalah contoh makefile tingkat atas untuk hierarki direktori yang menggunakan pemuatan implisit
untuk membangun sebuah program yang terdiri dari banyak perpustakaan bersama (tetapi lihat "Apakah Anda benar-benar membutuhkan a
perpustakaan?" di makepp_cookbook, karena membuat program dari sekumpulan perpustakaan bersama
belum tentu merupakan ide yang bagus):

# Makefile tingkat atas:
program : main.o **/*.la # Tautan di pustaka bersama dari semua subdirektori.
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(masukan) -o $(keluaran) $(LIBS)

Cukup banyak yang Anda butuhkan di makefile tingkat atas. Di setiap subdirektori, Anda
mungkin akan melakukan sesuatu seperti ini:

# Makefile di setiap subdirektori:
sertakan standard_defs.mk # Pencarian ., .., ../ .., dst. sampai
# menemukan file include yang ditunjukkan.
# menimpa beberapa definisi variabel di sini
SPECIAL_FLAGS := -lakukan_sesuatu_berbeda

Setiap makefile mungkin hampir sama jika perintah untuk membangun target
cukup mirip.

Akhirnya, Anda akan memasukkan yang berikut ke dalam standar_defs.mk file (yang mungkin seharusnya
terletak di direktori tingkat atas):

# Pengaturan variabel umum dan aturan pembuatan untuk semua direktori.
CFLAG := -g -O2
INCLUDE_DIR := $(find_upwards termasuk)
# Pencarian ., .., ../ .., dll. untuk file atau
# direktori disebut termasuk, jadi jika Anda meletakkan
# semua file yang Anda sertakan di sana, ini akan
# Temukan mereka.
TERMASUK := -I$(TERMASUK_DIR)

%.lo : %.c
$(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(TERMASUK) -c $(input) -o $(output)

lib$(relative_to ., ..).la: $(only_targets *.lo)
$(LIBTOOL) --mode=tautan $(CC) $(CFLAGS) -o $(output) $(input)
# $(relative_to ., ..) mengembalikan nama saat ini
# subdirektori relatif terhadap tingkat atas
# subdirektori. Jadi jika makefile ini adalah xyz/Makefile,
# aturan ini akan membangun xyz/libxyz.la.

# Publikasikan file sertakan publik ke dalam direktori include tingkat atas:
$(INCLUDE_DIR)/public_%.h : publik_%.h
:build_periksa symlnk
&ln -fr $(masukan) $(keluaran)

Satu makefile untuk setiap direktori: eksplisit pemuatan

Jika Anda ingin meletakkan semua .o file ke dalam subdirektori yang bergantung pada arsitektur, lalu
contoh di atas harus dimodifikasi menjadi seperti ini:

# Makefile tingkat atas:
MAKEFILES := $(wildcard **/Makeppfile) # Daftar semua subdirektori ke
# dapatkan makefile dari.

load_makefile $(MAKEFILES) # Muat semuanya.

include standard_defs.mk # Dapatkan perintah kompilasi untuk main.o.

program : $(ARCH)/main.o */**/$(ARCH)/*.la
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(masukan) -o $(keluaran) $(LIBS)
# */**/$(ARCH) tidak termasuk subdirektori
# $(ARCH), di mana kita tidak ingin membangun
# perpustakaan bersama.

Setiap makefile akan sama persis seperti sebelumnya:

# Makefile di setiap subdirektori:
sertakan standard_defs.mk
# ... penggantian variabel di sini

Dan akhirnya, standar_defs.mk akan berisi sesuatu seperti berikut:

# Pengaturan variabel umum dan aturan pembuatan untuk semua direktori.
ARCH ;= $(Shell uname -s)-$(Shell uname -m)-$(Shell uname -r)
# Terkadang orang hanya menggunakan $(shell uname -m), tapi
# ini akan sama untuk FreeBSD dan Linux di
# sebuah x86. -r tidak terlalu berguna di Linux,
# tetapi penting untuk OS lain: binari untuk
# SunOS 5.8 biasanya tidak akan berjalan di SunOS 5.7.
&mkdir -p $(ARCH) # Pastikan direktori keluaran ada.
CFLAG := -g -O2
INCLUDE_DIR := $(find_upwards termasuk)
# Pencarian ., .., ../ .., dll. untuk file atau
# direktori disebut termasuk, jadi jika Anda meletakkan
# semua file yang Anda sertakan di sana, ini akan
# Temukan mereka.
TERMASUK := -I$(TERMASUK_DIR)

$(ARCH)/%.lo : %.c
$(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(TERMASUK) -c $(input) -o $(output)

$(ARCH)/ lib$(relative_to ., ..).la: $(hanya_target *.lo)
$(LIBTOOL) --mode=tautan $(CC) $(CFLAGS) -o $(output) $(input)
# $(relative_to ., ..) mengembalikan nama saat ini
# subdirektori relatif terhadap tingkat atas
# subdirektori. Jadi jika makefile ini adalah xyz/Makefile,
# aturan ini akan membangun xyz/$(ARCH)/libxyz.la.

# Salin file sertakan publik ke direktori include tingkat atas:
$(INCLUDE_DIR)/public_%.h : publik_%.h
&cp $(masukan) $(keluaran)

Secara otomatis penyusunan itu makefile

Jika makefile Anda semuanya sangat mirip (seperti pada contoh di atas), Anda dapat memberi tahu Makepp
untuk membangunnya secara otomatis jika tidak ada. Cukup tambahkan yang berikut ini ke level teratas Anda
file make:

SUBDIRS := $(filter_out unknown_dir1 unknown_dir2, $(wildcard */**))
$(foreach)/Makeppfile: : foreach $(SUBDIRS)
&echo "include standard_defs.mk" -o $(output)
&echo "_include additional_defs.mk" -o >>$(output)
# Jika file tambahan_defs.mk ada, maka
# akan disertakan, tetapi jika tidak ada,
# pernyataan _include akan diabaikan.

Sekarang makefile sendiri akan dibuat secara otomatis.

Satu makefile hanya at itu puncak tingkat

Jika semua makefile Anda identik, Anda mungkin bertanya: mengapa saya harus memiliki makefile di masing-masing?
tingkat? Mengapa tidak memasukkan semuanya ke dalam makefile tingkat atas?

Ya, ini bisa dilakukan. Kerugian utama adalah menjadi lebih sulit untuk ditentukan
opsi build yang berbeda untuk setiap subdirektori. Kerugian kedua adalah bahwa Anda
makefile mungkin akan menjadi sedikit lebih sulit untuk dibaca.

Berikut ini contoh melakukan hal itu:

# Makefile tingkat atas untuk hierarki direktori. Membangun program
# dari kumpulan pustaka bersama sebagai contoh. (Lihat peringatan di atas
# mengapa Anda mungkin ingin menggunakan penautan tambahan atau lainnya
# pendekatan daripada perpustakaan bersama.)
makepp_percent_subdirs := 1 # Izinkan % untuk mencocokkan beberapa direktori.
SUBDIRS := $(filter_out *CVS* other-unwanted_dirs $(wildcard **))
CFLAG := -g -O2
TERMASUK := -Termasuk

%.lo: %.c
$(LIBTOOL) --mode=compile $(CC) $(TERMASUK) $(CFLAGS) -c $(input) -o $(output)

$(untuk setiap)/ lib$(notdir $(foreach)).la: $(foreach)/*.lo : foreach $(SUBDIRS)
$(LIBTOOL) --mode=tautan $(CC) $(CFLAGS) -o $(output) $(input)
# Aturan untuk membuat semua perpustakaan.

program : main.o**/*.la
$(LIBTOOL) --mode=tautan $(CC) $(CFLAGS) -o $(output) $(input)

include/$(notdir $(foreach)) : $(foreach) : foreach **/public_*.h
&cp $(masukan) $(keluaran)
# Contoh aturan untuk menyalin secara publik
# file .h yang dapat diakses ke tempat yang tepat.

A membersihkan target

Makefile tradisional berisi target bersih, yang memungkinkan menghapus semua yang ada
dibuat. Ada tiga alasan mengapa Anda tidak boleh melakukan ini dengan makepp:

1. Makepp berusaha keras untuk memastikan build yang benar. Jadi putus asa "Saya tidak
tahu apa yang salah", membuat Anda ingin memulai dari awal adalah sesuatu dari masa lalu.

2. Orang kadang-kadang akan mencoba menghemat waktu dengan melakukan dua hal yang bertentangan sekaligus:
"bersihkan semua". Ini dapat membingungkan sistem wildcard pintar makepp, karena akan
dapatkan faktanya terlebih dahulu sebelum melakukan sesuatu. Kemudian datang tindakan bersih, yang tidak
tidak memberi tahu makepp apa yang dilakukannya (memang tidak bisa, karena itu membatalkan sesuatu -- the
bertentangan dengan kegunaan alat build). Kemudian muncul "semua", tetapi file terbaru,
yang di mana ada, hilang secara misterius.

3. Ada perintah "makeppclean", yang melakukan hal yang sama, dan lebih efisien.

Namun demikian, kami mempertahankan bagian sejarah ini, karena bagian ini memberi tahu Anda sesuatu tentang
cara kerja makepp: Target palsu yang disebut "bersih" hanyalah nama untuk serangkaian perintah untuk
hapus semua file yang dihasilkan dari proses make. Biasanya target yang bersih terlihat
sesuatu seperti ini:

$(bersih palsu):
&rm -fm $(wildcard *.o .makepp_log)
# -m dan .makepp_log membuang semua sampah makepp.

Alih-alih secara eksplisit mencantumkan file yang ingin Anda hapus, Anda juga dapat memberi tahu makepp untuk
hapus semua yang diketahui cara membangunnya, seperti ini:

$(bersih palsu):
&rm -fm .makepp_log $(only_targets *)

Ini memiliki keuntungan bahwa jika salah satu file sumber Anda dapat dibuat dari file lain,
mereka akan dihapus juga; di sisi lain, basi .o file (file yang dulunya
buildable tetapi file sumbernya telah dihapus) tidak akan dihapus.

Jika Anda memiliki build yang melibatkan makefile di beberapa direktori berbeda, top-
level makefile dapat mereferensikan target "bersih" (atau target palsu lainnya) dengan cara yang berbeda
file make:

# Makefile tingkat atas
SUBDIRS := sub1 sub2

# buat aturan di sini

# Bersihkan setelah membangun:
$(bersih palsu): $(SUBDIRS)/bersih
&rm -fm .makepp_log $(only_targets *)

Atau, Anda dapat menempatkan target "bersih" Anda hanya di makefile tingkat atas, dan memilikinya
proses semua direktori, seperti ini:

$(bersih palsu):
&rm -fm $(only_targets **/*)

Menggunakan Qt's kekuasaan preprosesor
Contoh ini menunjukkan makefile untuk utilitas yang menggunakan pustaka Qt GUI Nokia (lihat
<http://qt.nokia.com>). Satu-satunya hal yang sedikit tidak biasa tentang ini adalah kamu
harus menjalankan praprosesor yang disebut "moc" pada sebagian besar file ".h" yang berisi definisi widget,
tetapi Anda tidak ingin menjalankan "moc" pada file ".h" yang tidak menggunakan makro "Q_OBJECT".

Secara otomatis menentukan yang arsip perlu kekuasaan arsip

Anda dapat, tentu saja, hanya mencantumkan semua file ".h" yang perlu menjalankan "moc" di dalamnya.
Namun, jika Anda mengembangkan widget baru dengan cepat, mungkin akan mengganggu
terus perbarui daftar di makefile. Anda dapat menyiasati kebutuhan untuk membuat daftar moc
modul secara eksplisit dengan sesuatu seperti ini:

MOC := $(QTDIR)/bin/moc
MODUL:= modul apa pun yang Anda miliki di program Anda
MOC_MODULES := $(patsubst %.h, moc_%, $(&grep -l /Q_OBJECT/ *.h))
# Memindai semua file .h untuk makro Q_OBJECT.

program_saya: $(MODULES).o $(MOC_MODULES).o
$(CXX) $(masukan) -o $(keluaran)

moc_%.cxx: %.h # Membuat file moc dari file .h.
$(MOC) $(masukan) -o $(keluaran)

%.o: %.cxx
$(CXX) $(CXXFLAGS) -c $(masukan) -o $(keluaran)

Pendekatan ini memindai setiap .h file setiap kali makepp dijalankan, mencari
Makro "Q_OBJECT". Ini terdengar mahal, tapi mungkin tidak akan lama. (NS .h
semua file harus dimuat dari disk melalui proses kompilasi, jadi mereka akan
di-cache.)

#include itu .moc fillet

Pendekatan lain adalah dengan "#include" output dari preprocessor "moc" di widget Anda
berkas implementasi. Ini berarti Anda harus ingat untuk menulis "#include", tetapi memiliki
keuntungannya adalah lebih sedikit modul untuk dikompilasi, sehingga kompilasi berjalan lebih cepat.
(Untuk sebagian besar kompilasi C++, sebagian besar waktu dihabiskan untuk membaca file header, dan
output dari praprosesor perlu menyertakan file yang hampir sama banyaknya dengan widget Anda
bagaimanapun.) Misalnya:

// widget_saya.h
class MyWidget : QWidget publik {
Q_OBJEK
// ...
}

// widget_saya.cpp

#sertakan "my_widget.h"
#include "my_widget.moc" // my_widget.moc adalah output dari
// praprosesor moc.
// Hal-hal implementasi lainnya di sini.
MyWidget::MyWidget(QWidget * induk, const char * nama):
QWidget(orang tua, nama)
{
// ...
}

Sekarang Anda perlu memiliki aturan di makefile Anda untuk membuat semua file ".moc", seperti ini:

MOC := $(QTDIR)/bin/moc
# Aturan untuk membuat file .moc:
%.moc: %.h
$(MOC) $(masukan) -o $(keluaran)

Makepp cukup pintar untuk menyadari bahwa ia perlu membuat "my_widget.moc" jika tidak
sudah ada, atau jika sudah ketinggalan zaman.

Pendekatan kedua ini adalah yang biasa saya gunakan karena mempercepat kompilasi.

Penggantian untuk usang membuat idiom
MEMBUAT TUJUAN

Terkadang orang memiliki aturan di makefile mereka tergantung pada target apa yang mereka bangun,
menggunakan variabel khusus "MAKECMDGOALS". Misalnya, seseorang terkadang melihat hal-hal seperti
ini:

ifneq ($(produksi filter, $(MAKECMDGOALS)),)
CFLAG := -O2
lain
CFLAG := -g
endif

Ini akan bekerja dengan baik dengan makepp. Namun, saya sarankan untuk tidak menggunakan "MAKECMDGOALS" untuk itu
kasus (dan begitu juga GNU membuat manual). Anda lebih baik menempatkan Anda dioptimalkan dan
dikompilasi debug .o file di direktori terpisah, atau memberi mereka awalan yang berbeda atau
sufiks, atau menggunakan repositori, untuk memisahkannya.

Mungkin satu-satunya waktu ketika Anda mungkin benar-benar ingin merujuk "MAKECMDGOALS" adalah jika
membutuhkan waktu lama untuk memuat makefile Anda, dan Anda tidak memerlukannya untuk target "bersih" Anda
(tetapi Anda tidak memerlukan target yang bersih). Sebagai contoh,

ifneq ($(MAKECMDGOALS),bersih)
load_makefile $(karakter pengganti **/Makeppfile)
lain
no_implicit_load . # Cegah pemuatan otomatis makefile lainnya.
endif

$(bersih palsu):
&rm -f $(wildcard **/*.o)

Rekursif membuat untuk membangun in berbeda direktori

Lihat "Tips untuk beberapa direktori" di makepp_cookbook.

Rekursif membuat untuk perubahan nilai of a variabel

Beberapa makefile memanggil kembali dirinya sendiri dengan nilai variabel yang berbeda, misalnya, debug
target di fragmen makefile berikut

.PHONY: semua debug

dioptimalkan:
$(BUAT) program CFLAGS=-O2

men-debug:
$(BUAT) program CFLAGS=-g

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

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

Jika pengguna mengetik "make debug", itu membangun program dalam mode default dengan debug diaktifkan
bukannya dengan optimasi.

Cara yang lebih baik untuk melakukannya adalah dengan membangun dua program yang berbeda, dengan dua set yang berbeda
file objek, seperti ini:

CFLAG := -O2
DEBUG_FLAGS := -g
MODUL := ab

program: $(MODUL).o
$(CC) $(CFLAGS) $(masukan) -o $(keluaran)

debug/program: debug/$(MODUL).o
$(CC) $(DEBUG_FLAGS) $(masukan) -o $(keluaran)

%.o : %.c
$(CC) $(CFLAGS) -c $(masukan) -o $(keluaran)

debug/%.o : %.c
$(CC) $(DEBUG_FLAGS) -c $(masukan) -o $(keluaran)

$(debug palsu): debug/program

Keuntungan melakukannya dengan cara ini adalah (a) Anda tidak perlu membangun kembali semuanya saat Anda
beralih dari debug ke dioptimalkan dan kembali lagi; (B)

Di atas dapat ditulis agak lebih ringkas menggunakan repositori. Pengikut
makefile persis sama:

debug repositori=. # Membuat subdirektori debug terlihat seperti salinan dari
# subdirektori saat ini.
load_makefile men-debug CFLAGS=-g
# Ganti CFLAGS saat dipanggil di subdirektori debug
CFLAGS := -O2 # Nilai CFLAGS saat dipanggil di subdirektori ini

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

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

$(debug palsu): debug/program
# Jika pengguna mengetik "makepp debug", build
# debug/program alih-alih program.

bermacam-macam Tips
Seterpercayaapakah Olymp Trade? Kesimpulan do I membangun satu bagian berbeda hanya sekali?

Makepp membuat ini sulit dilakukan karena hasilnya tidak sesuai dengan aturan.
Tetapi ada situasi di mana Anda mungkin memerlukan ini, misalnya untuk mengkompilasi hanya satu modul dengan
informasi debug berat. Anda dapat mencapai ini dalam dua langkah dengan terlebih dahulu membangun
ketergantungan secara terpisah, dan kemudian mengecualikannya dari fase tautan:

makepp DEBUG=3 buggy.o # Bangun dengan opsi lain.
makepp --dont-build=buggy.o buggy # Gunakan, meskipun opsi build "salah".

Seterpercayaapakah Olymp Trade? Kesimpulan do I membuat yakin my keluaran direktori ada?

Anda dapat menentukan aturan untuk membangun direktori keluaran, kemudian pastikan bahwa setiap file yang
berjalan di direktori output tergantung padanya. Tapi biasanya lebih mudah untuk melakukan sesuatu seperti
ini:

#Cara klasik
dummy := $(test shell -d $(OUTPUT_DIRECTORY) || mkdir -p $(OUTPUT_DIRECTORY))
# Ini biasanya lebih mudah daripada membuat semua file bergantung pada
# $(OUTPUT_DIRECTORY) dan memiliki aturan untuk membuatnya.
# Perhatikan bahwa Anda harus menggunakan := alih-alih = untuk memaksanya
# segera eksekusi.
# Pendekatan alternatif: menggunakan kode Perl, OUTPUT_DIRECTORY var lokal
perl_begin
-d $OUTPUT_DIRECTORY atau mkdir $OUTPUT_DIRECTORY;
perl_end
# Cara modern, tidak melakukan apa pun untuk direktori yang ada
&mkdir -p $(OUTPUT_DIRECTORY)

Salah satu pernyataan ini harus berada di dekat bagian atas makefile Anda, sehingga dieksekusi
sebelum apa pun yang mungkin membutuhkan direktori.

Seterpercayaapakah Olymp Trade? Kesimpulan do I kekuatan a Command untuk menjalankan on setiap membangun?

Cara termudah adalah tidak menggunakan mekanisme aturan sama sekali, tetapi cukup menjalankannya, seperti
ini:

dummy := $(tanggal shell > last_build_timestamp)

Atau taruh di blok perl, seperti ini:

perl_begin
system("perintah untuk dieksekusi");
perl_end

Pendekatan ini memiliki kelemahan bahwa itu akan dieksekusi bahkan jika target yang tidak terkait adalah
sedang dijalankan.

Pendekatan kedua adalah mendeklarasikan file tersebut sebagai target palsu, bahkan jika itu adalah file asli.
Ini akan memaksa makepp untuk mengeksekusi ulang perintah untuk membangunnya setiap saat, tetapi hanya jika itu
muncul dalam daftar ketergantungan dari beberapa aturan.

Seterpercayaapakah Olymp Trade? Kesimpulan do I mempersingkat itu ditampilkan membangun perintah?

Seringkali ada begitu banyak opsi untuk mengkompilasi perintah yang ditampilkan di
layar tidak terbaca. Anda dapat mengubah apa yang ditampilkan dengan menekan tampilan
seluruh perintah, dan kemudian secara eksplisit mencetak bagian yang menarik dari perintah. Dia
mudah untuk mencetak hanya bagian yang relevan dari perintah dengan menggunakan "$(filter_out )", seperti
ini:

SEMUA_CFLAGS = $(CFLAGS) $(TERMASUK) $(ADDL_CXX_FLAGS) $(DEBUG_FLAGS)

%.o : %.c
@&echo $(notdir $(CC)) ... \
$(filter_out -I* $(ADDL_CXX_FLAGS), $(ALL_CFLAGS)) \
-c $(masukan)
@$(CC) $(ALL_CFLAGS) -c $(masukan) -o $(keluaran)

("@" di depan perintah menekan pencetakan perintah.)

Ini akan memungkinkan Anda untuk melihat sebagian besar opsi yang menarik tetapi tidak akan menampilkan semua
sertakan direktori (yang seringkali jumlahnya sangat banyak!). Jika bagian yang Anda minati
in bersebelahan dengan perintah Anda, Anda juga dapat menggunakan fungsi "cetak" (yang menambahkan a
baris baru, jadi Anda tidak ingin beberapa di antaranya):

target:
@... $(cetak bagian yang menarik) ...

Seterpercayaapakah Olymp Trade? Kesimpulan do I mengubah a fillet ke ketergantungan?

Untuk beberapa format file yang tidak jelas, tidak ada gunanya menerapkan pemindai. Dalam satu proyek
kami memiliki file xml, katakanlah foobar.xml yang berisi dependensi untuk foobar.keluar:


A
B
C


Kami memutuskan untuk mematuhi tata letak sederhana ini, jadi kami tidak perlu mengurai xml. Dengan
builtin &sed, inilah yang kami lakukan dengan tiga substitusi sederhana untuk tiga jenis
baris:

%.d: %.xml
&sed! !$(batang).keluar: \\! || S! (.+) !$$1 \\! || S! !# Kosong!' \
$(masukan) -o $(keluaran)

termasuk foobar.d

Mencoba memasukkan ini, hasilkan "foobar.d" terlebih dahulu:

foobar.keluar: \
A \
B \
C \
# Kosong

Baris kosong (hanya komentar atau benar-benar kosong) menghindari keharusan khawatir tentang trailing
garis miring terbalik. Alternatif menghasilkan daftar multiline adalah:

%.d: %.xml
&sed! !$(stem).out: \$$((! || s! !))! || s!<.+?>!!g' \
$(masukan) -o $(keluaran)

termasuk foobar.d

Ini menghasilkan setara:

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

Jika Anda memiliki penulisan ulang yang lebih rumit untuk dilakukan, tentukan fungsi di dalam makefile atau di a
modul yang Anda sertakan. Misalnya, undefining $_ akan melewati baris input:

sub filter saya {
kembalikan undef $_ jika /
$batang saya = f_stem;
S! !$stem.out: \$((! || s! !))! || s!<.+?>!!g;
}

%.d: %.xml
&sed! !$(stem).out: \$$((! || s! !))! || s!<.+?>!!g' \
$(masukan) -o $(keluaran)

termasuk foobar.d

Gunakan makepp_cookbook online menggunakan layanan onworks.net


Server & Workstation Gratis

Unduh aplikasi Windows & Linux

Perintah Linux

Ad