Errors linking statically the libxml2

34 Views Asked by At

Trying to build statically an application using libxml2 I have errors like

undefined reference to `__imp_xmlTextReaderRead'

Removing the -static option it works perfectly.

The command I used is:

gcc -o myapp.exe `xml2-config --cflags` -I /mingw64/include myapp.c `xml2-config --libs` -static
1

There are 1 best solutions below

2
Mike Kinghan On

To rectify the undefined references to symbols of the form __imp_xml*, predefine preprocessor macro LIBXML_STATIC on your gcc commandline, like so:

gcc -DLIBXML_STATIC -o myapp.exe `xml2-config --cflags` \
    -I /mingw64/include myapp.c `xml2-config --libs` -static
    

Why?

You are working with gcc on Windows. The undefined references of the form __imp_xml* show that your compiler is working in the expectation that your code will be dynamically linked against libxml2.dll at runtime, and to that end will be linked against that DLL's import library libxml2.lib at buildtime. The __imp_xml* references will be resolved by that buildtime import library in proxy for libxml2.dll. Your compiler is emitting these references to discharge DLL import declarations of the form __declspec(dllimport) xml* that it finds in the source code, after preprocessing.

The presence of these dllimport declarations proves that the compiler is seeing preprocessed code not intended to enable static linkage against libxml2, i.e. linkage against the static library libxml2.a, in which symbols are defined without the __imp_ prefix.

But you are a specifying static linkage (-static). This prohibits the linker from considering import libraries, even if they are available. The library options that accrue in your commandline by shell-expansion of xml2-config --libs will be of the form -l xml2 [...]. In the presence of -static, the linker will attempt to resolve -l xml2 by scanning its search directories only for a libxml2.a, not libxml2.lib

Accordingly, the undefined __imp_xml* reference errors go away, as you observe, when you remove the -static option from your commandline - because the linker is then at liberty to search for libxml2.lib.

Since you want a static linkage, the compiler ought not to be seeing preprocessed code destined for dynamic linkage. But however that problem might be solved for the compiler, the -static option will not do it, because that is a linkage option and does not influence compilation.

The preprocessor does influence compilation and libxml2 uses the preprocessor macro LIBXML_STATIC as a switch to decide whether the API function declarations in its public header files will emerge from preprocessing prefixed with __declspec(dllimport), or with __declspec(dllexport), or with neither. The relevant preprocessor boilerplate is found in the header file libxml2/libxml/exmlexports.h, which will be included by any libxml2 public header file that you include in your own code.

...[cut]...
#if defined(_WIN32) || defined(__CYGWIN__)  /* We are on Windows */

#ifdef LIBXML_STATIC        /* We are building for static linkage * 
  #define XMLPUBLIC         /* Our public API symbols are left as seen */
/* Else we are building for dynamic linkage  
#elif defined(IN_LIBXML)    /* If we are building libxml2 itself */
  #define XMLPUBLIC __declspec(dllexport)   /* DLL export our API symbols */ 
#else /* We are building client code */
  #define XMLPUBLIC __declspec(dllimport)   /* DLL import our API names */
#endif
...[cut]...

(The comments are all mine.)

That's why you need to define LIBXML_STATIC before compilation commences, per commandline option -DLIBXML_STATIC, to suppress the default production of client code that presumes dynamic linkage.

But...

Be forewarned that not all undefined symbol linkage errors will necessarily go away with the __imp_xml* ones. If you specify -static, then the linker must find static versions of all the libraries required by your program: not just libxml2, but also all those that libxml2 recursively depends on. There are quite a few of those and it is not unlikely you haven't installed static versions of them all.

If you do have them all, your app will be a very large executable with a very small power-to-weight ratio. You may or may not have already reckoned with that. If it would suffice for your needs to link libxml2 itself statically, but not its whole dependency chain, you can do that too. Consult the GNU linker's commandline options to learn about the relevant linker options -Bstatic and -Bdynamic, and also the GCC's commandline options concerning the option -Wl to see how gcc can pass linker-specific options to the linker.