Makefile là gì ?

Makefile là gì ? Các vấn đề có liên quan tới makefile và cách đơn giản để tiếp cận và làm quen với makefile là như thế nào ? Mình cùng tìm hiểu qua các ví dụ đơn giản sau nhé.

Vấn đề

Khi biên dịch một chương trình đơn giản như bài viết trước thì quá khỏe, chỉ có một vài file. Nếu số lượng file cần biên dịch tăng lên, chương trình phức tạp hơn, nhiều lệnh hơn, nhiều modul hơn và nhiều người tham gia viết hơn thì sẽ có vấn đề phát sinh:

  • Khó quản lý một file lớn (cả người và máy)
  • Mỗi thay đổi cần thời gian biên dịch lâu
  • Nhiều người lập trình không thể thay đổi cùng một file đồng thời
  • Chương trình được phân ra thành nhiều module

Giải pháp cho vấn đề này là gì ?

  • Chia project ra thành các modul một cách đúng đắn
  • Thời gian biên dịch phải ngắn nếu có sự thay đổi
  • Dễ dàng bảo trì cấu trúc project

 

Makefile là gì?

  • Makefile là một file dạng script chứa các thông tin:
    • Cấu trúc project (file, sự phụ thuộc)
    • Các lệnh để tạo file
  • Lệnh make sẽ đọc nội dung Makefile, hiểu kiến trúc của project và thực thi các lệnh

 

Một số ví dụ cơ bản

Mình sẽ đi vào một số ví dụ với makefile cơ bản để mọi người có thể nắm bắt luôn.

Chương trình đơn giản in ra dòng Hello makefiles được viết thành 3 file

Để bắt đầu chúng ta cần có 3 file bỏ chung vào 1 thư mục là hellomake.c tương ứng chương trình chính, hellofunc.c là file hàm in thông báo, và hellomake.h là file header khai báo hàm in.

Thông thường chúng ta có thể compile code và xem kết quả một cách đơn giản bằng lệnh sau

gcc -o hellomake hellomake.c hellofunc.c -I.
./hellomake

Lệnh này sẽ thực hiện compile 2 file .c. -I. có nghĩa là include gcc sẽ thực hiện tìm kiếm trong thư mục hiện tại(.) để thêm file hellomake.h.

Nếu không có makefile thì mỗi compile chúng ta lại phải mở terminal lên và gõ lệnh gcc -o … vào, điều này trở nên quá phiền hà, đặc biệt là khi chúng ta add thêm nhiều file .c khác vào trong chương trình hoặc khi chúng ta sửa lại nội dung code trong các file .c

Vậy makefile sẽ khắc phục hạn chế ở trên như thế nào ?

Makefile 1

Trước tiên để dùng được makefile thì phải tạo file có tên là Makefile hoặc makefile trong thư mục chứa code hiện có với nội dung

Một cấu trúc make file cơ bản sẽ có dạng cơ bản như sau

Rule: các rule cần thực hiện khi compile

Dependency: là các file cần thiết để tạo ra target

Action: là câu lệnh compile để tạo ra Target từ Dependency. Action được thụt lùi vào 1 Tab (phím tab trên bàn phím) so với Target

Target: là file đích, nghĩa là file được hình thành sau khi quá trình make được thực hiện.

Vậy là trong thư mục chúng ta sẽ có 4 file hellofunc.c hellomake.c hellomake.h và Makefile

Chạy chương trình bằng lệnh trên Terminal

make
./hellomake

Makefile 2

Chúng ta tiếp tục phát triển thêm một chút bằng cách thêm CC và CFLAGS vào Makefile ở trên

  • CC: là compiler C được sử dụng
  • CFLAGS: là danh sách các flag của compiler

Có một điểm khác nữa là thêm 2 file object là hellomake.ohellofunc.o trong dependency list và trong rule để make biết rằng đây là lần đầu tiên của quá trình biên dịch.

Với việc sử dụng makefile như trên thì đã có thể làm được các project nhỏ nhỏ rồi. Tuy nhiên vẫn còn thiếu dependency là các file include. Giả sử như ta có thay đổi trên file hellomake.h thì make sẽ không biên dịch lại file .c. Để khắc phục lỗi này thì ta cần phải thông báo cho make rằng tất cả các file .c đều bị phụ thuộc vào file .h, khi compile nhớ phải lưu ý nha make em.

Makefile 3

Như mình đã nói ở trên, ở Makefile này sẽ tạo ra một macro là DEPS để chỉ ra file .h mà các file .c phụ thuộc vào. Ngoài ra sẽ có một định nghĩa về rule áp dụng cho tất cả các file .o, rule này thông báo rằng các file .o phụ thuộc vào các file .c và .h được định nghĩa trong macro là DEPS (dòng 5). Rule sẽ tạo ra file .o, make được dùng C compile được định nghĩa trong CC để compile các file c.(dòng 6)

Có một số lưu ý:

  • -c là tạo ra các object file
  • -o $@ là tạo ra output của quá trình biên dịch trong tập tin bên trái dấu :
  • $< là thành phần đàu tiên trong danh sách của dependency và CFLAGS là macro đã được định nghĩa ở dòng 2

Tiếp tục bước cuối cùng là sử dụng các macro đặc biệt như $@ và @^ để lấy thông tin bên trái và bên phải của dấu : để làm cho quá trình biên dịch được tổng quát hơn, cụ thể là các file include sẽ được đưa vào trong  macro DEPS, tất cả các object file được đưa vào macro OBJ như makefile 4

Makefile 4

Ta sẽ thấy một số file được sinh ra sau quá trình make như hình dưới

Để hiểu thêm về các hàm của makefile bạn có thể tham khảo thêm tại GNU Make Manual.

Tạm kết

Coi như chúng ta đã tìm hiểu được make thông qua một số ví dụ, chỉ dừng ở mức độ đơn giản và tìm hiểu, phục vụ được cho các project nhỏ, nó sẽ có một vấn đề với các project lớn, phức tạp hơn, mình xin để dành cho bài viết tiếp theo 😀

2
Leave a Reply

avatar
2 Comment threads
0 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
2 Comment authors
tran thanhHieu.D Recent comment authors

Website này sử dụng Akismet để hạn chế spam. Tìm hiểu bình luận của bạn được duyệt như thế nào.

  Subscribe  
newest oldest most voted
Notify of
Hieu.D
Guest
Hieu.D

Thanks! Bài viết đọc dễ hiểu, rất hữu ích!

tran thanh
Guest
tran thanh

thanks alots