Относительные пути не работают в Xcode C++
В сети есть многочисленные сообщения, в которых подробно рассказывается, как относительные пути не работают в XCode. У меня есть шаблон Xcode, который я скачал, где относительные пути действительно работают, однако я не смог выяснить, почему и не воспроизвести его в других проектах.
Во-первых, я использую C++ в Xcode 3.1. Я не использую Objective-C, ни какие-либо фреймворки Cocoa/Carbon, просто чистый C++.
Вот код, который работает в моем другом шаблоне Xcode:
sound->LoadMusic( (std::string) "Resources/Audio/Pop.wav" );
Этот относительный путь работает для меня также в Windows. Выполнение следующей команды дает мне абсолютный путь к полному пути приложения:
std::cout << "Current directory is: " << getcwd( buffer, 1000) << "\n";
/ Применение / MYAPP
Как мы можем получить относительные пути для работы в пакете Xapp.app?
5 ответов
У меня ушло около 5 часов работы с Google и пробовал разные вещи, чтобы НАКОНЕЦ найти ответ!
#ifdef __APPLE__
#include "CoreFoundation/CoreFoundation.h"
#endif
// ----------------------------------------------------------------------------
// This makes relative paths work in C++ in Xcode by changing directory to the Resources folder inside the .app bundle
#ifdef __APPLE__
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);
char path[PATH_MAX];
if (!CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8 *)path, PATH_MAX))
{
// error!
}
CFRelease(resourcesURL);
chdir(path);
std::cout << "Current Path: " << path << std::endl;
#endif
// ----------------------------------------------------------------------------
Я добавил несколько дополнительных модулей защиты, потому что это позволяет компилировать только Apple (я разрабатываю кроссплатформенность) и делает код приятнее.
Я благодарю двух других парней за ваши ответы, ваша помощь в конечном итоге вывела меня на правильный путь, чтобы найти этот ответ, поэтому я проголосовал за вас обоих. Спасибо, парни!!!!
Не зависит от текущего рабочего каталога в двоичном коде. Просто не надо. Вы не можете доверять операционной системе или оболочке, чтобы установить их там, где вы ожидаете, на Mac, Windows или Unix.
Для прямой C используйте _NSGetExecutablePath в dyld.h, чтобы получить путь к вашему текущему исполняемому файлу, после чего вы можете пойти относительно.
Если вы просто экспериментируете и хотите, чтобы это работало, в Xcode выберите "Проект"> "Редактировать активный исполняемый файл", и там есть панель, в которой вы можете установить начальный рабочий каталог в каталог проекта, родительский каталог исполняемого файла или любой произвольный каталог. Это следует использовать только в целях тестирования. В Mac OS, когда вы пишете реальное приложение и запускаете его из Finder, рабочим каталогом является /. А для приложений Unix вы не имеете никакого контроля над рабочим каталогом.
Я предполагаю, что тип создаваемого вами приложения - это одноразовый исполняемый файл, а не исполняемый пакет приложений. В OS X и Unixes в целом ресурсы загружаются из абсолютного корня диска, который отличается от трактовки Visual C++ "корня" как пути относительно корня проекта. Не полагайтесь на путь, когда-либо относящийся к чему-то конкретному в разных ОС (или версиях ОС в этом отношении). Вы можете установить рабочий каталог в Xcode, но это повлияет только на приложения, запущенные из Xcode. Если бы вы выполняли его из каталога сборки в Finder, он снова был бы установлен в корень диска.
Просто комментарий об относительных путях и xcode.
Недавно я заметил, что если в вашем приложении нет файлов, которые будут скопированы в папку ресурсов, текущим рабочим каталогом будет каталог фактического.app - например, на уровне: myApp.app
Однако, если вы добавляете файл в свой проект и копируете его в папку "Ресурсы" вашего комплекта приложений, он устанавливает 3 уровня глубины в.app. например, на уровне myApp.app/Contents/MacOS/myApp
Кажется, xcode пытается быть умным для вас и предполагает, что если у вас нет ресурсов в вашем комплекте приложений, вы захотите загружать файлы на уровне.app, а не на уровне внутренних исполняемых файлов.
Это сохраняется даже при запуске приложения из Finder. Так что, возможно, еще одна причина, чтобы избежать относительных путей.
Если вы используете SDL, как я,
SDL_GetBasePath()
возвращает каталог ресурсов в OSX.
Вот простая функция-оболочка:
std::string GetLoadFilename( const std::string& filename ) {
std::string path;
auto* base_path = SDL_GetBasePath();
if( base_path == nullptr )
return "./"+filename;
path = std::string(base_path);
path += filename;
SDL_free(base_path);
return path;
}
который можно назвать
sound->LoadMusic(GetLoadFilename("Audio/Pop.wav"));
если вы используете вопрос OP.