EnglishFrenchSpanyol

Ad


Favicon OnWorks

makepp_cookbook - Dalam Talian di Awan

Jalankan makepp_cookbook dalam penyedia pengehosan percuma OnWorks melalui Ubuntu Online, Fedora Online, emulator dalam talian Windows atau emulator dalam talian MAC OS

Ini ialah arahan makepp_cookbook yang boleh dijalankan dalam penyedia pengehosan percuma OnWorks menggunakan salah satu daripada berbilang stesen kerja dalam talian percuma kami seperti Ubuntu Online, Fedora Online, emulator dalam talian Windows atau emulator dalam talian MAC OS.

JADUAL:

NAMA


makepp_cookbook -- Cara terbaik untuk menyediakan makefiles untuk pelbagai situasi

DESCRIPTION


Saya mendapati bahawa secara praktikalnya tiada siapa yang pernah membaca manual untuk alat pembuatan, kerana terus terang
tiada siapa yang benar-benar berminat dengan proses pembuatan itu sendiri--kami hanya berminat dengan hasil.
Jadi buku masakan ini disusun dengan harapan orang ramai akan dapat apa yang mereka perlukan
cepat daripada contoh tanpa mengharungi manual. Ini menunjukkan cara menaip
soalan, manakala arahan pemasangan dan batu penghalang akan ditemui dalam
soalan yang sering diajukan.

Bangunan perpustakaan
Do anda benar-benar perlu a perpustakaan?

Saya telah melihat beberapa program besar yang terdiri daripada sejumlah besar modul, setiap satu
yang tinggal dalam direktorinya sendiri. Lazimnya, setiap direktori dimasukkan ke dalam perpustakaannya sendiri,
dan kemudian program terakhir dipautkan dengan semua perpustakaan.

Dalam banyak kes, saya fikir daripada menggunakan perpustakaan, terdapat pendekatan yang lebih baik. Perpustakaan
bukanlah penyelesaian yang betul jika setiap modul tidak boleh atau tidak akan digunakan semula dalam mana-mana modul lain
program, kerana kemudian anda mendapat semua kelemahan perpustakaan dan tiada satu pun daripadanya
kelebihan. Perpustakaan berguna dalam kes berikut:

1. Apabila anda mempunyai sekumpulan subrutin yang perlu dikaitkan dengan beberapa yang berbeza
program, dan tiada program yang benar-benar menggunakan 100% daripada subrutin--setiap program menggunakan a
subset yang berbeza. Dalam kes ini, mungkin idea yang baik untuk menggunakan perpustakaan statik (a
.a fail, atau fail arkib).

2. Apabila anda mempunyai modul yang harus dipautkan ke beberapa program yang berbeza, dan anda
mahu memuatkannya secara dinamik supaya setiap program tidak perlu mempunyai salinan berasingan
Perpustakaan. Perpustakaan dinamik boleh menjimatkan ruang fail boleh laku dan kadangkala dipertingkatkan
prestasi sistem kerana hanya terdapat satu salinan perpustakaan yang dimuatkan untuk semua
program yang berbeza yang menggunakannya.

3. Apabila masa pautan anda terlalu lama, gunakan perpustakaan kongsi untuk kepingan besar
program ini boleh mempercepatkan pautan dengan ketara.

Menggunakan perpustakaan statik mempunyai satu kelemahan utama: pada beberapa sistem (cth Linux), susunannya
di mana anda memautkan perpustakaan adalah sangat penting. Penghubung memproses perpustakaan
dalam susunan yang dinyatakan pada baris arahannya. Ia merebut semua yang difikirkannya diperlukan
setiap perpustakaan, kemudian beralih ke perpustakaan seterusnya. Jika beberapa perpustakaan berikutnya merujuk kepada a
simbol yang belum lagi digabungkan daripada perpustakaan sebelumnya, pemaut tidak
tahu untuk kembali dan ambil dari perpustakaan sebelumnya. Akibatnya, ia mungkin perlu
untuk menyenaraikan perpustakaan beberapa kali pada baris arahan pemaut. (Saya bekerja pada projek
di mana kami terpaksa mengulang keseluruhan senarai perpustakaan tiga kali. Projek ini yang dibuat
saya lebih suka pendekatan alternatif yang dicadangkan di bawah, iaitu pemautan tambahan.)

Menggunakan perpustakaan dinamik mempunyai beberapa kelemahan. Pertama, program anda boleh sedikit
lebih perlahan untuk dimulakan jika perpustakaan belum lagi digunakan oleh beberapa program lain, kerana
ia perlu dicari dan dimuatkan. Kedua, ia boleh menjadi kerumitan sebenar untuk mendapatkan semua dinamik
perpustakaan dipasang di lokasi yang betul; anda tidak boleh hanya menyalin program boleh laku,
anda juga perlu memastikan bahawa anda menyalin semua perpustakaannya. Ketiga, pada beberapa sistem, ia
sukar untuk menyahpepijat kod di dalam perpustakaan kongsi kerana penyahpepijat tidak menyokong
mereka dengan baik.

Jika modul anda tidak akan digunakan dalam mana-mana program lain, maka terdapat sedikit sebab untuk digunakan
perpustakaan: anda mendapat semua keburukan menggunakan perpustakaan dan tiada satu pun kelebihan.
Teknik yang saya suka ialah menggunakan pemautan tambahan, di mana ia tersedia.

Inilah cara anda boleh melakukannya di Linux:

my_module.o : $(filter_out my_module.o, $(wildcard *.o))
ld -r -o $(output) $(inputs)

Perkara ini akan lakukan ialah mencipta satu lagi .o fail dipanggil my_module.o, yang akan terdiri daripada
semua .o fail dalam subdirektori ini. Penghubung akan menyelesaikan seberapa banyak
rujukan yang boleh, dan akan meninggalkan rujukan yang tinggal untuk diselesaikan dalam a
peringkat penghubung yang seterusnya. Di peringkat atas, apabila anda akhirnya membina program anda,
bukannya menghubungkan dengan libmy_module.a or libmy_module.so, anda hanya akan memautkan dengan
my_module.o. Apabila anda memaut .o fail, anda tidak menghadapi masalah dengan kebergantungan pesanan dalam fail
baris arahan penghubung.

