1

I have a project written in C. Currently it's using UNIX makefiles to compile itself for Linux, but recently I've been looking into CMake, to be more portable.

The executable, when running, needs to access some asset files that are part of the project. When using makefiles, I would just compile the project with:

make prefix=/usr
make prefix=/usr install

So while the project is compiled, it knows that it will end up in /usr, and when running, it searching for its own project files there (in something like /usr/share/my-project/).

I created a very basic CMakeLists.txt, that compiles the .exe file, and installs it together with one other asset file in the install directory. I then run the following commands to create an NSIS installer for Windows:

cmake.exe --build --config Release .
cpack.exe

Which succesfully gives me the NSIS installer. When run, it shows the user a few steps, one of them is to decide where the project will be installed, which the user can modify.

So my question is, at that point the project has already been compiled, so how can I pass to my project its own install location, so it can access files included in the project? How do other projects do this? I couldn't find much information online about it, which makes me think I might be taking the wrong approach.

2
  • Just get the path of the exe and search relative to that path for additional files installed? Btw: using cmake to trigger the installation should work for both systems: cmake --install <path to binary dir> --prefix <install path>
    – fabian
    Commented Jan 18, 2022 at 18:47
  • @fabian if I understand this correctly, I could use the command you specified to install the project manually, but I would ideally like to generate an installer, so that users that are less technical could install the project without much hassle. Commented Jan 18, 2022 at 20:29

1 Answer 1

1

For anyone stuck in a similar problem, I found one solution.

Upon looking online, this seems to be something not recommended for Unix systems, and setting the install location during compilation is pretty standard.

For windows, however, I found the function GetModuleFileNameW (GetModuleFileNameW function (libloaderapi.h)).

It returns the path to the current executable (something like C:\Program Files\<my-app>\bin\my-app.exe). I've confirmed it returns the right path, even when I install the project on different directories. It returns the result using wchar_t, so unicode directories are also supported.

Here is a small example of how it can be used:

// to keep the example simple, this is assuming maximum 1000 characters in the path
wchar_t dynamicProjectLocationW[1000];
GetModuleFileNameW(NULL, dynamicProjectLocationW, 999);
dynamicProjectLocationW[999] = L'\0';

// given a path like "C:\X\Y\bin\myapp.exe" find the second to last slash
// so we can get the path "C:\X\Y\"
wchar_t *pointer = dynamicProjectLocationW;
wchar_t *secondToLastSlash = 0;
wchar_t *lastSlash = 0;
while (pointer[0] != L'\0') {
    if (pointer[0] == L'\\') {
        secondToLastSlash = lastSlash;
        lastSlash = pointer;
    }
    pointer++;
}

// cut the path short, so we can use the project path to find other files
if (secondToLastSlash) {
    secondToLastSlash++;
    secondToLastSlash[0] = L'\0';
}

This is solving my problem for now, so I'll be using this until a better solution is found.

Not the answer you're looking for? Browse other questions tagged or ask your own question.