Makefile规则
“终极目标”是执行make的唯一目的,其所在的规则作为第一个执行的规则。而其他的规则是在完成重建“终极目标”的过程中被连带出来的。所以这些目标所在规则在Makefile中的顺序无关紧要。因此,书写的makefile的第一个规则应该就是重建整个程序或者多个程序的依赖关系和执行命令的描述。
1.实例
pipe.c
/******************************************************************
** 管道的创建,对管道的读写
** 父进程写入数据到管道,子进程读取数据
*******************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#define READ_SIZE 100
//读管道
void read_from_pipe(int fd)
{
char message[READ_SIZE];
if((read(fd,message,READ_SIZE)) == -1){
printf("read failed!\n");
} else {
printf("read from pipe:%s\n",message);
}
}
//写管道
void write_to_pipe(int fd)
{
char *message = "Hello,pipe!\n";
int len = 0;
len = strlen(message) + 1;
if((write(fd,message,len) ) != len){
printf("write failed!\n");
} else {
printf("write successed! date:%s\n",message);
}
}
int main(void)
{
int fd[2]; /*定义两个文件的描述符,用于管道*/
pid_t pid;
if(pipe(fd)){
printf("create pipe failed!\n");
exit(1);
}else{
printf("create pipe successed!\n");
}
pid = fork(); //创建子进程
switch(pid){
case 0:
close(fd[1]); //子进程关闭fd1
read_from_pipe(fd[0]);
exit(0);
case -1:
printf("fork error!\n");
exit(1);
default:
close(fd[0]); //父进程关闭fd0
write_to_pipe(fd[1]);
exit(0);
}
return 0;
}
Makefile
target=pipe
objects=pipe.o
source=pipe.c
$(target):$(objects)
gcc -o $(target) $(objects) -Wall
$(objects):$(source)
gcc -c pipe.c -Wall
.PHONY:clean
clean:
-rm -f $(objects) $(target)
2.规则语法
通常的规则语法格式:
TARGETS:PREREQUISITES
COMMAND
…
或者:
TARGETS:PREREQUISITES;COMMAND
COMMAND
…
规则中的TARGETS可以是空格分开的多个文件名,也可以是一个标签,例如clean。TARGETS文件名可以使用通配符,通常规则只有一个目标文件,偶尔会在一个规则中需要多个目标。
1)规则的命令部分有两种书写方式:a.命令可以和目标:依赖描述放在同一行。命令在依赖文件列表后并使用分号和依赖文件列表分开。b.命令在目标:依赖的描述的下一行,作为独立的命令行。当作为独立的命令行时此行必须已[TAB]字符开始。在Makefile中,在第一个规则之后出现的所有以[TAB]字符开始的行都会被当作命令来处理。
2)Makefile中符号“$”有特殊的含义,表示变量或者函数的引用,在规则中需要使用“$”的地方,需要书写两个连续的“$$”。
3)对于Makefile中较长的行,我们可以使用反斜线“\”将其书写到几个独立的物理行上。虽然make对于Makefile文本行的最大长度是没有限制的,但还是建议这样做。书写方便且有利于别人的阅读,这是一个程序员修养的体现。
3.规则告诉make的两件事
1)目标在什么情况下已经过期
2)如果需要重建这个目标。如何去重建这个目标。目标是否过期是由哪些使用空格分割的规则的依赖文件所决定的。当目标文件不存在或者目标文件的最后修改时间比依赖文件中的任何一个晚时,目标就会被创建或者重建。目标文件的内容是由依赖文件决定的,依赖文件的任何一处改动,将导致目前已经存在的目标文件的内容过期。规则的命令为重建目标提供了方法。这些命令运行在系统shell之上。
4.上述例子的执行过程
在上述例子中,我们创建了一个pipe.c文件和一个Makefile文件,首先我们让两个文件放置在同一目录下,在shell界面输入make后回车,这时候该目录下生成了pipe.o和pipe文件,其中pipe是一个可执行文件,在shell下输入命令./pipe,pipe.c文件的功能将会被执行。那这个Makefile是怎么工作的呢?
1)首先我们的目的是要生成pipe,这个时候Makefile会检查是否存在pipe文件,如果不存在,将会去寻找pipe.o文件,如果pipe.o不存在,将会去寻找pipe.c文件,进而去执行指令gcc -c pipe.c -Wall;如果上述中pipe.o存在,这个时候去查找pipe.c文件有没有更新,如果有更新,仍会执行gcc -c pipe.c -Wall;这个时候会生成pipe.o文件,对于是否要生成要生成pipe,就去查找pipe.o是否存在或者更新,最终生成目标pipe。
2)想要删除刚才生成的文件,现在执行make clean即可。
5.实例2
上述例子实现了利用Makefile生成一个目标文件,这个时候我们要生成多个目标文件。
client
/********************************************************************
** 创建两个FIFO管道来实现不同进程间的全双工通信
**********************************************************************/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#define FIFO_READ "writefifo"
#define FIFO_WRITE "readfifo"
#define BUF_SIZE 1024
int main(void)
{
int wfd,rfd;
char buf[BUF_SIZE];
int len;
umask(0);
if( mkfifo(FIFO_WRITE,S_IFIFO|0666) ){
printf("Can't create FIFO %s because %s",FIFO_WRITE,strerror(errno));
exit(1);
}
umask(0);
wfd = open(FIFO_WRITE,O_WRONLY);
if(wfd == -1){
printf("open FIFO %s error:%s",FIFO_WRITE,strerror(errno));
exit(1);
}
while((rfd = open(FIFO_READ,O_RDONLY)) == -1){
sleep(1);
}
while(1){
printf("Server:");
fgets(buf,BUF_SIZE,stdin);
buf[strlen(buf)-1] = '\0';
if(strncmp(buf,"quit",4) == 0){
close(wfd);
unlink(FIFO_WRITE);
close(rfd);
exit(0);
}
write(wfd,buf,strlen(buf));
len = read(rfd,buf,BUF_SIZE);
if(len > 0){
buf[len] = '\0';
printf("Client:%s\n",buf);
}
}
}
server.c
//创建两个FIFO来实现不同进程间的全双工通信
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#define FIFO_READ "readfifo"
#define FIFO_WRITE "writefifo"
#define BUF_SIZE 1024
int main(void)
{
int wfd,rfd;
char buf[BUF_SIZE];
int len;
umask(0);
if( mkfifo(FIFO_WRITE,S_IFIFO|0666) ){
printf("Can't create FIFO %s because %s",FIFO_WRITE,strerror(errno) );
exit(1);
}
while((rfd = open(FIFO_READ,O_RDONLY)) == -1){
sleep(1);
}
wfd = open(FIFO_WRITE,O_WRONLY);
if(wfd == -1){
printf("Fail to open FIFO %s:%s",FIFO_WRITE,strerror(errno));
exit(-1);
}
while(1){
len = read(rfd,buf,BUF_SIZE);
if( len > 0){
buf[len] = '\0';
printf("Server:%s\n",buf);
}
printf("Client:");
fgets(buf,BUF_SIZE,stdin);
buf[strlen(buf)-1] = '\0';
if(strncmp(buf,"quit",4) == 0){
close(wfd);
unlink(FIFO_WRITE);
close(rfd);
exit(0);
}
write(wfd,buf,strlen(buf));
}
}
Makefile
all:server client
objs=server client server.o client.o
server:server.o
gcc -o server server.o
client:client.o
gcc -o client client.o
server.o:server.c
gcc -c server.c
client.o:client.c
gcc -c client.c
.PHONY:clean
clean:
-rm -f $(objs)
这里的话就不再废话了,自行验证即可。