I'm trying to use the adobe xmp library in an iOS application but I'm getting link errors. I have the appropriate headers and libraries in my path, but I'm getting link errors. I double-checked to make sure the headers and library are on my path. I checked the mangled names of the methods, but they aren't in the library (I checked using the nm
command). What am I doing wrong?
Library Header:
#if defined ( TXMP_STRING_TYPE )
#include "TXMPMeta.hpp"
#include "TXMPIterator.hpp"
#include "TXMPUtils.hpp"
typedef class TXMPMeta <TXMP_STRING_TYPE> SXMPMeta; // For client convenience.
typedef class TXMPIterator <TXMP_STRING_TYPE> SXMPIterator;
typedef class TXMPUtils <TXMP_STRING_TYPE> SXMPUtils;
.mm file:
#include <string>
using namespace std;
#define IOS_ENV
#define TXMP_STRING_TYPE string
#import "XMP.hpp"
void DoStuff()
{
SXMPMeta meta;
string returnValue;
meta.SetProperty ( kXMP_NS_PDF, "test", "{ formId: {guid} }" );
meta.DumpObject(DumpToString, &returnValue);
}
Link Errors:
(null): "TXMPMeta<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::DumpObject(int (*)(void*, char const*, unsigned int), void*) const", referenced from:
(null): "TXMPMeta<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::TXMPMeta()", referenced from:
(null): "TXMPMeta<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::SetProperty(char const*, char const*, char const*, unsigned int)", referenced from:
(null): "TXMPMeta<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::~TXMPMeta()", referenced from:
(null): Linker command failed with exit code 1 (use -v to see invocation)
Basically what's happened is that you only have the definitions in the headers if I say
template<class T> T something(T);
somewhere, that tells the compiler "trust me bro, it exists, leave it to the linker"and it adds the symbol to the object file as if it did exist. Because it can see the prototype it knows how much stack space, what type it returns and such, so it just sets it up so the linker can just come along and put the address of the function in.
BUT in your case there is no address. You /MUST/ have the template definition (not just declaration) in the same file so the compiler can create one (with weak linkage) so here it's assumed they exist, but no where does it actually stamp out this class from a template, so the linker doesn't find it, hence the error.
Will fluff out my answer now, hope this helps.
Addendum 1:
This will compile but NOT link.
Output:
(I hijacked an open projet for this hence the names)
As you can see the compile command works fine (the one that ends in -o build/main.o) because we tell it "look this function exists"
So in the object file it says to the linker (in some "name managled form" to keep the templates) "put the location in memory of void output(int&); here" the linker can't find it.
Compiles and links
Notice line 2, we tell it "there exists a function, a template in T called output, that returns nothing and takes a T reference", that means it can use it in the main function (remember when it's parsing the main function it hasn't seen the definition of output yet, it has just been told it exists), the linker then fixes that. 'though modern compilers are much much smarter (because we have more ram :) ) and rape the structure of your code, link-time-optimisation does this even more, but this is how it used to work, and how it can be considered to work these days.
Output:
As you can see it compiled fine and linked fine.
Multiple files without include as proof of this
main.cpp
proof.cpp
Compile and link
(Outputs 5)
Remember #include LITERALLY dumps a file where it says "#include" (+ some other macros that adjust line numbers) this is called a translation unit. Rather than using a header file to contain "int TrustMeCompilerIExist();" which declares that the function exists (but the compiler again doesn't know where it is, the code inside of it, just that it exists) I repeated myself.
Lets look at proof.o
command
output
Right at the bottom there, there's a function, at offset 6 into the file, with debugging information, (the g is global though) you can see it's called _Z (this is why _ is reserved for some things, I forget what exactly... but it's to do with this) and Z is "integer", 21 is the name length, and after the name, the v is "void" the return type.
The zeros at the start btw are the section number, remember binaries can be HUGE.
Disassembly running:
objdump proof.o -S
givesBecause I have -g you can see it put the code that the assembly relates to (it makes more sense with bigger functions, it shows you what the following instructions until the next code block actually do) that wouldn't normally be there.
main.o
Here's the symbol table, obtained the same way as the above:
See how it says undefined, that's because it doesn't know where it is, it just knows it exists (along with the standard lib stuff, which the linker will find itself)
In closing USE HEADER GUARDS and with templates put #include file.cpp at the bottom BEFORE the closing header guard. that way you can include header files as usual :)