Avoiding duplicate symbols across packages (defining weak symbols) lazarus / 34-Windows ---------------------------------------------------------------------- H₂SO₄ · 2025-05-29 08:20 I'm using multiple statically-linked C libraries (in separate packages) in the same project. For maximum compatibility (i.e. to avoid having to install yet another VC++ redistributable) I'm linking against  msvcrt.dll  on Windows. It's a legacy component, but for my purposes it's sufficient. There is one caveat, however - it doesn't define  atexit,  which is used by the C library code. There's the Microsoft equivalent  _onexit,  so it'd be trivial to just declare a shim function: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function onexit(func: pcvoid): cint; cdecl; external name '_onexit'; function atexit(func: pcvoid): cint; cdecl; public name 'atexit';begin  Result := onexit(func);end; But then the question becomes where to place this definition: Within each project: Inelegant, would like to avoid such boilerplateWithin each package: Only works if exactly one such package is used in a project, because otherwise the  atexit  symbol is defined multiple times and the linker complainsI've also tried marking the  atexit  symbol as weak by implementing it in C with GCC's  __attribute__((weak)),  but then FPC's internal linker aborts because it can't recognize the symbol's type. So far it seems like the only viable option is to create a static library (e.g.  libmsvcrt_shim.a) containing the  atexit  definition and link against that, because I know from prior experience that FPC aggressively deduplicates  {$linklib}  directives. Any other suggestions? ---------------------------------------------------------------------- Thaddy · 2025-05-29 11:38 The shim should point to AddExitProc() or if you want (not recommended) to the exitProc entry point in system. You need to route the C code to the Pascal equivalent.  The Pascal system must be able to comply and exitproces are, well, exitprocs. You can' t mix them. You must make them point to the same entry point. I remember a similar situation about 25 years ago.(with Delphi) The C code will not be executed otherwise. This is a case of:"There can be only one".(Exit) The C code doesn't mind to use the Pascal ExitProc,because it is basically the same. ---------------------------------------------------------------------- H₂SO₄ · 2025-05-29 12:36 Quote from: Thaddy on May 29, 2025, 01:38:13 pmYou can' t mix them. You must make them point to the same entry point. I haven't run into this issue - in fact, the following works just fine and prints "Pascal" followed by "C", as expected, on my machine (linked against my shim library wrapping  _onexit): Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program TestExit; {$mode objfpc}{$H+} uses  SysUtils; procedure Pascal_Exit();begin  WriteLn('Pascal');  Sleep(1000);end; procedure C_Exit();begin  WriteLn('C');  Sleep(1000);end; function atexit(Func: Pointer): Integer; cdecl; external name 'atexit'; {$linklib msvcrt_shim} // Maps 'atexit' to '_onexit'{$linklib msvcrt} begin  AddExitProc(@Pascal_Exit);  atexit(@C_Exit);end. ---------------------------------------------------------------------- 440bx · 2025-05-30 17:06 if you don't mind that your program would only work with Windows 8 and above, kernelbase exports atexit. The prototype is exactly the same as the documented one (kernelbase's one isn't documented)  Also, just about every dll other than ntdll is dependent on kernelbase, therefore using it wouldn't add anything that your program isn't likely already using. HTH.