《博学谷C++》四.1-3Makefile(作业)

1) 有两个互不相干的文件a.c和b.c,编写Makefile之后,make生成可执行文件a和b。

deng@itcast:~/share/3rd/homework/2makefile$ ls

a.c b.c Makefile

deng@itcast:~/share/3rd/homework/2makefile$ make

deng@itcast:~/share/3rd/homework/2makefile$ ls

a a.c a.o b b.c b.o Makefile

deng@itcast:~/share/3rd/homework/2makefile$ ./a

hello a

deng@itcast:~/share/3rd/homework/2makefile$ ./b

hello b

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
SRC = ${wildcard *.c}
OBJS = ${patsubst %.c,%.o,${SRC}}
OUTS = ${patsubst %.c,%.out,${SRC}}

TAR = all

${TAR}:${OUTS}
@echo "success"

%.out:%.o
${CC} $< -o $@

%.o:%.c
${CC} -c $< -o $@

.PHONY: clean
clean:
rm -rf ${OBJS} ${OUTS}

image-20210624170326375

2) 在1makefile中有如下目录, 编写Makefile生成可执行文件test

源文件如下:

要求:生成的目标文件存储在obj目录中, 生成的可执行文件test存储在bin目录中。

执行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
SRC = ${wildcard ./src/*.c}
#TMP = ${patsubst %.c,%.o,${SRC}}
OBJ = ${addprefix ./obj/,${notdir ${patsubst %.c,%.o,${SRC}}}}
INC = -I./inc
TAR = bin/test
OBJDIR = ./obj/
SRCDIR = ./src/

${TAR}:${OBJ}
${CC} $^ -o $@

${OBJDIR}%.o:${SRCDIR}%.c
${CC} ${INC} -c $< -o $@

all:
echo ${SRC}
#echo ${TMP}
echo ${OBJ}

.PHONY:clean
clean:
rm -rf ${OBJ} ${TAR}

运行后目录结构和程序运行结果:

关于如何根据存放在src目录的源文件生成目标文件到obj目录的问题困扰了我几个小时,最后去网上找了一个类似的文章(见下面的引用),我奇怪为什么他的代码%.o和%.c前面要加上一个地址的变量,最后尝试之后我才知道:原来%.o并不是make根据依赖(这里是${OBJ})生成的带路径的.o文件,而是不加路径的.o文件

也就是说,这里%.o不是./obj/mul.o等,而是mul.o,这才是我的Makefile文件无效的根源。只需分别对%.o和%.c加上路径即可。

Makefile将目标文件从源文件的不同目录放入一个单独的目录中?

Linux学习笔记——例说makefile 索引博文

3)使用read和write实现文件拷贝。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h> 
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

int main()
{
int rfp = open("./infile",O_RDONLY);
int ofp = open("./outfile",O_WRONLY|O_CREAT,S_IRWXU); //只读且创建文件,所有者具有读、写、可执行权限
if (rfp ==-1|| ofp== -1){
perror("Error:");
return -1;
}

int SIZE = 1025;
char *buffer[SIZE];

while(1){
ssize_t rdnum = read(rfp,(void*)buffer,(size_t)(SIZE-1));
if(rdnum ==0)
break;

write(ofp,(void*)buffer,(size_t)rdnum);
}

close(rfp);
close(ofp);

return 0;
}

运行结果


答案(只有1、3题)

第一题Makefile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#一条规则
all: a b


a:a.o
gcc $< -o $@

b:b.o
gcc $< -o $@


#模式规则
%.o:%.c
gcc -c $< -o $@


.PHONY:clean
clean:
-rm --f a b *.o

第三题Makefile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#获取src目录中所有的.c文件
SRC=$(wildcard ./src/*.c)
#替换成目标文件 obj/*.o
OBJS=$(patsubst ./src/%.c, ./obj/%.o, $(SRC))

#变量定义
CC=gcc
INC=./inc
CFLAGS=-c
TARGET=./bin/test

$(TARGET):$(OBJS)
$(CC) $^ -o $@
@#mv $(TARGET) bin/

#将对应的.c生成对应的.o文件
./obj/%.o:./src/%.c
@#gcc -c -I./inc $< -o $@
$(CC) $(CFLAGS) -I$(INC) $< -o $@


#伪目标
.PHONY:clean all
clean:
$(RM) $(OBJS) $(TARGET)

#辅助调试
all:
echo $(SRC)
echo $(OBJS)
echo $(RM)