swift-argument-parser icon indicating copy to clipboard operation
swift-argument-parser copied to clipboard

Use FoundationEssentials if it's available

Open 0xTim opened this issue 1 year ago • 6 comments

Use FoundationEssentials if it's available. This stops all of Foundation being linked when not needed and reduces binary sizes

Checklist

  • [x] I've added at least one test that validates that my change is working, if appropriate
  • [x] I've followed the code style of the rest of the project
  • [x] I've read the Contribution Guidelines
  • [x] I've updated the documentation if necessary

0xTim avatar Oct 24 '24 11:10 0xTim

@swift-ci test

MaxDesiatov avatar Oct 24 '24 12:10 MaxDesiatov

@swift-ci test

MaxDesiatov avatar Oct 24 '24 14:10 MaxDesiatov

This feature will also be very useful to me. After applying the patch locally I still see libFoundationInternationalization.so being pulled in, though:

lukeh@liebling:~/CVSRoot/apple/swift-argument-parser$ ldd .build/debug/color
	linux-vdso.so.1 (0x0000fe8b15062000)
	libFoundationInternationalization.so => /opt/swift-6.0.2-RELEASE-ubuntu24.04-aarch64/usr/lib/swift/linux/libFoundationInternationalization.so (0x0000fe8b14800000)
	libFoundationEssentials.so => /opt/swift-6.0.2-RELEASE-ubuntu24.04-aarch64/usr/lib/swift/linux/libFoundationEssentials.so (0x0000fe8b14200000)
	libswiftSwiftOnoneSupport.so => /opt/swift-6.0.2-RELEASE-ubuntu24.04-aarch64/usr/lib/swift/linux/libswiftSwiftOnoneSupport.so (0x0000fe8b14fd0000)
	libswiftCore.so => /opt/swift-6.0.2-RELEASE-ubuntu24.04-aarch64/usr/lib/swift/linux/libswiftCore.so (0x0000fe8b13a00000)
	libswift_Concurrency.so => /opt/swift-6.0.2-RELEASE-ubuntu24.04-aarch64/usr/lib/swift/linux/libswift_Concurrency.so (0x0000fe8b14f20000)
	libswift_StringProcessing.so => /opt/swift-6.0.2-RELEASE-ubuntu24.04-aarch64/usr/lib/swift/linux/libswift_StringProcessing.so (0x0000fe8b14b10000)
	libswift_RegexParser.so => /opt/swift-6.0.2-RELEASE-ubuntu24.04-aarch64/usr/lib/swift/linux/libswift_RegexParser.so (0x0000fe8b140e0000)
	libswiftGlibc.so => /opt/swift-6.0.2-RELEASE-ubuntu24.04-aarch64/usr/lib/swift/linux/libswiftGlibc.so (0x0000fe8b14ef0000)
	libBlocksRuntime.so => /opt/swift-6.0.2-RELEASE-ubuntu24.04-aarch64/usr/lib/swift/linux/libBlocksRuntime.so (0x0000fe8b14ec0000)
	libdispatch.so => /opt/swift-6.0.2-RELEASE-ubuntu24.04-aarch64/usr/lib/swift/linux/libdispatch.so (0x0000fe8b14a90000)
	libswiftDispatch.so => /opt/swift-6.0.2-RELEASE-ubuntu24.04-aarch64/usr/lib/swift/linux/libswiftDispatch.so (0x0000fe8b14e70000)
	libFoundation.so => /opt/swift-6.0.2-RELEASE-ubuntu24.04-aarch64/usr/lib/swift/linux/libFoundation.so (0x0000fe8b13200000)
	libm.so.6 => /lib/aarch64-linux-gnu/libm.so.6 (0x0000fe8b13950000)
	libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000fe8b13040000)
	/lib/ld-linux-aarch64.so.1 (0x0000fe8b15025000)
	lib_FoundationICU.so => /opt/swift-6.0.2-RELEASE-ubuntu24.04-aarch64/usr/lib/swift/linux/lib_FoundationICU.so (0x0000fe8b10a00000)
	libgcc_s.so.1 => /lib/aarch64-linux-gnu/libgcc_s.so.1 (0x0000fe8b14a40000)
	libswiftSynchronization.so => /opt/swift-6.0.2-RELEASE-ubuntu24.04-aarch64/usr/lib/swift/linux/libswiftSynchronization.so (0x0000fe8b14a10000)
	libstdc++.so.6 => /lib/aarch64-linux-gnu/libstdc++.so.6 (0x0000fe8b10600000)

This is my last Foundation dependency for a particular daemon which will shrink the stripped/release/static stdlib size from 62MB to 14MB.

lhoward avatar Jan 03 '25 22:01 lhoward

