Ooook. Found the BPL twister. Not, it would probably not cry foul on FPC, as FPC seem to have correct const longstring finalizer.
But maybe other cases would.
The first question is - which of the units in the package and when should be initialized/finalized?
The secondary question would be WHAT EXACTLY is included in initialization/finalization. Like const longstrings, if they belong to PE/ELF data segment, then they are no subject to be initialized- but then they neither should be finalized, because if we have multiple init/fini-init-fini-init-fini runs without dll/so unloaded and reloaded - that data ends up destroyed
The tertiary quesiton would be platform restrictions. For example in the Windows DLL Delphi units initialization sections are called withing DLLMain context, in which execution environment was NOT establioshed yet, and 99% of Win32 API are prohibited to be called. AFAIR that is not do with BPLs but it is so with DLLs (DevExpress used to have code that was working in BPLs but not DLLs, and in mixed BPL+monolythic-DLL projects that was a total mess screwing even IDE debugger)
Back to the first question. Imagine we have A.BPL carrying units A1 to A4, and B.BPL caryrin B1 to B4.
We also have EXE, that is statically linked to A.BPL but not to B.BPL
A.BPL serves, among other things, a patch panel for plugins.
B.BPL is one of those plugins, it gets dynamically loaded (`LoadPackage`) to do some service, then unloaded.
EXE is linked to A1 and A2 units.
B.BPL units are linked to A2 and A3.
How does Delphi XE2 behave? When EXE starts it calls initializers for A1 and A2. It does not call initializers for A3 and A4. This optimization saves time and memory, but complicates things. I am not sure it was worth it.
When EXE runs LoadPackage(B) it does not have (and can not have) compile-time informaiton which B's units would end up used, so it runs initializers for ALL B1 to B4 units. This all-or-some strategies are different.
Now, B.BPL should do something about units A2 (initialized by EXE) and A3 (not initialized). I do not remember exactly what it does.
Then we have UnloadPackage(B), and after B1 to B4 are deinitialized - the question comes if A2 and A3 should be deinitialized. Maybe Delpihi RTL should have made reference counting, maybe it even did so - i don't remember those details, they looked kind of spagetti to me and i was bad at memorizing them.
Can finalization of ALL units be deferred until the binary file is unloaded (BPL or EXE)?
If developers follow RAII pattern, then surely A3 unit should be finalized by B's unloading. Because who knows which platform resources were locked by class constructors. And if we set on "never finlize until unmapping binary file" - then we can trigger platform resources leak.
However, can we be sure all the developers develop their units in a way, that would not break on multiplt init-fini-init-fini? Or, it would it just be their blame not yours?
I don't know which evil it lesser here.
--------------
There is a yet worse can of worms that i did not explore, because i already had enough, and because i was exploring specific trouble of constants destruction.
When if we have TWO loadable packages, B and C ? And C would use A1, A3 and A4 units (B used A2 and A3, EXE linked to A1 and A2)
And then we have overlapped B-load, C-load, B-unload, C-unload cycle.
This seems to go to combinatorial explostion, if units initialization and finalization would not become some smart and sealed abstraction (personalyl i think today units should just be classes, conceptually)
--------
So, the attached are sources for this EXE/A/B triad, that makes const static array of longstrings be destoryed on Delphi XE2. Probably would not do it on FPC, but might serve as some framework for other managed types and for more convoluted use cases (like EXE/A/B/C).
The log, when executed with 0 (no workarounds) mode this project writes the following, attached too (it is sad this forum has no spoilers).