C/C++ Library Mechanisms
The OpenHarmony NDK provides industry standard libraries libc and libc++. This topic describes the mechanisms of these libraries in OpenHarmony. Understanding these mechanisms helps you avoid pitfalls during NDK development.
C++ Compatibility
In OpenHarmony, both the system library and application native library use C++ standard library (see libc++). However, the C++ standard library used by the system library is updated with the image version, and the C++ standard library used by the application native library is updated with the SDK used for compilation. Since both the C++ standard libraries have multiple major versions, the different update approach may cause ABI compatibility issues. To solve this problem, OpenHarmony differentiates the two C++ standard libraries as follows:
- System library: uses libc++.so, which is released with the system image.
- Application native library: uses libc++_shared.so, which is released with the application.
The two libraries use different C++ namespaces. libc++.so uses __h, and libc++_shared.so uses __n1.
NOTE
The system and application cannot use the same C++ standard library. Native APIs are C APIs, which are used to isolate the C++ running environment. If the libc++_shared.so version in the HAR file is different from that of the application, incompatibility issues may occur. To solve this problem, use the same SDK version to update the HAR file.
Known C++ Compatibility Issues
If "symbol not found, s=__emutls_get_address" is reported when an application starts or when dlopen() is called, update the SDK of the application or HAR. This symbol is not provided by libc++_shared.so in the API version 9 or earlier, and is available since API version 11.
musl libc Dynamic Linker
Linker Namespace
Unlike the namespace in C++, a linker namespace (also referred to as ns) is a mechanism provided by the dynamic linker to isolate shared libraries within different namespaces. For example, the system native library can load the native library in the system directories, such as /system/lib64 or /vendor/lib64; a common application can load only the common application native library and NDK library, but cannot directly load the system native library.
The dynamic linker must be associated with a specific namespace when it loads the shared library specified by DT_NEEDED in compilation or calls dlopen to load a shared library.
OpenHarmony has the following types of linker namespaces:
-
Default ns: default namespace created for locating the .so files in /system/lib{abi} and /vendor/lib{abi} when the dynamic linker stats.
-
NDK ns: default namespace created for exposing the NDK interfaces in .so files in /system/lib{abi}/ndk when the dynamic linker stats.
-
App ns: namespace created when an application is started. It directs to the application installation path (sandbox path), that is, the .so file used to load the application.
The namespace mechanism restricts the invocation between the application native library and the system native library, as shown in the following figure.
The default ns and NDK ns can access all .so files of each other, but cannot access the .so files of the app ns. The app ns can access all .so files of the NDK ns, but cannot access the .so files of the default ns.

rpath
Run-time path (rpath) is a mechanism for specifying the runtime search path of a shared library. This mechanism allows a runtime search path to be embedded in an executable file or shared library. The dynamic linker uses this path to find required libraries.
The namespace mechanism allows an application to load only the native libraries in its installation directory (for example, libs/arm64 on the ARM64 platform). If an application needs to load multiple native libraries, the native library in the newly created directory cannot be loaded. In this case, you can use the rpath mechanism to specify the search path during compilation.
For example, libhello.so in the application installation directory lib/arm64 depends on libworld.so in the newly created directory lib/arm64/module. Set rpath in the CMakeLists.txt file of the application and compile the file, and run readelf to view the rpath of libhello.so. As shown in the following figure, $ORIGIN indicates the path of libhello.so. The application can load libworld.so in the module directory during running.
SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
SET(CMAKE_INSTALL_RPATH "\${ORIGIN}/module")

