Написание кросс-платформенного кода на С++ (Windows, Linux и Mac OSX)
Это моя первая попытка записать что-либо даже немного сложное в С++, я пытаюсь создать общую библиотеку, с которой я могу взаимодействовать с Objective-C и .NET-приложениями (хорошо, эта часть приходит позже)..)
Код, который у меня есть, -
#ifdef TARGET_OS_MAC
// Mac Includes Here
#endif
#ifdef __linux__
// Linux Includes Here
#error Can't be compiled on Linux yet
#endif
#ifdef _WIN32 || _WIN64
// Windows Includes Here
#error Can't be compiled on Windows yet
#endif
#include <iostream>
using namespace std;
bool probe(){
#ifdef TARGET_OS_MAC
return probe_macosx();
#endif
#ifdef __linux__
return probe_linux();
#endif
#ifdef _WIN32 || _WIN64
return probe_win();
#endif
}
bool probe_win(){
// Windows Probe Code Here
return true;
}
int main(){
return 1;
}
У меня есть предупреждение о компиляторе, просто untitled: In function ‘bool probe()’:untitled:29: warning: control reaches end of non-void function
- но я также очень ценю любую информацию или ресурсы, которые люди могли бы предложить, как лучше писать такой код....
Ответы
Ответ 1
Я рассмотрю эту конкретную функцию:
bool probe() {
#ifdef TARGET_OS_MAC
return probe_macosx();
#elif defined __linux__
return probe_linux();
#elif defined _WIN32 || defined _WIN64
return probe_win();
#else
#error "unknown platform"
#endif
}
Записывая его таким образом, как цепочку if-elif-else, устраняет ошибку, потому что невозможно скомпилировать без действительного оператора return или удара #error.
(Я считаю, что WIN32 определен как для 32-, так и для 64-битных Windows, но я не мог сказать вам окончательно, не глядя на него. Это упростило бы код.)
К сожалению, вы не можете использовать #ifdef _WIN32 || _WIN64: см. http://codepad.org/3PArXCxo для примера сообщения об ошибке. Вы можете использовать специальный оператор, определенный только для предварительной обработки, как я уже говорил выше.
Что касается разделения платформ в соответствии с функциями или целыми файлами (как предложил), вы можете или не захотите это сделать. Он будет зависеть от деталей вашего кода, например, насколько распределен между платформами и что вам (или вашей команде) лучше всего подходит для синхронизации функций, среди других проблем.
Кроме того, вы должны обрабатывать выбор платформы в своей системе сборки, но это не означает, что вы не можете использовать препроцессор: используйте макросы, условно определенные (с помощью makefile или build system) для каждой платформы. На самом деле это часто наиболее практичное решение с шаблонами и встроенными функциями, что делает его более гибким, чем попытка прерватьпроцессор. Он хорошо сочетается с целым файловым подходом, поэтому вы по-прежнему используете его там, где это необходимо.
Возможно, вы захотите иметь один заголовок конфигурации, который переводит все различные макросы для компилятора и платформы в хорошо известные и понятные макросы, которые вы контролируете. Или вы можете добавить -DBEAKS_PLAT_LINUX в свою командную строку компилятора - через вашу систему сборки - для определения этого макроса (не забудьте использовать префикс для имен макросов).
Ответ 2
вместо повторения себя и записи тех же строк #ifdef.... снова и снова, возможно, вам лучше объявить метод probe() в заголовке и предоставить три разных исходных файла, один для каждой платформы. Это также имеет преимущество: если вы добавляете платформу, вам не нужно изменять все существующие источники, а просто добавлять новые файлы. Используйте свою систему сборки, чтобы выбрать соответствующий исходный файл.
Пример структуры:
include/probe.h
src/arch/win32/probe.cpp
src/arch/linux/probe.cpp
src/arch/mac/probe.cpp
Предупреждение вызвано тем, что probe() не возвращает значение. Другими словами, ни один из трех #ifdefs не соответствует.
Ответ 3
Кажется, что ни один из TARGET_OS_MAC
, __linux__
, _WIN32
или _WIN64
не был определен во время компиляции вашего кода.
Таким образом, ваш код был следующим:
bool probe(){
}
Вот почему компилятор жалуется на достижение конца не-void функции. Нет предложения return
.
Кроме того, для более общего вопроса, вот мои рекомендации при разработке программного обеспечения/библиотек с несколькими платформами/архитектурой:
Избегайте конкретных случаев. Попробуйте написать код, который является OS-агностиком.
При работе с конкретными элементами системы попробуйте обернуть вещи в "непрозрачные" классы. Например, если вы имеете дело с файлами (разными API-интерфейсами в Linux и Windows), попробуйте создать класс File
, который будет вставлять всю логику и предоставлять общий интерфейс независимо от операционной системы. Если какая-либо функция недоступна в одной из ОС, справитесь с ней: если эта функция не имеет смысла для конкретной ОС, она часто ничего не делает вообще.
Короче: чем меньше #ifdef
, тем лучше. И независимо от того, насколько портативен ваш код, протестируйте его на каждой платформе, прежде чем выпускать его.
Удачи;)
Ответ 4
Предупреждение объясняется тем, что если ни одно из определений не определено, то у вас нет функции return
в вашей функции зондирования. Исправление для этого помещается по умолчанию return
.
Ответ 5
Чтобы добавить что-то еще к этому, кроме выдающихся опций выше, директивы __linux__
и _WIN32
известны компилятору, где директива TARGET_OS_MAC
не указана, это можно решить, используя __APPLE__
, Источник: http://www.winehq.org/pipermail/wine-patches/2003-July/006906.html