虽然我认为使用构建系统来处理跨平台文件是最好的,但是可以简单地编写源代码来通过预处理器来处理它。然而,这种非常常见、快速和肮脏的方法,即在代码中散布平台检查是有问题的,应该避免。
相反,您应该使用更高度结构化的方法来组织特定于平台的代码,以避免随着项目变大而出现问题。
平台特定代码应在文件级别明确标识:例如,使用每个平台的目录结构,并将所有平台特定源文件放在适当的目录中。源文件不应包含用于多个平台的代码或任何预处理器平台检查(但有一个例外)。此外,平台特定的源通常不应直接构建或#include
d. 相反,平台特定代码只能通过非平台特定源文件间接使用,这些源文件除了平台检查和#include
平台特定文件之外什么都不包含。
示例源组织:
src/
main.cpp
foo.h
foo.cpp
windows/
foo.cpp.inc
posix/
foo.cpp.inc
示例源内容:
// main.cpp
#include "foo.h"
int main() {
foo();
}
// foo.h
void foo();
// foo.cpp
#if defined(_WIN32)
# include "windows/foo.cpp.inc"
#elif __has_include(<unistd.h>)
# include<unistd.h>
# if defined(_POSIX_VERSION)
# include "posix/foo.cpp.inc"
# endif
#else
# error Unknown platform
#endif
// windows/foo.cpp.inc
#include "foo.h"
#include <iostream>
#include <Windows.h>
void foo() {
std::cout << "Windows\n";
}
// posix/foo.cpp.inc
#include "foo.h"
#include <iostream>
#include <unistd.h>
void foo() {
std::cout << "POSIX\n";
}
Windows 构建和输出:
cl.exe /EHsc /W4 /WX src\main.cpp src\foo.cpp
main
视窗
Linux 构建和输出:
g++ -Wall -Wextra -Werror -Isrc src/main.cpp src/foo.cpp
./a.out
POSIX
当不同平台的代码可以合理地共享相同的文件组织时,上面示例中显示的方法非常有效。如果不同平台的代码差异很大,以至于您希望每个平台都有不同的文件结构,那么使用这种技术会更加困难,并且转向使用构建系统来管理不同平台的代码会变得更加明显。
也可以将这种技术与构建系统混合使用;跨平台共享文件结构的代码可以使用它,而不同平台特有的模块可以由构建系统处理。