0

I use this project hierarchy:

- root:
  - Module1
  - Module2
  - Module3
  - main.cpp

main.cpp uses the class instance from module which contains members from Module2 & Module3. In the last module, there is a function for reading files. So, if I use relative paths, I face an issue about the wrong end path because relative paths work relatively by the folder where I launched my executable file instead of relative paths by the folder where the executable file is.

Then I created a small function for getting the root path:

static std::string rootFolder{""};
int main(int argc, char *argv[])
{
  char buffer[MAX_PATH];
  GetModuleFileNameA(NULL, buffer, MAX_PATH);
  std::string::size_type pos = std::string(buffer).find_last_of("\\/");
  rootFolder = std::string(buffer).substr(0, pos) + "/../";
  return EXIT_SUCCESS;
}

P.S.: So far I have added implementation for Windows only.

In the main function, it works. But I need to transfer rootFolder to a class in Module3 and then I added a file with globals - globals.hpp (I didn't add a cpp implementation because I think a code less than 20 lines I can store in a header).

#ifndef APP_GLOBALS
#define APP_GLOBALS
#include <string>
#include <Windows.h>
#include <string>

static std::string rootFolder{""};

inline void initGlobals()
{
    char buffer[MAX_PATH];
    GetModuleFileNameA(NULL, buffer, MAX_PATH);
    std::string::size_type pos = std::string(buffer).find_last_of("\\/");
    rootFolder = std::string(buffer).substr(0, pos) + "/../";
}
#endif

And in the main function and Module3 source file, I added the following lines:

#include "globals.hpp"

main func:

/// Other code here
int main(int argc, char *argv[])
{
  initGlobals();
  /// Other code here
}

But when I tried to compile the app, I got an error:

cmd.exe /C "cd . && C:\PROGRA~1\mingw64\bin\G__~1.EXE -g  CMakeFiles/VulkanTriangle.dir/src/app.cpp.obj CMakeFiles/VulkanTriangle.dir/src/main.cpp.obj CMakeFiles/VulkanTriangle.dir/src/pipeline.cpp.obj CMakeFiles/VulkanTriangle.dir/src/core/window.cpp.obj -o ..\bin\VulkanTriangle.exe -Wl,--out-implib,libVulkanTriangle.dll.a -Wl,--major-image-version,0,--minor-image-version,0 -LD:/Documents/programming/vulkanTriangle/lib -lglfw3  -lvulkan-1  -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 && cd ."
CMakeFiles/VulkanTriangle.dir/src/pipeline.cpp.obj:D:/Documents/programming/vulkanTriangle/src/globals.hpp:10: multiple definition of `initGlobals()'
CMakeFiles/VulkanTriangle.dir/src/main.cpp.obj:D:/Documents/programming/vulkanTriangle/src/globals.hpp:10: first defined here
collect2.exe: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.

So, then I started to google about the multiple definition error and I found another question from stackoverflow.

Question 1:

As it was written in one of the answers, I added the inline keyword before initGlobals function. And yes! It worked. But can't understand why. Can you explain? As I understand HEADER GUARD logic, it works like this:

#ifndef MY_SUPER_UNIQUE_HEADER // Ok, it was defined. Then pass the code below.
#define THAT_HEADER
#endif

Question 2:

So, if get the multiple definition error, it seems I don't understand a header loading logic. Can you explain it?

And perhaps I have a main question:

Is there any better solution to init and transfer rootFolder variable to Module3. Sorry for the TLDR :)

Wusiki Jeronii
  • 159
  • 1
  • 8
  • Why you do not use CMAKE? You can create constants for relative paths to create header file with constants. See `configure_file()` in [link](https://cmake.org/cmake/help/latest/command/configure_file.html) CMAKE doc. – Buddy Sep 20 '22 at 17:17
  • @Buddy I use cmake and ninja for building. It's a question about workspacefolder in source code (for process a function argument, for example). Cmake is uses for compiling, linking, launching external scripts, e.t.c – Wusiki Jeronii Sep 20 '22 at 17:23
  • `static std::string rootFolder{""};` is not a global variable. Every source file that includes the header gets its own copy of that variable; that's what `static` means. – Igor Tandetnik Sep 20 '22 at 17:24
  • Header files protect against including the header more than once into the same source file. They don't help with putting the same definition into multiple source files. – Igor Tandetnik Sep 20 '22 at 17:26
  • @IgorTandetnik about static are you sure? I thought static variables have to do opposite effect. For example in class. You declare one variable for all instance by the class. I also checked. If I remove static keyword the error is changes to `multiple definition of `rootFolder[abi:cxx11]'` – Wusiki Jeronii Sep 20 '22 at 17:30
  • @IgorTandetnik About header - thanks and now I understand whu inline functions works in my case and why I get errors in headers – Wusiki Jeronii Sep 20 '22 at 17:31
  • I meant "Header **guards** protect against including the header more than once...". Not "header files...". – Igor Tandetnik Sep 20 '22 at 17:32
  • `static` is heavily overloaded, used for [several different unrelated things](https://en.cppreference.com/w/cpp/keyword/static). Here you use it in the "declarations of namespace members with static storage duration and internal linkage" sense, not in the "declarations of class members not bound to specific instances" sense. Anyway, I expect that, even though you call `initGlobals()` in `main.cpp`, you will find that `rootFolder` is still an empty string when accessed from `Module3` (or any source file other than `main.cpp`) – Igor Tandetnik Sep 20 '22 at 17:36
  • You're right. Empty string. So, what am I to do? How to initialise a variable and share it? Use atomic? – Wusiki Jeronii Sep 20 '22 at 17:41
  • [How to declare a global variable in C++](https://stackoverflow.com/q/9702053) – Igor Tandetnik Sep 20 '22 at 19:02
  • I have already seen that. I get the error: `undefined reference to `rootFolder[abi:cxx11]'` . I understand why 'cos initialising variable exists only in `initGlobals` function. I also can't init value by returnn result 'cos process of defining executable work in runtime mode. I added a implementation file and yes - it worked. I get right value from `rootFolder`. But I wonder is it only one possible solution. Because then I must to store a separate file really with 2 code lines – Wusiki Jeronii Sep 20 '22 at 19:14

0 Answers0