- Ang isang mahusay na idinisenyong Makefile ay nag-o-automate ng compilation, namamahala sa mga dependency, at pinapadali ang mga gawain tulad ng paglilinis at pag-iimpake, pag-optimize ng daloy ng trabaho sa mga proyekto ng software.
- Ang paggamit ng mga variable, implicit na mga panuntunan, mga espesyal na layunin, at ang tamang deklarasyon ng mga dependency ay nagpapataas ng kahusayan at kakayahang mapanatili, na nagpapahintulot sa proyekto na mapalawak nang walang mga komplikasyon.
- Ang mga alternatibo tulad ng CMake ay nag-aalok ng cross-platform na pamamahala at advanced na automation, ngunit ang pag-master ng Makefile ay nananatiling mahalaga para sa mga programmer sa mga kapaligiran Unix at upang lubos na maunawaan ang mga proseso ng konstruksiyon.
Sa mundo ng programming at software development, ang pag-optimize sa proseso ng pagbuo at pamamahala ng proyekto ay mahalaga, lalo na kapag ang bilang ng mga file ay lumalaki at ang mga kumplikadong dependency ay nagsimulang lumitaw. Ito ay kung saan ang paggamit ng mga tool tulad ng gumawa at ang paghahanda ng mga file Makefile pumagitna sa entablado. Kung naisip mo na kung paano i-automate ang pagbuo ng binary sa iyong mga proyekto sa C o C++, o gusto lang gawing mas madali ang buhay para sa sinumang nagtatrabaho sa iyong code, ang pag-master ng mga lihim ng Makefiles ay nagiging isang halos mandatoryong pangangailangan.
Sa malawak na artikulong ito makikita mo, hakbang-hakbang at kumpleto, Paano gumawa at mag-customize ng sarili mong Makefiles anuman ang laki ng iyong proyekto, mula sa pinakapangunahing mga halimbawa hanggang sa mas advanced na mga pagsasaayos, na sumasaklaw sa parehong mahahalagang teorya at praktikal na payo, Trick upang maiwasan ang mga karaniwang pagkakamali at modernong alternatibo tulad ng CMake. Ang layunin ay, sa oras na matapos mo ang pagbabasa, magkakaroon ka ng malinaw at kumpletong pag-unawa sa kung paano gumagana ang Make, kung bakit ito kapaki-pakinabang, at kung paano mo ito masusulit sa pamamagitan ng pag-angkop nito sa iyong aktwal na mga pangangailangan sa pag-unlad.
Ano ang make at para saan ang isang Makefile?
Ang make ay isa sa mga pinakaluma at pinaka-versatile na utility sa Unix/Linux universe, bagama't mayroon ding mga pagpapatupad para sa iba OS bilang Windows (NMAKE, bukod sa iba pa). Ang pangunahing layunin nito ay ang pamahalaan ang automation ng pag-compile at pagbuo ng mga proyekto, lalo na kapag binubuo ang mga ito ng maraming source file, library, at header. Ang Makefile ay ang script kung saan nakuha ang lohika ng pagtatayo ng proyekto.: tumutukoy kung ano ang dapat gawin, sa anong pagkakasunud-sunod at kung anong mga dependency, na nagpapahintulot sa sarili na gawin lamang ang mga kinakailangang gawain kapag may mga pagbabago.
Isipin ang karaniwang problema: Mayroon kang proyekto na may dose-dosenang mga .c at .h na file. Kung kino-compile mo ito "sa pamamagitan ng kamay," ang proseso ay mabagal, nakakapagod, at madaling magkamali sa pamamagitan ng paglimot sa isang parameter, dependency, o muling pag-compile ng lahat sa bawat pagkakataon. Sa pamamagitan ng make at isang mahusay na disenyong Makefile, ang compilation ay nagiging halos isang lakad sa parke., dahil ang mga sangkap lamang na talagang nangangailangan nito ay muling nabuo, nakakatipid ng oras at sakit ng ulo. Higit pa rito, ang Makefile ay hindi lamang kapaki-pakinabang para sa pag-compile: maaari itong magamit upang linisin pansamantalang mga file, package code, i-install ang mga binary, magpatakbo ng mga pagsubok, at marami pang iba.
Mga kalamangan ng paggamit ng Makefile sa iyong mga proyekto
- Build Automation: Kalimutan ang tungkol sa mahabang manu-manong linya ng comandos mag-compile. Sa isang simpleng "make" command, alam ng system kung ano ang gagawin.
- Pamamahala ng dependency: I-compile lamang kung ano ang nagbago o depende sa mga binagong file, na nakakatipid ng oras.
- Mas mahusay na portability at kadalian para sa iba pang mga developer: Maaaring i-compile ng sinuman ang iyong proyekto sa isang standardized na paraan.
- Posibilidad ng pagtukoy ng mga karagdagang gawain: Paglilinis ng mga pansamantalang file, pagbuo ng mga pakete, pagpapatakbo ng mga awtomatikong pagsubok, atbp.
Paano gumawa ng trabaho sa loob?
Ang paggawa ay batay sa dependency at target na lohika: bawat "pakay" ng Makefile ay nag-ugnay ng ilan "mga dependency" (mga file na nakasalalay sa pagbuo) at ilang mga recipe (ang mga utos na isasagawa, palaging naka-indent sa mga tab). Kapag nag-execute ka "gumawa ng target"Sinusuri ng programa kung umiiral na ang target na iyon at kung napapanahon ang mga dependency nito. Kung ang anumang mga dependency ay mas bago kaysa sa target, pinapatakbo nito ang nauugnay na recipe upang muling itayo ito.
Ang pangunahing syntax ay:
target: dependencies
utos1 utos2
Halimbawa, upang mag-compile ng isang executable na tinatawag pangunahin mula sa mga archive pangunahing.c y kapaki-pakinabang.o:
pangunahing: main.c util.o gcc -o main main.c util.o
Tulad ng nakikita mo, ang layunin ay pangunahin, at ito ay depende sa pangunahing.c y kapaki-pakinabang.oKung magbago ang alinman sa mga file na ito, tatakbo ang make sa recipe sa ibaba lamang (ang gcc command).
Pagsisimula: Basic Compilation na walang Makefile
Bago tayo sumisid sa paglikha ng Makefile, tingnan natin kung paano tradisyonal na pinagsama-sama ang isang simpleng programa. Ipagpalagay na mayroon kang file na ito sa C:
#isama int main() { printf("Kumusta mundo\n"); bumalik 0; }
Upang i-compile ito nang manu-mano:
gcc hello.c -o hello
Perpekto, nasa iyo na ngayon ang iyong executable. hoy. Gayunpaman, kung babaguhin mo ang source file, kakailanganin mong muling patakbuhin ang buong command na ito sa bawat oras. At habang lumalaki ang iyong proyekto, ang mga linya ay magiging mas mahaba at mahirap tandaan.
Pag-compile gamit ang make: ang magic ng implicit at awtomatikong mga panuntunan

