Skip to content

Commit 6ef6d96

Browse files
authored
Merge pull request #185 from giginet/strip-debug-symbol
Add feature to strip DWARF symbols from the final binary
2 parents 56379ba + 9c807e7 commit 6ef6d96

File tree

13 files changed

+131
-25
lines changed

13 files changed

+131
-25
lines changed

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
swift build
2727
- name: Run Tests
2828
run: |
29-
swift test
29+
swift test --no-parallel
3030
env:
3131
ENABLE_INTEGRATION_TESTS: 1
3232
IS_CI: 1

Sources/ScipioKit/BuildOptions.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ struct BuildOptions: Hashable, Codable, Sendable {
1313
extraBuildParameters: ExtraBuildParameters?,
1414
enableLibraryEvolution: Bool,
1515
keepPublicHeadersStructure: Bool,
16-
customFrameworkModuleMapContents: Data?
16+
customFrameworkModuleMapContents: Data?,
17+
stripDWARFSymbols: Bool
1718
) {
1819
self.buildConfiguration = buildConfiguration
1920
self.isDebugSymbolsEmbedded = isDebugSymbolsEmbedded
@@ -24,6 +25,7 @@ struct BuildOptions: Hashable, Codable, Sendable {
2425
self.enableLibraryEvolution = enableLibraryEvolution
2526
self.keepPublicHeadersStructure = keepPublicHeadersStructure
2627
self.customFrameworkModuleMapContents = customFrameworkModuleMapContents
28+
self.stripDWARFSymbols = stripDWARFSymbols
2729
}
2830

2931
let buildConfiguration: BuildConfiguration
@@ -38,6 +40,14 @@ struct BuildOptions: Hashable, Codable, Sendable {
3840
/// - Note: It have to store the actual file contents rather than its path,
3941
/// because the cache key should change when the file contents change.
4042
let customFrameworkModuleMapContents: Data?
43+
44+
/// Whether DWARF symbols are stripped from the final binary.
45+
/// The compiler will embed DWARF information in the final binary.
46+
/// However, it contains absolute path of the build machine, so it's not suitable for distribution.
47+
/// It causes a problem when the debugger loads the symbols. (e.g. *.pcm is not found)
48+
/// If you set the option, you should use dSYM file for debugging instead.
49+
/// Set `DEBUG_INFORMATION_FORMAT = dwarf-with-dsym` to make dSYM instead of embedding debug symbols.
50+
let stripDWARFSymbols: Bool
4151
}
4252

4353
public struct ExtraFlags: Hashable, Codable, Sendable {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import Foundation
2+
3+
/// Strip debug symbols from a binary.
4+
struct DWARFSymbolStripper {
5+
private let executor: any Executor
6+
7+
init(executor: some Executor) {
8+
self.executor = executor
9+
}
10+
11+
func stripDebugSymbol(_ binaryPath: URL) async throws {
12+
try await executor.execute(
13+
"/usr/bin/xcrun",
14+
"strip",
15+
"-S",
16+
binaryPath.path(percentEncoded: false)
17+
)
18+
}
19+
}

Sources/ScipioKit/Producer/PIF/FrameworkBundleAssembler.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ struct FrameworkBundleAssembler {
2626
}
2727

2828
@discardableResult
29-
func assemble() throws -> TSCAbsolutePath {
29+
func assemble() throws -> URL {
3030
try fileSystem.createDirectory(frameworkBundlePath, recursive: true)
3131

3232
try copyBinary()
@@ -46,7 +46,7 @@ struct FrameworkBundleAssembler {
4646
destinationFrameworkBundlePath: frameworkBundlePath
4747
)
4848

49-
return frameworkBundlePath
49+
return frameworkBundlePath.asURL
5050
}
5151

5252
private func copyBinary() throws {

Sources/ScipioKit/Producer/PIF/PIFCompiler.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ struct PIFCompiler: Compiler {
6060
packageLocator: descriptionPackage
6161
)
6262

63+
let debugSymbolStripper = DWARFSymbolStripper(executor: executor)
64+
6365
for sdk in sdks {
6466
let toolchain = try await makeToolchain(for: sdk)
6567
let buildParameters = try makeBuildParameters(toolchain: toolchain)
@@ -78,11 +80,17 @@ struct PIFCompiler: Compiler {
7880
)
7981

8082
do {
81-
try await xcBuildClient.buildFramework(
83+
let frameworkBundlePath = try await xcBuildClient.buildFramework(
8284
sdk: sdk,
8385
pifPath: pifPath,
8486
buildParametersPath: buildParametersPath
8587
)
88+
89+
if buildOptions.stripDWARFSymbols && buildOptions.frameworkType == .static {
90+
logger.info("🐛 Stripping debug symbols")
91+
let binaryPath = frameworkBundlePath.appending(component: buildProduct.target.c99name)
92+
try await debugSymbolStripper.stripDebugSymbol(binaryPath)
93+
}
8694
} catch {
8795
logger.error("Unable to build for \(sdk.displayName)", metadata: .color(.red))
8896
logger.error(error)

Sources/ScipioKit/Producer/PIF/XCBuildClient.swift

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ struct XCBuildClient {
5151
sdk: SDK,
5252
pifPath: TSCAbsolutePath,
5353
buildParametersPath: TSCAbsolutePath
54-
) async throws {
54+
) async throws -> URL {
5555
let xcbuildPath = try await fetchXCBuildPath()
5656

5757
let executor = XCBuildExecutor(xcbuildPath: xcbuildPath)
@@ -63,16 +63,14 @@ struct XCBuildClient {
6363
target: buildProduct.target
6464
)
6565

66-
try assembleFramework(sdk: sdk)
67-
68-
// Copy modulemap to built frameworks
69-
// xcbuild generates modulemap for each frameworks
70-
// However, these are not includes in Frameworks
71-
// So they should be copied into frameworks manually.
72-
// try copyModulemap(for: sdk)
66+
let frameworkBundlePath = try assembleFramework(sdk: sdk)
67+
return frameworkBundlePath
7368
}
7469

75-
private func assembleFramework(sdk: SDK) throws {
70+
/// Assemble framework from build artifacts
71+
/// - Parameter sdk: SDK
72+
/// - Returns: Path to assembled framework bundle
73+
private func assembleFramework(sdk: SDK) throws -> URL {
7674
let frameworkComponentsCollector = FrameworkComponentsCollector(
7775
buildProduct: buildProduct,
7876
sdk: sdk,
@@ -95,7 +93,7 @@ struct XCBuildClient {
9593
fileSystem: fileSystem
9694
)
9795

98-
try assembler.assemble()
96+
return try assembler.assemble()
9997
}
10098

10199
private func assembledFrameworkPath(target: ScipioResolvedModule, of sdk: SDK) throws -> TSCAbsolutePath {

Sources/ScipioKit/Runner.swift

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ extension Runner {
132132
public var keepPublicHeadersStructure: Bool
133133
/// An option indicates use custom modulemaps for distributionb
134134
public var frameworkModuleMapGenerationPolicy: FrameworkModuleMapGenerationPolicy
135+
/// Whether to strip DWARF symbols or not
136+
public var stripDWARFSymbols: Bool
135137

136138
public init(
137139
buildConfiguration: BuildConfiguration = .release,
@@ -143,7 +145,8 @@ extension Runner {
143145
extraBuildParameters: [String: String]? = nil,
144146
enableLibraryEvolution: Bool = false,
145147
keepPublicHeadersStructure: Bool = false,
146-
frameworkModuleMapGenerationPolicy: FrameworkModuleMapGenerationPolicy = .autoGenerated
148+
frameworkModuleMapGenerationPolicy: FrameworkModuleMapGenerationPolicy = .autoGenerated,
149+
stripDWARFSymbols: Bool = false
147150
) {
148151
self.buildConfiguration = buildConfiguration
149152
self.platforms = platforms
@@ -155,6 +158,7 @@ extension Runner {
155158
self.enableLibraryEvolution = enableLibraryEvolution
156159
self.keepPublicHeadersStructure = keepPublicHeadersStructure
157160
self.frameworkModuleMapGenerationPolicy = frameworkModuleMapGenerationPolicy
161+
self.stripDWARFSymbols = stripDWARFSymbols
158162
}
159163
}
160164
public struct TargetBuildOptions {
@@ -170,6 +174,8 @@ extension Runner {
170174
/// If this is false or nil, public headers are copied to Headers directory flattened (default).
171175
public var keepPublicHeadersStructure: Bool?
172176
public var frameworkModuleMapGenerationPolicy: FrameworkModuleMapGenerationPolicy?
177+
/// Whether to strip DWARF symbols or not
178+
public var stripDWARFSymbols: Bool?
173179

174180
public init(
175181
buildConfiguration: BuildConfiguration? = nil,
@@ -181,7 +187,8 @@ extension Runner {
181187
extraBuildParameters: [String: String]? = nil,
182188
enableLibraryEvolution: Bool? = nil,
183189
keepPublicHeadersStructure: Bool? = nil,
184-
frameworkModuleMapGenerationPolicy: FrameworkModuleMapGenerationPolicy? = nil
190+
frameworkModuleMapGenerationPolicy: FrameworkModuleMapGenerationPolicy? = nil,
191+
stripDWARFSymbols: Bool? = nil
185192
) {
186193
self.buildConfiguration = buildConfiguration
187194
self.platforms = platforms
@@ -193,6 +200,7 @@ extension Runner {
193200
self.enableLibraryEvolution = enableLibraryEvolution
194201
self.keepPublicHeadersStructure = keepPublicHeadersStructure
195202
self.frameworkModuleMapGenerationPolicy = frameworkModuleMapGenerationPolicy
203+
self.stripDWARFSymbols = stripDWARFSymbols
196204
}
197205
}
198206

@@ -330,7 +338,8 @@ extension Runner.Options.BuildOptions {
330338
extraBuildParameters: extraBuildParameters,
331339
enableLibraryEvolution: enableLibraryEvolution,
332340
keepPublicHeadersStructure: keepPublicHeadersStructure,
333-
customFrameworkModuleMapContents: customFrameworkModuleMapContents
341+
customFrameworkModuleMapContents: customFrameworkModuleMapContents,
342+
stripDWARFSymbols: stripDWARFSymbols
334343
)
335344
}
336345

@@ -381,7 +390,8 @@ extension Runner.Options.BuildOptions {
381390
frameworkModuleMapGenerationPolicy: fetch(
382391
\.frameworkModuleMapGenerationPolicy,
383392
by: \.frameworkModuleMapGenerationPolicy
384-
)
393+
),
394+
stripDWARFSymbols: fetch(\.stripDWARFSymbols, by: \.stripDWARFSymbols)
385395
)
386396
}
387397
}

Sources/scipio/CommandType.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ extension Runner {
4646
isSimulatorSupported: buildOptions.supportSimulators,
4747
isDebugSymbolsEmbedded: buildOptions.embedDebugSymbols,
4848
frameworkType: buildOptions.frameworkType,
49-
enableLibraryEvolution: buildOptions.shouldEnableLibraryEvolution
49+
enableLibraryEvolution: buildOptions.shouldEnableLibraryEvolution,
50+
stripDWARFSymbols: buildOptions.shouldStripDWARFSymbols
5051
)
5152
let runnerOptions = Runner.Options(
5253
baseBuildOptions: baseBuildOptions,

Sources/scipio/Options.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ struct BuildOptionGroup: ParsableArguments {
3838
help: "Whether to enable Library Evolution feature or not")
3939
var shouldEnableLibraryEvolution = false
4040

41+
@Flag(name: [.customLong("--strip-dwarf-symbols")],
42+
inversion: .prefixedNo,
43+
help: "Whether to strip DWARF symbol from static built binary or not")
44+
var shouldStripDWARFSymbols: Bool = false
45+
4146
@Flag(name: [.customLong("only-use-versions-from-resolved-file")],
4247
help: "Whether to disable updating Package.resolved automatically")
4348
var shouldOnlyUseVersionsFromResolvedFile: Bool = false

Sources/scipio/scipio.docc/prepare-cache-for-applications.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ All XCFrameworks are generated into `MyAppDependencies/XCFramework` by default.
9595
| -\-support-simulators | Whether also building for simulators of each SDKs or not | - |
9696
| -\-cache-policy | How to reuse built frameworks | project |
9797
| -\-enable-library-evolution | Whether to enable Library Evolution feature or not | - |
98+
| -\-strip-dwarf-symbols | Whether to strip DWARF symbols from built static binary or not | false |
9899
| -\-only-use-versions-from-resolved-file | Whether to disable updating Package.resolved automatically | false |
99100

100101

0 commit comments

Comments
 (0)