Why public symbols are always no_dead_strip?

I noticed Swift public symbols are always marked as no_dead_strip, so the public symbols defined in a static library won't be stripped from the executable even they're not used, which results in larger binary size.

I'm wondering why public symbols are default to no_dead_strip. Is there a way to control this behavior?


Here is the sample code,

// lib.swift
public struct PublicStruct {
    public func f1() { print("public print") }
}

struct InternalStruct {
    func f2() { print("internal print") }
}
> swiftc -parse-as-library -c -o lib.o -Xfrontend -disable-reflection-metadata lib.swift
> nm -m lib.o | grep "no dead strip"
0000000000000000 (__TEXT,__text) external [no dead strip] _$s3lib12PublicStructV2f1yyF
00000000000001c0 (__TEXT,__text) external [no dead strip] _$s3lib12PublicStructVMa
000000000000021c (__TEXT,__const) external [no dead strip] _$s3lib12PublicStructVMn
0000000000000270 (__DATA,__const) external [no dead strip] [alt entry] _$s3lib12PublicStructVN
0000000000000264 (__TEXT,__const) weak private external [no dead strip] ___swift_reflection_version
00000000000002a0 (__LLVM,__swift_modhash) non-external [no dead strip] l_llvm.swift_module_hash
0000000000000298 (__TEXT,__swift5_types) non-external [no dead strip] l_type_metadata_table

As you can see, public symbols are no dead strip while internal symbols are not. I also verified that the string "internal print" can be stripped away by the linker while "public print" cannot.

2 Likes

It's not strictly necessary; it's a legacy of Swift's original priorities being to support dynamic libraries with stable ABIs, and we're working to make it unnecessary when building static libraries. See:

8 Likes

Thank you for the quick response. It's good to know that there is some good progress on that already.

I'm currently thinking for some prebuilt 3rd party libraries, maybe I can write a tool to scrub the symbol table and mark off N_NO_DEAD_STRIP in nlist.n_desc field. Anything obviously wrong with this approach?

You'll want to be careful, because there are things that might rely on runtime lookup that won't be obviously alive to the linker, like metadata for types that are looked up by name, or protocol conformances for types that are dynamically cast using as? Protocol casts. For most other things, that should be safe, though.

1 Like

We need to decide whether "reflection on types you don't use" is the right default. I think it would be much better to have a "don't strip" attribute you can opt into.

4 Likes

This is a pretty big problem for getting (e.g.) the stdlib to scale down right now. It isn't a matter of just LTO'ing your app and the stdlib together, it is a language issue that all those protocols (and their metadata etc) aren't strippable.

In fact there is an active thread about this right now.

Also this one:

I agree that having types be reflectable by default is unnecessary and it should ultimately be opt-in.

1 Like
Terms of Service

Privacy Policy

Cookie Policy