Sunday, July 20, 2025

Makefile

 

1. Makefile là gì?

⦁ Makefile là file cấu hình được dùng bởi lệnh make, giúp tự động hóa quá trình biên dịch mã nguồn.

2. Cấu trúc cơ bản của một Makefile

target: dependencies
<TAB>command

Lưu ý: Dòng lệnh sau target phải bắt đầu bằng một tab (không phải dấu cách!).

3. Ví dụ đơn giản

program: lib1.c lib2.c main.c
    gcc -c main.c -o main.o
    gcc -c lib1.c -o lib1.o
    gcc -c lib2.c -o lib2.o
    gcc lib1.o lib2.o main.o -o program
  • Makefile này sẽ hoạt động như sao:
    • targer là program
    • dependencies: lib1.c lib2.c main.c

--> Có nghĩa là:

  • Để build được target (program) thì chúng ta cần những dependency kia
  • Khi một trong những file trong dependencies thay đổi nội dung thì target sẽ đc chạy

4. Tự động hóa với makefile

4.1. Khi chúng ta chỉ thay đổi main.c, trigger build thì nó sẽ build lại file main.c và cả 2 file lib gây tốn thời gian do đó chúng ta tách ra như thế này:

program: lib1.o lib2.o main.o
    gcc lib1.o lib2.o main.o -o program

lib1.o: lib1.c
    gcc -c lib1.c -o lib1.o

lib2.o: lib2.o
    gcc -c lib2.c -o lib2.o

main.0: main.c
    gcc -c main.c -o main.o
  • lúc này program sẽ dependency lib1.o lib2.o main.o (chứ không phải các file .c)
  • mỗi file .o sẽ được tạo ra từ các file .c --> khi thôi đổi file.c nào thì file.o sẽ được build lại, chứ không phải build lại tất cả --> chúng ta sẽ tiết kiệm được khá nhiều thòi gian

4.2. Makefile ở trên cũng còn nhược điểm, trong project của chúng ta chỉ có 3 file .c thôi, thì cũng ta viết nổi, chứ project có 10000 file.c là không viết nổi luôn

program: lib1.o lib2.o main.o
 	gcc lib1.o lib2.o main.o -o program

%.o: %.c
    gcc -c $^ -o $@
  • $^ : là danh sách dependencies
  • $@ : là targer

4.3. Chúng ta có thể print log để debug trong Makefile

program: lib1.o lib2.o main.o
 	gcc lib1.o lib2.o main.o -o program

%.o: %.c
    $(info Dang build @^ thanh $@)
 	gcc -c $^ -o $@
  • sử dụng $(info ...) để in information (ngoài ra chúng ta có thể sử dụng error, debug...)

4.4. Trong dependencies của program vẫn chưa tối ưu

SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o)
program: $(OBJS)
 	gcc $(OBJS) -o $@

%.o: %.c
    $(info Dang build $^ thanh $@)
 	gcc -c $^ -o $@
debug:
    $(info sources: $(SRCS))
    $(info objects: $(OBJS))
  • $(wildcard *.c) tìm tất cả các file .c trong thư mục hiện tại.
  • Gán danh sách đó cho biến SRCS.
  • $(SRCS:.c=.o) chuyễn lib1.c lib2.c main.c thành lib1.o lib2.o main.o
D:\Temp_Dir\c_sample> make debug
sources: lib1.c lib2.c main.c
objects: lib1.o lib2.o main.o

4.5. Với makefile trên thì khi chúng ta thay đổi nội dung file.h thì nó không rebuild

CC=gcc
SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o)
FLAG=-MMD
program: $(OBJS)
	$(info link all object files to $@)
	$(CC) $(OBJS) -o $@
%.o: %.c
	$(info build $< to $@)
	$(CC) -c $(FLAG) $< -o $@
debug:
	$(info sources: $(SRCS))
	$(info objects: $(OBJS))

clear: 
	rm *.o *.exe
-include *.d
  • Sử dụng -MMD để gcc tạo ra những file.d trong file.d đó nó sẽ liệt kê các file cần thiết cho quá trình biên dịch của file đó. VD ta có một main.d
PS D:\Temp_Dir\c_sample> cat main.d
main.o: main.c lib2.h lib1.h

