Conditionally compiling for differences in libxml2

2019-07-07 11:02发布

When using iOS 7 SDK, due to changes in libxml2 I had to change a single line of a library to use the new output buffer accessor methods for the xmloutput buffer.

NSData * result = [[[NSData alloc] initWithBytes:outputBuffer->buffer->content 
                                  length:outputBuffer->buffer->use] autorelease];

Resulted in compile error 'Incomplete definition of type struct_xmlBuf'. Using the new accessor methods this became:

NSData * result = [[NSData alloc] initWithBytes:xmlOutputBufferGetContent(outputBuffer)
                                  length:xmlOutputBufferGetSize(outputBuffer)];

This works fine but when run on iOS 6 it not surprisingly crashes with 'lazy symbol binding failed: Symbol not found' for the new methods with mentions of libxml2.2.dylib.

How can you do this change conditionally in a way which will compile with base SDK iOS 7 and still run on iOS 5, 6 & 7?

Note: The usual checking iOS version at runtime like other problems is insufficient as the old line no longer compiles.

I have been trying and considering:

  • Checking xmlOutputBufferGetContent != NULL, always true
  • Using libxml2.2 instead of libxml2
  • Checking LIBXML_DOTTED_VERSION, always 2.9.0
  • Checking for LIBXML2_NEW_BUFFER new methods defined, always true

All of these result in only one line always being chosen before or after compilation, largely based on the SDK. The few other people dealing with this change in non-iOS projects (Googling) appear to be always compiling targeting one version of libxml.

1条回答
The star\"
2楼-- · 2019-07-07 11:25

Something like following should work:

#include <dlfcn.h>

typedef const xmlChar *(*getContent_t)(xmlOutputBufferPtr out);
typedef size_t (*getSize_t)(xmlOutputBufferPtr out);

Then:

int libxmlVersion = atoi(xmlParserVersion);

if (libxmlVersion < 20900) {
    xmlBufferPtr oldStyleBuffer = (xmlBufferPtr)outputBuffer->buffer;
    NSData * result = [[[NSData alloc] initWithBytes:oldStyleBuffer->content 
                              length:oldStyleBuffer->use] autorelease];
}
else {
    getContent_t getContent = dlsym(RTLD_DEFAULT, "xmlOutputBufferGetContent");
    getSize_t getSize = dlsym(RTLD_DEFAULT, "xmlOutputBufferGetSize");
    NSData * result = [[NSData alloc] initWithBytes:getContent(outputBuffer)
                              length:getSize(outputBuffer)];
}

For older versions of libxml2 (before 2.9.0), the old buffer struct is used. For newer versions, the new accessors are searched using dlsym. Caching the function pointers returned by dlsym will improve performance.

查看更多
登录 后发表回答