GNU/Linux >> Belajar Linux >  >> Linux

Apa itu Makefile dan bagaimana cara kerjanya?

Jika Anda ingin menjalankan atau memperbarui tugas saat file tertentu diperbarui, tombol make utilitas dapat berguna. make utilitas memerlukan file, Makefile (atau makefile ), yang mendefinisikan serangkaian tugas yang akan dieksekusi. Anda mungkin pernah menggunakan make untuk mengkompilasi program dari kode sumber. Sebagian besar proyek open source menggunakan make untuk mengkompilasi biner akhir yang dapat dieksekusi, yang kemudian dapat diinstal menggunakan make install .

Dalam artikel ini, kita akan menjelajahi make dan Makefile menggunakan contoh dasar dan lanjutan. Sebelum Anda mulai, pastikan bahwa make diinstal di sistem Anda.

Contoh dasar

Mari kita mulai dengan mencetak "Hello World" klasik di terminal. Buat direktori kosong myproject berisi file Makefile dengan konten ini:

say_hello:
        echo "Halo Dunia"

Sekarang jalankan file dengan mengetikkan make di dalam direktori myproject . Outputnya adalah:

$ make
echo "Halo Dunia"
Halo Dunia

Pada contoh di atas, say_hello berperilaku seperti nama fungsi, seperti dalam bahasa pemrograman apa pun. Ini disebut target . Prasyarat atau dependensi mengikuti sasaran. Demi kesederhanaan, kami belum mendefinisikan prasyarat apa pun dalam contoh ini. Perintah echo "Hello World" disebut resep . resep menggunakan prasyarat untuk membuat target . Target, prasyarat, dan resep bersama-sama membuat aturan .

Untuk meringkas, di bawah ini adalah sintaks dari aturan umum:

target:prasyarat
resep

Sebagai contoh, target mungkin berupa file biner yang bergantung pada prasyarat (file sumber). Di sisi lain, prasyarat juga bisa menjadi target yang bergantung pada dependensi lain:

final_target:sub_target final_target.c
        Recipe_to_create_final_target

sub_target:sub_target.c
        Recipe_to_create_sub_target

Target tidak harus berupa file; itu bisa saja hanya nama untuk resepnya, seperti dalam contoh kita. Kami menyebutnya "target palsu".

Kembali ke contoh di atas, ketika make dieksekusi, seluruh perintah echo "Hello World" ditampilkan, diikuti oleh output perintah yang sebenarnya. Kita sering tidak menginginkan itu. Untuk menekan gema perintah yang sebenarnya, kita perlu memulai echo dengan @ :

say_hello:
        @echo "Halo Dunia"

Sekarang coba jalankan make lagi. Outputnya hanya akan menampilkan ini:

$ make
Halo Dunia

Mari tambahkan beberapa target palsu lagi:generate dan clean ke Makefile :

say_hello:
        @echo "Hello World"

hasilkan:
        @echo "Membuat file teks kosong..."
        sentuh file-{1. .10}.txt

bersih:
        @echo "Membersihkan..."
        rm *.txt

Jika kita mencoba menjalankan make setelah perubahan, hanya target say_hello akan dieksekusi. Itu karena hanya target pertama di makefile yang menjadi target default. Sering disebut tujuan default , inilah alasan Anda akan melihat all sebagai target pertama di sebagian besar proyek. Ini adalah tanggung jawab all untuk memanggil target lain. Kami dapat mengganti perilaku ini menggunakan target palsu khusus yang disebut .DEFAULT_GOAL .

Mari kita sertakan itu di awal makefile kita:

.DEFAULT_GOAL := generate 

Ini akan menjalankan target generate sebagai default:

$ make
Membuat file teks kosong...
touch file-{1..10}.txt

Seperti namanya, target palsu .DEFAULT_GOAL hanya dapat menjalankan satu target pada satu waktu. Inilah sebabnya mengapa sebagian besar makefile menyertakan all sebagai target yang dapat memanggil target sebanyak yang dibutuhkan.

