Search code examples
c++visual-studiolinkericu

Unresolved external symbol with ICU


We have code that uses the ICU library for working with Unicode strings. When we try to build it, we get no compile errors, but the link fails. I created a small test program with the following code:

#define U_STATIC_IMPLEMENTATION
#undef INT64_C
#undef UINT64_C
#include <unicode/coll.h>

void icu_test()
{
    UErrorCode success = U_ZERO_ERROR;
    Collator* myCollator = Collator::createInstance(success);
    VERIFY(U_SUCCESS(success));
    myCollator->setStrength(Collator::QUATERNARY);
    UChar Word1[10] = _T("this");
    UChar Word2[10] = _T("that");

    // Compare two strings in the default locale
    bool result = myCollator->greater(Word1, Word2);
}

This program also fails to link with:

error LNK2019: unresolved external symbol "public: __thiscall icu_3_2::UnicodeString::UnicodeString(wchar_t const *)" (??0UnicodeString@icu_3_2@@QAE@PB_W@Z) referenced in function "void __cdecl icu_test(void)" (?icu_test@@YAXXZ)

(Is 0UnicodeString the constructor, perhaps?) When I use dumpbin to look at the exported symbols in the ICU libraries, I see the following:

??0UnicodeString@icu_3_2@@QAE@ABV01@@Z (public: __thiscall icu_3_2::UnicodeString::UnicodeString(class icu_3_2::UnicodeString const &)) ??0UnicodeString@icu_3_2@@QAE@ABV01@H@Z (public: __thiscall icu_3_2::UnicodeString::UnicodeString(class icu_3_2::UnicodeString const &,int)) ??0UnicodeString@icu_3_2@@QAE@ABV01@HH@Z (public: __thiscall icu_3_2::UnicodeString::UnicodeString(class icu_3_2::UnicodeString const &,int,int)) ??0UnicodeString@icu_3_2@@QAE@CPBGH@Z (public: __thiscall icu_3_2::UnicodeString::UnicodeString(signed char,unsigned short const *,int)) ??0UnicodeString@icu_3_2@@QAE@G@Z (public: __thiscall icu_3_2::UnicodeString::UnicodeString(unsigned short)) ??0UnicodeString@icu_3_2@@QAE@H@Z (public: __thiscall icu_3_2::UnicodeString::UnicodeString(int)) ??0UnicodeString@icu_3_2@@QAE@HHH@Z (public: __thiscall icu_3_2::UnicodeString::UnicodeString(int,int,int)) ??0UnicodeString@icu_3_2@@QAE@PAGHH@Z (public: __thiscall icu_3_2::UnicodeString::UnicodeString(unsigned short *,int,int)) ??0UnicodeString@icu_3_2@@QAE@PBD0@Z (public: __thiscall icu_3_2::UnicodeString::UnicodeString(char const *,char const *)) ??0UnicodeString@icu_3_2@@QAE@PBDH0@Z (public: __thiscall icu_3_2::UnicodeString::UnicodeString(char const *,int,char const *)) ??0UnicodeString@icu_3_2@@QAE@PBDHPAUUConverter@@AAW4UErrorCode@@@Z (public: __thiscall icu_3_2::UnicodeString::UnicodeString(char const *,int,struct UConverter *,enum UErrorCode &)) ??0UnicodeString@icu_3_2@@QAE@PBDHW4EInvariant@01@@Z (public: __thiscall icu_3_2::UnicodeString::UnicodeString(char const *,int,enum icu_3_2::UnicodeString::EInvariant)) ??0UnicodeString@icu_3_2@@QAE@PBG@Z (public: __thiscall icu_3_2::UnicodeString::UnicodeString(unsigned short const *)) ??0UnicodeString@icu_3_2@@QAE@PBGH@Z (public: __thiscall icu_3_2::UnicodeString::UnicodeString(unsigned short const *,int)) ??0UnicodeString@icu_3_2@@QAE@XZ (public: __thiscall icu_3_2::UnicodeString::UnicodeString(void))

So none of these quite match the first unresolved external, because of the stuff at the end of the identifier (e.g. @@QAE@PB_W@Z), which does not come from our code. Not sure how this is generated or what to do about it.

I tried downloading the latest version of ICU (60.2), but it only comes in a x64 version, while our program builds for x86.

I made sure that the ICU library folder is included in the link settings.

We also made sure to define U_STATIC_IMPLEMENTATION, as described in this post:

Why do I get link errors when the symbol is clearly present in the static library I link against?

In that post, they were able to locate the relevant symbol in the library, but we cannot.

Can anyone help us understand what is causing this link error?


Solution

  • I tried building a static library of ICU 60.2 but ran into problems and I was unable to get help from ICU support to build it.

    I tried downloading pre-built ICU 59.1 libraries from this website. But had a different linker error and no idea what to do with that.

    I saw that my code was trying to pass a wchar_t* to icu::greater(), which expects UnicodeString arguments, so I inferred that this is where type conversion causes the UnicodeString to be constructed. I changed the code to do an explicit conversion to UnicodeString and then pass that, but I still got the same linker error.

    Finally, my coworker found some information about a potential problem with wchar_t. So that was it - our best understanding is that since our code was originally working with MS Visual C++ 6.0, and it was able to link to ICU 3.2 in that context, it was linking with the old definition of wchar_t, but the new definition of wchar_t was changing the way the name decoration was being generated. Adding -Zc:wchar_t- to the compile options (in VS 2017, go to Project Properties, C/C++ All Options, 'Additional Options' line), caused it to link successfully after a full recompile.

    Very subtle.