一、什么是 make 工具?
make
是一個自動化構建工具,主要用于管理 C/C++ 項目的編譯和鏈接過程。它通過讀取 Makefile
文件中定義的規則,自動判斷哪些文件被修改,并僅重新編譯這些部分,從而大幅提高構建效率。
二、什么是 Makefile?
Makefile
是 make
工具的配置文件,它以純文本形式存在,主要用于描述:
構建目標(如:最終生成的可執行文件)
依賴關系(如:源代碼、頭文件)
構建命令(如:gcc 編譯命令)
通過 Makefile
,我們可以實現對大型項目的自動化編譯管理。
三、Makefile 的基本語法
1. 基本格式
目標文件: 依賴文件列表 命令(以Tab鍵開頭)
注意:命令必須以 Tab 縮進,否則 make 會報錯。
示例:
a.out: main.c fun.c
? ? gcc main.c fun.c -o a.out -I$(INC) -L$(LIB)
目標文件:a.out(最終生成的可執行文件)
依賴文件:main.c、fun.c
命令:gcc 編譯命令,帶有頭文件和庫路徑參數
四、常用編譯參數說明
-I$(INC)
:指定頭文件目錄(如include/
)-L$(LIB)
:指定庫文件目錄(如lib/
)-o
:指定輸出文件名稱
五、Makefile 中的變量使用
1. 自定義變量
CC = gcc
TARGET = app
SRC = main.c fun.c
INC = ./include
LIB = ./lib
引用變量方式:$(變量名
)
$(TARGET): $(SRC)
? ? $(CC) $(SRC) -o $(TARGET) -I$(INC) -L$(LIB)
2. 系統自動變量
$@
:表示當前規則的目標文件$^
:所有依賴文件(去重)$<
:第一個依賴文件
示例:
app: main.c fun.c tool.c gcc $^ -o $@
等價于:
gcc main.c fun.c tool.c -o app
六、make 的時間戳機制
make 會對比文件的時間戳來判斷是否需要重新編譯:
若依賴文件比目標文件更新 → 執行構建命令
否則跳過(顯示
make: 'xxx' is up to date.
)
這種機制確保了編譯效率,尤其適合大型項目。
七、GCC 編譯的四個階段
預處理(Preprocessing)
處理#include
、#define
等預處理指令,生成.i
文件:gcc -E main.c -o main.i
編譯(Compilation)
將.i
轉為匯編.s
文件:gcc -S main.i -o main.s
匯編(Assembly)
將.s
文件生成.o
目標文件:gcc -c main.s -o main.o
鏈接(Linking)
將多個.o
文件和庫鏈接為可執行程序:gcc main.o fun.o -o app
八、Makefile 示例(推薦寫法)
# 定義變量
CC = gcc
CFLAGS = -I./include -Wall # 編譯選項:指定頭文件目錄 + 顯示警告
LDFLAGS = -L./lib -lm # 鏈接選項:指定庫目錄 + 鏈接數學庫
TARGET = app
SRCS = main.c fun.c
OBJS = $(SRCS:.c=.o) # 將 .c 文件轉換為 .o 文件(如 main.c → main.o) # 默認目標(第一個目標為默認)
all: $(TARGET) # 生成可執行文件
$(TARGET): $(OBJS) $(CC) $(OBJS) -o $@ $(LDFLAGS) # 生成目標文件(.o)
%.o: %.c # 模式規則:所有 .o 依賴對應的 .c $(CC) -c $< -o $@ $(CFLAGS) # 清理編譯產物
clean: rm -f $(OBJS) $(TARGET)
使用方法:
- 編譯項目:
make
(默認執行?all
?目標) - 清理文件:
make clean
- 重新編譯:
make clean && make
九、Makefile 使用方法
操作 | 命令 |
---|---|
編譯項目 | make (默認執行 all) |
清理項目 | make clean |
重新編譯 | make clean && make |
十、雙線鏈表基礎語法
頭文件
#ifndef _SIZEOF_DOUBLE_
#define _SIZEOF_DOUBLE_typedef struct stu
{int id;char name[32];int score;
}Data_type;typedef struct dounode
{Data_type data;struct dounode *ppre;struct dounode *pnext;
}DNode;typedef struct doulink
{DNode *phead;int clen;
}Dlink;extern Dlink *creatDoulink();
extern int IsEmptyDouLink(Dlink *pdlink);
extern int insertHeadDouLink(Dlink *pdlink, Data_type data);
extern void printDouLink(Dlink *pdlink, int dir);
extern int insertTailDouLink(Dlink *pdlink, Data_type data);
extern int deleteHeadDouLink(Dlink *pdlink);
extern int deleteTailDouLink(Dlink *pdlink);
extern int DestroyDouLink(Dlink *pdlink);extern DNode *findNameDouLink(Dlink *pdlink, char *s);extern int modifyScoreByName(Dlink *pdlink, char *s, int Score);
extern int deleteNodeByName(Dlink *pdlink, char *s);
#endif
定義函數
#include "doulink.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>Dlink *creatDoulink()
{Dlink *pdlink = malloc(sizeof(Dlink));if (NULL == pdlink){printf("malloc error\n");return NULL;}pdlink->phead = NULL;pdlink->clen = 0;return pdlink;
}int IsEmptyDouLink(Dlink *pdlink)
{return NULL == pdlink->phead;
}int insertHeadDouLink(Dlink *pdlink, Data_type data)
{DNode *pnode = malloc(sizeof(DNode));if(NULL == pnode){printf("malloc error\n");return -1;}pnode->data = data;pnode->pnext = NULL;pnode->ppre = NULL;if(IsEmptyDouLink(pdlink)){pdlink->phead = pnode;}else{pnode->pnext = pdlink->phead;pdlink->phead->ppre = pnode;pdlink->phead = pnode; }pdlink->clen++;return 0;
}void printDouLink(Dlink *pdlink, int dir)
{if(IsEmptyDouLink(pdlink)){return ;}DNode *temp = pdlink->phead;if(dir){while(temp){printf("%d %s %d\n", temp->data.id, temp->data.name, temp->data.score);temp = temp->pnext;}}else{temp = pdlink->phead;while(temp->pnext){temp = temp->pnext; }while(temp){printf("%d %s %d\n", temp->data.id, temp->data.name, temp->data.score);temp = temp->ppre;}}return ;
}int insertTailDouLink(Dlink *pdlink, Data_type data)
{if(IsEmptyDouLink(pdlink)){insertHeadDouLink(pdlink, data);return 1;}else{DNode *pnode = malloc(sizeof(DNode));if(NULL == pnode){printf("malloc error\n");return -1;}pnode->data = data;pnode->ppre = NULL;pnode->pnext = NULL;DNode *temp = pdlink->phead;while (temp->pnext){temp = temp->pnext;}pnode->ppre = temp;temp->pnext = pnode;pdlink->clen++;return 1;}
}int deleteHeadDouLink(Dlink *pdlink)
{if(IsEmptyDouLink(pdlink)){return -1;}if(pdlink->phead->pnext == NULL){free(pdlink->phead);pdlink->phead = NULL;pdlink->clen--;return 1;}else{DNode *temp = pdlink->phead->pnext;temp->ppre = NULL;free(pdlink->phead);pdlink->phead = temp;pdlink->clen--;return 1;}}int deleteTailDouLink(Dlink *pdlink)
{if(IsEmptyDouLink(pdlink)){return -1;}if(pdlink->phead->pnext == NULL){free(pdlink->phead);pdlink->phead = NULL;pdlink->clen--;return 1;}else{DNode *temp = pdlink->phead;while(temp->pnext){temp = temp->pnext;}temp->ppre->pnext = NULL;free(temp);pdlink->clen--;return 1;}
}int DestroyDouLink(Dlink *pdlink)
{DNode *temp = pdlink->phead;while(temp){pdlink->phead = temp->pnext;free(temp);temp = pdlink->phead;}free(pdlink);return 1;
}DNode *findNameDouLink(Dlink *pdlink, char *s)
{if(IsEmptyDouLink(pdlink)){return NULL;}DNode *temp = pdlink->phead;while(temp){if(strcmp(temp->data.name, s) == 0){return temp;}temp = temp->pnext;}return NULL;
}int modifyScoreByName(Dlink *pdlink, char *s, int Score)
{DNode *temp = findNameDouLink(pdlink, s);if(temp == NULL){return -1;}temp->data.score = Score;return 1;
}int deleteNodeByName(Dlink *pdlink, char *s)
{if(IsEmptyDouLink(pdlink)){return -1;}DNode *temp = findNameDouLink(pdlink, s);if(temp->ppre == NULL){deleteHeadDouLink(pdlink);return 1;}if(temp->pnext == NULL){deleteTailDouLink(pdlink);return 1;}temp->pnext->ppre = temp->ppre;temp->ppre->pnext = temp->pnext;free(temp);pdlink->clen--;return 1;
}
主函數
#include "doulink.h"
#include<stdio.h>int main(int argc, char const *argv[])
{Data_type stus[5] = {{1, "zhangsan", 99},{2, "lisi", 100},{3, "wangwu", 90},{4, "maliu", 56},{5, "tianqi", 66},};Dlink *pdlink = creatDoulink();if(NULL == pdlink){return -1;}insertHeadDouLink(pdlink, stus[0]);insertHeadDouLink(pdlink, stus[1]);insertHeadDouLink(pdlink, stus[2]);insertHeadDouLink(pdlink, stus[3]);// insertHeadDouLink(pdlink, stus[4]);printDouLink(pdlink, 1);// printDouLink(pdlink, 0);// deleteHeadDouLink(pdlink);
// deleteTailDouLink(pdlink);printf("----------find----------\n");// insertTailDouLink(pdlink, stus[4]);// printDouLink(pdlink, 1);DNode * temp = findNameDouLink(pdlink, "lisi");printf("%d %s %d\n", temp->data.id, temp->data.name, temp->data.score);printf("----------modify----------\n");modifyScoreByName(pdlink, "wangwu", 999);printDouLink(pdlink, 1);printf("----------deletes design----------\n");deleteNodeByName(pdlink, "zhangsan");printDouLink(pdlink, 1);DestroyDouLink(pdlink);return 0;
}