Ubuntu 同一个项目不同文件层次Makefile文件编译
文件结构介绍
文件夹名字叫my,即项目的根目录。Ubuntu下是tree这样的,蓝色字体是文件夹,
大体上是这样的,main.c调用a.c文件里的void a()函数,而a函数分别调用了b.c和c.c的void b()和void c()函数,都是简单打印的进行打印,而a函数自己也执行了打印功能,不是很复杂,a.c,b.c,c.c都调用了code.h里面宏定义好的代码值了。具体代码可以看下面的代码,我贴出来了。
/my/a文件夹介绍
a.c 文件:其实里面用"header.h"声明头文件还是<header.h>都是可以的
#include <stdio.h>
#include <stdlib.h>
#include "a.h"
#include "b.h"
#include "c.h"
#include <code.h>
void a(){
c();
b();
printf( "%d: This is a function!\n" , A );
printf( "Well done!\n" );
}
a.h文件:
#include <stdio.h>
void a();
/my/b文件夹介绍
b.c文件
#include <stdio.h>
#include <stdlib.h>
#include "b.h"
#include <code.h>
void b(){
printf( "%d: This is b function!\n" , B );
}
b.h文件
#include <stdio.h>
void b();
/my/include文件夹介绍
code.h文件
#include <stdio.h>
#include <stdlib.h>
#define A 1
#define B 2
#define C 3
/my/obj文件夹介绍
只有一个可执行文件main,即最终生成的目标文件
/my文件夹介绍
c.c文件
#include <stdio.h>
#include <stdlib.h>
#include <c.h>
#include <code.h>
void c(){
printf( "%d: This is c function!\n" , C );
}
c.h文件:
#include<stdio.h>
void c();
main.c文件:
#include <stdio.h>
#include "a.h"
#include "b.h"
#include "c.h"
void main(){
a();
}
Makefile文件:
ROOT=$(PWD)
A=$(ROOT)/a
B=$(ROOT)/b
INCLUDE=$(ROOT)/include
APP=$(ROOT)/obj
CFLAGS=-I$(A) -I$(B) -I$(ROOT) -I$(INCLUDE)
OBJS = main.o $(A)/a.o $(B)/b.o c.o
TARGET = $(APP)/main
$(TARGET):$(OBJS)
$(CC) -o $(TARGET) $(OBJS) $(CFLAGS)
-$(RM) $(OBJS)
Makefile文件解释
ROOT=$(PWD)
这里面的PWD指的是当前文件夹的根目录,不需要用户手动输入,只要使用PWD这个参数即可。ROOT代表my文件夹的完整路径,在这个项目里面,再次强调本文里面我们视my为根目录。
A=$(ROOT)/a
B=$(ROOT)/b
INCLUDE=$(ROOT)/include
APP=$(ROOT)/obj
这几句可以简单理解成赋值语句吧,A=/根目录/a,即A代表的是文件夹a的实际完整路径(存有a.c,a.h),同理B代表b文件夹的实际完整路径(存有b.c,b.h),INCLUDE代表破文件夹include的实际完整路径(存有code.h),APP代表文件夹obj实际完整路径。
实际完整路径:
ROOT: /home/xmx/AItest/test/my
A: /home/xmx/AItest/test/my/a
B: /home/xmx/AItest/test/my/b
INCLUDE: /home/xmx/AItest/test/my/include
APP: /home/xmx/AItest/test/my/obj
CFLAGS=-I$(A) -I$(B) -I$(ROOT) -I$(INCLUDE)
这句话的意思就是添加头文件的搜索文件夹,我们把my,a,b和include文件夹加进去,在搜索时make文件会自动搜索这几个文件夹,最重要的是c.h文件在根目录my下面,所以也要加进去搜索。
OBJS = main.o $(A)/a.o $(B)/b.o c.o
这句话意思是,我们把所有生成的.o文件放在了各自对应的文件夹里面
TARGET = $(APP)/main
这句话就是我们想要生成的最终可执行的目标文件,我们把它指定存在obj文件夹下面,
$(TARGET):$(OBJS)
$(CC) -o $(TARGET) $(OBJS) $(CFLAGS)
不是我吹,make最强大的地方在这,这里会自动推导依赖,比如已知main.o,make可以推导出main.c文件,你只要知道这是自动推导整个过程,经历中间文件的产生,最终生成可执行文件main
-$(RM) $(OBJS)
这句话为什么要放在这呢,因为我这边不想手动make clean去删除中间的.o文件,如果为了慎重点 你们可以改成这样
$(TARGET):$(OBJS)
$(CC) -o $(TARGET) $(OBJS) $(CFLAGS)
clean:
-$(RM) $(OBJS)
说明一下,copy代码很容易出现格式错误,记住里面要检查一下是不是Tab键,不然会报错的