{: .no_toc }
{: .no_toc .text-delta }
This page documents the ICU4C DLL Plug-in capability. This feature is a Technology Preview which first appeared in ICU4C version 4.3.4. It may be altered or removed in subsequent releases, and feedback is appreciated.
As per ticket ICU-11763, the plugin mechanism discussed here is disabled by default as of ICU 56. Use --enable-plugins and/or define UCONFIG_ENABLE_PLUGINS=1 to enable the mechanism.
ICU4C has functionality for registering services, setting mutex/allocation handlers, etc. But they must be installed ‘before any ICU services are used’ The ICU plugin mechanism allows small code modules, called plugins, to be loaded automatically when ICU starts.
At u_init time, ICU will read from a list of DLLs and entrypoints, and attempt to load plugins found in the list. plugins are called and can perform any ICU related function, such as registering or unregistering service objects. At u_cleanup time, plugins have the opportunity to uninstall themselves before they are removed from memory and unloaded.
The current plugin API is documented as icuplug.h Some sample plugins are available at: testplug.c Here is a simple, trivial plugin:
U_CAPI UPlugTokenReturn U_EXPORT2 myPlugin (UPlugData *data, UPlugReason reason, UErrorCode *status) { if(reason==UPLUG_REASON_QUERY) { uplug_setPlugName(data, "Simple Plugin"); /* optional */ uplug_setPlugLevel(data, UPLUG_LEVEL_HIGH); /* Mandatory */ } else if(reason==UPLUG_REASON_LOAD) { /* ... load ... */ /* Set up some ICU things here. */ } else if(reason==UPLUG_REASON_UNLOAD) { /* ... unload ... */ } return UPLUG_TOKEN; /* Mandatory. */ }
The UPlugData*
is an opaque pointer to the plugin-specific data, and is used in all other API calls.
The API contract is:
the plugin MUST always return UPLUG_TOKEN as a return value- to indicate that it is a valid plugin.
when the ‘reason’ parameter is set to UPLUG_REASON_QUERY, the plugin MUST call uplug_setPlugLevel()
to indicate whether it is a high level or low level plugin.
when the ‘reason’ parameter is UPLUG_REASON_QUERY, the plugin SHOULD call uplug_setPlugName
to indicate a human readable plugin name.
You can see a sample configuration file here: icuplugins_windows_sample.txt At ICU startup time, the environment variable “ICU_PLUGINS” will be queried for a directory name. If it is not set, the #define DEFAULT_ICU_PLUGINS
will be checked for a default value. DEFAULT_ICU_PLUGINS
will be set, on autoconf'ed and installed ICU versions, to “$(prefix)/lib/icu” if not set otherwise by the build environment. Within the above-named directory, the file “icuplugins##.txt” will be opened, if present, where ## is the major+minor number of the currently running ICU (such as, 44 for ICU 4.4). So, for example, by default, ICU 4.4 would attempt to open $(prefix)/lib/icu/icuplugins44.txt
The configuration file has the following format:
LIBRARYNAME ENTRYPOINT [ CONFIGURATION .. ]
An example configuration file is, in its entirety:
# this is icuplugins44.txt testplug.dll myPlugin hello=world
The DLL testplug.dll is opened, and searched for the entrypoint “myPlugin”, which must meet the API contract above. The string “hello=world” is passed to the plugin verbatim.
Plugins are categorized as “high” or “low” level. Low level are those which must be run BEFORE high level plugins, and before any operations which cause ICU to be ‘initialized’. If a plugin is low level but causes ICU to allocate memory or become initialized, that plugin is said to cause a ‘level change’. At load time, ICU first queries all plugins to determine their level, then loads all ‘low’ plugins first, and then loads all ‘high’ plugins. Plugins are otherwise loaded in the order listed in the configuration file.
The new command line utility, icuinfo
, will not only print out ICU version information, but will also give information on the load status of plugins, with the “-L” option. It will list all loaded or possibly-loaded plugins, give their level, and list any errors encountered which prevented them from loading. Thus, the end user can validate their plugin configuration file to determine if plugins are missing, unloadable, or loaded in the wrong order. For example the following run shows that the plugin named “myPluginFailQuery” did not call uplug_setPlugLevel()
and thus failed to load.
$ icuinfo -v -L Compiled against ICU 4.3.4, currently running ICU 4.3.4 ICUDATA is icudt43l plugin file is: /lib/plugins/icuplugins43.txt Plugins: # Level Name Library:Symbol config| (configuration string) >>> Error | Explanation ----------------------------------- #1 HIGH Just a Test High-Level Plugin plugin| /lib/plugins/libplugin.dylib:myPlugin config| x=4 #2 HIGH High Plugin plugin| /lib/plugins/libplugin.dylib:myPluginHigh config| x=4 #3 INVALID this plugin did not call uplug_setPlugName() plugin| /lib/plugins/libplugin.dylib:myPluginFailQuery config| uery \\\ status| U_PLUGIN_DIDNT_SET_LEVEL /// Error: This plugin did not call uplug_setPlugLevel during QUERY. #4 LOW Low Plugin plugin| /lib/plugins/libplugin.dylib:myPluginLow config| x=4 Default locale is en_US Default converter is UTF-8.