PS D:\Temp_Dir\c_sample> cat lib1.d
lib1.o: lib1.c
  • Trong main.c có #include "lib2.h" trong lib2.h của #include "lib1.h" do đó depedencies của main.o là main.clib2.h và lib1.h
  • Trong lib1.c không có include thư viện nào cả, nên nó chỉ có depedency một file `lib1.c' thôi
  • Cuối cùng là sử dụng -include *.d để thêm tất cả các file.d vào khi chạy make

Friday, January 10, 2025

 Nhân build YOCTO - Build SDK

1. Mục tiêu

- Bình thường chúng ta cần phải download source của kernal về và một số BSP để build OS. Thay vì vậy mình sử dụng yocto project để build SDK cho đồng bộ

2. Build SDK

vbuser@Ubuntu18:~/Desktop/selfstudy/poky/build$ bitbake core-image-minimal -c populate_sdk

Loading cache: 100% |#############################################################################################################################| Time: 0:00:00

Loaded 1306 entries from dependency cache.

NOTE: Resolving any missing task queue dependencies


Build Configuration:

BB_VERSION           = "1.44.0"

BUILD_SYS            = "x86_64-linux"

NATIVELSBSTRING      = "universal"

TARGET_SYS           = "i686-poky-linux"

MACHINE              = "qemux86"

DISTRO               = "poky"

DISTRO_VERSION       = "3.0.4"

TUNE_FEATURES        = "m32 core2"

TARGET_FPU           = ""

meta                 

meta-poky            

meta-yocto-bsp       

meta-skeleton        = "zeus:daf096e295121ea49ebf21f8070e9a6e28f5d46c"


Initialising tasks: 100% |########################################################################################################################| Time: 0:00:01

Sstate summary: Wanted 352 Found 0 Missed 352 Current 472 (0% match, 57% complete)

NOTE: Executing Tasks

NOTE: Setscene tasks completed

NOTE: Tasks Summary: Attempted 3058 tasks of which 2051 didn't need to be rerun and all succeeded.


3. Run SDK installer

- Đầu tiên chúng ta cần cài đặt SDK vào host (cái máy dùng để build kernel). Cái SDK installer này là mấy file .sh (shell script), nó sẽ được tìm thấy trong "build/tmp/deploy/sdk" ở đây mình sử dụng "core-image-minimal" nên mọi người có thể sử dụng "poky-glibc-x86_64-core-image-minimal-core2-32-qemux86-toolchain-3.0.4.sh" để cài đặt SDK.  


vbuser@Ubuntu18:~/Desktop/selfstudy/poky/build$ cd tmp/deploy/sdk

vbuser@Ubuntu18:~/Desktop/selfstudy/poky/build/tmp/deploy/sdk$ tree -L 1 .

.

├── poky-glibc-x86_64-core-image-minimal-core2-32-qemux86-toolchain-3.0.4.host.manifest

├── poky-glibc-x86_64-core-image-minimal-core2-32-qemux86-toolchain-3.0.4.sh

├── poky-glibc-x86_64-core-image-minimal-core2-32-qemux86-toolchain-3.0.4.target.manifest

└── poky-glibc-x86_64-core-image-minimal-core2-32-qemux86-toolchain-3.0.4.testdata.json


0 directories, 4 files



***Chú ý: SDK installer sẽ hỏi mọi nguời thư mục cài đặt SDK

vbuser@Ubuntu18:~/Desktop/selfstudy/poky/build/tmp/deploy/sdk$ ./poky-glibc-x86_64-core-image-minimal-core2-32-qemux86-toolchain-3.0.4.sh 

Poky (Yocto Project Reference Distro) SDK installer version 3.0.4

=================================================================

Enter target directory for SDK (default: /opt/poky/3.0.4): /home/vbuser/Desktop/selfstudy/SDK

You are about to install the SDK to "/home/vbuser/Desktop/selfstudy/SDK". Proceed [Y/n]? Y

Extracting SDK.............................................done

Setting it up...done

SDK has been successfully set up and is ready to be used.

Each time you wish to use the SDK in a new shell session, you need to source the environment setup script e.g.

 $ . /home/vbuser/Desktop/selfstudy/SDK/environment-setup-core2-32-poky-linux



4. Using the SDK

- Chúng ta có thể sử dụng cái SDK để dev application

4.1. Run SDK environment setup script

- Tạo một cái working directory để chứa một cái example app để sử dụng SDK.
- Sao đó chúng ta chúng ta chạy environment để sử dụng SDK, à chú ý: chúng ta đứng ở thư mục mới tạo và source environment trong thư mục SDK đã cài đặt

vbuser@Ubuntu18:~/Desktop/selfstudy$ mkdir App_Workspace

vbuser@Ubuntu18:~/Desktop/selfstudy$ cd App_Workspace/

vbuser@Ubuntu18:~/Desktop/selfstudy/App_Workspace$ source ../SDK/

environment-setup-core2-32-poky-linux  site-config-core2-32-poky-linux        sysroots/                              version-core2-32-poky-linux

vbuser@Ubuntu18:~/Desktop/selfstudy/App_Workspace$ source ../SDK/environment-setup-core2-32-poky-linux 


4.2. Bây giờ chúng ta tạo hello world bằng code C thôi


vbuser@Ubuntu18:~/Desktop/selfstudy/App_Workspace$ cat helloworld.c 

#include <stdio.h>



void main()

{

printf("Hello world \r\n");

}


vbuser@Ubuntu18:~/Desktop/selfstudy/App_Workspace$ cat Makefile 

all: helloworld

$(CC) helloworld.c -o helloworld

clean:

rm helloworld


vbuser@Ubuntu18:~/Desktop/selfstudy/App_Workspace$ make

i686-poky-linux-gcc  -m32 -march=core2 -mtune=core2 -msse3 -mfpmath=sse -fstack-protector-strong  -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/home/vbuser/Desktop/selfstudy/SDK/sysroots/core2-32-poky-linux  -O2 -pipe -g -feliminate-unused-debug-types   -Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed -fstack-protector-strong -Wl,-z,relro,-z,now  helloworld.c   -o helloworld

i686-poky-linux-gcc  -m32 -march=core2 -mtune=core2 -msse3 -mfpmath=sse -fstack-protector-strong  -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/home/vbuser/Desktop/selfstudy/SDK/sysroots/core2-32-poky-linux helloworld.c -o helloworld


--> Mọi người có thể thấy rằng, nó sử dụng i686-poky-linux-gcc (cái này là compiler của yocto build cho core-image-minimal) mọi người có thể copy vào máy ảo chạy ./helloworld để xem kết quả.