Napakatalino ng make tool na, kahit na walang tahasang Makefile, maaari itong mag-compile ng mga simpleng programa mula sa mga panloob na convention nito.. Halimbawa, kung mayroon ka kumusta.c sa iyong folder at patakbuhin ang:
kumusta
Nakikita ng Make ang presensya ng file at, gamit ang mga implicit na panuntunan nito, ginagamit ang naaangkop na compiler upang bumuo ng binary. hoy mula sa pinagmulan kumusta.c. Kung ang executable ay nagawa na at mas bago kaysa sa source, wala itong gagawin. Kung tatanggalin mo ang executable at patakbuhin itong muli kumusta, ito ay muling i-compile ito nang hindi mo kailangang tandaan ang mga parameter.
Bakit mahalaga ang Makefile sa mga proyekto sa totoong buhay?
Mabilis na mauubos ang mahika ng mga panloob na panuntunan ng make sa sandaling magsimulang magkaroon ng maraming source file, header, at cross-dependencies ang proyekto. Sa kasong iyon, hindi malalaman kung ano ang isasama, kung anong mga opsyon ng compiler ang gagana, o kung paano mag-link ng mga bagay. Doon ang Makefile ay naging iyong pinakamahusay na kakampi, dahil sinasabi nito kung paano ituring ang bawat file, kung paano i-compile ang mga indibidwal na bagay, at kung paano i-link ang mga ito nang magkasama upang makagawa ng isa o higit pang mga executable.
Ang Makefile Structure: Teorya at Practice
Ang isang tradisyunal na Makefile ay binubuo ng isa o higit pang mga panuntunan na binubuo ng tatlong bahagi: ang target, mga dependency nito, at isang recipe ng command. Ang mga command line na naisasagawa ay dapat magsimula (oo o oo) na may tab, hindi kailanman puwang. Kung hindi, mabibigo ang make.
target: dependencies command1 command2 ...
Paliwanag ng mga termino:
- Objetivo: Ito ay karaniwang ang pangalan ng executable, isang object file, o kahit isang panloob na aksyon tulad ng "malinis."
- Mga dependency: Mga file na dapat na umiiral at napapanahon para sa target na mabuo. Kung ang anumang dependency ay mas bago kaysa sa target, make run ang recipe.
- Mga Utos: Dapat na may naka-indent ang mga tagubilin sa pag-compile, tanggalin, package, atbp tabulator.
Napakapangunahing halimbawa ng Makefile Para mag-compile ng dalawang source file at bumuo ng executable:
pagsubok: test.o main.o gcc -o test test.o main.o test.o: test.c gcc -o test.o -c test.c main.o: main.c test.h gcc -o main.o -c main.c
Kaya, kung gagawin mo gumawa, susuriin muna nito kung umiiral ang mga bagay; kung hindi, ito ay mag-compile sa kanila, at pagkatapos ay i-link ang mga ito sa test executable.
Pagsusuri ng mga pangunahing konsepto batay sa aktwal na daloy ng trabaho
Habang nagiging mas kumplikado ang iyong proyekto, mahalagang maunawaan kung paano ayusin ang mga dependency, bagay, at panuntunan upang makagawa lamang ng mga recompile kung ano ang kinakailangan. Halimbawa, kung babaguhin mo lamang ang isang .h file, gugustuhin mong tiyakin na ang lahat ng .c file na kasama nito ay muling pinagsama-sama, ngunit wala nang iba pa..
Ipagpalagay na mayroon kang sumusunod na hanay ng mga file:
- pangunahing.c: ang pangunahing programa, kasama ang hello.h
- kumusta.c: mga pantulong na function
- hello.h: header ng function
Ang isang simple ngunit functional na Makefile ay:
hello: main.o hello.o gcc -o hello main.o hello.o main.o: main.c hello.h gcc -c main.c hello.o: hello.c hello.h gcc -c hello.c
Ngayon ang lahat ay nakasalalay sa kung ano ang hinawakan nito, at kung ano lamang ang nagbago o nakasalalay sa kung ano ang nagbago ay muling pinagsama-sama.
Mga variable sa Makefile: muling gamitin at pasimplehin
Ang isa sa pinakamakapangyarihang armas ng Makefiles ay mga variable.Sa kanila, maaari mong tukuyin, halimbawa, ang compiler, mga karaniwang flag, binary na pangalan, mga bagay, atbp. Sa ganitong paraan, kailangan mo lamang baguhin ang isang bagay sa isang linya, at ang natitirang bahagi ng Makefile ay awtomatikong nag-a-update.
Karaniwang halimbawa:
CC=gcc CFLAGS=-I. OBJ=main.o hello.o hello: $(OBJ) $(CC) -o hello $(OBJ) $(CFLAGS) %.o: %.c hello.h $(CC) -c -o $@ $< $(CFLAGS)
Dito:
- $(CC) ay ang variable ng compiler.
- $(CFLAGS) ay ang mga opsyon na ipinasa sa compiler.
- $(OBJ) naglalaman ng listahan ng mga bagay.
- $@ ay pinalitan ng pangalan ng target, at $< sa pamamagitan ng unang dependency.
Nagbibigay-daan ito sa iyo na bumuo ng mas pangkalahatan at nababaluktot na mga panuntunan. Halimbawa, kung magdaragdag ka ng isa pang .o, kakailanganin mo lang baguhin ang variable ng OBJ.
Rekomendasyon: Gumamit ng mga variable upang maiwasan ang mga pag-uulit at mapadali ang mga pagbabago.
Ang pagtukoy sa mga variable sa simula ng Makefile ay isang pangunahing kasanayan para sa pagpapanatili at pagiging madaling mabasa ng proyekto.Maaari mong tukuyin ang lahat mula sa executable na pangalan hanggang sa header, object, at source na mga direktoryo:
CC=gcc CFLAGS=-Wall -g -I./include OBJ=main.o func.o utils.o my_program: $(OBJ) $(CC) -o $@ $^ $(CFLAGS)
$^ kumakatawan sa lahat ng mga dependency (sa kasong ito, mga bagay). Kaya, kailangan mo lang pindutin ang OBJ variable para baguhin ang source list.
Pagdaragdag ng mga espesyal na panuntunan: lahat, malinis at iba pang mga kapaki-pakinabang na gawain
Sa karamihan ng mga proyekto, kailangan mo ng mga karagdagang gawain bukod sa compilation. Halimbawa:
- Nililinis ang mga intermediate (.o) at binary file (linisin).
- Pagbuo ng lahat ng binary nang sabay-sabay (lahat).
- Pagbuo ng mga pakete, dokumentasyon, pagsubok, atbp.
Halimbawa ng makefile sa lahat at malinis:
CC=gcc CFLAGS=-I. OBJ=main.o hello.o all: hello hello: $(OBJ) $(CC) -o hello $(OBJ) $(CFLAGS) %.o: %.c hello.h $(CC) -c -o $@ $< $(CFLAGS) clean: rm -f hello *.o
Ngayon, kung tatakbo ka gumawa o gawin ang lahat, ang binary ay bubuuin. Kung tatakbo ka gawing malinis, ang mga binary at object file ay tinanggal.
Mahalaga: Kung mayroon kang file sa direktoryo na tinatawag na "clean", hindi tatakbo ng make ang recipe kapag gumagamit ng "make clean" maliban kung idedeklara mo ang target bilang .PHONY:
.PHONY: malinis malinis: rm -f kumusta *.o
Pag-optimize at Pagpapanatili ng Dependency: Isama nang tama ang mga .h na file
Ang isa sa mga pinakakaraniwang pagkakamali na ginagawa ng mga nagsisimula ay ang hindi pagdedeklara ng mga dependency sa mga .h na file., na maaaring humantong sa mga pinagmumulan na may kasamang header na hindi muling kino-compile kapag binago ang isang header.
Para ayusin ito, tahasang ideklara ang dependency ng bawat object sa katumbas nitong .h object(s).. O kaya, gumamit ng mga awtomatikong panuntunan:
%.o: %.c hello.h $(CC) -c -o $@ $< $(CFLAGS)
Kaya, sa bawat oras hello.h mga pagbabago, gumawa ng mga recompile na umaasa na mga bagay.
Advanced na Dependency Automation: MakeDepend at Mga Alternatibo
Para sa malalaking proyekto, ang pamamahala sa mga dependency sa pamamagitan ng kamay ay maaaring maging napakahirap., lalo na kung ang ilang .h file ay may kasamang iba. Ito ay kung saan gusto ng mga tool makedepend, na idinisenyo upang awtomatikong buuin ang mga ito at panatilihing napapanahon ang Makefile. Upang mahawakan ang mas kumplikadong mga kaso, lalo na kapag nagtatrabaho sa mga cross-platform na platform, maaaring makatulong na maunawaan ang mahusay at flexible.
- Patakbuhin:
makedepend -I./include *.c
- Ito ay magdaragdag ng tamang mga linya ng dependency sa dulo ng Makefile.
Karaniwang istraktura ng isang propesyonal na Makefile
CFLAGS=-I./include OBJECTS=main.o utils.o func.o SOURCES=main.c utils.c func.c program: $(OBJECTS) gcc $(OBJECTS) -o program depend: makedepend $(CFLAGS) $(SOURCES) clean: rm -f program *.o
Makefile para sa mga proyekto na kumalat sa maraming direktoryo
Kapag dumami ang bilang ng mga direktoryo (halimbawa, na may ilang mga module at library), normal na magkaroon ng pangunahing Makefile na nagde-delegate sa iba pang pangalawang Makefiles.Halimbawa, maaari kang magkaroon ng Makefile sa root directory na tumatawag sa Makefile ng bawat module na may:
module1: gumawa -C module1 module2: gumawa -C module2
At pagkatapos ay ang huling link ng lahat ng .oo library na nabuo sa bawat folder.
Pagsasama ng Makefiles sa mga hindi Unix na kapaligiran: Visual Studio at NMAKE
Kung nagtatrabaho ka sa Windows, nag-aalok ang Visual Studio ng suporta para sa mga proyektong nakabatay sa Makefile. Gamit ang tool na NMAKE o ang opsyong Makefile Projects, maaari kang lumikha ng isang proyekto mula sa template ng Makefile, tukuyin ang iyong compilation, cleanup, at output command mula sa wizard, at isama ang iyong Makefile sa IDE, na sinasamantala ang mga tool tulad ng IntelliSense at advanced na pag-debug.
Sa Visual Studio 2017 at mas bago:
- Piliin ang “File > New > Project,” hanapin ang “Makefile,” piliin ang template, at tukuyin ang mga command para sa pag-compile, paglilinis, at pag-debug.
- Sa tab na mga katangian ng proyekto maaari mong i-configure ang mga landas, mga utos at mga pagpipilian.
- Para sa mas mahusay na pagsasama, tingnan ang tutorial sa Paano pamahalaan ang mga error sa Windows.
Mga Makabagong Makefile na Alternatibo: CMake at Higit Pa
Bagama't ang Makefile ay nananatiling de facto na pamantayan sa mga kapaligiran ng Unix, ang ibang mga sistema tulad ng CMake ay nakakuha ng maraming katanyagan., lalo na dahil sa mga cross-platform na kakayahan nito at mas mapapamahalaan na syntax para sa napakalaking proyekto. Para sa praktikal na patnubay, maaaring kapaki-pakinabang na malaman ito kasabay ng CMake.
Bumubuo ang CMake ng Makefiles para sa iyo mula sa isang mataas na antas ng paglalarawan. Para sa isang simpleng proyekto, sapat na ang isang file. CMakeLists.txt Kaya:
cmake_minimum_required(VERSION 2.8) project(Hello) add_executable(hello main.c hello.c)
Pagkatapos ay patakbuhin ang "cmake." upang makabuo ng Makefiles at "gumawa" upang i-compile. Maaari ka ring lumikha ng isang subdirectory magtayo, isagawa cmake.. mula doon at pagkatapos gumawa upang mapanatiling maayos at nasusukat ang proyekto.
Pinakamahuhusay na kagawian at pangunahing tip para sa Makefile
- Alagaan ang mga tab: Ang mga utos ng recipe ay dapat palaging magsimula sa isang tab, hindi isang espasyo.
- Ipahayag nang tama ang lahat ng mga dependency, kabilang ang mga .h file: Pipigilan nito ang hindi tamang recompilation at mga error dahil sa lumang code.
- Gumamit ng mga variable para sa mga executable na pangalan, direktoryo, at flag: Pinapadali ang pagbabago at binabawasan ang mga error.
- Kasama ang mga layunin tulad ng malinis, lahat, depende: Sa ganitong paraan ang iyong proyekto ay magiging mas madaling gamitin at mapanatili.
- Para sa malalaking proyekto, isaalang-alang ang paggamit ng makedepend o CMake: Sa ganitong paraan maaari mong i-automate ang dependency at pamamahala ng scale nang mas mahusay.
- Sinusuportahan ang paglilinis ng mga pansamantalang file: Huwag punan ang direktoryo ng mga hindi nagamit na bagay o binary na maaaring magdulot ng mga problema kapag nagbabahagi ng code.
- Gawin ang unang target na pangunahing executable o ang "lahat" na target: Kaya kapag ang isang tao ay gumawa ng walang mga argumento, ito ang isasama.
- Magdagdag ng mga komento sa Makefile kung saan naaangkop: Bagama't hindi sapilitan, ginagawa nitong mas madali para sa iba (o para sa iyo sa loob ng ilang linggo) na maunawaan.
Mga karaniwang pagkakamali at kung paano maiiwasan ang mga ito
- Nakakalito ang mga puwang at tab kapag nagsisimula ng mga recipe ng command.
- Nakakalimutang magdeklara ng mga dependency sa mga file ng header (.h).
- Huwag magdeklara ng target bilang .PHONY kung hindi ito bubuo ng file, na maaaring humantong sa kakaibang gawi kung mayroong file o direktoryo na may ganoong pangalan.
- Huwag gumamit ng mga variable para sa mga pangalan at landas, pagdoble ng impormasyon at pagpapahirap sa pagpapanatili.
- Hindi nililinis ang mga pansamantala o binary na file bago ang mga bagong build, na maaaring humantong sa mga nakalilitong error.
Pag-customize ng iyong Makefile para sa mga kumplikadong gawain
Bilang karagdagan sa pag-compile at paglilinis, maaari kang lumikha ng mga custom na panuntunan para sa:
- I-package ang code sa isang ZIP o TAR file.
- Awtomatikong ilunsad ang executable pagkatapos mag-compile.
- Bumuo ng dokumentasyon (halimbawa, gamit ang Doxygen).
- Magpatakbo ng mga awtomatikong pagsubok at ipakita ang mga resulta.
- Ihanda ang code para sa pamamahagi, pagkopya lamang ng mga nauugnay na mapagkukunan at file.
Halimbawa, upang makabuo ng isang naka-compress na file:
dist: zip my_project.zip *.c *.h Makefile README.md
Halimbawa ng Comprehensive Makefile para sa isang kumpletong proyekto
CC=gcc CFLAGS=-Wall -g -I. DEPS=hello.h OBJ=main.o hello.o %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) hello: $(OBJ) $(CC) -o $@ $^ $(CFLAGS) .PHONY: clean dist clean: rm -f hello *.o
Mga totoong kaso at panghuling rekomendasyon
Sa paglipas ng mga taon, ang make at Makefile ay nananatiling kailangan para sa mahusay at organisadong pagsasama-sama ng mga proyekto sa C, C++, at marami pang ibang wika.Bagama't may mga modernong alternatibo tulad ng CMake, ang pag-master ng Makefile ay isang pundasyon na tutulong sa iyo sa anumang seryosong kapaligiran sa pag-unlad.
Tandaan na ang bawat proyekto ay maaaring mangailangan ng mga partikular na pagsasaayos sa Makefile nitoAng pinakamahalagang bagay ay upang maunawaan ang lohika ng mga target, dependency, at mga recipe, upang maaari mong gamitin ang kapangyarihan ng paggawa sa pamamagitan ng pag-automate ng anumang mga kinakailangang gawain. Huwag mag-atubiling pag-aralan ang mga Makefile ng ibang proyekto, gumamit ng mga automated na tool sa pamamahala ng dependency, at mag-eksperimento sa mga karagdagang target.
Ang paglalapat ng lahat ng iyong natutunan dito ay makakatulong sa iyong mabawasan ang pagkakamali ng tao, makatipid ng oras, at gawing mas madali para sa iba (o sa iyong sarili sa hinaharap) na bumuo, magpanatili, at ipamahagi ang iyong software nang propesyonal at mahusay, anuman ang laki ng proyekto.
Masigasig na manunulat tungkol sa mundo ng mga byte at teknolohiya sa pangkalahatan. Gustung-gusto kong ibahagi ang aking kaalaman sa pamamagitan ng pagsusulat, at iyon ang gagawin ko sa blog na ito, ipakita sa iyo ang lahat ng mga pinaka-kagiliw-giliw na bagay tungkol sa mga gadget, software, hardware, teknolohikal na uso, at higit pa. Ang layunin ko ay tulungan kang mag-navigate sa digital na mundo sa simple at nakakaaliw na paraan.