Sign in to follow this  

Relative File Names (how to call them from anywhere?)

This topic is 4301 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

A classic problem i'm sure. ISSUE #1: I'm have my program located here: c:/foo/bar/SomeProgram.exe SomeProgram.exe contains code that look something like this: . . . resource = LoadResource("dir/some_file.bla"); // relative file name . . . So if we run SomeProgram.exe from the command line in the directory it resides in, the program will find some_file, like so: (change directory to the program directory) cd c:/foo/bar/ (run app) ./SomeProgram.exe (app finds file at ...) c:/foo/bar/dir/some_file.bla Hey, works great. Until i try to run the app from somewhere else. I change my working directory to some arbitrary directory *or* click an icon from the desktop, my app can't find it's dependent files. How do i get an app to find files it needs in a specific location without knowing where it's installed? How do other programmer solve this? Bonus question: will the same strategy work on windows and unix? ISSUE #2: (Related problem) I have a library @ /some/dir/libSomeLib I run a program that uses the library, located @ /foo/bar/SomeProgram.exe When i run the program, it would seem that relative file names in libSomeLib now base off of /foo/bar (the app's directory) and not /some/dir (the lib's directory)! How do i get libSomeLib to "stay in it's own directory"? (ps - i wrote the app and the lib both) Thanks for your help. I'm sure this is an easy question. It's just one i never got around to answering. Thanks!

Share this post


Link to post
Share on other sites
What programming language are you using? What operating system?

In windows, you can use the GetModuleName API function to retrieve the full path and file name of an executable or dll. You'll have to split it apart yourself and append the relative path, though. If you just want to tack on the current directory, you can use GetFullPathName

Share this post


Link to post
Share on other sites
For issue #1, you shouldn't write your program to try and find the resources it needs if they've been purposely moved elsewhere by the user; your program should just assume the resources will be in the same directory, because otherwise it's the user's fault for moving things around. Plus, to account for such a thing would require you to write some search algorithm that scanned the users entire system, which even then you're not guaranteed to find the resource.

For issue #2... not sure why you're getting that problem....

Share this post


Link to post
Share on other sites
There are methods for determining in which directory the currently loaded module is executed; for Windows, such method is GetModuleFileName (I don't remember the equivalent for Unix). To get the path from the full path + filename string, just split the string before it's last "\" (again, in Windows) or "/" (in Unix).

You shouldn't rely on "cd" in multi-process environments, as any other app or even your own file accesses can change the current directory without you getting any warning.

EDIT: Too late [grin]

Share this post


Link to post
Share on other sites
I'm using C++

I need it on both linux and windows. Mostly linux at the moment, but i intend to release my project on windows as well. I'm developing on linux.

I'm assuming i have to call some kind of system call like WhereAmI() and parse the string, correct?

EDIT: jeez you guys are fast! you just stay up late at night waiting to pounce on new threads don't you? :-)

Share this post


Link to post
Share on other sites
Quote:
Original post by Nik02You shouldn't rely on "cd" in multi-process environments, as any other app or even your own file accesses can change the current directory without you getting any warning.


That was just an example. That isn't code the app runs. That's me running the app from the command line.

Share this post


Link to post
Share on other sites
Quote:
Original post by leiavoia
Quote:
Original post by Nik02You shouldn't rely on "cd" in multi-process environments, as any other app or even your own file accesses can change the current directory without you getting any warning.


That was just an example. That isn't code the app runs. That's me running the app from the command line.


Yes, but it doesn't matter if you change it manually or programmatically. In either case, some other process can change it again even before you run your program in the next command.

Share this post


Link to post
Share on other sites
Maybe i'm not wording this correctly. The above example is me in a console / DOS prompt changing to the correct directory and then executing the program. It has nothing to do with code.

$ cd /some/dir
$ ./some_app.exe
(program runs)

Because that's usually how i "start" my programs. I don't click on a link or icon or something because then it doesn't work right.

Did i explain it better?

Share this post


Link to post
Share on other sites
It would appear that full pathnames are basically the way to go on unix systems:

Quote:
from http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC23
The most common reason people ask this question is in order to locate configuration files with their program. This is considered to be bad form; directories containing executables should contain nothing except executables, and administrative requirements often make it desirable for configuration files to be located on different filesystems to executables.


That's good for unix, but most windows games i played in years past usually come in one big lump with no installation (especially freebie games that you just unzip and run).

Would you agree? What should my approach on a windows system be? I prefer the "one big lump" technique, but that's just me with my unenlightened viewpoint.

Share this post


Link to post
Share on other sites
Yes, if you plan to really distribute your app on linux, then installation will not place your binary together with your data and configuration files.

Plan on it from the beginning, it can be a mess with all sorts of filenames embedded in .cpp files. If you package as a .rpm or .deb then your program probably ends up in /usr/bin, while if you have a tar.gz then it probably ends in /usr/local/bin. Make a hidden directory or file to store user-specific configuration files in the users home directory.

Share this post


Link to post
Share on other sites
Quote:
Original post by leiavoia
That's good for unix, but most windows games i played in years past usually come in one big lump with no installation (especially freebie games that you just unzip and run).


Lei,

As far as Windows games are concerned (commercial ones at least), the 'big lump' approach is beginning to more or less disappear these days. It seems a common practice now that the games will install themselves and the basic data into some directory of the user's choosing (usually C:\Program Files\ by default), but will put the user-specific data, like user preferences, saved games, and mods somewhere in the user's home directory (usually the My Documents folder). That way the user sort of sees the separation between the files he can mess without breaking the game, and those that should probably not be touched unless the user knows what he's doing.

But of course, for smaller games, especially ones that don't require installation, probably just one big lump is the best approach. Although, this needs a qualifier. It's probably still a good idea to organize your big lump. ;) Don't just stick all the files in the same directory as the executable, but, ya know, make like a "data" folder, or like a "models" folder, and what-not. It's probably obvious.

