Thursday, June 25, 2015


Bài viết liên quan:
+ Makefile (Part 1)

3. Khuôn dạng đầy đủ của Makefile
sum.h (giữ nguyên)
sum.c (giữ nguyên)
main.c (thêm #ifdef ... #endif)
 #include <stdio.h>  
 #include "sum.h"  
   
 int main(int argc, char **argv){  
        
      int x;  
      x= sum(1, 2);  
        
 #ifdef DEBUG  
      printf("x = %d \n", x);  
 #endif  
   
      return 1;  
 }  
   

Makefile
 .PHONY: all, install, clean  
   
 TARGET=sum  
   
 HDRS+= sum.h  
 CSRCS+= main.c sum.c  
 CPPSRCS+=  
   
 OBJSDIR=./build  
 OBJS:= $(patsubst %.cpp, $(OBJSDIR)/%.o, $(CPPSRCS))  
 OBJS+= $(patsubst %.c, $(OBJSDIR)/%.o, $(CSRCS))  
   
 CFLAGS += -I./include -DDEBUG -Wall -g  
 LDFLAGS += -L./lib -lm  
   
 CC:= gcc  
 CXX:= g++  
   
 all: ${TARGET}  
 ${TARGET} : $(OBJS)  
      @echo " [LINK] $@"  
      @mkdir -p $(shell dirname $@)  
      @$(CXX) $(OBJS) -o $@ $(LDFLAGS)  
        
 $(OBJSDIR)/%.o: %.c $(HDRS)  
      @echo " [CC]  $@"  
      @mkdir -p $(shell dirname $@)  
      @$(CC) -c $< -o $@ $(CFLAGS)  
   
 $(OBJSDIR)/%.o: %.cpp $(HDRS)  
      @echo " [CXX] $@"  
      @mkdir -p $(shell dirname $@)  
      @$(CXX) -c $< -o $@ $(CFLAGS)  

 install:
      cp -rf ${TARGET} /usr/local/bin   
    
 clean:  
      rm -rf ${OBJSDIR}/*.o  
      rm -rf ${TARGET}  
   


Giải thích:
3.1 all, install, clean, .PHONY 
+ all
Là target mặc định, khi bạn thực hiện lệnh make thì chương trình make sẽ tiến hành compile để tạo ra chương trình cuối cùng tương ứng với target này, trong ví dụ này là ${TARGET} tương ứng với sum; hai lệnh dưới đây là tương đương

 make  
 make all   

+ install, clean
Các target do người dùng tự định nghĩa, tương ứng với các câu lệnh:

 make install  #thực hiện action cp
 make clean    #thực hiện action rm 

+ .PHONY target
Target này có tác dụng chống xung đột cho chương trình make trong trường hợp trong thư mục source code có một file source nào đó trùng tên với các target trong Makefile, ví dụ all.c, install.c hay clean.c. Tốt nhất trong Makefile luôn dùng từ khóa này.

3.2 Phép gán: TARGET, CC, CXX, ...
Các từ in hoa như trên biểu diễn cho phép gán, có thể hiểu nó tương tự như #define trong C, nó giúp cho chương trình sáng sủa, dễ hiểu và rút ngắn Makefile đáng kể. Phép gán được thực hiện bằng các cách sau:
+ "=" gán cố định
+ ":=" tương tự như "="
+ "+=" phép gán nối dài (append), ví dụ khi viết hai dòng

 CSRCS+= main.c  
 CSRCS+= sum.c   
 => CSRCS = main.c sum.c   

Để lấy giá trị của phép gán thì dùng các cách sau:
 ${TARGET}   
 hoặc  
 $(CFLAGS)  


+ HDRS / CSRCS /CPPSRCS
Header , C source, C++ source file. Trong vd trên các file đều nằm trong folder gốc, nếu file nào nằm ở các thư mục con, bạn cũng cần chỉ đúng đường dẫn đễn file, vd:
  HDRS+= ./src/sum.h   
  CSRCS+= main.c \
          ./src/sum.c   
  CPPSRCS+=  

"\" là ký tự xuống dòng.

+ OBJSDIR / OBJS
Thư mục chứa các object / các object

+ CFLAGS / LDFLASG
Các flags chứa các options để pass vào cho compiler, xem lại tại đây (mục 7).
Chú ý -DDEBUG tương ứng với define DEBUG để pass vào source code, ví dụ trong main.c ở trên.

+ CC / CXX
Compiler để compile, trong vd này sử dụng gcc/g++ để chạy trên máy tính chứ không phải board nhúng, khi cross compiler thì bạn chỉ cần đặt đúng compiler tương ứng với platform cho board là được, vd:

 CC=arm-linux-gcc  
 CXX=arm-linux-g++  

3.3 Lệnh Shell
Lệnh Shell được đưa vào trong cặp khóa $( ) như dưới đây:

 OBJS:= $(patsubst %.cpp, $(OBJSDIR)/%.o, $(CPPSRCS))   
 mkdir -p $(shell dirname $@)   

3.4 Makefile tương đương: $<, $@, $*, $?, ...

Macro Definition
$< Source code hiện tại để compile, tương ứng với %.c và %.cpp, ví dụ: main.c, sum.c
$@ Target hiện tại tương ứng với $(OBJSDIR)/%.o, ví dụ: main.o, sum.o
$* Tương tự $< nhưng không có suffix, ví dụ: main, sum
$? Danh sách dependency tương ứng với %.c $(HDRS), ví dụ: tương ứng với main.o là main.c và sum.h

Được sử dụng trong đoạn Makefile chính:
 ${TARGET} : $(OBJS)   
    @echo " [LINK] $@"   
    @mkdir -p $(shell dirname $@)   
    @$(CXX) $(OBJS) -o $@ $(LDFLAGS)   
       
  $(OBJSDIR)/%.o: %.c $(HDRS)   
    @echo " [CC] $@"   
    @mkdir -p $(shell dirname $@)   
    @$(CC) -c $< -o $@ $(CFLAGS)   
     
  $(OBJSDIR)/%.o: %.cpp $(HDRS)   
    @echo " [CXX] $@"   
    @mkdir -p $(shell dirname $@)   
    @$(CXX) -c $< -o $@ $(CFLAGS)  

Bạn đọc có thể trace các macro bằng các dòng lệnh sau:
 @echo " [CC]  $@ $< $* $?"  
 @echo " [CXX]  $@ $< $* $?"  

Nguyên lý hoạt động:
Chỉ cần đoạn lệnh ngắn gọn trên là đủ để để compile tất cả các target được liệt kê trong OBJS thông qua ký tự đại diện "%"; compile main.o từ main.c, compile sum.o từ sum.c, tất nhiên có các dependency HDRS

3.5 Các ký tự khác
+ @ ở đầu các Action trong Makefile
Loại bỏ các dòng trace mặc định của chương trình make khi đang compile
+ -f
Nếu bạn đặt tên của script không phải mặc định là Makefile (ví dụ: MyMakefile) thì bạn cần thêm option -f vào
 make -f MyMakefile  
 make -f MyMakefile install  
 make -f MyMakefile clean  
 ...  
   

4. Tạo Makefile theo kiểu module cho project lớn
Nếu project lớn có nhiều subfolder thì bạn nên chia thành nhiều phần cho dễ quản lý, cũng theo vd trên nhưng bây giờ giả sử sum.h và sum.c ở trong một subfolder gọi là src


Trong trường hợp này bạn thêm một makefile phụ là src.mk đặt trong thư mục src

src.mk
 CSRCS+= ./src/sum.c  
   
 CPPSRCS+=   
    
 HDRS+= $(wildcard ./src/*.h)  

Makefile
 .PHONY: all, install, clean  
   
 TARGET:=sum  
   
 -include ./src/src.mk  
 CSRCS+= main.c  
   
 OBJSDIR=./build  
 OBJS:= $(patsubst %.cpp, $(OBJSDIR)/%.o, $(CPPSRCS))  
 OBJS+= $(patsubst %.c, $(OBJSDIR)/%.o, $(CSRCS))  
   
 INCDIR+= -I./src  
 CFLAGS += -DDEBUG -Wall -g  
 LDFLAGS += -L./lib -lm  
   
   
   
 CC:= gcc  
 CXX:= g++  
   
 all: ${TARGET}  
 ${TARGET} : $(OBJS)  
      @echo " [LINK] $@"  
      @mkdir -p $(shell dirname $@)  
      @$(CXX) $(OBJS) -o $@ $(LDFLAGS)  
        
 $(OBJSDIR)/%.o: %.c $(HDRS)  
      @echo " [CC]  $@"  
      @mkdir -p $(shell dirname $@)  
      @$(CC) -c $< -o $@ $(CFLAGS) ${INCDIR}  
   
 $(OBJSDIR)/%.o: %.cpp $(HDRS)  
      @echo " [CXX] $@"  
      @mkdir -p $(shell dirname $@)  
      @$(CXX) -c $< -o $@ $(CFLAGS) ${INCDIR}  
   
 install:  
      cp -rf ${TARGET} /usr/local/bin  
             
 clean:  
      rm -rf ${OBJSDIR}  
      rm -rf ${TARGET}  


{ 5 nhận xét... read them below or Comment }

  1. This comment has been removed by the author.

    ReplyDelete
  2. There is a mistake in section 3.3, the brackets { } are not used in the example.

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. I found Long at here ^^
    this article is very specific

    ReplyDelete

- Copyright © Lập trình hệ thống nhúng Linux . Powered by Luong Duy Ninh -