Хотя я думаю, что лучше всего использовать систему сборки для обработки кроссплатформенных файлов, можно просто написать свой исходный код для обработки его через препроцессор. Однако очень распространенный, быстрый и грязный способ сделать это, когда вы распространяете проверки платформы по всему коду, проблематичен и его следует избегать.
Вместо этого вам следует использовать более структурированный метод организации кода, специфичного для платформы, чтобы избежать проблем по мере роста проекта.
Код, специфичный для платформы, должен быть четко определен на уровне файлов: например, используйте структуру каталогов с каталогами для каждой платформы и поместите все исходные файлы для конкретной платформы в соответствующий каталог. Исходные файлы не должны содержать код для нескольких платформ или любые проверки платформ препроцессора (за исключением одного исключения). Кроме того, источник, специфичный для платформы, как правило, не должен создаваться напрямую или #include
d. Вместо этого, специфичный для платформы код должен использоваться только косвенно, через неплатформенные исходные файлы, которые не содержат ничего, кроме проверок платформы и #include
s специфичных для платформы файлов.
Пример исходной организации:
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
Windows
Сборка и вывод Linux:
g++ -Wall -Wextra -Werror -Isrc src/main.cpp src/foo.cpp
./a.out
1042 * POSIX *
Метод, показанный в приведенном выше примере, работает достаточно хорошо, когда код для разных платформ может разумно использовать одну и ту же файловую организацию. Если код для разных платформ настолько различен, что вам нужны разные файловые структуры для каждой платформы, то этот метод сложнее использовать, и переход к использованию системы сборки для управления кодом для разных платформ становится более очевидным.
Также возможно смешать эту технику с использованием системы сборки; код, который разделяет файловую структуру между платформами, может использовать это, в то время как модули, уникальные для разных платформ, могут обрабатываться системой сборки.