一、什么是 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 示例(推荐写法)
cs
# 定义变量
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 |
十、双线链表基础语法
头文件
cs
#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
定义函数
cs
#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;
}
主函数
cs
#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;
}