After applying the patch:

lukeh@liebling:~/CVSRoot/apple/swift-argument-parser/.build/debug/ArgumentParser.build$ nm *.o|grep Foundation|grep -v FoundationEssentials|sort|uniq|grep "U "|awk '{print $2}'|xargs swift-demangle 
$s10Foundation7NSErrorCMa ---> type metadata accessor for Foundation.NSError
$ss5ErrorP10FoundationE20localizedDescriptionSSvg ---> (extension in Foundation):Swift.Error.localizedDescription.getter : Swift.String
$sSy10FoundationE20replacingOccurrences2of4with7options5rangeSSqd___qd_0_SS0A10EssentialsE14CompareOptionsVSnySS5IndexVGSgtSyRd__SyRd_0_r0_lF ---> (extension in Foundation):Swift.StringProtocol.replacingOccurrences<A, B where A1: Swift.StringProtocol, B1: Swift.StringProtocol>(of: A1, with: B1, options: (extension in FoundationEssentials):Swift.String.CompareOptions, range: Swift.Range<Swift.String.Index>?) -> Swift.String
$sSy10FoundationE5range2of7optionsAB6localeSnySS5IndexVGSgqd___SS0A10EssentialsE14CompareOptionsVAiJ6LocaleVSgtSyRd__lF ---> (extension in Foundation):Swift.StringProtocol.range<A where A1: Swift.StringProtocol>(of: A1, options: (extension in FoundationEssentials):Swift.String.CompareOptions, range: Swift.Range<Swift.String.Index>?, locale: FoundationEssentials.Locale?) -> Swift.Range<Swift.String.Index>?
$sSy10FoundationE8containsySbqd__SyRd__lF ---> (extension in Foundation):Swift.StringProtocol.contains<A where A1: Swift.StringProtocol>(A1) -> Swift.Bool

It turns out we need to enable Swift 6 language mode for the #if swift(>=6.0) guards to work. If we remove those:

/home/lukeh/CVSRoot/apple/swift-argument-parser/Sources/ArgumentParser/Usage/MessageInfo.swift: 0:
/home/lukeh/CVSRoot/apple/swift-argument-parser/Sources/ArgumentParser/Usage/MessageInfo.swift:14:23: error: class 'NSError' does not exist in module 'FoundationEssentials'
 12 | #if canImport(FoundationEssentials)
 13 | internal import protocol FoundationEssentials.LocalizedError
 14 | internal import class FoundationEssentials.NSError
    |                       `- error: class 'NSError' does not exist in module 'FoundationEssentials'

What we could do is only use LocalisedError and localizedDescription on Darwin.

That still leaves replacingOccurrences(of:with:), range(of:) and contains(). I suppose these shouldn't be difficult to reimplement.

lhoward avatar Jan 04 '25 05:01 lhoward

@swift-ci Please test

natecook1000 avatar Jan 22 '25 06:01 natecook1000

This still isn't working for me on Linux.

lukeh@liebling:~/CVSRoot/apple/swift-argument-parser$ swift --version
Swift version 6.0.2 (swift-6.0.2-RELEASE)
Target: aarch64-unknown-linux-gnu
lukeh@liebling:~/CVSRoot/apple/swift-argument-parser$ ldd .build/debug/color|grep libFoundation
	libFoundationInternationalization.so => /opt/swift-6.0.2-RELEASE-ubuntu24.04-aarch64/usr/lib/swift/linux/libFoundationInternationalization.so (0x0000f81b2a400000)
	libFoundationEssentials.so => /opt/swift-6.0.2-RELEASE-ubuntu24.04-aarch64/usr/lib/swift/linux/libFoundationEssentials.so (0x0000f81b29e00000)
	libFoundation.so => /opt/swift-6.0.2-RELEASE-ubuntu24.04-aarch64/usr/lib/swift/linux/libFoundation.so (0x0000f81b28e00000)

The issue is the one I described before:

lukeh@liebling:~/CVSRoot/apple/swift-argument-parser/.build/debug$ nm color|grep ' U $sSy10Foundation'
                 U $sSy10FoundationE20replacingOccurrences2of4with7options5rangeSSqd___qd_0_SS0A10EssentialsE14CompareOptionsVSnySS5IndexVGSgtSyRd__SyRd_0_r0_lF
                 U $sSy10FoundationE5range2of7optionsAB6localeSnySS5IndexVGSgqd___SS0A10EssentialsE14CompareOptionsVAiJ6LocaleVSgtSyRd__lF
                 U $sSy10FoundationE8containsySbqd__SyRd__lF

lhoward avatar Jan 23 '25 22:01 lhoward

superseded by: #804

rauhul avatar Sep 09 '25 20:09 rauhul