Linker Probleme
-
Hallo zusammen,
ich habe mit dem RAD Studio 12.1 und dem 64Bit Linker merkwürdige Linkerfehler und möchte verstehen, was da genau schiefläuft. Ich habe die libpqxx (Postgres C++ API) als Bibilotheksprojekt und lasse das RAD Studio eine .lib (32 Bit) und .a (64 Bit) statische Linkbibliothek bauen.
Beim Linken der Anwendung, die diese Bibliothek benutzt, erhalte ich für die 64 Bit Plattform einige Linkerfehler, für die 32 Bit Plattform läuft der Linker problemlos durch.#include <vcl.h> #pragma hdrstop #include <tchar.h> #pragma comment (lib, "libpqxx" ) #pragma comment (lib, "libpq-17-2.a" ) #include "libpqxx/src/libpqxx/pqxx/connection" #include "libpqxx/src/libpqxx/pqxx/nontransaction" int main( int argc, char* argV[] ) { pqxx::connection connection; pqxx::nontransaction transaction( connection ); return 0; }
Und hier die zugehörigen Linkerfehler:
[ilink64 Fehler] Error: Unresolved external 'std::exception::exception(char const*)' referenced from D:\__OUT__\LIB\LIBPQXX.A|connection.o [ilink64 Fehler] Error: Unresolved external 'std::ios_base::ios_base()' referenced from D:\__OUT__\LIB\LIBPQXX.A|strconv.o [ilink64 Fehler] Error: Unresolved external 'std::locale::locale()' referenced from D:\__OUT__\LIB\LIBPQXX.A|connection_base.o [ilink64 Fehler] Error: Unresolved external 'std::ios_base::imbue(std::locale const&)' referenced from D:\__OUT__\LIB\LIBPQXX.A|strconv.o [ilink64 Fehler] Error: Unresolved external 'std::locale::locale(std::locale const&)' referenced from D:\__OUT__\LIB\LIBPQXX.A|strconv.o [ilink64 Fehler] Error: Unresolved external 'std::locale::operator=(std::locale const&)' referenced from D:\__OUT__\LIB\LIBPQXX.A|strconv.o [ilink64 Fehler] Error: Unresolved external 'std::ios_base::precision(long long)' referenced from D:\__OUT__\LIB\LIBPQXX.A|strconv.o [ilink64 Fehler] Error: Unresolved external 'std::ios_base::getloc() const' referenced from D:\__OUT__\LIB\LIBPQXX.A|strconv.o [ilink64 Fehler] Error: Unresolved external 'std::locale::id::operator unsigned long long()' referenced from D:\__OUT__\LIB\LIBPQXX.A|strconv.o [ilink64 Fehler] Error: Unresolved external 'std::locale::_Getfacet(unsigned long long) const' referenced from D:\__OUT__\LIB\LIBPQXX.A|strconv.o [ilink64 Fehler] Error: Unresolved external 'std::locale::c_str() const' referenced from D:\__OUT__\LIB\LIBPQXX.A|strconv.o [ilink64 Fehler] Error: Unresolved external 'std::ios_base::flags() const' referenced from D:\__OUT__\LIB\LIBPQXX.A|strconv.o [ilink64 Fehler] Error: Unresolved external 'std::ios_base::rdstate() const' referenced from D:\__OUT__\LIB\LIBPQXX.A|strconv.o [ilink64 Fehler] Error: Unresolved external 'std::ios_base::good() const' referenced from D:\__OUT__\LIB\LIBPQXX.A|connection_base.o [ilink64 Fehler] Error: Unresolved external 'std::ctype<char>::is(short, char) const' referenced from D:\__OUT__\LIB\LIBPQXX.A|strconv.o [ilink64 Fehler] Error: Unresolved external 'std::ios_base::fail() const' referenced from D:\__OUT__\LIB\LIBPQXX.A|strconv.o [ilink64 Fehler] Error: Unresolved external 'std::ios_base::operator bool() const' referenced from D:\__OUT__\LIB\LIBPQXX.A|strconv.o [ilink64 Fehler] Error: Unresolved external 'std::ios_base::width() const' referenced from D:\__OUT__\LIB\LIBPQXX.A|connection_base.o [ilink64 Fehler] Error: Unresolved external 'std::ios_base::width(long long)' referenced from D:\__OUT__\LIB\LIBPQXX.A|connection_base.o Misslungen Verstrichene Zeit: 00:00:06.2
Hm, schaut so aus, als würden einige templates nicht instanziiert und kein Code dafür erzeugt, deshalb kann der Linker nicht linken.
Mit folgendem Fix läuft der Linker problemlos durch:
#include <vcl.h> #pragma hdrstop #include <tchar.h> #pragma comment (lib, "libpqxx" ) #pragma comment (lib, "libpq-17-2.a" ) #include "libpqxx/src/libpqxx/pqxx/connection" #include "libpqxx/src/libpqxx/pqxx/nontransaction" #include <memory> #include <iostream> #include <sstream> void fix_win64_linker_issues() { auto ct = std::make_unique<std::ctype<char>>(); ct->is( static_cast<short>( 10 ), static_cast<char>( 5 ) ); std::stringstream ss; static_cast<bool>( ss ); ss.flags(); ss.good(); ss.fail(); ss.width(); ss.width( 4 ); ss.imbue( std::locale::classic() ); ss.precision( std::int64_t( std::numeric_limits<unsigned int>::digits10 +2 ) ); } int main( int argc, char* argV[] ) { fix_win64_linker_issues(); pqxx::connection connection; pqxx::nontransaction transaction( connection ); return 0; }
Und nu meine Frage: Was kann da schiefgehen? Und vor allem: Wie fixe ich das? Ich kann jetzt natürlich in die Bibliothek den Fix einbauen, aber was erwartet mich dann später noch?
-
@DocShoe Ich sehe nur ein Template (
std::ctype<char>
), würde also erstmal nicht von einem Template-Problem ausgehen. Mein erster Instinkt ist, dass die Standardbibliothek nicht, oder eine inkompatible Version dazu gelinkt wird.Ich würde jedenfalls erstmal sicherstellen, dass sämtlicher Code (Library und Anwendung) mit den gleichen Compiler- und Linker-Flags gebaut wird und dass es auch keine Diskrepanz zwischen statischem und dynamischem Linken gibt (z.B. einmal die Standardbibliothek statisch und einmal dynamisch gelinkt). Die Compiler-Version und die der Standardbibliothek sollten natürlich auch bei Library und Anwendung identisch sein.
Auch muss bei statischem Linken beim Kompilieren der Anwendung auch jede Abhängigkeit der Bibliothek mit dazu gelinkt werden (wie z.B. die Standardbibliothek) auch wenn die Anwendung diese selbst nicht direkt verwendet. Irgendwo müssen die Funktionen und anderen Symbole ja herkommen, die von der Bibliothek referenziert werden.
Dein "Fix" verwendet vermutlich die fehlenden Symbole nochmal explizit. Es ist auch möglich, dass der Linker vorher meinte, diese Funktionen und anderen Symbole würden nicht verwendet und er sie deshalb rausgeworfen hat (gibts auch alles, aber eher mit entsprechenden Flags um solche nicht-referenzierte Funktionen zu eliminieren).
Ansonsten weiss ich auch nicht wirklich, wie die RAD Studio Compiler z.B. die Standardbibliothek linken. Wenn das z.B. auch über solche "lib"-Pragmas gemacht wird, dann würde die natürlich nur dann mit dazu gelinkt, wenn man sie auch explizit im Code verwendet, so wie du das bei deinem Fix gemacht hast. Vielleicht befindet sich ja z.B. im
<iostream>
-Header so ein pragma á la#pragma comment (lib, "libstd" )
? Das würde es auch erklären und die Antwort lautet in dem Fall, die Standardbibliothek explizit mit dazu zu linken in den Linker Flags. Sonst weiss er vermutlich einfach nicht, dass die auch mit dazu gehört, weil nur die Library sie verwendet, dein Programm aber (eventuell) nicht.Edit: Vielleicht ist das hier ja auch relevant?
https://gist.github.com/GermanAizek/58fe06404dc7e9d879963cedefe4234cSolution: Check in project properties 'Link with Dynamic RTL'
Das ist eventuell das "explizit die Standardbibliothek dazu linken" von dem ich gesprochen habe. Klingt jedenfalls sehr danach.
-
Danke für deine Antwort, ich glaube, ich muss da ein paar Infos ergänzen.
Das ganze Projekt befindet sich in einer Projektgruppe und wird komplett aus der IDE gebaut. Die Projektgruppe enthält vier Projekte, die jeweils eine statische Bilbiothek erzeugen und ein Projekt, das die Anwendung erzeugt und die vier statischen Bibliotheken benötigt. Für jedes Projekt kann man individuell die Plattform festlegen, für das es erzeugt werden soll (Windows 32 Bit, Windows 64 Bit und Windows 64 Bit (Modern)). Ich baue alle Projekte für Windows 64 Bit und alle Projekte benutzen den gleichen Compiler und Linker. Eine Auswahl zwischen verschiedenen Standardbibliotheken, gegen die man linken kann, gibt es praktisch auch nicht (es gibt ne Ausnahme, aber die ist irrelevant). Die Anwendung wird ausschließlich statisch gelinkt, die Anwendung selbst braucht keine weiteren DLLs (mit Ausnahme der Postgres DLLs).
Die meisten dieser Linkerfehler kommen aus der Datei
libpqxx/pqxx/strconv.cxx
, da werden eigene stream-Klassen definiert, die vonstd::stringstream
erben.std::stringstream
selbst ist auch nur ein Spezialisierung vonstd::basic_stringstream
, was wiederum ein Template ist. So ganz bin ich von der fehlenden Instanziierung immer noch nicht weg.
Außerdem scheint ja ansonsten (std::string, std::vector, std::array, etc.) gefunden zu werden. Und letztendlich benutzt die Anwendung auch die STL, schon daher wird gegen sie gelinkt.
-
@DocShoe Auch wenn ich glaube, dass man nicht von Klassen der Standardbibliothek erben sollte (mit Ausnahme von vielleicht
std::exception
), glaube ich nicht wirklich dass das das Problem ist.Ich bin auch bei RAD Studio und dessen Compilern etwas überfragt (bin eher so ein Clang/GCC und CMake-Typ). Bei meinen Projekten hätte ich mir jetzt mal die Compiler-Kommandozeilen genau angesehen, ob da was komisches passiert und die auch mal "manuell" ausgeführt und dann ein paar Flags drangehängt (wie z.B. nochmal explizit die
libstdc++.a
/libc++.a
dazu linken, wo die Symbole eigentlich drin sein müssten und gucken, was passiert.Daher kann ich in dem Fall nur ne KI fragen. Vielleicht sind ja ein paar Tips in deren Antwort, die weiterhelfen:
KI-Antwort ---------------------------
This is a classic C++ linking issue with static libraries. The most common causes for this problem are:
Primary Causes:
- C++ Standard Library ABI Mismatch
- The static library (LIBPQXX) was compiled with a different C++ standard library version than your main project
- Different compiler versions or settings between the library and main project
- Mixing static and dynamic runtime libraries (e.g., one uses static CRT, the other uses dynamic)
- Compiler Version Incompatibility
- LIBPQXX was built with a different version of RAD Studio/C++ Builder
- Different C++ standard implementations (Dinkumware, libstdc++, etc.)
- Runtime Library Configuration
- Mismatch in runtime library settings (Debug vs Release, static vs dynamic)
- Different optimization settings or preprocessor definitions
RAD Studio Specific Solutions:
- Check Runtime Library Settings:
- Ensure both projects use the same runtime library:
- Project → Options → C++ Compiler → Classic Compiler → Runtime Library
- Both should use the same (e.g., "Dynamic RTL" or "Static RTL")
- Ensure both projects use the same runtime library:
- Verify Compiler Versions:
- Ensure both projects use the same compiler version
- Check Target Platform settings match
- Library Build Configuration:
- Rebuild LIBPQXX with the exact same RAD Studio version and settings as your main project
- Use the same build configuration (Debug/Release) for both
- Linker Options:
- Add proper library paths in:
- Project → Options → C++ Linker → Library Path
- Ensure all required C++ runtime libraries are linked
- Add proper library paths in:
Quick Diagnostic Steps:
- Check what's missing:
Shell:tdump -m LIBPQXX.A | grep precision
- Verify your project's runtime:
- Look for RLD* or similar symbols to identify runtime library version
- Common fix:
- Clean and rebuild both projects in the same IDE session
- Ensure no pre-built LIBPQXX binaries from different compiler versions
Prevention:
- Always build all static libraries with the same compiler version and settings
- Use package/project groups to ensure consistent build configurations
- Consider using dynamic libraries if you need to mix compiler versions
The key is consistency - every component must be built with identical compiler settings, especially the C++ runtime library configuration.
- C++ Standard Library ABI Mismatch
-
@DocShoe
Mal eine Frage. Benötigst du in deinem Workaround die Funktion die Funktionfix_win64_linker_issues()
überhaupt?BTW: Hast du mehrere Versionen von libpqxx? Nicht dass das folgende zutrifft:
Some users have reported problems using the above syntax, however, particularly when multiple versions of libpqxx are partially or incorrectly installed on the system. If you get massive link errors, try removing the "-lpqxx" argument from the command line and replacing it with the name of the libpqxx library binary instead. That's typically libpqxx.a, but you'll have to add the path to its location as well, e.g. /usr/local/pqxx/lib/libpqxx.a. This will ensure that the linker will use that exact version of the library rather than one found elsewhere on the system, and eliminate worries about the exact right version of the library being installed with your program..
-
Schau dir mal die Reihenfolge in der Linker Befehlszeile an, wie die Libs gelinkt werden: zuerst muß die
libpqxx
angegeben sein und dahinter dann erst die Standard C++ Library.
-
Kann ich fast alles ausschließen.
- Alle Projekte werden mit derselben Toolchain gebaut
- Alle Projekte werden im Release-Modus gebaut (auch wenn alle im Debug-Modus gebaut werden bekomme ich die Linker Fehler)
- Alle Projekte verwenden die gleiche Linkage (static), die Standardbibliotheken werden nicht statisch gelinkt.
- Es gibt nur eine libpqxx.a im Suchpfad für den Linker (hab sie umbenannt -> Linker kann Datei nicht finden -> Abbruch)
- Die cp64mt.a (ich vermute, dass das die Standard C++ Library ist) wird zuletzt angegeben.
-
@DocShoe
Hast du mal die Präprozessordefinitionen überprüft? Nicht dass z.B. ein gesetztes PQXX_AUTOLINK Probleme macht. Siehe header-pre.hxx