File paths appear to be resolved relative to source

I'm doing some asynchronous asset loading for a game, and I'm stumped by what seems completely weird to me. I have a root folder for the project with a makefile, a src/ directory for all the c/c++ source, and an asset/ directory for all the assets that are loaded this way. The executable is built to and run from this root directory. In my understanding, as long as I run from the root directory (where both the executable and "assets/" are), then it should be fine to load a file directly from assets (i.e. load_mesh("assets/obj/model.obj")), but it can't find the files this way. The only way I'm able to load these files are if I do load_mesh("../assets/obj/model.obj)", in other words, I can only load a file from a path relative to the SOURCE file where the loading code is, and not my current working directory. Any ideas?

Yeah, the idea of "current" directory varies depending on how you run the program in the first place.

- Double clicking on the exe in your file explorer
- running from the command line
- Pressing 'run program' in your IDE

$ cat foo.cpp
#include <iostream>
using namespace std;

int main(int argc, char *argv[])
  cout << argv[0] << endl;
 return 0;

$ ( cd cppForum/ ; ../a.out )
$ ./a.out 

First check whether argv[0] is an absolute or relative path.

Sorry, I should have been clearer. I'm running from the command line, and argv[0] is a relative path.
So append the relative path of argv[0] onto the end of what getcwd() returns.
getcwd() returns the expected directory, the root of the project, where the binary and /assets are.
Does load_mesh() do something with the path?
I don't think so, but it does in turn call an asset import library which does the actual opening of the file. So I did a quick test, and did this in main:

FILE *fp = fopen("./assets/audio/sound.ogg", "r");
if (fp == NULL) {
    printf("failed to open file\n");

And this too fails, whereas FILE *fp = fopen("../assets/audio/sound.ogg", "r"); works just fine. I've ever seen this before!
> getcwd() returns the expected directory, the root of the project, where the binary and /assets are.
> And this too fails, whereas FILE *fp = fopen("../assets/audio/sound.ogg", "r"); works just fine.
One of these things doesn't make any sense.

You can't at the same time claim getcwd() is pointing to a directory containing "assets" and then go onto claim you need "../assets" in a relative path just to open a file.

That's exactly what's so weird! The only way the loading works is if I use "../assets", and not "assets/". I'm really at a loss :P There must be something stupid I've overseen. I'll do some more debugging tomorrow and see.
Last edited on
You've gone full circle on this. Have you displayed your current directory? That's the only way you can tell if a relative directory makes sense.
Hehe, I'm really worried there must be some stupid oversight somewhere :) I'm on macOS catalina, and using fish shell, any chance that could be the source of any weirdness?
Last edited on
OK, confusion pt II: I know that getcwd returned the expected directory before, but when I run it now it returns the same directory PLUS "/resources". So the path issue makes sense now. But why does getcwd not report the directory I'm running the program from??

EDIT: In other words, getcwd != pwd

EDIT 2: OK, the reason why getcwd showed something different now than before is probably the order I ran things in. If getcwd is the first thing that happens, it shows the correct directory, and my simple file opening test works. BUT if I do it after creating my OpenGL context (using GLFW), it has changed to the /resources directory...
Last edited on
OK, it turns out it's a macos-specific caveat of "glfwInit()" that I had overlooked.

From their docs:

macOS: This function will change the current directory of the application to the Contents/Resources subdirectory of the application's bundle, if present. This can be disabled with the GLFW_COCOA_CHDIR_RESOURCES init hint.

Thanks for the help!
Topic archived. No new replies allowed.