When developing a plugin, you might need to adjust constants or switch between algorithms during runtime. While you can hard-code values or use preprocessor macros like #define, these traditional methods make it hard to test variations without recompiling your code.
To make runtime adjustments easier, use the IniConfig class from the nx_kit framework.
NOTE: IniConfig is designed for development, testing, and debugging. Do not use it for production settings aimed at end users. For production configurations, use plugin settings instead. |
Why use IniConfig?
Using IniConfig provides several advantages over hard-coded constants or conditional compilation:
Unconditional compilation: Compiles all code branches so alternate algorithms do not become outdated or broken during refactoring.
Explicit intent: Clearly marks configurable values directly in your source code.
Flexible experimentation: Allows testers and field engineers to change options by updating a
.inifile and restarting the application (or reloading configuration dynamically) without rebuilding the project.
Code example
The following step-by-step example shows how to refactor hard-coded macro definitions to use IniConfig.
1. Traditional approach (hard-coded)
In traditional code, conditional compilation #if defined and hard-coded values make it difficult to test alternative branches dynamically:
# define USE_FAST_DETECTION
const double detectionAccuracy = 0.8;
void executeDetection(Detector* detector)
{
#if defined(USE_FAST_DETECTION)
detector->execute(detectionAccuracy, Mode::fast);
#else
detector->execute(Mode::precise);
#endif
}2. Intermediate approach (struct with defaults)
To avoid conditional compilation, you can consolidate options into a single struct and use standard if statements:
struct Ini
{
const double detectionAccuracy = 0.8;
const bool useFastDetection = true;
};
const Ini ini;
void executeDetection(Detector* detector)
{
if (ini.useFastDetection)
detector->execute(ini.detectionAccuracy, Mode::fast);
else
detector->execute(Mode::precise);
}3. Optimized approach using IniConfig (Recommended)
To make these values configurable via a .ini file, inherit your structure from nx::kit::IniConfig and use the helper macros defined in nx/kit/ini_config.h:
#include <nx/kit/ini_config.h>
struct Ini: nx::kit::IniConfig
{
Ini(): IniConfig("my_module.ini") { reload(); }
NX_INI_FLAG(true, useFastDetection, "Try the fast detection algorithm.");
NX_INI_FLOAT(0.8, detectionAccuracy, "Detection accuracy.");
};
static Ini& ini()
{
static Ini ini;
return ini;
}
void executeDetection(Detector* detector)
{
if (ini().useFastDetection)
detector->execute(ini().detectionAccuracy, Mode::fast);
else
detector->execute(Mode::precise);
}NOTE: If you need to access this configuration across multiple .cpp files, define the struct in a header file (.h) and move the ini() function definition into a source file (.cpp). |
How file resolution works
When ini() is called for the first time, IniConfig handles configuration resolution automatically:
File check:
IniConfigsearches the designated system directory for a.inifile matching the filename passed to the constructor (my_module.iniin the example above).Parsing or generation:
If the file exists:
IniConfigparses the file and sets the option values accordingly.If the file exists but is empty:
IniConfigautomatically fills it with default values and descriptions. This is the recommended way to generate initial configuration files.If the file does not exist:
IniConfigfalls back to the default values defined in your code.
Logging: When a file is loaded or reloaded,
IniConfigoutputs the full file path and active values tostderr.
Directory search locations
The directory where IniConfig looks for .ini files depends on your operating system and execution context:
Windows (Service):
C:\Windows\System32\config\systemprofile\AppData\Local\nx_ini\Windows (User process):
C:\Users\<user>\AppData\Local\nx_ini\Linux (Non-root user):
$HOME/.config/nx_ini/Linux (Root or Service):
/etc/nx_ini/
For Nx Witness Server, you can locate the active directory by running the server and navigating to http://localhost:7001/api/iniConfig/ or sending a GET request to the REST API endpoint:
GET /api/iniConfigModify options in the .ini file
When IniConfig creates a .ini file, all option lines are commented out with # symbols by default.
Here is an example auto-generated file:
# Accuracy for the fast detection algorithm, 0..1. Default: 0.8
#detectionAccuracy=0.8
# Use the fast algorithm instead of the precise one. Default: 0
# useFastDetection=0To modify a parameter value:
Open the
.inifile in a text editor.Uncomment the option line by removing the leading
#.Update the value.
useFastDetection=1Save the file and restart the application (or invoke
ini().reload()in code if applicable).
NOTE: If you update default values or option names in your source code, existing .ini files on disk are not updated automatically. Keep option lines commented out whenever possible so your application continues to pick up updated defaults from source code |
Learn more
For additional details on path selection algorithms and complete header specifications, refer to the Doxygen reference documentation in nx/kit/ini_config.h.
Comments
0 comments
Article is closed for comments.