Thanks for the extra info, it kind of confirms what I was thinking:
- This is broken at embarcadero's side. We could workaround it with smartsetup by reading the LANGDIR env variable an passing the correct paths, but LANGDIR seems to be a mess, and it isn't guaranteed that what the IDE sees is what the command line sees. So we might still compile against the wrong lib because we are compiling from the command line, not the IDE.
- A small nitpick, because while we normally don't think much about the terms, it is important here: tms pack isn't linked against the english libs. In fact it isn't linked at all. The only link happens when you link the app, and there, if "en" and "de" libs are ABI compatible, you should be able to pick one or the other without recompiling tms pack against them. What gets linked is what is active when you build your app. The problem here is that tms pack is compiled against a different lib, which looks to have a different ABI, and so it crashes when it tries to call anything in the swapped lib. But from what I see all those localized units seem to be just resourcestrings, so, unless some unit I haven't found yet is wrong, you should be able to compile against one and link against a different one.
What I also found out is that there seems to be a unit initialization issue (which I am not really sure how it relates to localized libs).
The error is happening here (unit System.Bindings.Methods.pas):
class procedure TBindingMethodsFactory.RegisterMethod(
AMethod: TMethodDescription);
begin
if FRegisteredMethods.ContainsKey(AMethod.ID) then
raise EBindMethodError.CreateResFmt(@sDuplicatedMethodName, [AMethod.ID]);
FMethodScope := nil;
FRegisteredMethods.Add(AMethod.ID, AMethod);
end;
Because FRegisteredMethods wasn't initialized yet. But then, it should have been because that class has a class constructor:
class constructor TBindingMethodsFactory.Create;
begin
FRegisteredMethods := TBindingMethods.TMethodList.Create;
end;
Now, if you debug, put a breakpoint in Data.Bind.EngExt.pas -> procedure RegisterMethods, and move the blue arrow to the end (so it skips the method):
you will see that after it ends, then it calls the class constructor:
So it is also a problem of initialization order too.
Further going into the "order of initialization" issue, if I go and manually change the order of linked libraries in the .cbproj, then it compiles fine.
I had:
<AllPackageLibs>rtl.lib;vcl.lib;bindcomp.lib;bindengine.lib;dbrtl.lib;vclwinx.lib;vclimg.lib;xmlrtl.lib;vclie.lib;vcledge.lib;VclSmp.lib;vclx.lib</AllPackageLibs>
And this crashed:
In the same place as yours:
But, if I swap the order of bindcomp.lib and bindengine.lib:
<AllPackageLibs>rtl.lib;vcl.lib;bindengine.lib;bindcomp.lib;dbrtl.lib;vclwinx.lib;vclimg.lib;xmlrtl.lib;vclie.lib;vcledge.lib;VclSmp.lib;vclx.lib</AllPackageLibs>
Then it works (!!)
I wonder if you see the same in your project. (note that when you change allPackageLibs, it is better to restart the IDE and do a full build, because there is a lot of caching going on)
I've been testing in a simpler setup than yours, not against tms pack, but against a simpler package instead of fnc pack. I could reproduce it with this package:
And this app:
To make it a little more interesting, I changed the "UBindings.pas" to be:
unit UBindings;
interface
uses Data.Bind.EngExt, System.Bindings.Consts;
procedure WriteMessage;
implementation
procedure WriteMessage;
begin
Writeln('From library: ' + sFormatArgError);
end;
end.
And the app calling the library to be:
#include <vcl.h>
#include <tchar.h>
#pragma link "LocalizedBindings.lib"
#include "UBindings.hpp"
#include <System.Bindings.Consts.hpp>
#include <iostream>
int _tmain(int argc, _TCHAR* argv[])
{
auto p = System_Bindings_Consts_sFormatArgError;
WriteMessage();
std::wcout << "From app: " << p << std::endl;
}
As you can see, it calls "WriteMesage" in the library (which was compiled with "EN" locale) and then prints the same parameter, but from the app. If I switch the AllLibs order as mentioned above, I get:
Which also confirms that there is a single linked localized lib. Even when the lib was compiled against the english locale, WriteMessage writes the message localized, because the app was linked with the localized libs.
I don't know what else to say here. This is a weird error, but the actual issue is the order that libraries are linked in your app (for some reason, it is triggered by linking libs compiled against different localizations, but that doesn't seem to be the issue). We can't fix that, probably embarcadero should rewrite the bindings code so the initialization of a unit doesn't depend in the initialization of the other.
Also when this happens, it is really hard to find out the actual bug. We were lucky you went through all the effort to find out how to reproduce it, but we might not be so lucky next time. I'll open a bug report with embarcadero.