Relative Paths do not work in Xcode using C

Discussion in 'Mac Programming' started by RedBull27, May 13, 2008.

  1. RedBull27 macrumors newbie

    Joined:
    May 13, 2008
    #1
    Hi,

    I have written code using Visual Studio 6 under XP and i'm trying to port the code to Mac OS X under Xcode. I've narrowed my problem down to the fact that the compiled application under Xcode appears to convert my relative paths to absolute paths, which strangely enough default to the home folder.
    :mad:

    Code:
    char fileCarpetBlue128[40] = "CarpetTexture-128.raw";
    The above code under Windows will load the texture as long as it is in the same directory as the .exe file.

    However under Mac OS X 10.5 with Xcode 3.0, it will try to load the folder from the home directory. eg: ~/CarpetTexture-128.raw

    I discovered this was happening by using this:
    Code:
    printf("cwd is: %s\n", getcwd(NULL, 0));
    Can someone please tell me how to force the path to be relative to the application under OS X.
     
  2. gnasher729 macrumors P6

    gnasher729

    Joined:
    Nov 25, 2005
    #2
    Go to developer.apple.com. Type "bundle" into the search field. The first link is most likely "Bundle Programming Guide: Introduction to Bundle Programming Guide". Click on the link.

    This lets you find resources relative to the application bundle, automatically finding the right resource depending on the user's language when needed.
     
  3. RedBull27 thread starter macrumors newbie

    Joined:
    May 13, 2008
    #3
    I did that. I can and do not want to use bundles for what should be a simple problem. I don't need to do localization and I am using C. From what I could see bundles are Objective-C specific and the code I am writing needs to be cross-platform.

    This is for a university project. Maybe I should just stick with Visual Studio and Windows. It seems to be much more straight forward in this regard.
     
  4. yeroen macrumors 6502a

    yeroen

    Joined:
    Mar 8, 2007
    Location:
    Cambridge, MA
    #4
    This has nothing to do with Xcode, but rather the POSIX specification. When you call getcwd(), it's returning the path that the executable file was run from. So if you're in your home directory, getcwd() will return the path of your home directory. If you 'cd' to the /etc directory (leaving your executable where it is) and run your program again, getcwd() will return '/etc'.

    If you want to set the working directory relative to the executable path, the trick is to use argv[0], which is always the path of the executable.

    chdir( argv[0] );


    For example, try compiling and running this simple program:

    Code:
    /* 
     * path.c
     */
    #include <stdio.h>
    #include <unistd.h>
    
    int main (int argc, char **argv)
    {
      printf("%s\n", getcwd(NULL, 0));
      printf("%s\n", chdir(argv[0]));
      printf("%s\n", getcwd(NULL, 0));
    }
    
    Far from being straightforward, Windows' POSIX non-conformance makes it the odd-man out in this regard.
     
  5. gnasher729 macrumors P6

    gnasher729

    Joined:
    Nov 25, 2005
    #5
    Only if argc > 0, which is not guaranteed, depending on how the application is started. If argc == 0, then argv[0] is not defined.
     
  6. yeroen macrumors 6502a

    yeroen

    Joined:
    Mar 8, 2007
    Location:
    Cambridge, MA
    #6
    argc is always greater than or equal to one, since argv[0], being implicit, is always there. If it wasn't, you'd have no program running in the first place.
     
  7. Krevnik macrumors 68030

    Krevnik

    Joined:
    Sep 8, 2003
    #7
    If this is a GUI app on OS X, it will be in a bundle, C or not. Carbon just has a different mechanism for getting at the bundle path (CFBundle APIs).

    In the case of OS X, it is assumed that all your resources (images, strings, etc) are in the bundle rather than floating about the file system. The intent is that if someone wants to drag your app around to a new location, copy it to a different machine, it will just work.

    If you are in the command-line environment, you need to approach development on the Mac like BSD/Linux/POSIX, rather than Windows, as commented earlier.

    Will the individuals running this be on Windows-only? Then it might be. Cross-platform apps are never as simple as they first appear, especially when you are first delving into cross-platform development. There are a lot of gotchas like these floating around that you need to consider when writing for more than one platform.
     
  8. RedBull27 thread starter macrumors newbie

    Joined:
    May 13, 2008
    #8
    Thank you Yeroen,

    What you've said makes the most sense to me although I would like to thank everyone else for your responses.
    Okay so I get it that Windows is non-standard (no surprises there :) ) however I did try what you said.

    I did:
    Code:
      printf("%s\n", getcwd(NULL, 0));
      printf("%s\n", chdir(argv[0]));
      printf("%s\n", getcwd(NULL, 0));
    From a different file (im not running the code inside the main file)
    and it said it could not find argv[0]. It was 'undefined'.

    So I guess the scope of argv and argc is inside main only. Is there another way I could access argv[0] outside of main,
    besides copying its string into a global variable? Thanks


     
  9. Nutter macrumors 6502

    Joined:
    Mar 31, 2005
    Location:
    London, England
    #9
    Yes, the scope of any function argument in C is limited to within the function itself. By all means, copy it to a global variable in main().

    You can also use ProcessInformationCopyDictionary() to get at this information.
     
  10. yeroen macrumors 6502a

    yeroen

    Joined:
    Mar 8, 2007
    Location:
    Cambridge, MA
    #10
    Well, you don't have to put the pathname into a global variable, although there is nothing wrong (however unfashionable) with declaring such a variable, assign to it the contents of argv[0] in main(), and declaring it as an 'extern' variable in your other files which reference it.

    But unless your code is calling chdir() multiple times, declaring a global variable to set the relative path is unecessary. It is sufficient to call chdir() once in main() and be done with it for the duration of your program.

    One thing you will have to do, which I forgot to mention before, is to strip off the executable name from argv[0], i.e. everything to the right of the last "/", so you get the directory it's in rather than the executable itself.
     
  11. lazydog macrumors 6502a

    Joined:
    Sep 3, 2005
    Location:
    Cramlington, UK
    #11
    I know I'm being pedantic but argc is not guaranteed to be > 0. For example, execl( argv[ 0 ], 0L ) will run a copy of itself but without any arguments.

    b e n
     

Share This Page