dlclose
You can use dlclose to uninstall a dynamic library.
symbol-version
symbol-version is a symbol retrieval mechanism provided by libc for symbol relocation in dynamic linking. It supports relocation of the symbols of different versions and helps solve the problem of duplicate symbols. For details, see LD Version Scripts (GNU Gnulib).
Fortified Check of the FD in select()
If the file descriptor (fd) passed in FD_SET or FD_CLR is not within the value range [0, 1024), abort crash will be triggered.
If the fd value passed in FD_ISSET is not within the value range [0, 1024), false will be returned.
Globalization
Since API version 12, locale in newlocale() and setlocale() can be set to any of the following values: C, C.UTF-8, en_US, en_US.UTF-8, zh_CN, and zh_CN.UTF-8. strtod_l, wcstod_l, and localeconv support the locale values zh_CN and zh_CN.UTF-8. Note that strtod_l() and wcstod_l() do not support conversion of hexadecimal numbers and floating-point numbers.
fdsan
File descriptor sanitizer (fdsan) helps detect the user-after-close and double-close issues of FDs.
Signal Usage
To avoid conflicts with system reserved signals, comply with the following rules when using signals:
- Signals 1 to 34 are reserved for the system and cannot be used.
- Signals 35 to 45 have been occupied by internal system modules (such as memory, DFX, runtime, and system services) by API version 19. To avoid conflicts with system behaviors and unexpected problems, do not use these signals.
- The values of SIGRTMIN and __libc_current_sigrtmin are 35, indicating the start number of real-time signals available to applications (applications can actually use only signals 46 and later).
The HarmonyOS internal signals are as follows.
| ID | Name | Description | ID | Name | Description |
|---|---|---|---|---|---|
| 1 | SIGHUP | Terminal suspension control. | 24 | SIGXCPU | CPU time limit exceeded. |
| 2 | SIGINT | Interrupted. | 25 | SIGXFSZ | Maximum file size exceeded. |
| 3 | SIGQUIT | Keyboard exit. | 26 | SIGVTALRM | Virtual timer. |
| 4 | SIGILL | Invalid instruction. | 27 | SIGPROF | Profiling timer expired. |
| 5 | SIGTRAP | Debug breakpoint. | 28 | SIGWINCH | Terminal window size changed. |
| 6 | SIGABRT | Aborted. | 29 | SIGIO | I/O availability notification. |
| 7 | SIGBUS | Bus error. | 30 | SIGPWR | Power fault. |
| 8 | SIGFPE | Arithmetic exception. | 31 | SIGSYS | Invalid system call. |
| 9 | SIGKILL | Forcible termination. | 32 | SIGTIMER | Timer. |
| 10 | SIGUSR1 | Custom signal 1. | 33 | SIGCANCEL | Thread canceled. |
| 11 | SIGSEGV | Invalid memory access. | 34 | SIGSYNCCALL | Synchronous call. |
| 12 | SIGUSR2 | Custom signal 2. | 35 | MUSL_SIGNAL_NATIVE_REMOTE (SIGRTMIN + 0) | System reserved. |
| 13 | SIGPIPE | Pipe damaged. | 36 | MUSL_SIGNAL_HOOK (SIGRTMIN + 1) | System reserved. |
| 14 | SIGALRM | Alarm. | 37 | MUSL_SIGNAL_UNHOOK (SIGRTMIN + 2) | System reserved. |
| 15 | SIGTERM | Application termination request. | 38 | MUSL_SIGNAL_NATIVE_LOCAL (SIGRTMIN + 3) | System reserved. |
| 16 | SIGSTKFLT | Coprocessor stack error. | 39 | MUSL_SIGNAL_JSHEAP (SIGRTMIN + 4) | System reserved. |
| 17 | SIGCHLD | Child process exit/stop. | 40 | MUSL_SIGNAL_JSHEAP_PRIV (SIGRTMIN + 5) | System reserved. |
| 18 | SIGCONT | Continue the execution. | 41 | MUSL_SIGNAL_SAMPLE_STACK (SIGRTMIN + 6) | System reserved. |
| 19 | SIGSTOP | Forcible stop. | 42 | MUSL_SIGNAL_LEAK_STACK (SIGRTMIN + 7) | System reserved. |
| 20 | SIGTSTP | Stop inputting on the terminal. | 43 | MUSL_SIGNAL_RECYCLE_JEMALLOC (SIGRTMIN + 8) | System reserved. |
| 21 | SIGTTIN | Background terminal reading. | 44 | MUSL_SIGNAL_MEMCHECK (SIGRTMIN + 9) | System reserved. |
| 22 | SIGTTOU | Background terminal writing. | 45 | MUSL_SIGNAL_FDTRACK (SIGRTMIN + 10) | System reserved. |
| 23 | SIGURG | Socket has urgent data. | - | - | - |