Membiarkan makepp memikirkan keluar yang perpustakaan modul adalah diperlukan

Walaupun anda mempunyai perpustakaan sebenar, di mana program tertentu memerlukan hanya beberapa fail daripadanya
(daripada setiap modul tunggal), makepp mungkin dapat mengetahui modul yang mana
diperlukan daripada perpustakaan dan masukkan hanya yang dalam binaan. Ini boleh menjimatkan kompilasi
masa jika anda membangunkan perpustakaan bersama-sama dengan program, kerana anda tidak mengganggu
susun modul perpustakaan yang tidak diperlukan untuk program tertentu yang anda sedang kerjakan.

Jika perpustakaan anda mematuhi konvensyen yang diisytiharkan oleh semua fungsi atau kelas
fail xyz.h dilaksanakan sepenuhnya dalam fail sumber yang dikompil ke xyz.o (iaitu, awak
jangan pecahkan pelaksanaannya xyz1.o and xyz2.o), maka anda boleh menggunakan
"$(infer_objects)" berfungsi untuk memberitahu makepp untuk mengeluarkan hanya modul yang berkaitan daripada
perpustakaan. Ini boleh berfungsi dengan baik untuk perpustakaan dengan berpuluh-puluh fail termasuk.
Pada asasnya, "$(infer_objects)" meneliti senarai .h fail yang disertakan, dan rupa
untuk sepadan .o fail. Jika anda sedang membangunkan perpustakaan dan program dengan pantas
bersama-sama, ini boleh menjimatkan masa penyusunan, kerana anda tidak pernah mengganggu untuk menyusun modul
perpustakaan yang tidak digunakan oleh program.

Berikut ialah contoh cara saya menggunakannya:

