Reputation: 1494
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.
Upvotes: 1
Views: 627
Reputation: 1494
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.
Upvotes: 1