12.3. Linker Plugin API Usage and Reference
12.3.1. Linker Wrapper
Plugins interacts with the linker using LinkerWrapper.
12.3.2. Plugin Abstract Data Types
12.3.2.1. Chunk
12.3.2.2. LinkerScriptRule
12.3.2.3. OutputSection
12.3.2.4. Section
12.3.2.5. Use
12.3.2.6. Symbol
12.3.2.7. INIFile
12.3.2.8. InputFile
12.3.2.9. PluginData
12.3.2.10. AutoTimer
12.3.2.11. Timer
12.3.2.12. RelocationHandler
12.3.3. LinkerPluginConfig
12.3.5. Plugin Diagnostic Framework
Plugin diagnostic framework provides a uniform and consistent solution for reporting diagnostics from plugins. It is recommended to avoid custom solutions for printing diagnostics from a plugin.
First, let’s go over some of the key benefits of using the Plugin Diagnostic Framework. After that, we’ll see how to effectively use the framework.
The framework allows for creating and reporting diagnositcs on the fly. Diagnostics can be reported with different severities such as Note, Warning, Error and more. Each severity has a unique color, and diagnostics are prefixed with “PluginName:DiagnosticSeverity”.
The linker keeps track of diagnostics emitted from the diagnostic framework.
This is required to maintain extensive logs for diagnostic purposes.
The framework also adjusts diagnostic behavior based on linker command-line
options that affect diagnostics. For example, if the --fatal-warnings
option is enabled, then warnings will be converted to fatal errors. If
the -Werror option is used, warnings are promoted to regular errors
instead of fatals.
The framework is thread-safe. Thus, diagnostics can be reported safely from
multiple threads simultaneously. This is crucial in situations where
thread-safety is neessary. In such cases, C++ std::cout and
std::cerr output streams cannot be used, as they are not thread-safe.
That’s enough about the theories. Now, let’s take a look at how to use the Plugin Diagnostic Framework.
The linker assigns a unique ID to each diagnostic template. A diagnostic template has a diagnostic severity and a diagnostic format string. Diagnostic template unique IDs are necessary for creating and reporting diagnostics. The code below demonstrates how to obtain a diagnostic ID for a diagnostic template.
// There are similar functions for other diagnostic severities.
// Linker is a LinkerWrapper object.
DiagnosticEntry::DiagIDType errorID = Linker->getErrorDiagID("Error diagnostic with two args: %0 and %1");
DiagnosticEntry::DiagIDType warnID = Linker->getWarningDiagID("Warning diagnostic with one arg: %0");
%0, %1 and so on in diagnostic format string are replaced by
diagnostic arguments. Diagnostic arguments must be provided when reporting a
diagnostic.
The below code demonstrates how to report a diagnostic using a diagnostic ID.
// arguments can be of any type. 'LinkerWrapper::reportDiag' is a
// variadic template function.
Linker->reportDiag(errorID, arg1, arg2);
Linker->reportDiag(warnID, arg1);
12.3.5.1. DiagnosticEntry
DiagnosticEntry packs complete diagnostic information, and can
be used to pass diagnostics from one location to another. Many plugin
framework APIs use DiagnosticEntry to return errors to the caller,
where they can be properly handled.
// diag represents a complete diagnostic.
// diagID encodes diagnostic severity and diagnostic format string.
DiagnosticEntry diag(diagID, {arg1, arg2, ...});
12.3.5.2. eld::Expected<ReturnType>
Many plugin framework APIs return values of type eld::Expected<ReturnType>.
At any given time, eld::Expected<ReturnType> holds either an
expected value of type ReturnType or an unexpected value of type
std::unique_ptr<eld::plugin::DiagnosticEntry>. Returning the error to the
caller allows plugin authors to decide how to best handle a particular error
for their use case. A typical usage pattern for this is.
eld::Expected<eld::plugin::INIFile> readFile = Linker->readINIFile(configPath);
if (!readFile) {
if (readFile.error()->diagID() == eld::plugin::Diagnostic::errr_file_does_not_exit) {
// handle this particular error
// ...
} else {
// Or, simply report the error and return.
Linker->reportDiagEntry(std::move(readFile.error()));
return;
}
}
eld::plugin::INIFile file = std::move(readFile.value());
12.3.5.3. Overriding Diagnostic Severity
Diagnostic severity can be overriden by using DiagnosticEntry
subclasses. DiagnosticEntry has subclasses for each diagnostic
severity level. Let’s explore how to use them to override diagnostic severity.
eld::Expected<eld::plugin::INIFile> readFile = Linker->readINIFile(configPath);
eld::plugin::INIFile file;
if (readFile)
file = std::move(readFile.value());
else {
// Let's report the error as a Note, and move on by using a default INI file.
eld::plugin::NoteDiagnositcEntry noteDiag(readFile.error()->diagID(), readFile.error()->args());
Linker->reportDiagEntry(noteDiag);
file = DefaultINIFile();
}