我有一个程序可以在 MacOS 和 Linux 上编译。在我的 makefile 中,我定义了一个变量:
# MAC
ifeq ($(UNAME), Darwin)
OS = APPLE
#LINUX
else
OS = LINUX
endif
INCLUDES = -Iincludes -Ilibft -I$(MLX_DIR) -D$(OS)
导致以下编译:
gcc -Wall -Wextra -Werror -O3 -Iincludes -Ilibft -I./minilibx_mms -DAPPLE -c srcs/parser/parser.c -o objs/parser/parser.o
gcc -Wall -Wextra -Werror -O3 -Iincludes -Ilibft -I./minilibx_mms -DAPPLE -c srcs/terminate/gameover_sys.c -o objs/terminate/gameover_sys.o
如您所见,我将
APPLE
作为宏传递,因此当我调用此函数时:
if (cub->mlx)
{
#ifdef LINUX
mlx_destroy_display(cub->mlx);
#endif
free(cub->mlx);
}
#ifdef
和#endif
之间的所有内容都应该在编译前删除,对吗?但是,唉,我从编译器那里得到了这个错误:
Call to undeclared function 'mlx_destroy_display'; ISO C99 and later do not support implicit function declarations clang(-Wimplicit-function-declaration)
函数只存在于库的Linux实现中。我对预处理器指令的理解哪里不正确?据我了解,当
#ifdef LINUX
宏不存在时,整个 LINUX
部分应该被删除。
如何修复应该由 #ifdef 之间的预处理器指令排除的编译器错误?
LINUX
是非常简单的通用名称,标准头文件或其他项目可能已经定义了它。为您的项目使用唯一的宏前缀。
# Makefile
ifeq ($(UNAME), Darwin)
OS = APPLE
else
OS = LINUX
endif
CFLAGS = -Iincludes -Ilibft -I$(MLX_DIR) -DYOUR_LIBRARY_NAME_OS_$(OS)
# C file
#ifdef YOUR_LIBRARY_NAME_OS_LINUX
另一种选择:
检查 reserved 符号,例如
__linux__
或 __MACH__
而不是定义您自己的符号。
来自 GCC 的在线预定义宏文档(注意,粗体部分):
C 标准要求所有系统特定的宏都是 保留命名空间。所有以两个下划线或一个下划线和一个大写字母开头的名称都保留给编译器和 图书馆随心所欲地使用。然而,历史上特定于系统 宏的名称没有特殊前缀;例如,它是 常见于 Unix 系统上定义的
。对于所有此类宏,GCC 提供一个在开头添加两个下划线的并行宏 和结束。如果定义了unix
,那么unix
也将被定义。那里 永远不会超过两个下划线;__unix__
的平行线是_mips
.__mips__
当
选项,或任何要求严格的-ansi
选项 一致性,被提供给编译器,所有系统特定的 保留命名空间之外的预定义宏被抑制。这 保留命名空间内的并行宏保持定义状态。-std
我们正在慢慢淘汰所有不在 保留命名空间。 ...
例如:
$ echo | gcc -dM -E - | grep -i linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1
#define linux 1
与
-std=c11
:
$ echo | gcc -std=c11 -dM -E - | grep -i linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1
通过使用保留符号,您还可以防止与第三方标头的名称冲突。
另外,请参阅如何使用预处理器指令检查操作系统?