我正在寻找一种模式来组织C ++中多个平台的头文件。
我有一个包装器.h文件,应该在Linux和Win32下编译。
这是我能做的最好的吗?
// defs.h
#if defined(WIN32)
#include <win32/defs.h>
#elif defined(LINUX)
#include <linux/defs.h>
#else
#error "Unable to determine OS or current OS is not supported!"
#endif
// Common stuff below here...
我真的不喜欢C ++中的预处理程序。是否有一种清洁(和理智)的方式来做得更好?
答案 0 :(得分:18)
您应该使用能够执行平台检查的配置脚本并生成适当的编译器标志和/或配置头文件。
有几种工具可以执行此任务,例如autotools,Scons或Cmake。
在你的情况下,我建议使用CMake,因为它很好地与Windows集成,能够生成Visual Studio项目文件,以及Mingw makefile。
这些工具背后的主要理念是您不再测试操作系统本身,而是针对可能存在或可能不存在的功能,或者哪些值可能不同的功能,从而降低代码无法编译的风险“平台不支持“错误。
这是一个评论的CMake示例(CMakeFiles.txt):
# platform tests
include(CheckFunctionExists)
include(CheckIncludeFile)
include(CheckTypeSize)
include(TestBigEndian)
check_include_file(sys/types.h HAVE_SYS_TYPES_H)
check_include_file(stdint.h HAVE_STDINT_H)
check_include_file(stddef.h HAVE_STDDEF_H)
check_include_file(inttypes.h HAVE_INTTYPES_H)
check_type_size("double" SIZEOF_DOUBLE)
check_type_size("float" SIZEOF_FLOAT)
check_type_size("long double" SIZEOF_LONG_DOUBLE)
test_big_endian(IS_BIGENDIAN)
if(IS_BIGENDIAN)
set(WORDS_BIGENDIAN 1)
endif(IS_BIGENDIAN)
# configuration file
configure_file(config-cmake.h.in ${CMAKE_BINARY_DIR}/config.h)
include_directories(${CMAKE_BINARY_DIR})
add_definitions(-DHAVE_CONFIG_H)
有了这个,您必须提供一个config-cmake.h.in模板,该模板将由cmake处理以生成包含您需要的定义的config.h文件:
/* Define to 1 if you have the <sys/types.h> header file. */
#cmakedefine HAVE_SYS_TYPES_H
/* Define to 1 if you have the <stdint.h> header file. */
#cmakedefine HAVE_STDINT_H
/* Define to 1 if your processor stores words with the most significant byte
first (like Motorola and SPARC, unlike Intel and VAX). */
#cmakedefine WORDS_BIGENDIAN
/* The size of `double', as computed by sizeof. */
#define SIZEOF_DOUBLE @SIZEOF_DOUBLE@
/* The size of `float', as computed by sizeof. */
#define SIZEOF_FLOAT @SIZEOF_FLOAT@
/* The size of `long double', as computed by sizeof. */
#define SIZEOF_LONG_DOUBLE @SIZEOF_LONG_DOUBLE@
我邀请您访问cmake网站,了解有关此工具的更多信息。
我个人是cmake的粉丝,我将其用于个人项目。
答案 1 :(得分:6)
执行此操作的一种方法是将特定于操作系统的标头放入不同的目录,并通过-I标志将该目录传递给编译器来控制找到的目录。
在你的情况下你就是
#include "defs.h"
答案 2 :(得分:4)
使用预处理器没有任何固有的“坏处”。它是出于某种原因而创建的,像这样的条件编译/包含是做得相当好的事情之一。
关键是要保持代码的可读性。如果您的代码中有很多#ifdef WIN32
块,或者您发现自己在大量文件中执行了此操作,那么这里有一些提示可以清理您的代码。
1)将条件包含移动到单独的文件中。您的源文件只是#include <defs.h>
,并将条件包含块移动到defs.h(即使该文件中只包含该文件)。
2)让makefile确定要包含哪个文件。同样,您的源文件只是#include <defs.h>
。您的makefile将检测当前平台并根据需要将-iwin32
或-ilinux
添加到编译器选项字符串。这是我通常采用的方法。您可以在makefile中或在配置阶段(如果您动态生成makefile)执行平台检测工作。我还发现这个选项最容易在以后添加对新平台的支持;它似乎可以最大限度地减少需要进行的更改次数。
3)如果您在Linux系统上构建(暗示任何Win32代码将由交叉编译器生成),您可以让构建脚本创建指向相应头文件目录的符号链接。您的代码可以将目录引用为#include <platform\defs.h>
,并让makefile或configure脚本担心对正确的文件夹进行符号链接。
答案 3 :(得分:2)
预处理器本身并不是一件坏事。它就像许多其他开发工具一样,是一个强大的工具。问题是你如何使用它?
如果您对预处理进行清晰,记录和逻辑处理,则根本不是问题。当你开始做“聪明”的技巧时,很难解释它成为一个问题。
理想情况下,您会限制执行此操作的频率。因此,您可能会在所有文件中包含defs.h
,并在该文件中包含您的操作系统特定逻辑。
答案 4 :(得分:1)
答案 5 :(得分:0)