Методы обеспечения кроссплатформенной совместимости (C ++)?

13

Я заканчивал один из моих ранних проектов C ++, который (в соответствии с фреймворком) должен был быть кроссплатформенным. Я полностью разработал проект в Windows и Visual Studio, полагая, что, поскольку все библиотеки являются кроссплатформенными, выполнение сборки OSX в дальнейшем будет тривиальным. Оказалось, что это не так, скорее «код Windows» не работает должным образом, и в нем были исправлены некоторые ошибки компиляции.

Какие методы существуют, чтобы заранее гарантировать, что код совместим со всеми платформами? Разрабатываете все платформы одновременно, и, таким образом, одновременно тестируете код для каждой платформы, когда добавляются новые функции, вместо того, чтобы разрабатывать разные версии платформ один за другим? (*)

Обращаю особое внимание на то, что советую не зависеть от инструментов, а, скорее, от «процессов разработки», которые способствуют межплатформенной совместимости, независимо от того, какие инструменты используются. Как и тот (*) выше.


В частности, я разрабатываю плагин VST с WDL-OL ( https://github.com/olilarkin/wdl-ol ) и некоторыми кроссплатформенными библиотеками DSP. В проектах WDL-OL настроены проекты как VS, так и Xcode, но я думаю, что проблемы связаны с библиотеками, а затем с различиями в компиляторах.

mavavilj
источник
1
нет способа обеспечить переносимость, есть только способы улучшить / максимизировать переносимость
phuclv
и почему это не дубликат? Я думаю, что было много подобных вопросов
phuclv
Что делает ваше приложение? Как бы вы использовали это? В командной строке или через какой-то графический интерфейс? Пожалуйста, отредактируйте свой вопрос, чтобы улучшить его.
Василий Старынкевич
А какие рамки вы используете?
Василий Старынкевич

Ответы:

15

Создание переносимого кода может быть очень сложным.

Сначала несколько очевидных советов, связанных с языком:

  • используйте стандарт C ++ и избегайте любых неопределенных действий
  • полагаться в первую очередь на стандартные библиотеки (и переносимые библиотеки, такие как boost )
  • всегда включайте все ожидаемые заголовки. Не думайте, что вам не нужен заголовок, потому что он включен в другой (то есть в одну конкретную реализацию !): Это может вызвать ошибки компиляции
  • Избегайте конструкций, которые поддерживаются компилятором, но не гарантируются стандартом C ++ (например, анонимная структура или массив переменной длины ): может вызвать ошибки компиляции.
  • использовать параметры компилятора, чтобы помочь вам обеспечить соблюдение (отключение определенных расширений компилятора, максимизировать уровень возвращаемых предупреждений)
  • имейте в виду, что недостаточно того, чтобы код работал: существует много подводных камней, зависящих от реализации: размер (даже элементарных) типов данных, символы, которые могут быть подписаны или не подписаны по умолчанию , допущения о порядке байтов , порядок вычисления в выражениях, когда эти использовать побочные эффекты и т. д.

Затем пара дизайнерских рекомендаций:

  • Предпочитаю стандартную библиотеку альтернативную эквивалентной функциональности операционной системы
  • Максимально изолируйте использование зависимостей операционной системы (например, в функции-обертке, управляемой с помощью условной компиляции)

Наконец тонкие моменты:

  • кодировка символов: во многих системах вы можете положиться utf8 . Но для Windows это более деликатно, так как система ожидает ANSI или UTF-16. Конечно, вы можете положиться на typedef (например TCHAR), но это может быть сложным в сочетании со стандартной библиотекой (например, coutпротив wcoutиспользования в зависимости от использования charили wchar_t)
  • Если для графического интерфейса / графики / расширенного ввода-вывода вы не можете найти переносимую библиотеку, которая соответствует вашим ожиданиям / требованиям, спроектируйте общую архитектуру, чтобы изолировать компоненты, специфичные для ОС. Обертки могут быть недостаточными из-за множества различных взаимодействий и концепций.
  • Воспользуйтесь некоторыми интересными шаблонами дизайна, такими как, например, абстрактная фабрика (идеально подходит для проектирования семейств связанных объектов, например, в пользовательском интерфейсе ОС) или посредник (идеально подходит для реализации совместной работы семейств связанных объектов) и используйте их вместе с условной компиляцией ,

Но это только советы. В этой области вы не можете получить уверенность.

Christophe
источник
-Wall -Wextra -Werror
труба
1
@pipe Ты тоже должен быть -pedantic.
5gon12eder
@ 5gon12eder Очень хороший момент в контексте этого ответа.
труба
11

Нет ничего, что могло бы гарантировать совместимость кода с платформой, кроме сборки, запуска и тестирования на нем. Поэтому подход всех здравомыслящих людей состоит в том, чтобы создавать, запускать и тестировать свои приложения на каждой платформе, которую они проектируют, для которой необходимо будет создавать, запускать и тестировать.

Непрерывная интеграция (CI) может значительно облегчить эту нагрузку для небольших проектов, поскольку вы можете получить дешевые или бесплатные агенты сборки для некоторых платформ (в основном Linux), заниматься разработкой под Windows и просто вернуться к Linux в случае возникновения проблемы.

OSX CI довольно сложно, хотя.

DeadMG
источник
Там нет упоминания, что такое CI?
Мававиль
5
Непрерывная интеграция - в основном группа серверов, которые выполняют сборки и тесты для вас.
DeadMG
@DeadMG Вы имеете в виду, как Mozilla Tinderbox?
Дамиан Йеррик
1
Travis CI предоставляет бесплатные хосты для сборки OSX
Daenyth
Просто используйте Cmake.
Радж
9

Если вы запрашиваете «процессы разработки» и ваша основная платформа разработки - Windows с Visual Studio, я бы посоветовал попробовать построить ваш проект без «windows.h». Вы получите много ошибок компиляции, которые укажут вам во многих местах, где вам нужно реорганизовать свой код. Например, «DWORD» не будет #defined, и вам нужно будет заменить его uint32_tвезде (обратитесь к Google, stdint.hи вы найдете полезную информацию о целочисленных типах и их кроссплатформенных определениях). Далее вам нужно будет заменить все вызовы Win32 API, такие как,Sleep()с их кросс-платформенным эквивалентом (опять же, Google - ваш лучший друг, который покажет соответствующие вопросы и ответы на стеках * .com сайтов). Вероятно, вам не удастся найти все соответствующие кроссплатформенные замены для вашего кода, и вам придется вернуть свою include "windows."директиву, но указать ее #ifdef _WIN32- подробности здесь

Продолжайте задавать более конкретные вопросы и получать ответы - это общее предложение о том, «каким должен быть процесс разработки»

РЕДАКТИРОВАТЬ 1 Другим моим предложением является использование gcc и / или clang на вашей машине для разработки Windows (вместе с Visual Studio)

mvidelgauz
источник
3

Это зависит от "некоторых ошибок компиляции", которые вы упоминаете. Не зная, кем они были, невозможно быть конкретным.

У меня есть кроссплатформенный код для Windows / Linux / iOS / Android / Mac. Каждая новая платформа приносила дополнительные ошибки и предупреждения при первом добавлении. Вы быстро узнаете, какие конструкции приносят проблемы. Либо избегайте их, либо абстрагируйте различия в заголовок с помощью #ifdefs. Старайтесь никогда не переходить #ifdefмежду платформами внутри вашего кода.

Один пример:

void myfunction(MyClass &);
myfunction(MyClass());

создает временный экземпляр, MyClassкоторый удаляется после myfunctionвозвращения. В некоторых моих компиляторах C ++ этот экземпляр предназначен для чтения / записи (и тот факт, что он является временным и скоро будет уничтожен, не беспокоит компилятор). С другими, myfunctionдолжен быть переопределен, чтобы взять const MyClass &, или компилятор жалуется. Неважно, что говорится в стандарте C ++, или какой компилятор верен, а какой нет. После пары раз обнаруженных ошибок я знаю (а) либо объявить временную переменную типа MyClassи передать ееmyfunction или (б) объявить ссылку constв myfunctionи использованияmutable здесь и там deconstify.

Итог: накапливайте опыт и разрабатывайте собственные стандарты кодирования.

Мартин Кочански
источник
2
Это ошибка MSVC. Если ваша точка зрения состоит в том, что разработка на 1 системе позволяет им закрадываться, точка взята. Но эта конкретная вещь не то, что вы должны делать.
JDługosz
1
Хорошей особенностью использования нескольких цепочек инструментов является то, что общее подмножество, которое они принимают, с большей вероятностью будет правильным, соответствует стандартам C ++, чем то, что каждый из них принимает индивидуально. В вашем случае приведенный код явно неверен стандартом, и оба упомянутых исправления являются допустимыми альтернативами. Я бы сказал, что имеет значение, что говорит стандарт.
5gon12eder
1
Или я бы сказал, что кроссплатформенный C ++ более строг, чем то, что говорится в стандарте. Другими словами, даже если в стандарте говорится об этом, вы по-прежнему используете наименьшие общие знаменатели (или возможности наименьшего поставщика) для платформ, которые вы должны поддерживать. Существует множество библиотек с открытым исходным кодом, которые пришлось исключить, скажем, C ++ 11, потому что часть их составляющих (как у граждан) не поддерживает C ++ 11.
Руонг
3

Возможный способ помочь переносимости может заключаться в том, чтобы полагаться только на объявления и функции, предоставляемые стандартом C ++ 11 , и с помощью кроссплатформенных библиотек и сред, таких как POCO & Qt .

Но даже это не безотказно. Помни афоризм

нет такой вещи, как переносимая программа, есть только программы, которые были успешно перенесены (на определенную платформу)

С практикой, дисциплиной и большим опытом, перенос программы на другую платформу обычно может быть сделан быстро. Но опыт и ноу-хау имеют большое значение.

Василий Старынкевич
источник
1
Другой совет заключается в том, что, когда портирование выполняется разными людьми и командой, изменения кода должны быть повторно интегрированы в основную линию. В противном случае различия между платформами становятся знанием, накопленным командой, которая это сделала.
Руонг