Как определить удобство использования ‹filesystem› на OSX?

Я хотел сделать кросс-платформенное, необязательное использование std::filesystem и использовал следующий код:

#ifdef __has_include
#if __has_include(<version>)
#include <version>
#endif
#endif

#ifdef __cpp_lib_filesystem
#include <filesystem>
// Use of std::filesystem::path
#endif

Затем я могу передать -std=c++11 или -std=c++17 и иметь или не иметь поддержку файловой системы.

Это отлично работает почти везде, но на недавней OSX без явного установленного уровня целевой платформы. Кажется, это по умолчанию для некоторых более старых OSX и вызывает ошибку компиляции:

ошибка: «путь» недоступен: введено в macOS 10.15
...
Applications / Xcode_11.3.1.app / Contents / Developer / Toolchains / XcodeDefault.xctoolchain / usr / bin /../ include / c ++ / v1 / filesystem: 739: 24:
примечание: 'путь' здесь явно отмечен как недоступный

Итак, как я должен справиться с этим в OSX, не полагаясь на проверки конфигурации, если такой код компилируется? Разве макрос определения функций __cpp_lib_filesystem не предназначался для того, чтобы сделать такие шаги настройки ненужными?


person Flamefire    schedule 07.10.2020    source источник
comment
Вы включили стандарт C ++ 17? Кроме того, могло ли это быть связано с stackoverflow.com/questions/58131130/?   -  person Zaiborg    schedule 07.10.2020
comment
@Zaiborg, даже если бы не вопрос OP, все равно было бы, почему __cpp_lib_filesystem установлен, если std::filesystem не полностью функционален. Поскольку тестирование функций с использованием этих определений должно позволить, например, используйте резервный код.   -  person t.niese    schedule 07.10.2020
comment
Да, этот вопрос связан. Однако мой код представляет собой библиотечный код, поэтому я не могу добавлять флаги компиляции, но должен определять поддержку через препроцессор. Я добавил предложение о включении данного стандарта, чтобы прояснить, что проблема возникает дальше. Спасибо за предложение   -  person Flamefire    schedule 07.10.2020
comment
В некоторой степени связано: stackoverflow.com/q/64009875/13156261. Включение fstream, похоже, не позволяет включать filesystem в OSX.   -  person Eddymage    schedule 07.10.2020


Ответы (1)


Проблема в том, какую версию OSX вы настроили для поддержки.

В OSX / MacOS стандартная библиотека C ++ является частью системы. Поэтому, если вы установите, что ваша программа поддерживает некоторую версию MacOS, компилятор будет проверять, есть ли в этой версии системы стандартная библиотека C ++, которая поддерживает определенную функцию.

Так, например, не имеет значения, что вы включили C ++ 17, но если ваша программа должна поддерживать OSX 10.13, эта программа не будет компилироваться:

int foo(std::optional<int> x)
{
   return x.value();
}

Поскольку это может вызвать исключение: std::bad_optional_access, который является частью стандартной библиотеки динамической библиотеки, поставляемой с ОС.

С другой стороны, этот код отлично скомпилируется:

int foo(std::optional<int> x)
{
   return x.value_or(0);
}

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

Точно такая же проблема присутствует с функциями файловой системы. Вот почему компилятор жалуется, что вам нужно настроить проект для поддержки MacOS 10.15 или новее.

Если вы используете cmake, добавьте это в root CMakeLists.txt:

# note this entry must be set before any target or project is created
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")

Если вы используете проект Xcode:  введите описание изображения здесь

Есть способ обнаружить платформу и сделать доступными эти функции 10.15. Вот SO-ответ, описывающий, как это сделать. Таким образом, у вас может быть приложение, некоторые функции которого доступны только при запуске на требуемой версии ОС.

person Marek R    schedule 07.10.2020
comment
Это действительно странное поведение компилятора, разве он не должен установить __cpp_lib_filesystem в false, если целевая версия ОС не поддерживает filesystem? Вы знаете, есть ли причина за этим решением? - person t.niese; 07.10.2020
comment
Компилятор поддерживает это, Deplyoment target - нет, поэтому вы получили сообщение об ошибке. Измените Deplyoment target на 10.15, и он отлично скомпилируется. - person Marek R; 07.10.2020
comment
Также обратите внимание на мой пример, std::optional доступен, но не все его функции. - person Marek R; 07.10.2020
comment
ИМХО все еще странно, что инструментальная цепочка затем позволяет использовать языковые функции С ++ 17 для цели, но не устанавливает соответствующее определение функции для установленной целевой ОС, что каким-то образом побеждает их цель. - person t.niese; 07.10.2020
comment
AFAIK можно добавить какой-то if, поэтому компилятор будет гарантировать, что во время выполнения вы проверите платформу перед использованием определенной функции, и int будет компилироваться. Вот как это работает на Swift. Не знаю, как этого можно добиться в C ++. - person Marek R; 07.10.2020
comment
afaik нет встроенной проверки во время выполнения. Как бы то ни было, как и в случае с OP, я также подозревал, что инструментальная цепочка будет устанавливать определения функций на основе выбранной версии c ++ и выбранной цели развертывания. В противном случае эти определения функций не имеют большого смысла и бесполезны. Вот почему я говорю, что это странное поведение цепочки инструментов. - person t.niese; 07.10.2020
comment
Вся идея заключается в обнаружении потенциальных проблем совместимости. В swift вы можете добавить if, который будет проверять во время выполнения текущий платформа и область действия в рамках этого, если позволяет использовать функции, доступные на проверенной платформе, минуя настройку цели развертывания. Поскольку компилятор такой же, должно быть аналогичное решение для C ++, я никогда не использовал это в C ++, поэтому не знаю, как это сделать. Альтернативные простейшие решения: увеличить цель развертывания или использовать ускорение. - person Marek R; 07.10.2020
comment
Немного погуглил, и я нашел решение для C ++ stackoverflow.com/a/57825758/1387438 - person Marek R; 07.10.2020
comment
Спасибо за ответ. Чтобы улучшить его, я бы рекомендовал удалить первую часть ответа о том, в чем проблема и как установить уровень OSX, потому что я заявил, что без явного набора уровня целевой платформы, ссылка на один из связанных вопросов с 1 Резюме предложения было бы неплохим, чтобы не отвлекать будущих читателей. Что на самом деле считается ответом, так это последний абзац, поскольку вопрос касался обнаружения. Теперь у меня есть следующая проблема: как определить, доступен ли __builtin_available? - person Flamefire; 07.10.2020