我正在学习 GNU Make 和 makefile 是如何工作的。
我有一个包含 7 个 *.c 和 *.h 文件以及一个 main.c 文件的小项目。
这是生成文件:
CC = "gcc"
CFLAGS = "-std=c11"
#PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin
# the PATH variable is set after I got the error. But adding this didnt change the result
src := src/lib
bin := bin
project: $(bin)/aaa.o $(bin)/bbb.o $(bin)/ccc.o $(bin)/ddd.o $(bin)/eee.o $(bin)/fff.o $(bin)/main.o
$(CC) $(CFLAGS) $(bin)/aaa.o $(bin)/bbb.o $(bin)/ccc.o $(bin)/ddd.o $(bin)/eee.o $(bin)/fff.o $(bin)/main.o -o $(bin)/project
$(bin)/aaa.o: $(src)/aaa.c $(src)/ddd.h
$(CC) $(CFLAGS) -c $(src)/aaa.c
$(bin)/bbb.o: $(src)/bbb.c $(src)/aaa.h $(src)/bbb.h $(src)/ddd.h $(src)/fff.h
$(CC) $(CFLAGS) -c $(src)/bbb.c
$(bin)/ccc.o: $(src)/ccc.c $(src)/aaa.h $(src)/fff.h
$(CC) $(CFLAGS) -c $(src)/ccc.c
# ... (and so on for all other .o files
clean:
rm $(bin)/*
aaa.c
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "aaa.h"
#include "ddd.h"
bbb.c
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "aaa.h"
#include "bbb.h"
#include "ddd.h"
#include "fff.h"
ccc.c
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include "aaa.h"
#include "fff.h"
运行时,它给了我这个错误:
"gcc" "-std=c11" -c src/lib/aaa.c
src/lib/aaa.c: In function ‘init_fileSize’:
src/lib/aaa.c:103:14: warning: implicit declaration of function ‘fileno’ [-Wimplicit-function-declaration]
103 | if((fd = fileno(arg->srcstream)) == -1)
| ^~~~~~
"gcc" "-std=c11" -c src/lib/bbb.c
"gcc" "-std=c11" -c src/lib/ccc.c
src/lib/ccc.c: In function ‘closeProgram’:
src/lib/ccc.c:10:15: error: ‘STDIN_FILENO’ undeclared (first use in this function)
10 | tcsetattr(STDIN_FILENO, TCSANOW, &(trml->termios_default));
| ^~~~~~~~~~~~
src/lib/ccc.c:10:15: note: each undeclared identifier is reported only once for each function it appears in
make: *** [makefile:19: bin/ccc.o] Error 1
从错误消息中,我得出结论,gcc 无法找到在标准头文件(如 stdio.h)中声明的函数和其他标识的定义。
这些预处理器符号和函数不是标准 C 的一部分。它们在 POSIX 标准中定义。
在程序启动时,与 流 stdin、stdout 和 stderr 是 0、1 和 2, 分别。 预处理器符号STDIN_FILENO, STDOUT_FILENO 和 STDERR_FILENO 是用这些值定义的
.
所以你失踪了:
#include <unistd.h>
对于宏。
和
fileno(3)
(在stdio.h
中声明),需要定义一个特性测试宏:
/* Before including any headers, define this at the top. */
#define _POSIX_C_SOURCE 200819L
/* Now include the headers. */
或者,您可以将
-std=cXX
替换为 -std=gnuXX
,这将包括对语言的各种扩展。
从错误消息中,我得出结论,gcc 无法找到在标准头文件(如 stdio.h)中声明的函数和其他标识的定义。
是的,但这与找不到
stdio.h
本身不同。如果它找不到标头,那么它也会发出有关该标头的诊断信息。
第一期在这里:
CFLAGS = "-std=c11"
告诉编译器不要对 C 语言启用句法和语义扩展。它也告诉编译器默认不启用任何标准库扩展。标准库中与整数文件句柄有关的所有内容都属于后一类,特别包括
fileno()
函数和 STDIN_FILENO
宏。
此外,
stdio.h
不是 STDIN_FILENO
宏的记录位置。如果启用了适当的功能,您仍然可以从 stdio.h
获得它,但是该宏的 (POSIX) 标准位置是标头 unistd.h
。整个标题是一个扩展。
在您想要使用
-std=c11
选项编译并且还想访问这些库功能的源文件中,您需要在任何 #include
指令之前定义适当的功能测试宏。并且您应该包括记录的标头以提供您需要的任何特定功能,而不是依赖于从未记录的来源获取它们。例如,
#define _POSIX_C_SOURCE 200809L
// ...
#include <stdio.h>
#include <unistd.h>
// ...
.