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

Swift中-dead_strip选项无法移除未使用类的问题咨询

关于Swift静态库-dead_strip选项无法移除未使用类的问题

场景复现

我创建了一个仅含单个源文件的简单Swift静态库,用于测试-dead_strip选项,代码如下:

public class UsedClass {
    public init() {}
    public func function() { print("print") }
}
public class PublicClas {
    func private_func() { print("print") }
}
class SimpleClass {
    func private_func() { print("print") }
}
public struct PublicStruct {
    func private_func() { print("print") }
}
struct SimpleStruct {
    func private_func() { print("print") }
}

同时创建了一个仅依赖该静态库中UsedClass类的动态库,代码如下:

public class MyClass {
    public func callModule() {
        let qq = UsedClass()
        qq.function()
    }
}

使用-dead_strip选项链接动态库后,执行命令nm -m test_lib | grep SimpleClass,发现二进制中仍保留SimpleClass的相关符号,输出如下:

0000000100003d54 (__TEXT,__const) non-external (was a private external) _$s13TestFramework11SimpleClassC11public_funcyyFTq
0000000100003d5c (__TEXT,__const) non-external (was a private external) _$s13TestFramework11SimpleClassC12private_funcyyFTq
0000000100003d64 (__TEXT,__const) non-external (was a private external) _$s13TestFramework11SimpleClassCACycfCTq
0000000100003e58 (__TEXT,__swift5_fieldmd) non-external _$s13TestFramework11SimpleClassCMF
0000000100003a38 (__TEXT,__text) non-external (was a private external) _$s13TestFramework11SimpleClassCMa
00000001000083e0 (__DATA,__data) non-external _$s13TestFramework11SimpleClassCMf
00000001000083b8 (__DATA,__data) non-external (was a private external) _$s13TestFramework11SimpleClassCMm
0000000100003d20 (__TEXT,__const) non-external (was a private external) _$s13TestFramework11SimpleClassCMn
00000001000083f0 (__DATA,__data) non-external (was a private external) _$s13TestFramework11SimpleClassCN
0000000100003a6c (__TEXT,__text) non-external (was a private external) _$s13TestFramework11SimpleClassCfD
0000000100008198 (__DATA,__objc_const) non-external __DATA__TtC13TestFramework11SimpleClass
0000000100008150 (__DATA,__objc_const) non-external __METACLASS_DATA__TtC13TestFramework11SimpleClass
0000000100003e24 (__TEXT,__swift5_typeref) non-external (was a private external) _symbolic ______ 13TestFramework11SimpleClassC

我已移除-ObjC选项,并尝试添加-internalize-at-link选项,但结果一致,仅私有结构体被移除。已知Apple静态库与Unix静态库存在差异,但不清楚具体区别,且认为该场景下常规C++链接器可移除未使用类,特此咨询原因及解决办法。

原因分析

  1. 链接粒度与元数据依赖:Unix静态库通常以单个目标文件(.o)为单位进行链接,若某个.o文件无引用则直接丢弃;但Swift静态库中,所有类都放在同一个源文件时,编译器会生成包含所有类型元数据的单个.o文件,链接器无法拆分其中的单个类符号进行移除——因为元数据、类型引用链是绑定在一起的,链接器无法判定SimpleClass的元数据完全没有被潜在引用。
  2. Swift与ObjC的兼容机制:即使是纯Swift类,编译时也会生成类似ObjC的类结构数据(如输出中的__DATA__TtC开头符号),这些数据会被Swift运行时的类型系统所依赖,链接器默认会保留这类元数据,避免运行时崩溃。
  3. -dead_strip的局限性:该选项主要针对显式未被引用的函数和数据,但Swift的类型信息、虚表等属于隐式依赖范畴,链接器无法精准判断这些是否属于“无用代码”,因此不会主动移除。

解决办法

  • 拆分源文件:将每个类单独放在一个.swift文件中,这样编译后每个类对应一个独立的.o文件。链接时,若某个.o文件完全无引用,会被-dead_strip直接排除。
  • 标记内部私有符号:使用Swift的@_spi(Private)标记未对外暴露的类,明确告知编译器该类仅内部使用,链接器可安全移除未被引用的相关符号:
    @_spi(Private) class SimpleClass {
        func private_func() { print("print") }
    }
    
  • 开启全模块优化:编译静态库时添加-whole-module-optimization选项,编译器会进行全局代码分析,标记真正未被使用的符号,帮助链接器更精准地执行dead strip。
  • 手动移除符号:使用-dead_strip_symbols选项配合符号列表文件,手动指定需要移除的SimpleClass相关符号,不过这种方式维护成本较高,仅适合特殊场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 19:18:10