Относительные пути не работают в 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.

Другие вопросы по тегам