一、什么是 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;
}