System information:
OS (Architecture): Windows 10 (AMD64/x86-64)
Lazarus Version: 2.0.12
FPC Version: 3.2.0
C Compiler: GCC 10.3.0 (TDM-GCC-64)Hello everyone,this is what I'm trying to achieve:
- Create an IDE-installable Lazarus package that statically links PCRE2; usable on Windows
- Create an IDE-installable Lazarus package that statically links SQLite3; usable on Windows
- Have the ability to independently use either one or both of these packages at once (without relying on glue/dummy packages)
In isolation I've managed to reach the first two goals: I've created two packages that bundle C source code, which (given a working installation of GCC) compile a static version of the respective library via a custom makefile. The Windows targets require some extra hand-holding; notably, instead of a simple
{$linklib c} they require the GNU-style static libraries
libgcc.a,
libmsvcrt.a and
libkernel32.a. These can be located automatically via GCC by using eg.
"gcc --print-file-name=libgcc.a", so besides conditionally
{$linklib}ing these, the makefile is able to handle this. The end result is a source-only package that compiles and links just fine on both Linux and Windows, plus it can be installed in (that is, linked into) Lazarus.
Now, this is where the complications begin (all on Windows, because of course it had to be Windows):
On x86-64, while linking PCRE2 I was initially hit with internal compiler error
200603061 ("
Only debug sections are allowed to have relocs pointing to unused sections") which stumped me for a while. The first thing I tried was switching to the external linker (
-Xe), which solved this issue (and
would solve most other issues I'm going to bring up), but then I found out that Lazarus itself won't link with
-Xe, making that option a dealbreaker since non-installable packages propagate that limitation to any downstream components. In other words,
it seems that for package interoperability only FPC's internal linker may be used.
(I eventually worked around the internal error by stumbling upon GCC's
mcmodel=small option, which gets rid of the relocations that the internal linker can't handle. So for anyone reading this in the future:
If you have problems trying to use FPC's internal linker to link object files stemming from multiple co-dependent translation units, try using -mcmodel=small)
Ok, so with two individual working packages and knowing that
-Xe is a no-no, I tried using both packages in the same project, and hit the roadblock I'm still stuck at today:
No more than one such package will successfully link at a time. By "such package" I mean a package that bundles a C library like so (also setting
-Fl[...] etc.):
unit Something_Interface;
implementation
procedure something_foo(); cdecl; external;
implementation
{$linklib something} // Contains definition of something_foo
{$if defined(WINDOWS)}
{$linklib gcc}
{$linklib msvcrt}
{$linklib kernel32}
{$else}
{$linklib c}
{$endif}
end.
The first issue I stumbled upon when I tried using both packages at once was that certain symbols from libgcc, libmsvcrt and libkernel32 remained undefined (
_strncmp,
__divdi3,
_imp_CloseHandle@4 etc.) remained undefined. Looking at the extended debug output (
-va), I found out why:
Debug: [2.001] Opening library [...]/libpcre2.a
Debug: [2.002] Opening library [...]/libgcc.a
Debug: [2.003] Opening library [...]/libmsvcrt.a
Debug: [2.004] Opening library [...]/libkernel32.a
Debug: [2.005] Opening library [...]/libsqlite3.a
A link order issue! After libpcre2 resolves all the symbols it needs, the remaining symbols are discarded. Unfortunately, this happends before libsqlite3 can resolve any additional symbols it needs from those libraries. (Please correct me if I'm wrong, but I think that is what's happening)
To me it seemed like FPC didn't bother opening the same library more than once, so I tried to trick the compiler by adding no-op modifications to the
{$linklib} file names like
{$linklib .//./libgcc.a} instead of
{$linklib libgcc.a} - which actually worked, but only when doing a clean rebuild (to be precise, when no
.ppu was present for the header translation units). So I tried using the advanced linker options (
-XLO,
-XLA,
-XLD; the first two seemed promising), but didn't notice any effects, so I dug into the FPC source (
release_3_2_0) and found that
-XLO and
-XLA are only handled on Linux, Android and BSD (no other target calls
ExpandAndApplyOrder).
I made a final attempt with the
-k option, but as I soon found out, it unfortunately only has an effect on Windows targets (uses
ParaLinkOptions) when using the external linker...
which I cannot use (as detailed above).
So now my only hope left is help from a true expert - let's hope one stumbles upon this post...