You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CMake无法隐藏符号但Android.mk可行,求助解决-fvisibility=hidden失效问题

Android NDK下CMake符号隐藏失效问题排查与解决

问题现象

在Android NDK环境中,使用CMake配置set(CMAKE_CXX_VISIBILITY_PRESET hidden),或给target添加-fvisibility=hidden编译选项,均无法实现符号隐藏。但-Wl,-Bsymbolic等其他编译选项可正常生效,编译宏也能正确传递。相同NDK环境下,用Android.mk配置-fvisibility=hidden却能成功隐藏符号。

相关配置与输出

CMakeLists.txt内容

cmake_minimum_required(VERSION 3.20)
project(multp)

message("generator: ${CMAKE_GENERATOR_PLATFORM}")
message("CMAKE_SIZEOF_VOID_P is ${CMAKE_SIZEOF_VOID_P}")
message("CMAKE_SYSTEM_NAME is ${CMAKE_SYSTEM_NAME}")
enable_testing()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
set(CMAKE_C_VISIBILITY_PRESET hidden)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
include(build/cmake/cmake-definition.cmake)
include(build/cmake/Format.cmake)
add_subdirectory(vendors/openssl/1.1.1s)
add_subdirectory(vendors/rapidjson)
add_subdirectory(vendors/gmssl)
add_subdirectory(platform/multp)
target_link_libraries(multp PUBLIC  gmssl rapidjson)
target_compile_options(multp PRIVATE "-Wl,--exclude-libs,ALL" "-Wl,-Bsymbolic" "-fvisibility=hidden")
target_link_options(multp PRIVATE "-Wl,--exclude-libs,ALL" "-Wl,-Bsymbolic" "-fvisibility=hidden")

编译命令行

cmake -DANDROID_ABI=arm64-v8a -DHDMW_CODEC_ENABLED=TRUE -DANDROID_PLATFORM=android-23 -DANDROID_STL=c++_shared -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=G:\Android\SDK\ndk\23.1.7779620\build\cmake\android.toolchain.cmake -DCMAKE_SYSTEM_NAME=Android -B ./cmake-android -S . -G Ninja

Android.mk内容

APP_STL        := c++_shared

APP_CFLAGS     += -O3 -DANDROID \
                  -Werror=return-type \
                  -Werror=implicit-int \
                  -Werror=incompatible-pointer-types \
                  -Werror=shadow \
                  -Werror=return-stack-address \
                  -Werror=uninitialized \
                  -Werror=format \
                  -Werror=sign-compare \
                  -Werror=int-conversion \
                  -Werror=inconsistent-missing-override \
                  -Werror=implicit-function-declaration \
                  -fvisibility=hidden

ifeq ($(NDK_DEBUG),1)
APP_CFLAGS     += -fsanitize=address \
                  -fno-omit-frame-pointer
APP_LDFLAGS    := -fsanitize=address
endif

ifdef BUILD_VERSION
APP_CFLAGS     += -DBUILD_VERSION=$(BUILD_VERSION)
endif

APP_CPPFLAGS   := $(APP_CFLAGS) -fexceptions -std=c++14

APP_PLATFORM   := android-21

#set as the ndk-build option,
#like this: ndk-build NDK_DEBUG=0/1
#0:release, 1:debug
#APP_OPTIM     := release

#the new ndk not support this setting.
#NDK_TOOLCHAIN_VERSION := 4.9

APP_ABI        := armeabi-v7a arm64-v8a
LOCAL_C_INCLUDES += \
                    $(LOCAL_PATH)/src \
                    $(LOCAL_PATH)/h \
                    $(LOCAL_PATH)/../../vendors/gmssl/include \
                    $(LOCAL_PATH)/../../vendors/openssl/1.1.1s/include

LOCAL_CFLAGS := $(MY_COMMON_DEFS)
LOCAL_CPPFLAGS += -frtti -fexceptions

LOCAL_LDLIBS += -lz -ldl -llog
LOCAL_STATIC_LIBRARIES := libgmssl \
                          libssl \
                          libcrypto 