Also, regarding the shortcuts, you may have figured it out by now, but basically, whenever you open up a shortcut, your working directory will be the one where the shortcut is located, so it's the same as if you just opened up the prompt in that directory and ran the program from there without the whole cd bit.

So... I hope I helped clarify some things, instead of confusing them further. :)

Share this post


Link to post
Share on other sites
On linux though, it doesn't seem to work like that (much of the time). Usually if i click a shortcut or something to my own program, it won't find its (relative file name) resources. Thus bringing up the whole topic.

Share this post


Link to post
Share on other sites
Quote:
Original post by leiavoia
Usually if i click a shortcut or something to my own program, it won't find its (relative file name) resources.


Right, what I meant was that's more or less the way it works in Windows, too.

Also, I just had the following simple idea, which I think might work well, though I haven't thought about it too much yet, so it might have drawbacks I haven't considered. At the start of the program, take the first item in the argv's, and use everything before the last slash as a prefix for paths in all your file opening functions.

That should work, because whichever directory you are executing your binary from, that will be the base directory for all the relative paths you use. Since everything before the name of the bin will be the path to the bin, by prefixing it to all your hard-coded paths (or relative paths you get from a config file or what-not), you'll basically turn every path into one relative to the location of the bin (if that's what you want to do). So then you would be able to locate your resources wherever you run the executable from, and you wouldn't need to use any platform-specific WhereAmI functions. (Since file manipulation functions don't mind constructs like /path/to/bin/../data, you won't even need to do much parsing to handle that special case.)

Share this post


Link to post
Share on other sites
http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC23
Quote:
1.14 How can I find a process' executable file?

This would be a good candidate for a list of `Frequently Unanswered Questions', because the fact of asking the question usually means that the design of the program is flawed. :-)

You can make a `best guess' by looking at the value of argv[0]. If this contains a `/', then it is probably the absolute or relative (to the current directory at program start) path of the executable. If it does not, then you can mimic the shell's search of the PATH variable, looking for the program. However, success is not guaranteed, since it is possible to invoke programs with arbitrary values of argv[0], and in any case the executable may have been renamed or deleted since it was started.

If all you want is to be able to print an appropriate invocation name with error messages, then the best approach is to have main() save the value of argv[0] in a global variable for use by the entire program. While there is no guarantee whatsoever that the value in argv[0] will be meaningful, it is the best option available in most circumstances.

The most common reason people ask this question is in order to locate configuration files with their program. This is considered to be bad form; directories containing executables should contain nothing except executables, and administrative requirements often make it desirable for configuration files to be located on different filesystems to executables.

A less common, but more legitimate, reason to do this is to allow the program to call exec() on itself; this is a method used (e.g. by some versions of sendmail) to completely reinitialise the process (e.g. if a daemon receives a SIGHUP).

1.14.1 So where do I put my configuration files then?

The correct directory for this usually depends on the particular flavour of Unix you're using; `/var/opt/PACKAGE', `/usr/local/lib', `/usr/local/etc', or any of several other possibilities. User-specific configuration files are usually hidden `dotfiles' under $HOME (e.g. `$HOME/.exrc').

From the point of view of a package that is expected to be usable across a range of systems, this usually implies that the location of any sitewide configuration files will be a compiled-in default, possibly using a `--prefix' option on a configure script (Autoconf scripts do this). You might wish to allow this to be overridden at runtime by an environment variable. (If you're not using a configure script, then put the default in the Makefile as a `-D' option on compiles, or put it in a `config.h' header file, or something similar.)

User-specific configuration should be either a single dotfile under $HOME, or, if you need multiple files, a dot-subdirectory. (Files or directories whose names start with a dot are omitted from directory listings by default.) Avoid creating multiple entries under $HOME, because this can get very cluttered. Again, you can allow the user to override this location with an environment variable. Programs should always behave sensibly if they fail to find any per-user configuration.

Share this post


Link to post
Share on other sites

This topic is 4301 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this