In the use of dynamic library development deployment, the most encountered problems may be undefined symbol, the cause of this problem has a variety of reasons, quickly find the reason, adopt the corresponding method to solve is the purpose of this paper.

Possible causes

  1. The dependent library was not found

This is the most common cause, usually not specified in the lookup directory, or not installed in the system lookup directory 2. Linked dependent libraries compile inconsistently with a higher version, and then link to a lower version for different machines, which may be missing some API 3. Hidden symbols If the dynamic library is hidden by default when compiled, external code uses a hidden symbol. 4. The most typical example of inconsistent abi versions of c++ is the problem between GCC 4.x and GCC 5.x versions, which are edited in 4.x and cannot be linked in 5.x.

The solution

  1. The dependent library was not found
  • Using LDD-R, determine whether a dependent library exists in the system library
  • Run the ldconfig command to update the LD cache
  • Perform ldconfig – p | grep {SO_NAME} see whether can find the corresponding libraries
  • Check whether LD_LIBRATY_PATH has a valid path set
  1. The linked library version is inconsistent

If the same library has been installed on your system before, or if there are multiple libraries, you need to determine which library to link to

One special case to note is that.so files have a default rpath for searching dependent libraries, which takes precedence over the system directory and LD_LIBRARY_PATH. If a.so file with the same name exists in rpath, the file with that path will be loaded first.

In case of undefined symbol problem, use the readelf – d | grep rpath view:

$ readelf -d libSXVideoEngineJni.so | grep rpath
 0x000000000000000f (RPATH)              Library rpath: 
 [/home/slayer/workspace/SXVideoEngine-Core/Render/cmake-build-
 debug:/home/slayer/workspace/SXVideoEngine-Core/Render/../../SXVideoEngine-Core-Lib/blend2d/linux/lib]
Copy the code

If the corresponding library exists in the path, you can rename the file first and then test to confirm.

The order in which you connect can be found in the documentation: man7.org/linux/man-p…

If a shared object dependency does not contain a slash, then it is searched for in the following order: o Using the directories specified in the DT_RPATH dynamic section attribute of the binary if present and DT_RUNPATH attribute does not exist. Use of DT_RPATH is deprecated. o Using the environment variable LD_LIBRARY_PATH, unless the executable is being run in secure-execution mode (see below), in which case this variable is ignored. o Using the directories specified in the DT_RUNPATH dynamic section attribute of  the binary if present. Such directories are searched only to find those objects required by DT_NEEDED (direct dependencies) entries and do not apply to those objects' children, which must themselves have their own DT_RUNPATH entries. This is unlike DT_RPATH, which is applied to searches for all children in the dependency tree. o From the cache file /etc/ld.so.cache, which contains a compiled list of candidate shared objects previously found in the augmented library path. If, however, the binary was linked with the -z nodeflib linker option, shared objects in the default paths are skipped. Shared objects installed in hardware capability directories (see below)  are preferred to other shared objects. o In the default path /lib, and then /usr/lib. (On some 64-bit architectures, the default paths for 64-bit shared objects are /lib64, and then /usr/lib64.) If the binary was linked with the -z nodeflib linker option, this step is skipped.Copy the code

Symbol hidden

The third party has already compiled the library, introduced the corresponding header file, used one of the methods, the final link appears undefined symbol, this situation may be the library developer did not export the symbol of this method.

# use the nm command to view the exported function symbol, Here to see the License related function $nm - gDC libSXVideoEngineJni. So | grep -i License of 0000000000008110 T __ZN13SXVideoEngine6Public7License10SetLicenseEPKc 0000000000008130 T __ZN13SXVideoEngine6Public7License13LicenseStatusEv 0000000000008190 T __ZN13SXVideoEngine6Public7License19IsVideoCutSupportedEv 0000000000008170 T __ZN13SXVideoEngine6Public7License26IsDynamicTemplateSupportedEv 0000000000008150 T __ZN13SXVideoEngine6Public7License26IsStadardTemplateSupportedEv # nm return is not the original function name, By c + + filt waste to obtain original name $c + + filt waste __ZN13SXVideoEngine6Public7License10SetLicenseEPKc SXVideoEngine::Public::License::SetLicense(char const*)Copy the code