nm命令输出

work-dir> nm -CD libmultp.so
                 U __cmsg_nxthdr
                 U __cxa_allocate_exception
                 U __cxa_atexit
                 U __cxa_begin_catch
                 U __cxa_end_catch
                 U __cxa_finalize
                 U __cxa_free_exception
                 U __cxa_pure_virtual
                 U __cxa_rethrow
                 U __cxa_throw
                 U __errno
                 U __FD_ISSET_chk
                 U __FD_SET_chk
                 U __gxx_personality_v0
                 U __register_atfork
                 U __sF
00000000001cfb9c T crc32_fast(void const*, unsigned long, unsigned int)
0000000000154b90 W void TrimString<CCmIsSpace>(CCmString&, CCmIsSpace)
000000000014bda0 T CalcCRC16_m(unsigned short&, CCmMessageBlock&, unsigned int)
00000000001d0224 T crc32_1byte(void const*, unsigned long, unsigned int)
00000000001403ac T init_config(char const*)
000000000015648c W void LTrimString<CCmIsSpace>(CCmString&, CCmIsSpace)
0000000000156534 W void RTrimString<CCmIsSpace>(CCmString&, CCmIsSpace)
000000000013fb10 T trim_string(char*)
00000000001d04bc T crc32_4bytes(void const*, unsigned long, unsigned int)
00000000001d05fc T crc32_8bytes(void const*, unsigned long, unsigned int)
0000000000141664 T get_local_ip()
00000000001b0e08 T ipv4_enabled()
00000000001b0db8 T ipv6_enabled()
0000000000141308 T resolve_2_ip(char*, char*)
00000000001d09ec T crc32_16bytes(void const*, unsigned long, unsigned int)
00000000001d00d4 T crc32_bitwise(void const*, unsigned long, unsigned int)
00000000001d0fc4 T crc32_combine(unsigned int, unsigned int, unsigned long)

排查与解决方法

  1. 检查CMAKE_CXX_VISIBILITY_PRESET生效时机
    CMAKE_CXX_VISIBILITY_PRESET必须在add_subdirectory或add_library/add_executable之前设置才会对目标生效。当前配置中虽已提前设置,但需确认build/cmake/cmake-definition.cmake是否覆盖了该变量,若有覆盖会导致原配置失效。

  2. 修正选项位置错误
    target_compile_options中不应包含-Wl,--exclude-libs,ALL和-Wl,-Bsymbolic这类链接选项,需将其移至target_link_options,仅保留编译相关选项:

    target_compile_options(multp PRIVATE "-fvisibility=hidden")
    target_link_options(multp PRIVATE "-Wl,--exclude-libs,ALL" "-Wl,-Bsymbolic")
    
  3. 补充C++符号隐藏辅助配置
    对于C++代码,需额外启用内联函数符号隐藏:

    set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
    

    该配置确保内联函数的符号不会暴露到最终SO中。

  4. 验证编译选项是否实际传递
    执行编译命令时添加VERBOSE=1,查看实际编译参数中是否包含-fvisibility=hidden:

    cmake --build ./cmake-android -- VERBOSE=1
    

    若未找到该选项,说明CMake配置被其他逻辑覆盖,需检查目标的编译选项优先级。

  5. 处理模板函数符号
    nm输出中的TrimString<CCmIsSpace>等模板符号(标记为W),需添加额外编译选项处理:

    target_compile_options(multp PRIVATE "-fvisibility-inlines-hidden")
    

    或在模板声明前手动添加__attribute__((visibility("hidden"))),强制隐藏模板实例化符号。

  6. 排查第三方依赖符号传递
    链接的gmssl、openssl等静态库若未启用符号隐藏,会将自身符号暴露到最终SO中。可尝试给第三方库也添加符号隐藏配置,或确认-Wl,--exclude-libs,ALL是否生效,彻底排除静态库的符号。


内容的提问来源于stack exchange,提问作者qian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 23:07:03