iT邦幫忙

2025 iThome 鐵人賽

DAY 9
0
Software Development

30 天精通 C 語言建置與除錯:從 Makefile 到 CMake 跨平台實戰系列 第 9

[Day 09] 了解makefile用途了齁? 那我們來寫看看makefile!

  • 分享至 

  • xImage
  •  

在這篇文章中,我們會了解...

還記得之前我們曾經使用 gcc 編譯 dog_meme畫出"this is fine ASCII art"嗎?

在看這篇文章之前,可以先問問這幾個問題

  1. 為何要用MAKE? 請看已經分享的文章↓

  2. MAKE 總共有幾個部分組成?

  3. makefile指令如何跟gcc指令做對照

    • 這篇主要的內容!
    • 如果想要用makefile 控制 gcc就要先了解 makefile gcc兩者的相互對照
  4. .h檔是用來做啥的? → 這篇簡單介紹,之後會深入介紹,會把相關的內容補在這邊,敬請期待!

  5. 如何用MAKE產生執行檔? → 下一篇會介紹

MAKE 要怎麼開始寫?

步驟

1. 先確定gcc 版本

gcc --version

如果你執行了,發現沒有gcc 版本號被印出來就要執行下面的指令安裝gcc!
如果沒有 gcc

sudo apt update
sudo apt install -y build-essential gdb

2. 沒有.h的檔案結構

首先,需要回去參考一下之前寫的文章~
[Day 03] 用gcc編譯我人生第一個 C 程式:不是 Hello World!

Day 03 的內容來看我們只是想要單純編譯出一個簡單的執行檔,所以我們把print_dog_meme的 function 寫在main.c 裡面這樣gcc就只需要指定編一main.c 這個檔案,所以簡簡單單就可以用下面的指令呼叫 gcc進行編譯,且不會出現任何警告標語,因為你沒有要gcc要把這些警告給 print 出來。
所以就可以直接下簡易的指令如下:

gcc main.c -o dog_meme

簡單來說就是 gcc + (要編譯.c檔案的名稱) + -o 編譯完成後的編譯黨的名稱
-o 是 output file的的意思後面會加上輸出檔名,如果沒有加上 -o 會是預設輸出的檔名a.out

這邊有指定檔名,所以執行後就會產生一個叫做dog_meme的執行檔,接著你就可以再下這個指令,簡簡單單去執行他。

./dog_meme

執行結果:
https://ithelp.ithome.com.tw/upload/images/20250908/20178484aPGgqDdLm6.png

3. 加入.h的概念

接下來我們要引入.h的概念,之後的文章中會再詳加介紹,大部分專案中,會把function跟main.c兩個分開寫,這樣在管理專案的時候會更好去做管理,因此在這邊我們要把main跟function的功能拆成兩個檔案來做,樹狀結構如下:

4. make 對照 gcc 編譯

加入.h概念之後我們可以在往下繼續...
首先,大家要先動手準備一下下面的檔案...

在開始寫makefile之前,請先把這幾個檔案準備好

首先你先準備一個階層像是這樣的檔案結構

C_PROJ/
├─ .vscode/
│  ├─ settings.json
│  └─ tasks.json
├─ dog_meme.c           ← 實作 print_dog_meme()
├─ dog_meme.h           ← 宣告 print_dog_meme()
├─ main.c               ← 呼叫 print_dog_meme()
└─ dog_meme*            ← 編譯後的產物會在這邊(執行檔)

準備完上面檔案的階層後,請填入檔案的內容:
main.c

#include "dog_meme.h"
void main(void) {
    print_dog_meme();
}

dog_meme.h

#ifndef DOG_MEME_H
#define DOG_MEME_H

void print_dog_meme(void);

#endif // DOG_MEME_H

dog_meme.c

#include <stdio.h>

#include "dog_meme.h"

  

void print_dog_meme(void) {

    printf("test test") // 內容可以上網自己找XD
}

setting,json 可以保持預設就可以了

{

    "files.associations": {

        "stdio.h": "c"

    }

}

task.json
可以保持空白

4.1.1 gcc 最基本的編譯

我們當然可以用之前的方法直接進行編譯,這樣也可以產生執行檔。但沒有警告標語的情況下必然不會看出程式隱藏的一些問題,也不能活用gcc的各種版本。

gcc main.c dog_meme.c -o dog_meme
4.1.2 Makefile 最基本的編譯
# Makefile (simple)
# 直接用最基本的參數編譯
.PHONY: all run clean
TARGET := dog_meme
SRCS   := main.c dog_meme.c
all: $(TARGET)
$(TARGET): $(SRCS)
	@gcc main.c dog_meme.c -o dog_meme
run: $(TARGET)
	@./dog_meme
clean:
	@rm -f $(TARGET)

如果想要指定gcc版本的話可以加上下面的指令

4.2.1 gcc 指定 C 標準

C11 (2011的版本)

gcc -std=c11 main.c dog_meme.c -o dog_meme
4.2.2 Makefile 指定C版本
# Makefile (c11)
# 指定 C 標準為 C11
.PHONY: all run clean
TARGET := dog_meme
SRCS   := main.c dog_meme.c

all: $(TARGET)

$(TARGET): $(SRCS)
	@gcc -std=c11 main.c dog_meme.c -o dog_meme

run: $(TARGET)
	@./dog_meme

clean:
	@rm -f $(TARGET)
4.3.1 gcc 加上警告資訊版本

嚴格警告 + 最常用優化/除錯旗標,並包含目前資料夾的標頭搜尋路徑(-I.)

gcc -Wall -Wextra -O2 -g -std=c11 -I. main.c dog_meme.c -o dog_meme
4.3.2 Makefile 加上除錯的資訊
# Makefile (strict)
# 嚴格警告 + 最常用優化/除錯旗標,並包含目前資料夾的標頭搜尋路徑(-I.)

.PHONY: all run clean

TARGET := dog_meme
SRCS   := main.c dog_meme.c

all: $(TARGET)

$(TARGET): $(SRCS)
	@gcc -Wall -Wextra -O2 -g -std=c11 -I. main.c dog_meme.c -o dog_meme

run: $(TARGET)
	@./dog_meme

clean:
	@rm -f $(TARGET)

上一篇
[Day 08] WSL 安裝問題解決
系列文
30 天精通 C 語言建置與除錯:從 Makefile 到 CMake 跨平台實戰9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言