1

I'm modifying a large codebase written in C. This code is designed to be compiled and ran from an arbitrary working directory. This is so configuration files can be read and output written to/from the working directory, making it easier to organize the setup and outputs of the code.

The additions I've made to this code need to read data from a few data files. I would like to place these in the same directory as the .c file where they are read, with a directory structure as follows:

big_project/
|-- models/
|   |-- my_file.c
|   |-- my_data.txt

My problem comes in when trying to open this data file using relative paths. Typically relative paths are relative to the working directory, which would not work in my case since the working directory can be arbitrary. From inside my_file.c, how can I open my_data.txt for reading using relative paths?

  • 2
    Did you look at this (i.e. `__FILE__` macro) before posting? https://stackoverflow.com/questions/8487986/file-macro-shows-full-path – code_dredd Apr 03 '19 at 21:27
  • Yes I did, although not that specific question. I have the opposite problem as that question when using `__FILE__`, as it only gives me the filename and not the full path. – Gillen Brown Apr 03 '19 at 21:32
  • 3
    As soon as anyone else has to use your program, that’s no longer appropriate. Locating config files or configuration information is a black art. Unix classically used an environment variable; Windows classically used the registry. Both have positive points and negative ones. But requiring users to have the source on their machine is usually not considered a good idea. – Jonathan Leffler Apr 03 '19 at 21:34
  • @JonathanLeffler The code in my case is a scientific simulation code I've inherited. Only a handful of folks use it, and they will most likely be modifying it themselves. While it may not be best practice it works well for our purposes. – Gillen Brown Apr 03 '19 at 21:42
  • @GillenBrown You may be better off creating a pre-determined location where config files and other program resources can be found, independent of the program's installation location. In GNU+Linux, it could be `/etc//[...]`. In Windows, it could be the location stored in the `%APPDATA%` env variable. Have you considered this? If so, why not go down this road instead? – code_dredd Apr 03 '19 at 21:48
  • @code_dredd The reason we have it set up this way is that having multiple configuration setups is essential to how we use the code. It's compiled and run multiple times with various sets of configuration files, which set various parameters used in the simulation. Having the configuration files in the same directory as the outputs is helpful for understanding how the outputs change with the parameters. – Gillen Brown Apr 03 '19 at 21:57
  • 1
    @GillenBrown There's nothing wrong with having multiple config files in the same `/etc/[...]` location. You could have the program use a default config when nothing else is specified or a config file passed in as an argument (e.g. `./your-program --config `). Also, did you try the [`GetFullPathName` function in Window or the `realpath` function in GNU+Linux](https://stackoverflow.com/questions/229012/getting-absolute-path-of-a-file)? – code_dredd Apr 03 '19 at 22:11
  • BTW, it'd be helpful if you specify the platform and compiler you're using (i.e. versions, etc). – code_dredd Apr 03 '19 at 22:12
  • 1
    Also, ***if you're completely sure*** about the program ***always*** being placed in the same directory ***for everyone***, then you can set the absolute path shown by the `__FILE__` macro if you send the full path when compiling; e.g. `gcc $(pwd)/your-file.c`, when it prints `__FILE__` will show the full path it had ***at compile time***, not run-time. Did you consider this? (Can't add enough disclaimers here, though.) – code_dredd Apr 03 '19 at 22:14
  • @code_dredd Ah, thanks for the tip to add send the full path when compiling. I think that solution actually will work. As long as the user doesn't move the source code after compiling it should work, no? It seems to work in my testing. – Gillen Brown Apr 05 '19 at 17:48
  • @GillenBrown I've added a more elaborate version of my previous comments as an answer. Please take a look at it and let me know if it was useful or if something's not entirely clear and can be improved. – code_dredd Apr 05 '19 at 18:12
  • 1
    @code_dredd Yes, that is very helpful. Thanks so much! – Gillen Brown Apr 05 '19 at 18:54

1 Answers1

2

Based on our conversation in the comments, you have several alternatives, which I'll list below from, IMHO, most to least desirable.

You never specified if you were in Windows, GNU+Linux, or were doing cross-platform development, but I'm sure you can adapt the suggestions to your platform.

Multiple and Custom Config Files (Recommended)

You could modify your program to look at your platform's standard location for program data and/or configuration files. For example, you could have it look for a standard config at /etc/<your-program>/default.conf in GNU+Linux or %APPDATA%\<your-program>\default.conf in Windows.

If different users need to use their own personal configs, the program could also be made to accept a config file path as an argument. For example:

GNU+Linux:

$ ./your-program --config ${HOME}/.your-program/my.conf

Windows:

> your-program.exe --config %userprofile%\your-program\my.conf

Note that the use of %userprofile% may change based on Windows versions and/or shells used (e.g. standard cmd.exe vs powershell).

Compiling in the Path (Not Recommended)

Based on your comments, a short-term workaround could be to compile the absolute path into it for the __FILE__ macro to give that back to you at runtime. As I said in my comment:

if you're completely sure about the program always being placed in the same directory for everyone, then you can set the absolute path shown by the __FILE__ macro if you send the full path when compiling; e.g. gcc $(pwd)/your-file.c, when it prints __FILE__ will show the full path it had at compile time, not run-time. (Can't add enough disclaimers here, though)

Please note that there're many reasons to not use this approach. I'm simply suggesting it as a short-term workaround to pull out of an existing crisis-level situation you may have, while you (hopefully) take a closer look at the more desirable approach to handle configurations and path-finding.

code_dredd
  • 5,915
  • 1
  • 25
  • 53