0

I'm making a text-based game, using ICU to process game text from UTF-8-encoded JSON files across the 3 major PC platforms. I'm able to compile and link the game binary with CMake while referencing ICU types such as UChar, UnicodeString, etc. and everything works properly. Bizarrely enough, there are certain headers from which I can't access any types or functions without causing an "Undefined symbols" linker error. Particularly, the header "ustdio.h" from which I need to access u_fopen(), u_fclose(), u_fgets(), etc. to extract unicode strings from my JSON files.

Undefined symbols for architecture x86_64: "_u_fclose_57", referenced from: FileReader::Close() in libsource.a(FileReader.cpp.o) "_u_fgets_57", referenced from: FileReader::HasNextLine() in libsource.a(FileReader.cpp.o) FileReader::NextLine() in libsource.a(FileReader.cpp.o) "_u_fopen_57", referenced from: FileReader::FileReader(std::__1::basic_string, std::__1::allocator >) in libsource.a(FileReader.cpp.o)

I'm using this CMake module file to locate the .h and .dylib files. From CMake output, I know it's linking against /usr/local/lib/libicuuc.dylib, but looking in that folder I also see plenty of other ICU-related dylibs. Another programmer directed me to check if the symbols I'm looking for are really defined in the dylib using nm and I can see in the symbol list that they aren't. Am I to assume these symbols are defined in one of the other dylib files? If they are, and I find the proper dylib, how do I modify FindICU.cmake to link against the extra dynamic library? The module seems really obtuse to me and I don't know where I'd change it to fix this.

Natman64
  • 93
  • 1
  • 6

1 Answers1

1

I figured it out by searching the symbol table of each ICU-related dylib file until I found the missing symbols (which are defined in libicuio.57.1.dylib). This helped me realize that the symbols were indeed not being found by FindICU.cmake. I then managed to parse through enough of the file to identify the problem: there's a variable, ICU_FIND_COMPONENTS that must be set to a list of desired components in order for the module file to link against the other dylibs. This variable wasn't documented anywhere, which is pretty frustrating. But I solved the linker error by adding this line to FindICU.cmake before line 121:

set(${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS io)

Additionally you can check whether a desired component is being linked by outputting the values of variables ICU_<component>_FOUND. In my case, ICU_IO_FOUND was returning false because the module doesn't search for the io dylib unless explicitly told to do so. This is what clued me into the need to modify FindICU.cmake in order to link the extra dylib file where the symbol comes from.

Natman64
  • 93
  • 1
  • 6