Mari sertakan target palsu all dan hapus .DEFAULT_GOAL :

all:say_hello generate

say_hello:
        @echo "Hello World"

generate:
        @echo "Membuat file teks kosong.. ."
        sentuh file-{1..10}.txt

clean:
        @echo "Membersihkan..."
        rm *.txt

Sebelum menjalankan make , mari sertakan target palsu khusus lainnya, .PHONY , di mana kita mendefinisikan semua target yang bukan file. make akan menjalankan resepnya terlepas dari apakah file dengan nama itu ada atau waktu modifikasi terakhirnya. Berikut makefile lengkapnya:

.PHONY:all say_hello generate clean

all:say_hello generate

say_hello:
        @echo "Hello World"

generate:
        @echo "Membuat file teks kosong..."
        sentuh file-{1..10}.txt

clean:
        @echo "Membersihkan naik..."
        rm *.txt

make harus menelepon say_hello dan generate :

$ make
Hello World
Membuat file teks kosong...
touch file-{1..10}.txt

Ini adalah praktik yang baik untuk tidak memanggil clean di all atau menjadikannya sebagai target pertama. clean harus dipanggil secara manual saat pembersihan diperlukan sebagai argumen pertama untuk make :

$ bersihkan
Bersihkan...
rm *.txt

Sekarang setelah Anda memiliki gagasan tentang cara kerja makefile dasar dan cara menulis makefile sederhana, mari kita lihat beberapa contoh lanjutan.

Contoh lanjutan

Variabel

Lebih banyak sumber daya Linux

  • Lembar contekan perintah Linux
  • Lembar contekan perintah Linux tingkat lanjut
  • Kursus online gratis:Ikhtisar Teknis RHEL
  • Lembar contekan jaringan Linux
  • Lembar contekan SELinux
  • Lembar contekan perintah umum Linux
  • Apa itu container Linux?
  • Artikel Linux terbaru kami

Dalam contoh di atas, sebagian besar nilai target dan prasyarat adalah hard-coded, tetapi dalam proyek nyata, ini diganti dengan variabel dan pola.

Cara paling sederhana untuk mendefinisikan variabel dalam makefile adalah dengan menggunakan = operator. Misalnya, untuk menetapkan perintah gcc ke variabel CC :

CC = gcc
 

Ini juga disebut variabel diperluas rekursif , dan digunakan dalam aturan seperti yang ditunjukkan di bawah ini:

halo:hello.c
    ${CC} hello.c -o halo

Seperti yang mungkin sudah Anda duga, resepnya berkembang seperti di bawah ini ketika diteruskan ke terminal:

gcc hello.c -o hello
 

Keduanya ${CC} dan $(CC) adalah referensi yang valid untuk memanggil gcc . Tetapi jika seseorang mencoba untuk menetapkan kembali variabel ke dirinya sendiri, itu akan menyebabkan loop tak terbatas. Mari kita verifikasi ini:

CC =gcc
CC =${CC}

semua:
    @echo ${CC}

Menjalankan make akan mengakibatkan:

$ make
Makefile:8:*** Variabel rekursif 'CC' mereferensikan dirinya sendiri (akhirnya). Berhenti.

Untuk menghindari skenario ini, kita dapat menggunakan := operator (ini juga disebut variabel yang diperluas secara sederhana ). Kita seharusnya tidak memiliki masalah menjalankan makefile di bawah ini:

CC :=gcc
CC :=${CC}

semua:
    @echo ${CC}

Pola dan fungsi

Makefile berikut dapat mengkompilasi semua program C dengan menggunakan variabel, pola, dan fungsi. Mari kita telusuri baris demi baris:

# Penggunaan:
# make        # kompilasi semua biner
# make clean  # hapus SEMUA biner dan objek

.PHONY =all clean

CC =gcc                        # compiler yang akan digunakan

LINKERFLAG =-lm

SRCS :=$(wildcard *.c)
BINS :=$(SRCS:%. c=%)

semua:${BINS}