my_program: $(infer_objects *.o, $(LIB1)/*.o $(LIB2)/*.o)
$(CXX) $(input) -o $(output) $(SYSTEM_LIBRARIES)

Fungsi "$(infer_objects )" mengembalikan hujah pertamanya (selepas melakukan kad bebas
pengembangan padanya), dan juga melihat senarai fail dalam hujah kedua, untuk
fail yang namanya sama dengan nama mana-mana .h fail yang disertakan oleh mana-mana fail yang pertama
hujah. Jika mana-mana fail sedemikian ditemui, ini akan ditambahkan pada senarai.

Bangunan a statik perpustakaan

Jika anda pasti anda benar-benar memerlukan perpustakaan dan pemautan tambahan tidak tersedia atau
bukan apa yang anda mahu lakukan, terdapat beberapa cara untuk melakukannya. Pertama, berikut adalah contoh
di mana semua fail disenaraikan secara eksplisit:

LIBRARY_FILES = abcde

libmine.a: $(LIBRARY_FILES).o
&rm -f $(output)
$(AR) cr $(output) $(input)
ranlib $(output) # Mungkin tidak diperlukan, bergantung pada OS anda.

&rm ialah arahan "rm" terbina dalam makepp. Jika anda biasa menulis makefiles, anda mungkin begitu
sedikit terkejut dengan arahan ini; anda mungkin terbiasa dengan sesuatu yang lebih seperti ini:

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

mana $? (juga dikenali sebagai "$(changed_inputs)") ialah pembolehubah automatik yang bermaksud sebarang fail
yang telah berubah sejak kali terakhir perpustakaan dibina, dan $@ adalah lebih kurang sama
sebagai "$(output)".

Pendekatan ini tidak disyorkan untuk beberapa sebab:

· Katakan anda mengalih keluar fail sumber daripada direktori semasa. Ia masih dalam
perpustakaan, kerana anda tidak membina semula perpustakaan dari awal. Akibatnya, apa sahaja
bahawa pautan dengan perpustakaan ini akan menjadi basi .o fail, dan itu boleh merosakkan anda
membina. (Saya pernah keliru dengan perkara ini apabila saya cuba mengalih keluar kod mati
daripada projek: Saya terus memadam fail dan ia masih dipautkan, jadi saya fikir kod itu
mati. Walau bagaimanapun, apabila orang lain membina semula projek itu dari awal, ia tidak memautkan mana-mana
lagi! Masalahnya ialah yang lama .o fail masih dalam arkib.)

Juga, bergantung pada pilihan anda untuk "ar" dan pelaksanaan "ar" anda (cth, jika anda
gunakan pilihan "q" dan bukannya "r"), anda boleh mempunyai beberapa versi
sama .o di dalam .a fail. Jika versi yang berbeza mentakrifkan global yang berbeza, the
penghubung boleh cuba menarik kedua-duanya. Ini mungkin perkara yang tidak baik.

Inilah sebabnya kami mula-mula mengalih keluar fail perpustakaan, dan menciptanya dari awal. Ini akan
mengambil sedikit masa lebih lama daripada hanya mengemas kini modul dalam perpustakaan, tetapi tidak lebih lama; pada
komputer moden, jumlah masa yang digunakan oleh ar program adalah sangat kecil berbanding
tentang perkara yang digunakan oleh pengkompil C dalam binaan biasa, jadi ia tidak patut dibimbangkan
mengenai.

· Salah satu cara makepp cuba menjamin binaan yang betul ialah ia akan melakukannya
bina semula secara automatik jika baris arahan untuk membina sasaran yang diberikan telah berubah. Tetapi
menggunakan $? pembolehubah boleh menyebabkan masalah, kerana setiap kali perpustakaan dikemas kini,
arahan bina adalah berbeza. (Anda boleh menyekat ini menggunakan
":build_check ignore_action"; lihat makepp_build_check untuk butiran.)

· Mengemas kini arkib dan bukannya membina semula ia akan menyebabkan makepp tidak dapat melakukannya
letakkan fail dengan betul ke dalam cache binaan (lihat makepp_build_cache untuk butiran).

Kadangkala anda mungkin mendapati penyenaraian semua fail agak menyakitkan, terutamanya jika a
projek sedang mengalami pembangunan pesat dan senarai fail sentiasa berubah. Ia
mungkin lebih mudah untuk membina perpustakaan menggunakan kad bebas, seperti ini:

libmine.a: $(only_targets *.o)
&rm $(output)
$(AR) cr $(output) $(input)

Ini meletakkan semua .o fail dalam direktori semasa ke dalam perpustakaan. Kad bebas
sepadan dengan mana-mana .o fail yang wujud atau boleh dibina, jadi ia akan berfungsi walaupun fail tidak
wujud lagi.

Fungsi "only_targets" digunakan untuk mengecualikan .o fail yang tidak mempunyai yang sepadan
fail sumber lagi. Katakan anda mempunyai fail yang dipanggil xyz.c yang pernah anda masukkan ke dalam anda
perpustakaan. Ini bermakna terdapat satu xyz.o fail bergelimpangan. Sekarang anda memadam xyz.c
kerana ia sudah usang, tetapi anda terlupa untuk memadam xyz.o. Tanpa "sasaran_sahaja"
fungsi, xyz.o masih akan dimasukkan dalam senarai .o fail yang dimasukkan ke dalam perpustakaan.

Bangunan a dinamik perpustakaan

Proses membina perpustakaan dinamik bergantung sepenuhnya kepada sistem. Saya akan sangat
mengesyorkan menggunakan libtool untuk membina perpustakaan dinamik (lihat
<http://www.gnu.org/software/libtool/>), jadi anda tidak perlu memikirkan cara untuk melakukannya
platform anda, dan supaya fail make anda akan terus berfungsi walaupun anda bertukar kepada a
OS yang berbeza. Lihat dokumentasi libtool untuk butiran. Berikut ialah contoh Makefile:

LIBTOOL := libtool

libflick.la : $(only_targets *.lo)
$(LIBTOOL) --mode=pautan $(CC) $(input) -o $(output)

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

Bangunan on beberapa berbeza mesin or rangkaian
Salah satu masalah yang paling menjengkelkan dengan makefiles ialah ia hampir tidak pernah berfungsi apabila anda
beralih ke mesin lain atau rangkaian lain. Jika makefiles anda perlu berfungsi
setiap mesin yang mungkin di planet ini, maka anda mungkin memerlukan beberapa jenis konfigurasi
skrip. Tetapi jika anda hanya perlu bekerja pada beberapa mesin yang berbeza, terdapat beberapa cara
anda boleh mendekati masalah ini:

Penggunaan a berbeza termasuk fail in semua yang persekitaran

Pada permulaan setiap makefile, anda boleh memasukkan baris seperti ini:

sertakan system_defs.mk

Fail system_defs.mk biasanya akan ditempatkan di tempat yang berbeza untuk setiap satu
persekitaran. Jika anda mahu direktori binaan anda sama pada semua mesin, kemudian letakkan
system_defs.mk dalam direktori di atas direktori binaan, atau berikan laluan sertakan
untuk makepp menggunakan pilihan baris arahan "-I".

Ini biasanya agak menyakitkan untuk dilakukan, tetapi ia berfungsi dengan baik jika terdapat sejumlah besar
perbezaan.

Penggunaan if kenyataan

Ini adalah cara paling hodoh untuk melakukannya, tetapi ia biasanya akan berfungsi.

ifsys i386
CC := gcc
lain ifsys sun4u
CC := cc
lain ifsys hpux11
CC = c89
ENDIF

Jika semua yang anda perlu lakukan ialah mencari beberapa program atau perpustakaan atau memasukkan fail dalam yang berbeza
tempat, mungkin ada cara yang lebih baik (lihat di bawah).

program_cari, first_available, findfile

Fungsi ini boleh mencari pelbagai direktori berbeza dalam sistem anda untuk mencari
fail yang sesuai. Ini tidak sekuat skrip konfigurasi, sudah tentu, tetapi saya dapati ia
berguna. Sebagai contoh, saya melakukan perkara berikut:

CXX ;= $(find_program g++ c++ pg++ cxx CC aCC)
# Pilih pengkompil C++ pertama yang tersedia dalam PATH.
# (Secara kebetulan, jika anda tidak mentakrifkan CXX sama sekali, ini
# ialah cara ia ditakrifkan.)
TCL_INCLUDE ;= -I$(dir_noslash $(cari fail 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 dalam setiap yang ditunjukkan
# direktori dan mengembalikan laluan penuh. Ini kemudian
# ditukar menjadi pilihan kompilasi dengan menanggalkan
# nama fail (meninggalkan direktori) dan awalan dengan -I.
%.o : %.cpp
$(CXX) $(CXXFLAGS) $(TCL_INCLUDE) $(input) -o $(output)

TCL_LIB ;= $((first_available
/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))
# Cari di mana perpustakaan Tcl berada. Ini kemudiannya secara eksplisit
# disenaraikan pada arahan pautan:
my_program : *.o
$(CXX) $(CXXFLAGS) $(input) -o $(output) $(TCL_LIB)

Mengambil kelebihan of Perl's config maklumat

Teknik di atas mungkin tidak mencukupi jika anda memerlukan beberapa maklumat tambahan tentang
sistem anda, seperti sama ada berganda panjang wujud, atau apakah susunan bait itu. Walau bagaimanapun,
perl telah mengira perkara ini, jadi anda boleh menggunakan jawapannya.

Skrip autokonfigurasi Perl menjadikan semua maklumat konfigurasinya tersedia melalui
cincang %Config. Tiada sintaks untuk mengakses cincang Perl secara langsung dalam makepp, tetapi anda boleh
jatuh ke dalam Perl dan tetapkan pembolehubah skalar, yang boleh diakses secara langsung daripada makepp:

perl_begin
# Ambil nilai daripada cincang konfigurasi.
gunakan Config;
$CC = $Config{'cc'}; # C pengkompil 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

Selain itu, sebaik sahaja anda telah melakukan 'use Config', anda boleh menggunakan pernyataan "$(perl )", seperti
ini:

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

Taip "perldoc Config" untuk melihat maklumat yang tersedia melalui cincang %Config.

Konfigurasi Perl ialah tempat yang baik untuk mendapatkan perkara seperti maklumat tentang jenis integer, bait
pesanan, dan perkara lain yang biasanya memerlukan skrip konfigurasi berasingan untuk dicari. Sebahagian daripada
maklumatnya yang berkaitan dengan kehadiran perkara dalam sistem fail mungkin tidak
sah. Sebagai contoh, $Config{'cc'} merujuk kepada pengkompil C yang perl dibina dengannya,
yang mungkin bukan pengkompil C yang sama yang anda mahu gunakan. Malah, ia mungkin tidak wujud
pada sistem anda, kerana anda mungkin memasang Perl melalui pakej binari.

Tips Untuk menggunakan kad bebas
Pemadanan semua fail kecuali a tertentu subset

Kad bebas Makepp tidak mempunyai sebarang cara pada masa ini untuk memadankan semua fail kecuali sesetengah
ditetapkan, tetapi anda boleh melakukannya dengan gabungan fungsi.

Sebagai contoh, katakan anda mempunyai program ujian untuk setiap modul dalam perpustakaan, tetapi anda tidak
ingin memasukkan program ujian di perpustakaan. Jika semua program ujian bermula dengan
ujian, maka anda boleh mengecualikan mereka seperti ini:

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

Fungsi "$(filter )" dan "$(filter_out )" ialah set penapis yang sangat berkuasa untuk dilakukan
semua jenis set persilangan dan operasi perbezaan. Sebagai contoh,

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

$(filter $(patsubst test_dir/test_%.o, %.o, $(wildcard test_dir/*.o)), \
$(wildcard *.o))
# Mengembalikan senarai fail .o dalam semasa
# direktori yang terdapat padanannya
# test_*.o fail dalam subdirektori test_dir.
$(filter_out $(patsubst man/man3/%.3, %.o, $(wildcard man/man3/*.3)), \
$(wildcard *.o))
# Mengembalikan senarai fail .o dalam semasa
# direktori yang tiada halaman manual
# dengan nama fail yang sama dalam subdirektori man/man3.

Menggunakan yang "$(sasaran_sahaja )" fungsi kepada menghapuskan sentiasa .o fail

Katakan anda sedang membina program atau perpustakaan dengan arahan binaan seperti ini:

program: *.o
$(CC) $(input) -o $(output)

Katakan anda kini memadamkan fail sumber. Jika anda terlupa untuk memadam yang sepadan .o fail,
ia masih akan dipautkan walaupun tiada cara untuk membinanya lagi. Di dalam
masa depan, makepp mungkin akan mengenali situasi ini secara automatik dan mengecualikannya daripada
senarai kad bebas, tetapi pada masa ini, anda perlu memberitahunya untuk mengecualikannya secara manual:

program: $(only_targets *.o)
$(CC) $(input) -o $(output)

Makepp tidak tahu apa-apa cara untuk membina basi .o fail lagi kerana fail sumbernya ialah
hilang, jadi fungsi "$(only_targets )" akan mengecualikannya daripada senarai kebergantungan.

Tips Untuk pelbagai direktori
Salah satu sebab utama menulis makepp adalah untuk memudahkan pengendalian berbilang
direktori. Makepp dapat menggabungkan arahan binaan daripada berbilang fail make, jadi ia boleh
berurusan dengan betul dengan peraturan dalam satu makefile yang bergantung pada fail yang dibina oleh a
makefile berbeza.

Servis kepada do in tempat of rekursif membuat

Makepp menyokong make rekursif untuk keserasian ke belakang, tetapi ia sangat disyorkan
bahawa anda tidak gunakannya. Jika anda tidak tahu apa itu, bagus.

Lihat "Sistem yang lebih baik untuk binaan hierarki" dalam makepp untuk mendapatkan butiran tentang sebab anda tidak mahu melakukannya
gunakan rekursif make, atau cari di web untuk "recursive make dianggap berbahaya".

Daripada membuat rekursif untuk menjadikan sasaran "semua" dalam setiap fail buatan, ia adalah
biasanya lebih mudah untuk membiarkan makepp memikirkan sasaran yang sebenarnya perlu dibina.
Tambahan pula, jika anda meletakkan semua anda .o dan fail perpustakaan dalam direktori yang sama dengan
makefiles, maka makepp secara automatik akan mengetahui makefiles mana yang diperlukan juga--the
Satu-satunya perkara yang diperlukan ialah minta peringkat atasan anda menyenaraikan fail yang diperlukan
untuk langkah penghubung akhir. Lihat contoh di bawah.

satu makefile Untuk setiap direktori: bersama tersirat loading

Cara paling biasa untuk mengendalikan berbilang direktori ialah meletakkan fail make dalam setiap direktori
yang menerangkan cara membina segala-galanya di dalam atau daripada direktori itu. Jika anda meletakkan .o gambar dalam
direktori yang sama dengan fail sumber, kemudian pemuatan tersirat (lihat "Pemuatan tersirat" dalam
makepp_build_algorithm) secara automatik akan mencari semua makefiles. Jika anda meletakkan anda .o
fail dalam direktori yang berbeza (cth, dalam subdirektori yang bergantung kepada seni bina), kemudian anda
mungkin perlu memuatkan semua makefiles yang berkaitan menggunakan pernyataan "load_makefile".

Berikut ialah contoh makefile peringkat atas untuk hierarki direktori yang menggunakan pemuatan tersirat
untuk membina program yang terdiri daripada banyak perpustakaan kongsi (tetapi lihat "Adakah anda benar-benar memerlukan a
perpustakaan?" dalam makepp_cookbook, kerana membuat program daripada sekumpulan perpustakaan kongsi
tidak semestinya idea yang baik):

# Makefile peringkat atas:
program : main.o **/*.la # Pautan dalam perpustakaan kongsi daripada semua subdirektori.
$(LIBTOOL) --mode=pautan $(CC) $(CFLAGS) $(input) -o $(output) $(LIBS)

Itu sahaja yang anda perlukan dalam makefile peringkat atas. Dalam setiap subdirektori, anda
mungkin akan melakukan sesuatu seperti ini:

# Makefile dalam setiap subdirektori:
sertakan standard_defs.mk # Carian ., .., ../ .., dan lain-lain sehingga ia
# mencari fail termasuk yang ditunjukkan.
# mengatasi beberapa definisi berubah di sini
BENDERA_KHAS := -buat_sesuatu_berbeza

Setiap makefile mungkin hampir sama jika arahan untuk membina sasaran
agak serupa.

Akhirnya, anda akan meletakkan yang berikut ke dalam standard_defs.mk fail (yang sepatutnya
terletak dalam direktori peringkat atasan):

# Tetapan pembolehubah biasa dan peraturan bina untuk semua direktori.
CFLAGS := -g -O2
INCLUDE_DIR := $(find_upwards termasuk)
# Carian ., .., ../ .., dsb. untuk fail atau
# direktori dipanggil termasuk, jadi jika anda meletakkan
# semua fail anda sertakan di sana, ini akan
# cari mereka.
TERMASUK := -I$(INCLUDE_DIR)

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

lib$(relative_to ., ..).la: $(only_targets *.lo)
$(LIBTOOL) --mode=pautan $(CC) $(CFLAGS) -o $(output) $(input)
# $(relative_to ., ..) mengembalikan nama semasa
# subdirektori relatif kepada peringkat atas
# subdirektori. Jadi jika makefile ini ialah xyz/Makefile,
# peraturan ini akan membina xyz/libxyz.la.

# Terbitkan fail termasuk awam ke dalam direktori termasuk peringkat teratas:
$(INCLUDE_DIR)/public_%.h : public_%.h
:build_check symlnk
&ln -fr $(input) $(output)

satu makefile Untuk setiap direktori: jelas loading

Jika anda ingin meletakkan semua anda .o fail ke dalam subdirektori yang bergantung kepada seni bina, kemudian
contoh di atas harus diubah suai menjadi seperti ini:

# Makefile peringkat atas:
MAKEFILES := $(wildcard **/Makeppfile) # Senarai semua subdirektori ke
# dapatkan makefiles daripada.

load_makefile $(MAKEFILES) # Muatkan kesemuanya.

sertakan standard_defs.mk # Dapatkan arahan penyusun untuk main.o.

atur cara : $(ARCH)/main.o */**/$(ARCH)/*.la
$(LIBTOOL) --mode=pautan $(CC) $(CFLAGS) $(input) -o $(output) $(LIBS)
# */**/$(ARCH) mengecualikan subdirektori
# $(ARCH), di mana kita tidak mahu membina
# perpustakaan kongsi.

Setiap makefile akan sama seperti sebelumnya:

# Makefile dalam setiap subdirektori:
sertakan standard_defs.mk
# ... tukar ganti di sini

Dan akhirnya, standard_defs.mk akan mengandungi sesuatu seperti berikut:

# Tetapan pembolehubah biasa dan peraturan bina untuk semua direktori.
ARCH ;= $(shell uname -s)-$(shell uname -m)-$(shell uname -r)
# Kadangkala orang hanya menggunakan $(shell uname -m), tetapi
# ini akan menjadi sama untuk FreeBSD dan Linux pada
# x86. The -r tidak begitu berguna pada Linux,
# tetapi penting untuk OS lain: binari untuk
# SunOS 5.8 biasanya tidak akan berjalan pada SunOS 5.7.
&mkdir -p $(ARCH) # Pastikan direktori output wujud.
CFLAGS := -g -O2
INCLUDE_DIR := $(find_upwards termasuk)
# Carian ., .., ../ .., dsb. untuk fail atau
# direktori dipanggil termasuk, jadi jika anda meletakkan
# semua fail anda sertakan di sana, ini akan
# cari mereka.
TERMASUK := -I$(INCLUDE_DIR)

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

$(ARCH)/ lib$(relative_to ., ..).la: $(only_targets *.lo)
$(LIBTOOL) --mode=pautan $(CC) $(CFLAGS) -o $(output) $(input)
# $(relative_to ., ..) mengembalikan nama semasa
# subdirektori relatif kepada peringkat atas
# subdirektori. Jadi jika makefile ini ialah xyz/Makefile,
# peraturan ini akan membina xyz/$(ARCH)/libxyz.la.

# Salin fail termasuk awam ke dalam direktori termasuk peringkat teratas:
$(INCLUDE_DIR)/public_%.h : public_%.h
&cp $(input) $(output)

Secara automatik membuat yang makefiles

Jika fail make anda semuanya sangat serupa (seperti dalam contoh di atas), anda boleh memberitahu Makepp
untuk membinanya secara automatik jika ia tidak wujud. Cuma tambahkan yang berikut pada peringkat teratas anda
makefile:

SUBDIRS := $(filter_out unwanted_dir1 unwanted_dir2, $(wildcard */**))
$(foreach)/Makeppfile: : foreach $(SUBDIRS)
&echo "include standard_defs.mk" -o $(output)
&echo "_include additional_defs.mk" -o >>$(output)
# Jika fail additional_defs.mk wujud, maka
# ia akan disertakan, tetapi jika ia tidak wujud,
# pernyataan _include akan diabaikan.

Kini makefiles itu sendiri akan dibina secara automatik.

satu makefile hanyalah at yang bahagian tahap

Jika semua fail make anda adalah sama, anda mungkin bertanya: mengapa saya perlu mempunyai fail make pada setiap satu
tahap? Mengapa tidak meletakkan semua itu ke dalam makefile peringkat atas?

Ya, ini boleh dilakukan. Kelemahan utama ialah ia menjadi lebih sukar untuk ditentukan
pilihan binaan yang berbeza untuk setiap subdirektori. Kelemahan kedua ialah anda
makefile mungkin akan menjadi lebih sukar untuk dibaca.

Berikut ialah contoh melakukan perkara itu:

# Makefile peringkat atas untuk hierarki direktori. Membina program
# daripada set perpustakaan kongsi sebagai contoh. (Lihat kaveat di atas
# sebab anda mungkin mahu menggunakan pemautan tambahan atau yang lain
# pendekatan dan bukannya perpustakaan kongsi.)
makepp_percent_subdirs := 1 # Benarkan % untuk memadankan berbilang direktori.
SUBDIRS := $(filter_out *CVS* other-unwanted_dirs $(wildcard **))
CFLAGS := -g -O2
TERMASUK := -Iincludes

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

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

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

termasuk/$(notdir $(foreach)): $(foreach) : foreach **/public_*.h
&cp $(input) $(output)
# Contoh peraturan untuk menyalin secara terbuka
# fail .h boleh diakses ke tempat yang betul.

A membersihkan sasaran

Makefiles tradisional mengandungi sasaran yang bersih, yang membolehkan mengalih keluar semua yang ada
dibina. Terdapat tiga sebab mengapa anda tidak sepatutnya melakukan ini dengan makepp:

1. Makepp berusaha keras untuk memastikan binaan yang betul. Jadi yang terdesak "Saya tidak
tahu apa yang salah", membuat anda ingin bermula dari awal adalah perkara yang sudah berlalu.

2. Orang kadang-kadang akan cuba menjimatkan masa dengan melakukan dua perkara yang bercanggah sekaligus:
"buat bersih semua". Ini boleh mengelirukan sistem kad bebas pintar makepp, kerana ia akan
dapatkan fakta dahulu sebelum melakukan sesuatu. Kemudian datang tindakan bersih, yang berlaku
tidak memberitahu makepp apa yang dilakukannya (memang ia tidak boleh, kerana ia membatalkan sesuatu -- the
bertentangan dengan kegunaan alat binaan). Kemudian datang "semua", tetapi fail terkini,
yang mana ada, hilang secara misteri.

3. Terdapat arahan "makeppclean", yang melakukan perkara yang sama, dan lebih cekap.

Walau bagaimanapun, kami mengekalkan bahagian sejarah ini, kerana ia memberitahu anda sesuatu tentang
cara makepp berfungsi: Sasaran palsu yang dipanggil "bersih" hanyalah nama untuk set perintah
alih keluar semua fail yang terhasil daripada proses pembuatan. Biasanya sasaran bersih kelihatan
sesuatu seperti ini:

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

Daripada menyenaraikan fail yang ingin anda padamkan secara eksplisit, anda juga boleh memberitahu makepp
alih keluar semua yang ia tahu bagaimana untuk membina, seperti ini:

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

Ini mempunyai kelebihan jika mana-mana fail sumber anda boleh dibina daripada fail lain,
ia juga akan dipadamkan; sebaliknya, basi .o fail (fail yang dahulunya
boleh dibina tetapi fail sumbernya telah dialih keluar) tidak akan dipadamkan.

Jika anda mempunyai binaan yang melibatkan makefiles dalam beberapa direktori berbeza, teratas anda
level makefile boleh merujuk sasaran "bersih" (atau mana-mana sasaran palsu lain) dalam yang berbeza
makefile:

# Makefile peringkat atas
SUBDIRS := sub1 sub2

# bina peraturan di sini

# Bersihkan selepas binaan:
$(palsu bersih): $(SUBDIRS)/bersih
&rm -fm .makepp_log $(sasaran_sahaja *)

Sebagai alternatif, anda boleh meletakkan sasaran "bersih" anda hanya dalam makefile peringkat atas, dan memilikinya
proses semua direktori, seperti ini:

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

Menggunakan Qt's kuasa prapemproses
Contoh ini menunjukkan fail make untuk utiliti yang menggunakan perpustakaan Qt GUI Nokia (lihat
<http://qt.nokia.com>). Satu-satunya perkara yang agak luar biasa tentang perkara ini ialah anda
mesti menjalankan prapemproses yang dipanggil "moc" pada kebanyakan fail ".h" yang mengandungi definisi widget,
tetapi anda tidak mahu menjalankan "moc" pada mana-mana fail ".h" yang tidak menggunakan makro "Q_OBJECT".

Secara automatik menentukan yang fail perlu kuasa fail

Anda boleh, sudah tentu, hanya menyenaraikan semua ".h" fail yang perlu mempunyai "moc" dijalankan pada mereka.
Walau bagaimanapun, jika anda sedang membangunkan widget baharu dengan pantas, ia mungkin sesuatu yang mengganggu
teruskan mengemas kini senarai dalam makefile. Anda boleh mendapatkan sekitar keperluan untuk menyenaraikan moc
modul secara eksplisit dengan sesuatu seperti ini:

MOC := $(QTDIR)/bin/moc
MODUL := apa sahaja modul yang anda ada dalam program anda
MOC_MODULES := $(patsubst %.h, moc_%, $(&grep -l /Q_OBJECT/ *.h))
# Mengimbas semua fail .h untuk makro Q_OBJECT.

my_program: $(MODULES).o $(MOC_MODULES).o
$(CXX) $(input) -o $(output)

moc_%.cxx: %.h # Membuat fail moc daripada fail .h.
$(MOC) $(input) -o $(output)

%.o: %.cxx
$(CXX) $(CXXFLAGS) -c $(input) -o $(output)

Pendekatan ini mengimbas setiap anda .h fail setiap kali makepp dijalankan, mencari fail
Makro "Q_OBJECT". Ini kedengaran mahal, tetapi ia mungkin tidak akan mengambil masa yang lama. (The .h
fail semua perlu dimuatkan dari cakera juga oleh proses penyusunan, jadi mereka akan melakukannya
dicache.)

#include yang .moc fail

Pendekatan lain ialah "#include" output daripada prapemproses "moc" dalam widget anda
fail pelaksanaan. Ini bermakna anda perlu ingat untuk menulis "#include", tetapi ada
kelebihan bahawa terdapat lebih sedikit modul untuk disusun, jadi penyusunan berjalan lebih cepat.
(Untuk kebanyakan kompilasi C++, sebahagian besar masa dihabiskan untuk membaca fail pengepala, dan
output daripada prapemproses perlu memasukkan hampir sama banyak fail dengan widget anda
bagaimanapun.) Contohnya:

// my_widget.h
kelas MyWidget : QWidget awam {
Q_OBJECT
// ...
}

// my_widget.cpp

#include "my_widget.h"
#include "my_widget.moc" // my_widget.moc ialah output daripada
// prapemproses moc.
// Perkara pelaksanaan lain di sini.
MyWidget::MyWidget(QWidget * induk, const char * nama):
QWidget(ibu bapa, nama)
{
// ...
}

Kini anda perlu mempunyai peraturan dalam fail make anda untuk membuat semua fail ".moc", seperti ini:

MOC := $(QTDIR)/bin/moc
# Peraturan untuk membuat fail .moc:
%.moc: %.h
$(MOC) $(input) -o $(output)

Makepp cukup bijak untuk menyedari bahawa ia perlu membuat "my_widget.moc" jika tidak
sudah wujud, atau jika ia sudah lapuk.

Pendekatan kedua ini adalah yang biasa saya gunakan kerana ia mempercepatkan penyusunan.

Penggantian Untuk deprecated membuat idiom
MAKECMDGOALS

Kadang-kadang orang mempunyai peraturan dalam makefile mereka bergantung pada sasaran yang mereka bina,
menggunakan pembolehubah khas "MAKECMDGOALS". Sebagai contoh, seseorang kadang-kadang melihat perkara seperti
ini:

ifneq ($(pengeluaran penapis, $(MAKECMDGOALS)),)
CFLAGS := -O2
lagi
CFLAGS := -g
ENDIF

Ini akan berfungsi dengan baik dengan makepp. Walau bagaimanapun, saya mengesyorkan untuk tidak menggunakan "MAKECMDGOALS" untuk itu
kes (dan begitu juga manual membuat GNU). Anda lebih baik meletakkan dioptimumkan dan
debug-compile .o fail dalam direktori berasingan, atau memberi mereka awalan yang berbeza atau
akhiran, atau menggunakan repositori, untuk memisahkannya.

Mungkin satu-satunya masa anda sebenarnya ingin merujuk "MAKECMDGOALS" adalah jika ia
mengambil masa yang lama untuk memuatkan fail make anda, dan anda tidak memerlukannya untuk sasaran "bersih" anda
(tetapi anda tidak memerlukan sasaran yang bersih). Sebagai contoh,

ifneq ($(MAKECMDGOALS),bersih)
load_makefile $(wildcard **/Makeppfile)
lagi
tiada_beban_implisit . # Cegah pemuatan automatik mana-mana fail buatan lain.
ENDIF

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

Rekursif membuat kepada membina in berbeza direktori

Lihat "Petua untuk berbilang direktori" dalam makepp_cookbook.

Rekursif membuat kepada menukar nilai of a berubah-ubah

Sesetengah makefiles memanggil semula diri mereka sendiri dengan nilai pembolehubah yang berbeza, contohnya, nyahpepijat
sasaran dalam serpihan makefile berikut

.PHONY: semua nyahpepijat

dioptimumkan:
program $(MAKE) CFLAGS=-O2

nyahpepijat:
program $(MAKE) CFLAGS=-g

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

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

Jika pengguna menaip "buat nyahpepijat", ia membina atur cara dalam mod lalai dengan nyahpepijat didayakan
bukannya dengan pengoptimuman.

Cara yang lebih baik untuk melakukannya ialah membina dua program berbeza, dengan dua set berbeza
fail objek, seperti ini:

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

atur cara: $(MODULES).o
$(CC) $(CFLAGS) $(input) -o $(output)

nyahpepijat/program: nyahpepijat/$(MODULES).o
$(CC) $(DEBUG_FLAGS) $(input) -o $(output)

%.o : %.c
$(CC) $(CFLAGS) -c $(input) -o $(output)

nyahpepijat/%.o : %.c
$(CC) $(DEBUG_FLAGS) -c $(input) -o $(output)

$(penyahpepijat palsu): nyahpepijat/program

Kelebihan melakukannya dengan cara ini ialah (a) anda tidak perlu membina semula segala-galanya apabila anda
beralih daripada nyahpepijat kepada dioptimumkan dan kembali semula; (b)

Di atas boleh ditulis dengan lebih ringkas menggunakan repositori. Yang berikut
makefile betul-betul setara:

nyahpepijat repositori=. # Menjadikan subdirektori nyahpepijat kelihatan seperti salinan
# subdirektori semasa.
load_makefile nyahpepijat CFLAGS=-g
# Gantikan CFLAGS apabila digunakan dalam subdirektori nyahpepijat
CFLAGS := -O2 # Nilai CFLAGS apabila digunakan dalam subdirektori ini

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

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

$(penyahpepijat palsu): nyahpepijat/program
# Jika pengguna menaip "makepp debug", membina
# nyahpepijat/program dan bukannya program.

Lain-lain tips
Cara do I membina 1 sebahagian berbeza hanya sekali?

Makepp membuat ini sukar dilakukan kerana hasilnya tidak konsisten dengan peraturan.
Tetapi terdapat situasi di mana anda mungkin memerlukan ini, contohnya untuk menyusun satu modul sahaja
maklumat penyahpepijatan berat. Anda boleh mencapai ini dalam dua langkah dengan membina terlebih dahulu
kebergantungan secara berasingan, dan kemudian mengecualikannya daripada fasa pautan:

makepp DEBUG=3 buggy.o # Bina dengan pilihan lain.
makepp --dont-build=buggy.o buggy # Gunakannya, walaupun pilihan binaan "salah".

Cara do I membuat pasti my output direktori wujud?

Anda boleh menentukan peraturan untuk membina direktori output, kemudian pastikan setiap fail itu
pergi dalam direktori output bergantung padanya. Tetapi biasanya lebih mudah untuk melakukan sesuatu seperti itu
ini:

# Cara klasik
dummy := $(ujian shell -d $(OUTPUT_DIRECTORY) || mkdir -p $(OUTPUT_DIRECTORY))
# Ini biasanya lebih mudah daripada membuat semua fail bergantung pada
# $(OUTPUT_DIRECTORY) dan mempunyai peraturan untuk membuatnya.
# Ambil perhatian bahawa anda mesti menggunakan := bukannya = untuk memaksanya
# laksanakan segera.
# Pendekatan alternatif: menggunakan kod Perl, OUTPUT_DIRECTORY local var
perl_begin
-d $OUTPUT_DIRECTORY atau mkdir $OUTPUT_DIRECTORY;
perl_end
# Cara moden, tidak melakukan apa-apa untuk direktori sedia ada
&mkdir -p $(OUTPUT_DIRECTORY)

Salah satu kenyataan ini hendaklah berada berhampiran bahagian atas fail make anda, supaya ia dilaksanakan
sebelum apa-apa yang mungkin memerlukan direktori.

Cara do I kekuatan a arahan kepada melaksanakan on setiap membina?

Cara paling mudah ialah tidak menggunakan mekanisme peraturan sama sekali, tetapi hanya untuk melaksanakannya, seperti
ini:

dummy := $(tarikh shell > last_build_timestamp)

Atau letakkannya dalam blok perl, seperti ini:

perl_begin
system("perintah untuk melaksanakan");
perl_end

Pendekatan ini mempunyai kelemahan bahawa ia akan dilaksanakan walaupun sasaran yang tidak berkaitan
sedang dijalankan.

Pendekatan kedua ialah mengisytiharkan fail sebagai sasaran palsu, walaupun ia adalah fail sebenar.
Ini akan memaksa makepp untuk melaksanakan semula arahan untuk membinanya setiap kali, tetapi hanya jika ia
muncul dalam senarai pergantungan beberapa peraturan.

Cara do I memendekkan yang dipaparkan membina arahan?

Selalunya terdapat begitu banyak pilihan untuk arahan penyusunan bahawa apa yang dipaparkan pada
skrin tidak boleh dibaca. Anda boleh menukar apa yang dipaparkan dengan menekan paparan
keseluruhan arahan, dan kemudian secara eksplisit mencetak bahagian perintah yang menarik. ia adalah
mudah untuk mencetak hanya bahagian arahan yang berkaitan dengan menggunakan "$(filter_out )", seperti
ini:

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

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

("@" di hadapan arahan menghalang pencetakan arahan.)

Ini akan membolehkan anda melihat kebanyakan pilihan yang menarik tetapi tidak akan memaparkan semua
sertakan direktori (yang selalunya terdapat banyak sekali!). Jika bahagian anda berminat
in adalah bersebelahan dalam arahan anda, anda juga boleh menggunakan fungsi "cetak" (yang menambah a
baris baharu, jadi anda tidak mahu beberapa daripadanya):

sasaran:
@... $(cetak bahagian menarik) ...

Cara do I menukar a fail ke dalam kebergantungan?

Untuk beberapa format fail yang tidak jelas adalah tidak berbaloi untuk melaksanakan pengimbas. Dalam satu projek
kami mempunyai fail xml, katakan foobar.xml yang mengandungi kebergantungan untuk foobar.out:


a
b
c


Kami memutuskan untuk mematuhi susun atur mudah ini, jadi kami tidak perlu menghuraikan xml. Dengan
builtin &sed, inilah yang kami lakukan dengan tiga penggantian mudah untuk tiga jenis
garisan:

%.d: %.xml
&sed 's! !$(stem).keluar: \\! || s! (.+) !$$1 \\! || s! !# Kosong!' \
$(input) -o $(output)

sertakan foobar.d

Mencuba untuk memasukkan ini, menghasilkan "foobar.d" dahulu:

foobar.out: \
a \
b \
c \
# Kosong

Baris kosong (hanya ulasan atau benar-benar kosong) mengelakkan diri daripada bimbang tentang ketinggalan
garis miring ke belakang. Alternatif untuk menghasilkan senarai berbilang talian ialah:

%.d: %.xml
&sed 's! !$(batang).keluar: \$$((! || s! !))! || s!<.+?>!!g' \
$(input) -o $(output)

sertakan foobar.d

Ini menghasilkan persamaan:

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

Jika anda mempunyai penulisan semula yang lebih kompleks untuk dilakukan, tentukan fungsi dalam makefile atau dalam a
modul yang anda sertakan. Cth undefining $_ akan melangkau baris input:

submyfilter {
return undef $_ if /
$stem saya = f_stem;
s! !$stem.out: \$((! || s! !))! || s!<.+?>!!g;
}

%.d: %.xml
&sed 's! !$(batang).keluar: \$$((! || s! !))! || s!<.+?>!!g' \
$(input) -o $(output)

sertakan foobar.d

Gunakan makepp_cookbook dalam talian menggunakan perkhidmatan onworks.net


Pelayan & Stesen Kerja Percuma

Muat turun apl Windows & Linux

Arahan Linux

Ad