1.2 GNU Make

GNU Make หรือ make เป็นเครื่องมือควบคุมการ build โปรแกรมของยูนิกซ์ ซึ่งเป็นตัวช่วยให้เราสามารถคอมไพล์โปรแกรมที่มี source code มากๆ ได้ง่ายขึ้น แนวคิดของ make คือ หากเราต้องการคอมไพล์โปรแกรมเราก็บอก make ว่า target คืออะไร หลังจากนั้นบอกให้ make รู้ว่ากฎการสร้าง target นั้นๆ คืออะไร (rules) โดยระบุสิ่งที่เกี่ยวข้องกับการคอมไพล์นั้น (dependencies) หากมีการเปลี่ยนแปลงเกิดขึ้นจะได้ rebuild ใหม่ได้ถูกต้อง โดยมีรูปแบบ Makefile ดังต่อไปนี้

target: dependencies
<TAB>command
<TAB>...

โดย <TAB> หมายถึงกดคีย์ Tab หนึ่งครั้ง

ตัวอย่าง Makefile

CFLAGS="-Wall"

reciprocal: main.o reciprocal.o
        g++ $(CFLAGS) -o reciprocal main.o reciprocal.o

main.o: main.c reciprocal.hpp
        gcc $(CFLAGS) -c main.c

reciprocal.o: reciprocal.cpp reciprocal.hpp
        g++ $(CFLAGS) -c reciprocal.cpp

clean:
        rm -f *.o reciprocal

เมื่อเราจะใช้งานก็พิมพ์คำสั่ง make <target> ลองพิมพ์คำสั่งดู

$ make
gcc -Wall -c main.c
g++ -Wall -c reciprocal.cpp
g++ -Wall -o reciprocal main.o reciprocal.o

make จะคอมไพล์ตามกฎที่เราเขียนขึ้นให้ทุกอัน เนื่องจากเมื่อเราพิมพ์คำสั่ง make โดยไม่มีอะไรตามหลัง โปรแกรม make จะหา target แรกสุดของ Makefile แล้วทำงานที่ target นั้น หากสังเกตดู target แรกของ Makefile ตัวอย่างคือ reciprocal ก็เริ่มทำงานที่กฎนี้ แต่ reciprocal มี dependencies สองอันคือ main.o reciprocal.o ก็ต้องทำรายการทั้งสองก่อน ซึ่งปรากฏว่าเป็น target ทั้งคู่ ดังนั้น make จึงเริ่มทำงานที่ main.o ก่อน โดยที่ main.o มี dependencies เป็นไฟล์สองไฟล์คือ main.c reciprocal.hpp ดังนั้น make จะตรวจสอบก่อนว่ามี main.c reciprocal.hpp อยู่จริงหรือไม่ ถ้าไม่มีก็จะขึ้นข้อความดังข้างล่าง และก็จบไปเลยไม่ทำต่อ

make: *** No rule to make target `main.c', needed by `main.o'.  Stop.

ถ้ามีไฟล์ครบตามต้องการก็จะสามารถคอมไพล์ได้ตามที่ต้องการ จากนั้น ก็ไปทำกับ target reciprocal.o ในทำนองเดียวกัน ซึ่งจะทำให้ dependencies ของกฎแรก คือ reciprocal นั้น update ครบทุกอัน และสามารถทำคำสั่งที่ใช้ build reciprocal ได้ ตามขั้นตอนที่เกิดขึ้นข้างต้น

ทีนี้ สมมุติว่าเราแก้ไขไฟล์ main.c แล้วสั่ง make อีกที โปรแกรม make ก็จะพบว่า main.o นั้นเก่ากว่า main.c ที่เป็น dependency และจัดการ update main.o ใหม่ตามกฎที่กำหนด ซึ่งก็คือการ compile ไฟล์ main.c ใหม่ ทำให้ได้ main.o ใหม่ออกมา ซึ่ง main.o ที่สร้างใหม่นี้ ก็จะไปทำให้ target ที่มี dependencies กับ target main.o เองล้าสมัยอีกเช่นกัน ซึ่งก็คือ reciprocal ดังนั้นหากเราพิมพ์ make ลงไปจะได้ ผลดังนี้

$ make
gcc -Wall -c main.c
g++ -Wall -o reciprocal main.o reciprocal.o

ผลก็คือ make จะคอมไพล์ไฟล์ที่มีการแก้ไข และ target ที่มี dependencies ที่เกี่ยวกับไฟล์ที่แก้ไขเท่านั้น โดยไม่ยุ่งกับไฟล์อื่น (เช่น reciprocal.o ในตัวอย่าง) ซึ่งจะช่วยลดเวลาการคอมไพล์โปรแกรมของเราไปได้ อีกทั้งง่ายต่อการใช้งานด้วยหากเราใช้ภาษา C และ C++ ร่วมกัน

คราวนี้มาลอง make แล้วตามด้วย target กันบ้าง

$ make clean
rm -f *.o reciprocal

make จะไปทำงานที่ target นั้นทันทีโดยไม่ทำ target ก่อนหน้า เช่นในตัวอย่างจะไปทำงานที่ clean เลย อีกทั้ง clean ไม่มี dependency กฎของ clean จะถูกเรียกขึ่นมาทำงานทันทีในที่นี้คือ คำสั่ง "rm -f *.o reciprocal"

หากต้องการศึกษาการใช้งานเพิ่มเติม สามารถอ่านได้ที่ GNU Make Manual หรือของคุณเทพที่เคยเขียนเอาไว้แล้วที่ GNU autotools

หมายเหตุ: อย่าลืมกดแท็บนะครับ

Taxonomy upgrade extras: 
Creative Commons License ลิขสิทธิ์ของบทความเป็นของเจ้าของบทความแต่ละชิ้น
ผลงานนี้ ใช้สัญญาอนุญาตของครีเอทีฟคอมมอนส์แบบ แสดงที่มา-อนุญาตแบบเดียวกัน 3.0 ที่ยังไม่ได้ปรับแก้