%:%.o
        @echo "Memeriksa.."
        ${CC} ${LINKERFLAG} $<-o $@

%.o:%.c
        @echo "Membuat objek.."
        ${CC} -c $<

bersih:
        @echo "Membersihkan..."
        rm -rvf *.o ${BINS}
  • Baris dimulai dengan # adalah komentar.

  • Baris .PHONY = all clean mendefinisikan target palsu all dan clean .

  • Variabel LINKERFLAG mendefinisikan flag yang akan digunakan dengan gcc dalam resep.

  • SRCS := $(wildcard *.c) :$(wildcard pattern) adalah salah satu fungsi untuk nama file . Dalam hal ini, semua file dengan .c ekstensi akan disimpan dalam variabel SRCS .

  • BINS := $(SRCS:%.c=%) :Ini disebut sebagai referensi substitusi . Dalam hal ini, jika SRCS memiliki nilai 'foo.c bar.c' , BINS akan memiliki 'foo bar' .

  • Baris all: ${BINS} :Target palsu all memanggil nilai di${BINS} sebagai target individu.

  • Aturan:

    %:%.o
      @echo "Memeriksa.."
      ${CC} ${LINKERFLAG} $< -o $@

    Mari kita lihat contoh untuk memahami aturan ini. Misalkan foo adalah salah satu nilai dalam ${BINS} . Kemudian % akan cocok dengan foo (% dapat cocok dengan nama target apa pun). Di bawah ini adalah aturan dalam bentuk yang diperluas:

    foo:foo.o
      @echo "Memeriksa.."
      gcc -lm foo.o -o foo

    Seperti yang ditunjukkan, % digantikan oleh foo . $< digantikan oleh foo.o . $< dipola untuk mencocokkan prasyarat dan $@ cocok dengan targetnya. Aturan ini akan dipanggil untuk setiap nilai di ${BINS}

  • Aturan:

    %.o:%.c
      @echo "Membuat objek.."
      ${CC} -c $<

    Setiap prasyarat dalam aturan sebelumnya dianggap sebagai target untuk aturan ini. Di bawah ini adalah aturan dalam bentuk yang diperluas:

    foo.o:foo.c
      @echo "Membuat objek.."
      gcc -c foo.c
  • Terakhir, kami menghapus semua file biner dan objek di target clean .

Di bawah ini adalah penulisan ulang makefile di atas, dengan asumsi itu ditempatkan di direktori yang memiliki satu file foo.c:

# Penggunaan:
# make        # kompilasi semua biner
# make clean  # hapus SEMUA biner dan objek

.PHONY =all clean

CC =gcc                        # compiler yang akan digunakan

LINKERFLAG =-lm

SRCS :=foo.c
BINS :=foo

semua :foo

foo:foo.o
        @echo "Memeriksa.."
        gcc -lm foo.o -o foo

foo.o :foo.c
        @echo "Membuat objek.."
        gcc -c foo.c

clean:
        @echo "Membersihkan..."
        rm -rvf foo.o foo

Untuk lebih lanjut tentang makefile, lihat manual GNU Make, yang menawarkan referensi dan contoh lengkap.

Anda juga dapat membaca Pengantar GNU Autotools kami untuk mempelajari cara mengotomatiskan pembuatan makefile untuk proyek pengkodean Anda.


Linux
  1. Tujuan .bashrc Dan Bagaimana Cara Kerjanya?

  2. Apa itu DNS dan Bagaimana Cara Kerjanya?

  3. Bagaimana sebenarnya sig_atomic_t bekerja?

  1. Apa itu NGINX? Bagaimana cara kerjanya?

  2. Apa itu Server Web, dan Bagaimana Cara Kerja Server Web?

  3. Bagaimana Cara Kerja Awk ‘!a[$0]++’?

  1. Bagaimana Cara Kerja Sticky Bit?

  2. Ssh – Bagaimana Tcp-keepalive Bekerja Di Ssh?

  3. Bagaimana rm bekerja? Apa yang rm lakukan?