The actual code I'm working with is complicated (and something I can't post) so I'm going to use a proxy example.
I have a Visual Studio Solution that contains a handful of projects (GameCore, GameInstaller, GameService):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
AsteroidsSolution
|_GameCore
|_Header
|_File1.h
|_...
|_Source
|_File1.cpp
|_...
|_GameInstaller
|_Header
|_File11.h
|_...
|_Source
|_File11.cpp
|_...
|_GameService
|_Header
|_Logger.h
|_File21.h
|_...
|_Source
|_Logger.cpp
|_File21.cpp
|_...
| |
GameCore and GameInstaller references (#includes) GameService/Logger.h and Source/Logger.cpp. Logger.h defines a basic logging class that logs to files.
GameCore is an application. GameService is a Windows System Service that runs at startup and GameInstaller is a .dll that is invoked by Windows LogonUI at the logon screen. All of this to say - the order in which log calls from any particular .cpp file, from any particular project is not guaranteed.
It's possible that any .cpp file, from any project, can create its own logfile. But assume the complete list of logfiles and where they're written to is known e.g.,
File1.cpp uses the logfile C:\Asteroid\GameCoreLogs\File1.log
File11.cpp uses C:\Asteroid\GameInstallerLogs\File11.log
File21.cpp uses C:\Asteroid\GameServiceLogs\File21.log
(and assume no other log files are created anywhere else)
The Problem
Since we don't know which project code will run first, we can't put the code to create all of the necessary log folders (GameCoreLogs, GameInstallerLogs, GameServiceLogs) in any particular project source file. For example, if we put the logic to create the log folders in GameInstaller, but it so happens that the code for GameService runs first, log function calls made in GameService will generate errors since the GameServiceLogs folder hadn't been created.
My Thoughts
We know that all 3 projects depend on Logger.h and Logger.cpp so perhaps we can use the fact that static variables are initialized before any class object are instantiated to force the creation of those 3 log folders. Something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
[Inside Logger.h]
class Logger
[
static bool logFoldersCreated = CreateAllLogFolders();
static bool CreateAllLogFolders(); // Returns true if successful
// Writes a log message out to the file logfilePath
static void Log(string msg, string functionName, string lineNumber, string logfilePath);
}
[Inside Logger.cpp]
bool Logger::CreateAllLogFolders()
{
// Checks if each folder already exists. If so, return true.
// Creates all log folders, returns true if successful.
}
| |
Even if each project "shares" Logger.cpp instruction code, they each might have their own copy of "logFoldersCreated" in their own virtual address space (i.e., the log folder creation status is not shared among project code). But because "logFoldersCreated" is static, it's guaranteed that any project that runs first will have to check for the creation of all log folders before any of their .cpp file calls Logger::Log. The other project code that runs subsequently, that calls CreateAllLogFolders(), will return true.
One thing that troubles me is whether it's possible for multiple processes to have the same file handle (to C:\Asteroid) in which to create the log folders. I'm assuming the OS will do the job of giving the handle to the first process (project code) but blocking subsequent processes from access to that handle until the first one has released it.
[1] SO: When are static C++ class members initialized?
https://stackoverflow.com/a/1421780