C++ Abi versions are inconsistent

Gcc’s new c++ features are added step by step, and if new features are implemented, it is possible to change the c++ abi and upgrade the version of glibc.

The most common Abi link errors are caused by different implementations of GCC 4.x and GCC 5.x of STD :: String and STD ::list. In GCC 4.x, GCC’s implementation of the standard string is placed in the STD namespace and expanded to STD ::basic_string at compile time. But starting with GCC 5.x, the implementation of string is in the STD ::__cxx11 space, which is compiled and expanded to STD ::__cxx11::basic_string. This results in a dynamic library compiled in GCC 4.x that exports STD ::basic_string if a function takes a string as an argument or return value. Unable to compile connection under GCC 5.x. Errors like this:

undefined symbol:  "std::__cxx11 ***"
Copy the code

A compromise in this case is to disable the c++11 abi by increasing -d_glibcxx_use_cxx11_abi =0 when compiling GCC 5.x or above. Of course, the best practice is to ensure that the major versions of the compiler are generally consistent. It is necessary to upgrade the GCC version and glibc in newly developed programs that use new c++ features.

Summary of Utility Commands

  1. The LDD command is used to check whether a library that a dynamic library depends on exists
Not found $ldd-r libsxvideoEngine. so linux-vdso.so.1 => (0x00007ffC337d2000) libz.so.1 => /lib64/libz.so.1 (0x00007f061cf41000) libX11.so.6 => /lib64/libX11.so.6 (0x00007f061cc03000) libEGL.so.1 =>  /lib64/libEGL.so.1 (0x00007f061c9ef000) libGLESv2.so.2 => /lib64/libGLESv2.so.2 (0x00007f061c7dd000) libpthread.so.0 =>  /lib64/libpthread.so.0 (0x00007f061c5c1000) libblend2d.so => /home/seeshion/workspace/SXVideoEngine-Core/Render/.. /.. /SXVideoEngine-Core-Lib/blend2d/linux/lib/libblend2d.so (0x00007f061c187000) libfreeimage.so.3 => /lib/libfreeimage.so.3  (0x00007f061b8ac000) libavcodec.so.58 => /lib/libavcodec.so.58 (0x00007f06198b6000) libavformat.so.58 => /lib/libavformat.so.58 (0x00007f06193e1000) libavutil.so.56 => /lib/libavutil.so.56 (0x00007f06190bd000) ...Copy the code
  1. The nm command is used to read symbols exported from the library
$ nm -gDC libSXVideoEngineJni.so | grep -i license 0000000000008110 T __ZN13SXVideoEngine6Public7License10SetLicenseEPKc  0000000000008130 T __ZN13SXVideoEngine6Public7License13LicenseStatusEv 0000000000008190 T __ZN13SXVideoEngine6Public7License19IsVideoCutSupportedEv 0000000000008170 T __ZN13SXVideoEngine6Public7License26IsDynamicTemplateSupportedEv 0000000000008150 T __ZN13SXVideoEngine6Public7License26IsStadardTemplateSupportedEvCopy the code
  1. Readelf Is used to read information about ELF files
$ readelf -d libSXVideoEngineJni.so | grep rpath
 0x000000000000000f (RPATH)              Library rpath: 
 [/home/slayer/workspace/SXVideoEngine-Core/Render/cmake-build-
 debug:/home/slayer/workspace/SXVideoEngine-Core/Render/../../SXVideoEngine-Core-Lib/blend2d/linux/lib]
Copy the code
  1. C++ filt is used to get the original name of the symbol
$ c++filt __ZN13SXVideoEngine6Public7License10SetLicenseEPKc
SXVideoEngine::Public::License::SetLicense(char const*)
Copy the code