tags:

views:

3211

answers:

4

There are numerous post over the net that detail how relative paths don't work in Xcode. I do have an Xcode template that I downloaded where the relative paths DO work, however I have not been able to figure out why nor replicate it in other projects.

Firstly, I am using C++ in Xcode 3.1. I am not using Objective-C, nor any Cocoa/Carbon frameworks, just pure C++.

Here is the code that works in my other Xcode template:

sound->LoadMusic( (std::string) "Resources/Audio/Pop.wav" );

This relative path works for me also in Windows. Running the following command gives me an absolute path to the application's full path:

std::cout << "Current directory is: " << getcwd( buffer, 1000) << "\n";

/Applications/myApp

How can we get relative paths to work in an Xcode .app bundle?

+8  A: 

Do not depend on the current working directory in binary code. Just don't. You cannot trust the operating system or shell to set it to where you expect it to be set, on Mac, Windows, or Unix.

For straight C, use _NSGetExecutablePath in dyld.h to get the path to your current executable, then you can go relative from there.

If you're just dicking around and want it to work, in Xcode choose Project > Edit Active Executable, and there's a panel there in which you can set the initial working directory to the project directory, the executable's parent directory, or any arbitrary directory. This should only be used for testing purposes. In the Mac OS, when you write a real app and launch it from the Finder, the working directory is /. And for Unix apps you have no control whatsoever over what the working directory is.

cdespinosa
Thanks for your comments cdespinosa, I am trying to access the Resources inside the myApp.app bundle. What you said about editing the active executable works, however as soon as the myApp.app is moved, it no longer works as this is not a relative path, but an absolute one
Brock Woolf
Ultimately I am trying to access resources INSIDE the .app bundle. This IS possible, I have another Xcode project template where relative paths DO work, however there is no code in the template. It works by default. The compiled .app from this template is moveable elsewhere and the paths still work
Brock Woolf
I forgot to mention this before. I am doing chdir((const char*)argv[0]), but it doesn't change the current directory no matter what I do. hmm
Brock Woolf
Better to use Core Foundation than hack around with private APIs (with underscore).
Ivan Vučica
+2  A: 

My guess is the type of app you're building is a one-off executable rather than being an executable app-bundle. On OS X and Unixes in general, resources are loaded from the absolute root of the drive which is different than Visual C++'s treatment of "root" being the path relative to project's root. Don't rely on the path ever being relative to anything in particular across OSes (or OS versions for that matter). You can set a working directory in Xcode but that will only impact applications launched from Xcode. If you were to execute it from the build directory in Finder, it'd once again be set to the root of the drive.

wisequark
+5  A: 

Took me about 5 hours of Google and trying different things to FINALLY find the answer!

#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
// ----------------------------------------------------------------------------

I've thrown some extra include guards because this makes it compile Apple only (I develop cross platform) and makes the code nicer.

I thank the other 2 guys for your answers, your help ultimately got me on the right track to find this answer so i've voted you both up. Thanks guys!!!!

Brock Woolf
You have no idea how much this helps. Thanks for posting it!
AboutRuby
A: 

Just a comment about relative paths and xcode.

I recently noticed that if your app has no files which would be copied into the resources folder the current working directory is set to be that of the actual .app - eg at the level of: myApp.app

However if you add a file to your project and have it copied to the Resources folder of your app bundle it sets the cwd to be 3 levels deep inside the .app. eg at the level of myApp.app/Contents/MacOS/myApp

It seems xcode is trying to be smart for you and assumes if you have no resources in your app bundle then you would want to be loading files a the .app level and not the internal executables level.

This persists even when the app is launched from the Finder. So maybe another reason to avoid relative paths.