Variabel(variable) adalah nama yang didefinisikan di dalam makefile untuk mewakili sebuah string teks, yang disebut nilai(value) dari variabel tersebut. Nilai-nilai ini disubstitusikan melalui permintaan eksplisit ke dalam target, prasyarat (prerequisite), resep (recipe), dan berbagai bagian lain dari makefile. (Pada beberapa versi make yang lain, variabel disebut makro(macro).)
Variabel dan fungsi di seluruh bagian makefile pada dasarnya diekspansi saat dibaca. Ada pengecualian: di dalam resep, di ruas kanan definisi variabel yang menggunakan ‘=’, dan di badan definisi variabel yang menggunakan direktif define, ekspansi tidak dilakukan pada saat itu. Nilai yang diperoleh ketika sebuah variabel diekspansi adalah nilai dari definisi paling akhir pada saat ekspansi tersebut terjadi. Dengan kata lain, variabel memiliki cakupan yang ditentukan secara dinamis (dynamically scoped).
Variabel dapat mewakili daftar nama file, opsi yang diteruskan ke kompiler, program yang akan dijalankan, direktori tempat mencari file sumber, direktori tempat menulis output, atau apa pun lain yang dapat Anda bayangkan.
Nama variabel dapat berupa sembarang rangkaian karakter yang tidak mengandung ‘:’, ‘#’, ‘=’, atau whitespace. Akan tetapi, nama variabel yang mengandung karakter selain huruf, angka, dan garis bawah harus diperlakukan dengan hati-hati, karena pada sebagian shell, variabel dengan nama seperti itu tidak dapat diteruskan ke sub-make melalui lingkungan (lihat Menyampaikan variabel ke sub-make). Nama variabel yang diawali dengan ‘.’ dan huruf kapital berpotensi diberi makna khusus pada versi make mendatang.
Nama variabel bersifat sensitif huruf besar/kecil (case-sensitive). Nama ‘foo’, ‘FOO’, dan ‘Foo’ semuanya merujuk ke variabel yang berbeda.
Secara tradisional, huruf kapital digunakan dalam nama variabel, tetapi buku ini menyarankan penggunaan huruf kecil untuk variabel yang dipakai untuk keperluan internal makefile, dan mencadangkan huruf kapital untuk parameter yang mengendalikan aturan implisit atau untuk parameter yang seharusnya dapat ditimpa (override) oleh pengguna melalui opsi perintah (lihat Menimpa variabel).
Sejumlah kecil variabel memiliki nama yang hanya terdiri dari satu karakter tanda baca atau beberapa karakter saja. Variabel-variabel ini disebut variabel otomatis(automatic variable), dan masing-masing memiliki kegunaan khusus tersendiri. Lihat Variabel otomatis.
override
Untuk menyisipkan nilai suatu variabel, tulis tanda dolar diikuti dengan nama variabel yang diapit tanda kurung atau kurung kurawal: baik ‘$(foo)’ maupun ‘${foo}’ merupakan referensi yang sah ke variabel foo. Justru karena ‘$’ memiliki makna khusus seperti ini, Anda harus menulis ‘$$’ jika ingin menyatakan satu tanda dolar itu sendiri di dalam nama file atau resep.
Referensi variabel dapat digunakan dalam konteks apa pun: target, prasyarat, resep, sebagian besar direktif, dan nilai variabel baru. Berikut ini adalah contoh umum, yaitu sebuah variabel yang menyimpan nama semua file objek yang membentuk sebuah program:
objects = program.o foo.o utils.o
program : $(objects)
cc -o program $(objects)
$(objects) : defs.h
Referensi variabel bekerja melalui substitusi tekstual yang ketat. Oleh karena itu, aturan berikut
foo = c
prog.o : prog.$(foo)
$(foo)$(foo) -$(foo) prog.$(foo)
dapat digunakan untuk mengompilasi program C prog.c. Karena whitespace sebelum nilai diabaikan dalam penetapan variabel, nilai foo tepatnya adalah ‘c’. (Jangan benar-benar menulis makefile Anda dengan cara seperti ini!)
Jika tanda dolar diikuti oleh satu karakter yang bukan tanda dolar, bukan kurung buka, dan bukan kurung kurawal buka, karakter tunggal itu diperlakukan sebagai nama variabel. Dengan demikian, variabel x dapat dirujuk dengan ‘$x’. Akan tetapi, cara penulisan ini dapat menimbulkan kebingungan (misalnya ‘$foo’ ditafsirkan sebagai variabel f yang diikuti oleh string oo). Oleh karena itu, kami menyarankan agar semua variabel—bahkan variabel satu karakter—diapit dengan tanda kurung atau kurung kurawal, kecuali jika menghilangkannya secara nyata meningkatkan keterbacaan. Salah satu kasus yang sering kali lebih mudah dibaca tanpa tanda kurung adalah variabel otomatis (lihat Variabel otomatis).
Pada GNU make, terdapat beberapa cara berbeda bagi sebuah variabel untuk memperoleh nilai; kita menyebutnya jenis(flavor) variabel. Jenis-jenis ini dibedakan berdasarkan cara mereka menangani nilai yang diberikan di dalam makefile, serta cara nilai tersebut dikelola ketika variabel kemudian digunakan dan diekspansi.
Jenis variabel yang pertama adalah variabel ekspansi rekursif(recursively expanded). Variabel jenis ini didefinisikan dengan baris yang menggunakan ‘=’ (lihat Menetapkan variabel), atau dengan direktif define (lihat Mendefinisikan variabel multi-baris). Nilai yang Anda tentukan disimpan apa adanya, secara harfiah. Jika nilai tersebut berisi referensi ke variabel lain, referensi-referensi itu akan diekspansi setiap kali variabel ini disisipkan (dalam proses mengekspansi string lain). Hal ini disebut ekspansi rekursif(recursive expansion).
Sebagai contoh,
foo = $(bar) bar = $(ugh) ugh = Huh? all:;echo $(foo)
akan mencetak ‘Huh?’: ‘$(foo)’ diekspansi menjadi ‘$(bar)’, yang diekspansi menjadi ‘$(ugh)’, yang akhirnya diekspansi menjadi ‘Huh?’.
Jenis variabel ini adalah satu-satunya jenis yang didukung oleh sebagian besar versi make lainnya. Jenis ini memiliki kelebihan sekaligus kekurangan. Salah satu kelebihannya (kata banyak orang) adalah:
CFLAGS = $(include_dirs) -O include_dirs = -Ifoo -Ibar
Contoh di atas bekerja sesuai maksudnya: ketika ‘CFLAGS’ diekspansi di dalam resep, ia akan diekspansi menjadi ‘-Ifoo -Ibar -O’. Kekurangan utamanya adalah Anda tidak dapat menambahkan sesuatu di akhir sebuah variabel, seperti berikut:
CFLAGS = $(CFLAGS) -O
sebab hal itu akan menyebabkan ekspansi variabel jatuh ke dalam loop tak berhingga. (Pada praktiknya, make mendeteksi loop tak berhingga tersebut dan melaporkan error.)
Kekurangan lainnya adalah fungsi apa pun (lihat Fungsi untuk transformasi teks) yang dirujuk di dalam definisi akan dieksekusi setiap kali variabel tersebut diekspansi. Hal ini membuat make berjalan lebih lambat; yang lebih buruk lagi, hal ini menyebabkan hasil dari fungsi wildcard dan shell menjadi tidak dapat diprediksi, karena Anda tidak dapat dengan mudah mengendalikan kapan fungsi-fungsi tersebut dipanggil, atau bahkan berapa kali dipanggil.
Untuk menghindari masalah dan ketidaknyamanan variabel ekspansi rekursif, terdapat satu jenis lagi: variabel ekspansi sederhana.
Variabel ekspansi sederhana(simply expanded variable) didefinisikan dengan baris yang menggunakan ‘:=’ atau ‘::=’ (lihat Menetapkan variabel). Pada GNU make, kedua bentuk ini setara, tetapi standar POSIX hanya mendefinisikan bentuk ‘::=’ (dukungan untuk ‘::=’ ditambahkan ke standar POSIX pada POSIX Issue 8).
Nilai variabel ekspansi sederhana dipindai satu kali saja, yaitu pada saat variabel didefinisikan, dan setiap referensi ke variabel atau fungsi lain diekspansi pada saat itu. Setelah ekspansi tersebut selesai, nilai variabel tidak akan pernah diekspansi lagi: ketika variabel digunakan, nilainya disalin apa adanya sebagai hasil ekspansi. Jika nilai tersebut mengandung referensi variabel, hasil ekspansinya akan berisi nilai-nilai referensi itu sebagaimana adanya pada saat variabel ini didefinisikan. Oleh karena itu,
x := foo y := $(x) bar x := later
setara dengan berikut ini.
y := foo bar x := later
Berikut ini adalah contoh yang sedikit lebih rumit, yang menunjukkan penggunaan ‘:=’ bersama dengan fungsi shell. (Lihat Fungsi shell.) Contoh ini juga menunjukkan penggunaan variabel MAKELEVEL, yang berubah saat diteruskan dari satu tingkat ke tingkat berikutnya. (Untuk detail tentang MAKELEVEL, lihat Menyampaikan variabel ke sub-make.)
ifeq (0,${MAKELEVEL})
whoami := $(shell whoami)
host-type := $(shell arch)
MAKE := ${MAKE} host-type=${host-type} whoami=${whoami}
endif
Keuntungan dari penggunaan ‘:=’ ini adalah resep khas untuk “turun ke direktori” dapat ditulis seperti berikut:
${subdirs}:
${MAKE} -C $@ all
Karena berperilaku seperti variabel pada sebagian besar bahasa pemrograman, variabel ekspansi sederhana membuat pemrograman makefile yang rumit menjadi lebih mudah diprediksi. Dengan variabel ekspansi sederhana, Anda dapat mendefinisikan ulang sebuah variabel menggunakan nilainya sendiri (atau nilainya sendiri yang telah diolah dengan salah satu fungsi ekspansi), dan dapat menggunakan fungsi ekspansi jauh lebih efisien (lihat Fungsi untuk transformasi teks).
Anda juga dapat menggunakan variabel ekspansi sederhana untuk menyisipkan whitespace terkendali di awal nilai variabel. Karakter whitespace di awal input dibuang sebelum substitusi referensi variabel dan pemanggilan fungsi dilakukan; artinya, Anda dapat menyertakan spasi di awal nilai variabel dengan melindunginya menggunakan referensi variabel, seperti berikut:
nullstring := space := $(nullstring) # end of the line
Di sini, nilai variabel space tepat berupa satu spasi. Komentar ‘# end of the line’ disertakan di sini hanya untuk kejelasan. Karena karakter whitespace di akhir nilai variabel tidak dibuang, cukup meletakkan satu spasi di akhir baris pun akan memberikan efek yang sama (meskipun cara ini akan sangat sulit dibaca). Jika Anda meletakkan whitespace di akhir nilai variabel, sebaiknya tambahkan komentar seperti di atas di akhir baris agar maksud Anda jelas. Sebaliknya, jika Anda tidak ingin ada karakter whitespace di akhir nilai variabel, Anda harus berhati-hati agar tidak menambahkan komentar sembarangan di akhir baris setelah whitespace tersebut, seperti berikut:
dir := /foo/bar # directory to put the frobs in
Di sini, nilai variabel dir menjadi ‘/foo/bar ’(dengan empat spasi di akhir), yang kemungkinan besar bukan yang dimaksudkan. (Bayangkan definisi ini digunakan seperti ‘$(dir)/file’!)
Ada satu lagi bentuk penetapan yang melakukan ekspansi segera, tetapi berbeda dengan penetapan sederhana, variabel yang dihasilkan tetap bersifat rekursif: variabel tersebut akan diekspansi ulang setiap kali digunakan. Untuk menghindari hasil yang tidak diharapkan, setelah nilai diekspansi segera, nilai tersebut secara otomatis akan dikutip (quoted): setiap kemunculan $ pada nilai hasil ekspansi diubah menjadi $$. Jenis penetapan ini menggunakan operator ‘:::=’. Sebagai contoh,
var = first OUT :::= $(var) var = second
menghasilkan variabel OUT yang berisi teks ‘first’. Sementara itu, pada kasus berikut,
var = one$$two OUT :::= $(var) var = three$$four
variabel OUT berisi teks ‘one$$two’. Karena nilai diekspansi pada saat variabel ditetapkan, hasilnya pertama-tama adalah ekspansi dari nilai awal var, yaitu ‘one$two’; kemudian, sebelum penetapan selesai, nilai tersebut di-escape ulang sehingga menghasilkan hasil akhir ‘one$$two’.
Setelah ini, variabel OUT diperlakukan sebagai variabel ekspansi rekursif, sehingga akan diekspansi ulang ketika digunakan.
Secara fungsional, penetapan ini tampak setara dengan operator ‘:=’ / ‘::=’, tetapi terdapat beberapa perbedaan:
Pertama, setelah penetapan, variabel tersebut adalah variabel ekspansi rekursif biasa. Ketika Anda menambahkan teks dengan ‘+=’, nilai di ruas kanan tidak langsung diekspansi. Jika Anda ingin operator ‘+=’ mengekspansi ruas kanan secara langsung, gunakan penetapan ‘:=’ / ‘::=’ sebagai gantinya.
Kedua, variabel jenis ini sedikit kurang efisien dibandingkan variabel ekspansi sederhana, karena perlu diekspansi ulang saat digunakan, bukan sekadar disalin. Meskipun demikian, karena semua referensi variabel sudah di-escape, ekspansi ini hanya melepas escape dari nilai tersebut; ekspansi ini tidak akan mengekspansi variabel lain atau menjalankan fungsi apa pun.
Berikut ini adalah contoh lainnya:
var = one$$two OUT :::= $(var) OUT += $(var) var = three$$four
Setelah ini, nilai OUT menjadi teks ‘one$$two $(var)’. Ketika variabel ini digunakan, ia akan diekspansi, dan hasilnya adalah ‘one$two three$four’.
Gaya penetapan ini setara dengan operator ‘:=’ pada make BSD tradisional. Seperti yang Anda lihat, cara kerjanya sedikit berbeda dari operator ‘:=’ pada GNU make. Operator :::= ditambahkan ke spesifikasi POSIX pada Issue 8 untuk menyediakan portabilitas.
Ada satu lagi operator penetapan untuk variabel, yaitu ‘?=’. Operator ini disebut operator penetapan variabel bersyarat, karena hanya berpengaruh jika variabel tersebut belum didefinisikan. Pernyataan berikut,
FOO ?= bar
sepenuhnya setara dengan berikut ini (lihat Fungsi origin):
ifeq ($(origin FOO), undefined) FOO = bar endif
Perhatikan bahwa variabel yang ditetapkan dengan nilai kosong tetap dianggap sudah “didefinisikan”. Oleh karena itu, ‘?=’ tidak akan menetapkan variabel tersebut.
Bagian ini menjelaskan beberapa fitur lanjutan yang dapat Anda gunakan untuk mereferensikan variabel dengan cara yang lebih fleksibel.
Referensi substitusi(substitution reference) menyisipkan nilai suatu variabel dengan perubahan yang Anda tentukan. Bentuknya adalah ‘$(var:a=b)’(atau ‘${var:a=b}’), dan maknanya adalah: ambil nilai variabel var, ganti setiap a di akhir kata dalam nilai tersebut dengan b, lalu sisipkan string hasilnya.
Yang dimaksud dengan “di akhir kata” di sini adalah, agar dapat diganti, a harus diikuti oleh whitespace atau berada di akhir nilai. Kemunculan a lainnya dalam nilai tersebut tidak diubah. Sebagai contoh,
foo := a.o b.o l.a c.o bar := $(foo:.o=.c)
menetapkan ‘bar’ menjadi ‘a.c b.c l.a c.c’. Lihat Menetapkan variabel.
Referensi substitusi adalah notasi singkat untuk fungsi ekspansi patsubst (lihat Fungsi untuk substitusi dan analisis string): ‘$(var:a=b)’ setara dengan ‘$(patsubst %a,%b,var)’. Kami menyediakan referensi substitusi selain patsubst demi kompatibilitas dengan implementasi make lainnya.
Ada satu jenis lagi referensi substitusi yang memungkinkan Anda memanfaatkan sepenuhnya kekuatan fungsi patsubst. Bentuknya sama dengan ‘$(var:a=b)’ yang disebutkan di atas, tetapi kali ini a harus mengandung satu karakter ‘%’. Dalam kasus ini, bentuknya setara dengan ‘$(patsubst a,b,$(var))’. Untuk penjelasan tentang fungsi patsubst, lihat Fungsi untuk substitusi dan analisis string. Sebagai contoh,
foo := a.o b.o l.a c.o bar := $(foo:%.o=%.c)
menetapkan ‘bar’ menjadi ‘a.c b.c l.a c.c’.
Nama variabel hasil komputasi adalah konsep lanjutan yang sangat berguna dalam pemrograman makefile yang lebih canggih. Anda tidak perlu memikirkannya dalam situasi sederhana, tetapi konsep ini dapat menjadi sangat berguna.
Variabel dapat dirujuk di dalam nama variabel lain. Hal ini disebut nama variabel hasil komputasi(computed variable name), atau referensi variabel bersarang(nested variable reference). Sebagai contoh,
x = y y = z a := $($(x))
mendefinisikan a sebagai ‘z’: ‘$(x)’ di dalam ‘$($(x))’ diekspansi menjadi ‘y’, sehingga ‘$($(x))’ diekspansi menjadi ‘$(y)’, yang selanjutnya diekspansi menjadi ‘z’. Di sini, nama variabel yang dirujuk tidak dituliskan secara eksplisit, melainkan dihitung melalui ekspansi ‘$(x)’. Referensi ‘$(x)’ di sini bersarang di dalam referensi variabel yang lebih luar.
Contoh sebelumnya menunjukkan dua tingkat penyarangan, tetapi penyarangan dapat dilakukan hingga berapa pun tingkatnya. Sebagai contoh, berikut ini adalah contoh tiga tingkat:
x = y y = z z = u a := $($($(x)))
Di sini, ‘$(x)’ yang paling dalam diekspansi menjadi ‘y’, sehingga ‘$($(x))’ diekspansi menjadi ‘$(y)’, yang selanjutnya diekspansi menjadi ‘z’; kini tersisa ‘$(z)’, yang menjadi ‘u’.
Referensi ke variabel ekspansi rekursif di dalam nama variabel diekspansi ulang seperti biasa. Sebagai contoh,
x = $(y) y = z z = Hello a := $($(x))
mendefinisikan a sebagai ‘Hello’: ‘$($(x))’ menjadi ‘$($(y))’, yang menjadi ‘$(z)’, yang menjadi ‘Hello’.
Referensi variabel bersarang, seperti referensi lainnya, juga dapat mengandung referensi yang dimodifikasi dan pemanggilan fungsi (lihat Fungsi untuk transformasi teks). Sebagai contoh, dengan menggunakan fungsi subst (lihat Fungsi untuk substitusi dan analisis string),
x = variable1 variable2 := Hello y = $(subst 1,2,$(x)) z = y a := $($($(z)))
pada akhirnya mendefinisikan a sebagai ‘Hello’. Sulit dibayangkan ada orang yang sungguh-sungguh ingin menulis referensi bersarang serumit ini, tetapi ini tetap berfungsi: ‘$($($(z)))’ diekspansi menjadi ‘$($(y))’, yang menjadi ‘$($(subst 1,2,$(x)))’. Ekspresi ini mengambil nilai ‘variable1’ dari x dan mengubahnya melalui substitusi menjadi ‘variable2’, sehingga seluruh string menjadi referensi variabel sederhana ‘$(variable2)’, yang nilainya adalah ‘Hello’.
Nama variabel hasil komputasi tidak harus terdiri dari satu referensi variabel saja. Nama tersebut dapat mengandung beberapa referensi variabel, ditambah dengan teks tetap. Sebagai contoh,
a_dirs := dira dirb 1_dirs := dir1 dir2
a_files := filea fileb 1_files := file1 file2
ifeq "$(use_a)" "yes" a1 := a else a1 := 1 endif
ifeq "$(use_dirs)" "yes" df := dirs else df := files endif dirs := $($(a1)_$(df))
memberikan dirs nilai yang sama dengan salah satu dari a_dirs, 1_dirs, a_files, atau 1_files, tergantung pada pengaturan use_a dan use_dirs.
Nama variabel hasil komputasi juga dapat digunakan di dalam referensi substitusi:
a_objects := a.o b.o c.o 1_objects := 1.o 2.o 3.o sources := $($(a1)_objects:.o=.c)
mendefinisikan sources menjadi ‘a.c b.c c.c’ atau ‘1.c 2.c 3.c’, tergantung pada nilai a1.
Satu-satunya batasan dalam penggunaan referensi variabel bersarang seperti ini adalah referensi tersebut tidak dapat digunakan untuk menentukan sebagian dari nama fungsi yang akan dipanggil. Ini karena pengecekan apakah suatu nama merupakan nama fungsi yang dikenali dilakukan sebelum ekspansi referensi bersarang. Sebagai contoh,
ifdef do_sort func := sort else func := strip endif
bar := a d b g q c
foo := $($(func) $(bar))
berupaya memberikan nilai variabel bernama ‘sort a d b g q c’ atau ‘strip a d b g q c’ sebagai nilai ‘foo’, bukan memberikan ‘a d b g q c’ sebagai argumen untuk fungsi sort atau strip. Batasan ini mungkin akan dihapus di masa depan jika perubahan tersebut terbukti merupakan ide yang baik.
Nama variabel hasil komputasi juga dapat digunakan di ruas kiri penetapan variabel, atau di dalam direktif define, seperti berikut:
dir = foo $(dir)_sources := $(wildcard $(dir)/*.c) define $(dir)_print = lpr $($(dir)_sources) endef
Contoh ini mendefinisikan variabel ‘dir’, ‘foo_sources’, dan ‘foo_print’.
Perhatikan bahwa referensi variabel bersarang cukup berbeda dari variabel ekspansi rekursif (lihat Dua jenis variabel), meskipun keduanya dapat digunakan bersama-sama dengan cara yang rumit saat melakukan pemrograman makefile.
Variabel dapat memperoleh nilai dengan beberapa cara berbeda:
make. Lihat Menimpa variabel.
let (lihat Fungsi let) atau fungsi foreach (lihat Fungsi foreach).
make. Lihat Variabel dari lingkungan.
Untuk menetapkan variabel dari makefile, tulis baris yang dimulai dengan nama variabel, diikuti oleh salah satu operator penetapan ‘=’, ‘:=’, ‘::=’, atau ‘:::=’. Apa pun yang mengikuti operator tersebut, tidak termasuk whitespace tepat setelah operator, menjadi nilainya. Sebagai contoh,
objects = main.o foo.o bar.o utils.o
mendefinisikan variabel bernama objects dengan nilai ‘main.o foo.o bar.o utils.o’. Whitespace di sekitar nama variabel, serta tepat setelah ‘=’, diabaikan.
Variabel yang didefinisikan dengan ‘=’ adalah variabel ekspansi rekursif. Variabel yang didefinisikan dengan ‘:=’ atau ‘::=’ adalah variabel ekspansi sederhana; definisi ini dapat mengandung referensi variabel, yang akan diekspansi sebelum definisi dibuat. Variabel yang didefinisikan dengan ‘:::=’ adalah variabel ekspansi segera. Setiap operator penetapan dijelaskan pada Dua jenis variabel.
Nama variabel dapat mengandung referensi fungsi dan referensi variabel, yang diekspansi saat baris dibaca untuk menentukan nama variabel yang sesungguhnya akan digunakan.
Tidak ada batasan panjang nilai variabel selain jumlah memori komputer. Untuk keterbacaan, Anda juga dapat memecah nilai variabel menjadi beberapa baris fisik (lihat Membagi baris panjang).
Sebagian besar nama variabel dianggap memiliki string kosong sebagai nilainya jika belum pernah ditetapkan. Beberapa variabel memiliki nilai awal bawaan yang tidak kosong, tetapi tetap dapat ditetapkan dengan cara biasa (lihat Variabel yang digunakan oleh aturan implisit). Beberapa variabel khusus secara otomatis diberi nilai baru untuk setiap aturan; variabel-variabel ini disebut variabel otomatis (lihat Variabel otomatis).
Jika Anda ingin menetapkan nilai variabel hanya jika belum ditetapkan, Anda dapat menggunakan operator singkat ‘?=’ sebagai pengganti ‘=’. Kedua penetapan variabel ‘FOO’ berikut ini identik (lihat Fungsi origin):
FOO ?= bar
dan
ifeq ($(origin FOO), undefined) FOO = bar endif
Operator penetapan shell ‘!=’ dapat digunakan untuk menjalankan skrip shell dan menetapkan variabel dengan keluarannya. Operator ini pertama-tama mengevaluasi ruas kanan, lalu meneruskan hasilnya ke shell untuk dieksekusi. Jika hasil eksekusi diakhiri dengan baris baru, satu baris baru tersebut akan dihapus; semua baris baru lainnya diganti dengan spasi. String yang dihasilkan kemudian disimpan ke dalam variabel ekspansi rekursif yang ditentukan. Sebagai contoh:
hash != printf '\043' file_list != find . -name '*.c'
Jika hasil eksekusi berpotensi mengandung $, dan Anda tidak ingin apa pun yang mengikutinya ditafsirkan sebagai referensi variabel atau fungsi make, Anda harus mengganti setiap $ dengan $$ sebagai bagian dari eksekusi tersebut. Sebagai alternatif, Anda dapat menetapkan variabel ekspansi sederhana dengan hasil eksekusi program menggunakan pemanggilan fungsi shell. Lihat Fungsi shell. Sebagai contoh:
hash := $(shell printf '\043') var := $(shell find . -name "*.c")
Sama seperti pada fungsi shell, status keluar dari skrip shell yang baru saja dijalankan disimpan dalam variabel .SHELLSTATUS.
Sering kali berguna untuk dapat menambahkan lebih banyak teks ke nilai variabel yang sudah didefinisikan. Anda melakukannya dengan baris yang mengandung ‘+=’, seperti berikut:
objects += another.o
Baris ini mengambil nilai variabel objects dan menambahkan teks ‘another.o’ ke dalamnya (didahului satu spasi, jika sudah memiliki nilai). Dengan demikian:
objects = main.o foo.o bar.o utils.o objects += another.o
menetapkan objects menjadi ‘main.o foo.o bar.o utils.o another.o’.
Penggunaan ‘+=’ mirip dengan berikut ini:
objects = main.o foo.o bar.o utils.o objects := $(objects) another.o
Namun, terdapat perbedaan yang menjadi penting saat Anda menggunakan nilai yang lebih rumit.
Jika variabel yang bersangkutan belum pernah didefinisikan sebelumnya, ‘+=’ berperilaku persis seperti ‘=’ biasa: yaitu mendefinisikan variabel ekspansi rekursif. Akan tetapi, jika sebelumnya sudah ada definisi, apa yang sesungguhnya dilakukan ‘+=’ bergantung pada jenis variabel yang didefinisikan sejak awal. Untuk penjelasan kedua jenis variabel tersebut, lihat Dua jenis variabel.
Ketika Anda menambahkan ke nilai suatu variabel dengan ‘+=’, pada dasarnya make berperilaku seolah-olah teks tambahan tersebut sudah disertakan dalam definisi awal variabel tersebut. Jika Anda mendefinisikannya pertama kali dengan ‘:=’ atau ‘::=’ sehingga menjadi variabel ekspansi sederhana, ‘+=’ akan menambahkan ke definisi ekspansi sederhana tersebut, dan mengekspansi teks baru sebelum menambahkannya ke nilai lama, sama seperti yang dilakukan ‘:=’ (untuk penjelasan lengkap tentang ‘:=’ atau ‘::=’, lihat Menetapkan variabel). Faktanya,
variable := value variable += more
sepenuhnya setara dengan berikut ini:
variable := value variable := $(variable) more
Di sisi lain, jika Anda menggunakan ‘+=’ pada variabel yang pertama kali didefinisikan sebagai variabel ekspansi rekursif dengan ‘=’ polos atau ‘:::=’, make akan menambahkan teks yang belum diekspansi ke nilai yang sudah ada, apa pun nilai tersebut. Artinya,
variable = value variable += more
kurang lebih setara dengan berikut ini:
temp = value variable = $(temp) more
Tentu saja, variabel bernama temp tidak pernah benar-benar didefinisikan. Hal ini menjadi penting ketika nilai lama variabel tersebut mengandung referensi variabel. Perhatikan contoh umum berikut:
CFLAGS = $(includes) -O … CFLAGS += -pg # enable profiling
Baris pertama mendefinisikan variabel CFLAGS dengan referensi ke variabel lain, includes. (CFLAGS digunakan oleh aturan untuk kompilasi C; lihat Katalog aturan bawaan.) Penggunaan ‘=’ untuk definisi ini membuat CFLAGS menjadi variabel ekspansi rekursif, yang berarti ‘$(includes) -O’ tidak diekspansi saat make memproses definisi CFLAGS. Oleh karena itu, includes belum perlu didefinisikan agar nilainya berlaku; includes hanya perlu didefinisikan sebelum referensi mana pun ke CFLAGS. Jika kita mencoba menambahkan ke nilai CFLAGS tanpa menggunakan ‘+=’, kita mungkin melakukannya seperti berikut:
CFLAGS := $(CFLAGS) -pg # enable profiling
Cara ini cukup mendekati, tetapi bukan yang kita inginkan. Penggunaan ‘:=’ akan mendefinisikan ulang CFLAGS sebagai variabel ekspansi sederhana. Ini berarti make akan mengekspansi teks ‘$(CFLAGS) -pg’ sebelum menetapkan variabel tersebut. Jika includes belum didefinisikan, kita akan mendapatkan ‘ -O -pg’, dan definisi includes setelahnya tidak akan berpengaruh. Sebaliknya, dengan menggunakan ‘+=’, kita menetapkan CFLAGS ke nilai yang belum diekspansi, yaitu ‘$(includes) -O -pg’. Dengan demikian, referensi ke includes tetap terjaga, sehingga jika variabel tersebut didefinisikan di suatu titik kemudian, referensi seperti ‘$(CFLAGS)’ akan tetap menggunakan nilainya.
override
Jika sebuah variabel telah ditetapkan melalui argumen perintah (lihat Menimpa variabel), penetapan biasa di dalam makefile akan diabaikan. Jika Anda ingin menetapkan variabel tersebut di dalam makefile meskipun sudah ditetapkan melalui argumen perintah, Anda dapat menggunakan direktif override, yaitu baris dengan bentuk seperti berikut:
override variable = value
atau
override variable := value
Untuk menambahkan lebih banyak teks ke variabel yang didefinisikan pada baris perintah, lakukan seperti berikut:
override variable += more text
Lihat Menambahkan teks ke variabel.
Penetapan variabel yang ditandai dengan flag override memiliki prioritas lebih tinggi daripada semua penetapan lainnya, kecuali override lain. Penetapan atau penambahan berikutnya ke variabel ini yang tidak ditandai override akan diabaikan.
Direktif override tidak diciptakan untuk mengeskalasi perselisihan antara makefile dan argumen perintah. Direktif ini diciptakan agar Anda dapat mengubah dan menambahkan nilai yang ditentukan pengguna melalui argumen perintah.
Sebagai contoh, misalkan Anda selalu ingin menyertakan switch ‘-g’ setiap kali menjalankan kompiler C, tetapi tetap ingin mengizinkan pengguna menentukan switch lainnya melalui argumen perintah seperti biasa. Anda dapat menggunakan direktif override berikut:
override CFLAGS += -g
Direktif override juga dapat digunakan bersama direktif define. Cara melakukannya sesuai dugaan Anda:
override define foo = bar endef
Lihat Mendefinisikan variabel multi-baris.
Cara lain untuk menetapkan nilai variabel adalah dengan menggunakan direktif define. Direktif ini memiliki sintaksis khusus yang memungkinkan nilai mengandung karakter baris baru, sehingga berguna untuk mendefinisikan rangkaian perintah baku (lihat Mendefinisikan resep baku (canned recipe)) maupun potongan sintaksis makefile yang digunakan dengan eval (lihat Fungsi eval).
Setelah direktif define, pada baris yang sama, dituliskan nama variabel yang akan didefinisikan dan operator penetapan (opsional), tanpa hal lain. Nilai yang diberikan ke variabel muncul pada baris-baris berikutnya. Akhir nilai ditandai dengan baris yang hanya berisi kata endef.
Selain perbedaan sintaksis ini, define bekerja persis seperti definisi variabel lainnya. Nama variabel dapat mengandung referensi fungsi dan referensi variabel, yang diekspansi saat direktif dibaca untuk menentukan nama variabel yang sesungguhnya akan digunakan.
Baris baru terakhir tepat sebelum endef tidak disertakan dalam nilai. Jika Anda ingin nilai tersebut mengandung baris baru di akhir, Anda harus menyisipkan baris kosong. Sebagai contoh, untuk mendefinisikan variabel yang mengandung karakter baris baru, Anda harus menggunakan dua baris kosong, bukan satu:
define newline endef
Anda dapat menghilangkan operator penetapan variabel sesuai keinginan. Jika dihilangkan, make akan menganggapnya sebagai ‘=’ dan membuat variabel ekspansi rekursif (lihat Dua jenis variabel). Jika Anda menggunakan operator ‘+=’, seperti pada operasi penambahan lainnya, nilai baru ditambahkan ke nilai sebelumnya dengan dipisahkan satu spasi antara nilai lama dan nilai baru.
Direktif define dapat disarangkan. make akan melacak direktif yang disarangkan tersebut dan melaporkan error jika tidak semuanya ditutup dengan benar menggunakan endef. Perhatikan bahwa baris yang dimulai dengan karakter awalan resep dianggap sebagai bagian dari resep, sehingga string define atau endef yang muncul pada baris seperti itu tidak dianggap sebagai direktif make.
define two-lines echo foo echo $(bar) endef
Jika digunakan di dalam resep, contoh sebelumnya secara fungsional setara dengan berikut ini:
two-lines = echo foo; echo $(bar)
Ini karena dua perintah yang dipisahkan titik koma berperilaku hampir sama seperti dua perintah shell yang terpisah. Namun, perhatikan bahwa jika menggunakan dua baris terpisah, make akan menjalankan shell dua kali, menjalankan sub-shell independen untuk setiap baris. Lihat Eksekusi resep.
Jika Anda ingin definisi variabel yang dibuat dengan define memiliki prioritas lebih tinggi daripada definisi variabel pada baris perintah, Anda dapat menggunakan direktif override bersama define:
override define two-lines = foo $(bar) endef
Lihat Direktif override.
Jika Anda ingin mengosongkan sebuah variabel, biasanya cukup dengan menetapkan nilainya menjadi kosong. Mengekspansi variabel semacam itu akan menghasilkan hasil yang sama (string kosong), baik variabel tersebut pernah ditetapkan maupun tidak. Akan tetapi, jika Anda menggunakan fungsi flavor (lihat Fungsi flavor) dan fungsi origin (lihat Fungsi origin), terdapat perbedaan antara variabel yang belum pernah ditetapkan dan variabel dengan nilai kosong. Dalam situasi seperti itu, Anda mungkin ingin menggunakan direktif undefine agar sebuah variabel tampak seolah-olah belum pernah ditetapkan. Sebagai contoh,
foo := foo bar = bar undefine foo undefine bar $(info $(origin foo)) $(info $(flavor bar))
Contoh ini akan menampilkan “undefined” untuk kedua variabel tersebut.
Jika Anda ingin membatalkan definisi variabel pada baris perintah, Anda dapat menggunakan direktif override bersama undefine, sama seperti pada definisi variabel:
override undefine CFLAGS
Variabel pada make dapat berasal dari lingkungan tempat make dijalankan. Setiap variabel lingkungan yang dilihat make saat dijalankan akan diubah menjadi variabel make dengan nama dan nilai yang sama. Akan tetapi, penetapan eksplisit di dalam makefile, atau penetapan melalui argumen perintah, akan menimpa lingkungan. (Jika flag ‘-e’ ditentukan, nilai dari lingkungan akan menimpa penetapan di dalam makefile. Lihat Ringkasan opsi. Namun, ini bukan praktik yang direkomendasikan.)
Oleh karena itu, dengan menetapkan variabel CFLAGS di lingkungan, Anda dapat membuat sebagian besar makefile menggunakan switch kompiler pilihan Anda untuk semua kompilasi C. Cara ini aman untuk variabel yang memiliki makna standar atau konvensional, karena Anda tahu tidak ada makefile yang akan menggunakannya untuk tujuan lain. (Namun, ini tidak sepenuhnya dapat diandalkan; sebagian makefile menetapkan CFLAGS secara eksplisit, sehingga tidak terpengaruh oleh nilai dari lingkungan.)
Saat make menjalankan resep, sebagian variabel yang didefinisikan di dalam makefile ditempatkan ke dalam lingkungan setiap perintah yang dipanggil make. Secara default, hanya variabel yang berasal dari lingkungan make atau yang ditetapkan pada baris perintah yang ditempatkan ke dalam lingkungan perintah tersebut. Untuk meneruskan variabel lainnya, Anda dapat menggunakan direktif export. Untuk detail lengkapnya, lihat Menyampaikan variabel ke sub-make.
Penggunaan lain dari variabel lingkungan tidak disarankan. Tidak bijaksana jika makefile menggantungkan fungsinya pada variabel lingkungan yang ditetapkan di luar kendalinya, karena hal itu akan menyebabkan pengguna yang berbeda mendapatkan hasil yang berbeda dari makefile yang sama. Hal ini bertentangan dengan tujuan utama sebagian besar makefile.
Masalah semacam ini terutama mudah terjadi pada variabel SHELL. SHELL biasanya ada di lingkungan untuk menentukan pilihan shell interaktif pengguna. Sangat tidak diinginkan jika pilihan ini memengaruhi make; oleh karena itu, make menangani variabel lingkungan SHELL dengan cara khusus. Lihat Memilih shell.
Nilai variabel pada make biasanya bersifat global; artinya, nilainya sama di mana pun dievaluasi (tentu saja, selama tidak ditetapkan ulang). Pengecualiannya adalah variabel yang didefinisikan dengan fungsi let (lihat Fungsi let) atau fungsi foreach (lihat Fungsi foreach), serta variabel otomatis (lihat Variabel otomatis).
Pengecualian lainnya adalah nilai variabel khusus target(target-specific variable value). Fitur ini memungkinkan Anda mendefinisikan nilai yang berbeda untuk variabel yang sama, bergantung pada target yang sedang dibangun make. Seperti variabel otomatis, nilai-nilai ini hanya tersedia di dalam konteks resep target tersebut (dan di dalam penetapan khusus target lainnya).
Nilai variabel khusus target ditetapkan seperti berikut:
target … : variable-assignment
Penetapan variabel khusus target dapat diberi awalan dengan salah satu atau semua kata kunci khusus export, unexport, override, atau private. Kata kunci ini menerapkan perilaku normalnya masing-masing hanya pada instansi variabel ini.
Jika Anda menentukan beberapa target, nilai variabel khusus target akan dibuat secara terpisah untuk setiap anggota daftar target tersebut.
variable-assignment dapat berupa bentuk penetapan valid apa pun: rekursif (‘=’), sederhana (‘:=’ atau ‘::=’), segera (‘:::=’), penambahan (‘+=’), atau bersyarat (‘?=’). Semua variabel yang muncul di dalam variable-assignment dievaluasi dalam konteks target; dengan demikian, nilai variabel khusus target yang sudah didefinisikan sebelumnya akan berlaku. Perhatikan bahwa variabel ini sebenarnya berbeda dari nilai “global” mana pun: kedua variabel tersebut tidak harus memiliki jenis yang sama (rekursif atau sederhana).
Variabel khusus target memiliki prioritas yang sama dengan variabel makefile lainnya. Variabel yang diberikan pada baris perintah (dan variabel lingkungan jika opsi ‘-e’ aktif) akan diprioritaskan. Dengan menentukan direktif override, Anda dapat membuat nilai variabel khusus target diprioritaskan.
Variabel khusus target memiliki satu fitur khusus lagi. Ketika Anda mendefinisikan variabel khusus target, nilai variabel tersebut juga berlaku secara rekursif untuk semua prasyarat target ini, dan prasyarat dari prasyarat tersebut, dan seterusnya (kecuali jika prasyarat-prasyarat tersebut menimpanya dengan nilai variabel khusus targetnya sendiri). Sebagai contoh, pernyataan berikut,
prog : CFLAGS = -g prog : prog.o foo.o bar.o
akan menetapkan CFLAGS menjadi ‘-g’ pada resep prog, tetapi juga akan menetapkan CFLAGS menjadi ‘-g’ pada resep yang membuat prog.o, foo.o, dan bar.o, serta pada resep mana pun yang membuat prasyarat-prasyarat tersebut.
Namun, perlu diperhatikan bahwa suatu prasyarat hanya akan dibangun paling banyak satu kali per eksekusi make. Jika file yang sama menjadi prasyarat dari beberapa target, dan masing-masing target tersebut memiliki nilai berbeda untuk variabel khusus target yang sama, target pertama yang dibangun akan menyebabkan prasyarat tersebut dibangun, dan prasyarat itu akan mewarisi nilai khusus target dari target pertama tersebut. Nilai khusus target dari target-target lainnya akan diabaikan.
Selain nilai variabel khusus target (lihat Nilai variabel khusus target), GNU make juga mendukung nilai variabel khusus pola. Dalam bentuk ini, variabel didefinisikan untuk target mana pun yang cocok dengan pola yang ditentukan.
Nilai variabel khusus pola ditetapkan seperti berikut:
pattern … : variable-assignment
di sini pattern adalah pola-%. Seperti pada nilai variabel khusus target, jika Anda menentukan beberapa pattern, nilai variabel khusus pola akan dibuat secara terpisah untuk setiap pola. variable-assignment dapat berupa bentuk penetapan valid apa pun. Penetapan variabel pada baris perintah akan diprioritaskan, kecuali jika override ditentukan.
Sebagai contoh,
%.o : CFLAGS = -O
akan memberikan nilai ‘-O’ pada CFLAGS untuk semua target yang cocok dengan pola %.o.
Jika sebuah target cocok dengan lebih dari satu pola, variabel khusus pola yang cocok dengan stem yang lebih panjang akan ditafsirkan lebih dahulu. Hal ini membuat variabel yang lebih spesifik diprioritaskan daripada variabel yang lebih umum. Sebagai contoh,
%.o: %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
lib/%.o: CFLAGS := -fPIC -g
%.o: CFLAGS := -g
all: foo.o lib/bar.o
Pada contoh ini, definisi kedua juga berlaku untuk target lib/bar.o, tetapi definisi pertama variabel CFLAGS-lah yang digunakan untuk memperbarui lib/bar.o. Variabel khusus pola yang memiliki panjang stem sama akan dipertimbangkan sesuai urutan pendefinisiannya di dalam makefile.
Variabel khusus pola dicari setelah variabel khusus target yang didefinisikan secara eksplisit untuk target tersebut, dan sebelum variabel khusus target yang didefinisikan untuk target induk.
Seperti telah dijelaskan pada bagian-bagian sebelumnya, variabel make diwariskan ke prasyarat. Fitur ini memungkinkan Anda mengubah perilaku suatu prasyarat berdasarkan target mana yang menyebabkannya dibangun ulang. Sebagai contoh, Anda dapat menetapkan variabel khusus target pada target debug, sehingga saat menjalankan ‘make debug’, variabel tersebut akan diwariskan ke semua prasyarat debug. Sebaliknya, jika Anda hanya menjalankan ‘make all’ (misalnya), penetapan tersebut tidak akan terjadi.
Namun, terkadang Anda tidak ingin sebuah variabel diwariskan. Untuk situasi seperti ini, make menyediakan pengubah (modifier) private. Pengubah ini dapat digunakan pada penetapan variabel apa pun, tetapi paling bermakna untuk variabel khusus target dan variabel khusus pola. Variabel yang ditandai private akan terlihat dari target lokalnya, tetapi tidak diwariskan ke prasyarat target tersebut. Variabel global yang ditandai private akan terlihat pada cakupan global, tetapi tidak diwariskan ke target mana pun, sehingga tidak terlihat dari resep mana pun.
Sebagai contoh, perhatikan makefile berikut:
EXTRA_CFLAGS = prog: private EXTRA_CFLAGS = -L/usr/local/lib prog: a.o b.o
Berkat pengubah private, a.o dan b.o tidak akan mewarisi penetapan variabel EXTRA_CFLAGS dari target prog.
GNU make mendukung beberapa variabel yang memiliki sifat khusus.
MAKEFILE_LIST
Menyimpan nama setiap makefile yang diuraikan (parse) oleh make, dalam urutan penguraiannya. Nama tersebut ditambahkan tepat sebelum make mulai menguraikan makefile itu. Oleh karena itu, jika hal pertama yang dilakukan sebuah makefile adalah memeriksa kata terakhir dalam variabel ini, kata tersebut akan menjadi nama makefile saat ini. Namun, setelah makefile saat ini menggunakan include, kata terakhir akan menjadi makefile yang baru saja dimasukkan (included).
Misalkan sebuah makefile bernama Makefile memiliki isi berikut:
name1 := $(lastword $(MAKEFILE_LIST))
include inc.mk
name2 := $(lastword $(MAKEFILE_LIST))
all:
@echo name1 = $(name1)
@echo name2 = $(name2)
maka Anda dapat mengharapkan output berikut:
name1 = Makefile name2 = inc.mk
.DEFAULT_GOAL
Menetapkan sasaran (goal) default yang digunakan jika tidak ada target yang ditentukan pada baris perintah (lihat Argumen untuk menentukan sasaran). Variabel .DEFAULT_GOAL memungkinkan Anda memeriksa sasaran default saat ini, memulai ulang algoritma pemilihan sasaran default dengan mengosongkan nilainya, atau menetapkan sasaran default secara eksplisit. Contoh berikut menggambarkan kasus-kasus tersebut:
# Query the default goal. ifeq ($(.DEFAULT_GOAL),) $(warning no default goal is set) endif .PHONY: foo foo: ; @echo $@ $(warning default goal is $(.DEFAULT_GOAL)) # Reset the default goal. .DEFAULT_GOAL := .PHONY: bar bar: ; @echo $@ $(warning default goal is $(.DEFAULT_GOAL)) # Set our own. .DEFAULT_GOAL := foo
Makefile ini akan mencetak:
no default goal is set default goal is foo default goal is bar foo
Perhatikan bahwa memberikan lebih dari satu nama target ke .DEFAULT_GOAL tidak valid dan akan menghasilkan error.
MAKE_RESTARTS
Variabel ini hanya ditetapkan jika instansi make ini telah dimulai ulang (restart) (lihat Cara makefile dibuat ulang): variabel ini berisi jumlah berapa kali instansi ini telah dimulai ulang. Perhatikan bahwa ini berbeda dari rekursi (yang dihitung oleh variabel MAKELEVEL). Anda tidak boleh menetapkan, mengubah, atau meng-ekspor variabel ini.
MAKE_TERMOUTMAKE_TERMERR
Saat dijalankan, make akan memeriksa apakah stdout dan stderr masing-masing menampilkan outputnya ke terminal. Jika ya, make akan menetapkan MAKE_TERMOUT dan MAKE_TERMERR, secara berurutan, ke nama perangkat terminal (atau true jika tidak dapat ditentukan). Jika ditetapkan, variabel-variabel ini akan ditandai untuk di-ekspor. Variabel-variabel ini tidak akan diubah oleh make, dan tidak akan diubah jika sudah ditetapkan sebelumnya.
Nilai-nilai ini dapat digunakan (terutama dikombinasikan dengan sinkronisasi output, lihat Output selama eksekusi paralel) untuk menentukan apakah make sendiri sedang menulis ke terminal; nilai ini dapat diuji untuk memutuskan, misalnya, apakah perintah resep perlu dipaksa menghasilkan output berwarna.
Jika Anda memanggil sub-make dan mengalihkan (redirect) stdout atau stderr-nya, dan makefile Anda bergantung pada variabel-variabel ini, maka menjadi tanggung jawab Anda untuk mereset atau meng-unexport variabel-variabel ini juga.
.RECIPEPREFIX
Karakter pertama dari nilai variabel ini digunakan sebagai karakter yang dianggap make sebagai penanda awal baris resep. Jika variabel ini kosong (seperti secara default), karakter tersebut adalah karakter tab standar. Sebagai contoh, berikut ini adalah makefile yang valid:
.RECIPEPREFIX = > all: > @echo Hello, world
Nilai .RECIPEPREFIX dapat diubah berkali-kali. Setelah ditetapkan, nilai tersebut akan terus berlaku untuk semua aturan yang diuraikan sesudahnya, hingga diubah kembali.
.VARIABLESDiekspansi menjadi daftar nama semua variabel global yang telah didefinisikan sejauh ini. Ini termasuk variabel yang memiliki nilai kosong, serta variabel bawaan (lihat Variabel yang digunakan oleh aturan implisit), tetapi tidak termasuk variabel apa pun yang hanya didefinisikan dalam konteks khusus target. Perhatikan bahwa nilai apa pun yang Anda tetapkan ke variabel ini akan diabaikan; variabel ini akan selalu mengembalikan nilai khususnya.
.FEATURES
Diekspansi menjadi daftar fitur khusus yang didukung oleh versi make ini. Nilai yang mungkin mencakup (tetapi tidak terbatas pada):
Mendukung file ar (archive) menggunakan sintaksis nama file khusus. Lihat Menggunakan make untuk memperbarui file arsip.
Mendukung flag -L (--check-symlink-times). Lihat Ringkasan opsi.
Mendukung kondisional “else if” yang tidak bersarang. Lihat Sintaksis kondisional.
Mendukung target khusus .EXTRA_PREREQS.
Mendukung sintaksis target berkelompok (grouped target) untuk aturan eksplisit. Lihat Banyak target dalam satu aturan.
Memiliki GNU Guile yang tersedia sebagai bahasa ekstensi bawaan. Lihat Integrasi dengan GNU Guile.
Mendukung build paralel yang ditingkatkan dengan “job server”. Lihat Eksekusi paralel.
Mendukung build paralel yang ditingkatkan dengan “job server” menggunakan named pipe. Lihat Mengintegrasikan GNU make.
Mendukung objek yang dapat dimuat secara dinamis (dynamically loadable) untuk membuat ekstensi kustom. Lihat Memuat objek dinamis.
Mendukung target khusus .NOTINTERMEDIATE. Lihat Mengintegrasikan GNU make.
Mendukung target khusus .ONESHELL. Lihat Menjalankan dalam satu shell.
Mendukung prasyarat order-only. Lihat Jenis-jenis prasyarat.
Mendukung opsi baris perintah --output-sync. Lihat Ringkasan opsi.
Mendukung ekspansi sekunder untuk daftar prasyarat.
Mendukung ekspor variabel make ke fungsi shell.
Menggunakan metode “stem terpendek” untuk memilih pola mana yang digunakan di antara beberapa pilihan yang berlaku. Lihat Bagaimana pola mencocokkan.
Mendukung penetapan variabel khusus target dan khusus pola. Lihat Nilai variabel khusus target.
Mendukung direktif undefine. Lihat Membatalkan definisi variabel.
.INCLUDE_DIRS
Diekspansi menjadi daftar direktori yang dicari make untuk makefile yang di-include (lihat Menyertakan makefile lain). Perhatikan bahwa mengubah nilai variabel ini tidak mengubah daftar direktori yang dicari.
.EXTRA_PREREQSSetiap kata dalam variabel ini adalah prasyarat baru yang ditambahkan ke target tempat variabel ini ditetapkan. Prasyarat-prasyarat ini berbeda dari prasyarat biasa karena tidak muncul pada variabel otomatis mana pun (lihat Variabel otomatis). Hal ini memungkinkan Anda mendefinisikan prasyarat yang tidak memengaruhi resep.
Perhatikan aturan untuk menautkan (link) sebuah program:
myprog: myprog.o file1.o file2.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
Sekarang misalkan Anda ingin meningkatkan makefile ini agar memastikan program ditautkan ulang jika ada pembaruan pada kompiler. Anda dapat menambahkan kompiler sebagai prasyarat, tetapi Anda harus memastikan bahwa kompiler tersebut tidak diteruskan sebagai argumen ke perintah link. Anda memerlukan sesuatu seperti berikut:
myprog: myprog.o file1.o file2.o $(CC)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \
$(filter-out $(CC),$^) $(LDLIBS)
Sekarang bayangkan jika ada beberapa prasyarat tambahan: semuanya harus difilter keluar. Dengan menggunakan .EXTRA_PREREQS dan variabel khusus target, Anda mendapatkan solusi yang lebih sederhana:
myprog: myprog.o file1.o file2.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
myprog: .EXTRA_PREREQS = $(CC)
Fitur ini juga berguna jika Anda ingin menambahkan prasyarat ke makefile yang tidak mudah diubah: Anda dapat membuat file baru seperti extra.mk:
myprog: .EXTRA_PREREQS = $(CC)
lalu memanggil make -f extra.mk -f Makefile.
Jika Anda menetapkan .EXTRA_PREREQS secara global, prasyarat-prasyarat tersebut akan ditambahkan ke semua target (yang belum menimpanya sendiri dengan nilai khusus target). Perhatikan bahwa make cukup cerdas untuk tidak menambahkan prasyarat yang tercantum dalam .EXTRA_PREREQS sebagai prasyarat bagi dirinya sendiri.