Reputation: 6408
I am looking for a DRY pattern for managing application configuration in a cross platform C++ application.
Ideally I would like to have a single definitive source of application configuration, to minimise the maintenance burden for the developer. This could be stored as txt,XML,JSON,YAML
This file would serve two purposes...
Firstly it be used to create a configuration file that was accessible to the user.
Secondly, it would determine the default values to be used in the case where a user decided to delete all or part of their configuration file.
Having some sort of pre processor compile the configuration file into the application at compile time. This does not appear to be possible.
Create a tool that reads the configuration file, and generates the necessary code to compile in the defaults into the application. This would work, but is adding complexity to our build process which I would like to avoid.
Create two configuration files, one that is user configurable, the other that contains the defaults, which are hidden. At application startup the default file is read, and then the user file is read, which applies the user settings by overriding the defaults. This is not ideal as it relies on a hidden file to keep the default values safe from the user.
Upvotes: 4
Views: 3148
Reputation: 2244
Config4Cpp provides direct support for what you want to do. For details, read the discussion in Chapter 3 of the Config4* Getting Started Guide about embedded configuration (to hard-code your default values into an application executable) and fallback configuration (essentially, lookup the value of a requested variable from a parsed configuration file and if that doesn't work, then "fallback" to looking up the value in the embedded configuration).
If you want to use this approach with another configuration file syntax (e.g., json or XML) then it boils down to the following steps:
Write a command-line utility similar to config2cpp
(discussed in Chapter 6 of the Config4* Getting Started Guide that turns a configuration file (or, indeed any text file) into a (singleton) C++ class that contains a snapshot of the contents of the configuration file, and can provide access to that snapshot via a public method. You will compile this generated C++ class with the rest of your application, so the application has "default" configuration variables embedded into it.
Use a parser for your favourite configuration file syntax, but make sure the parser can parse either an external file or an embedded configuration file. In other words, you should be able to execute cfg.parseFile("file.cfg")
or cfg.parseString(EmbeddedConfigurationClass::getString())
.
Write your own "wrapper" configuration API class that has two parsed configuration objects as instance variables. One of these variables will be the parsed external configuration file, and the other variable with be the parsed embedded configuration data. Implement the lookup()
method of the wrapper class so it looks for the specified variable first in the parsed external configuration file; if that fails, then the method looks for the specified variable in the embedded configuration data.
That's all there is to it. Config4* gives you the above functionality out-of-the-box but, as I have described in the steps above, it should be easy to emulate similar functionality for whatever is your favourite configuration file syntax.
By the way, if you implement this functionality, then I recommend that you make the external configuration file optional. Doing this will mean that you application will be able to work out-of-the-box without a user needing to first explicitly create a configuration file. In Config4*, I call this zero configuration.
Upvotes: 2