@@ -155,7 +155,7 @@ extension Module {
155
155
}
156
156
}
157
157
158
- var headerSearchPaths : ( key: String , value: String ) ? {
158
+ var headerSearchPaths : ( key: String , value: Plist ) ? {
159
159
let headerPathKey = " HEADER_SEARCH_PATHS "
160
160
var headerPaths = dependencies. flatMap { module -> AbsolutePath ? in
161
161
switch module {
@@ -174,36 +174,28 @@ extension Module {
174
174
}
175
175
176
176
guard !headerPaths. isEmpty else { return nil }
177
-
178
- if headerPaths. count == 1 , let first = headerPaths. first {
179
- return ( headerPathKey, first. asString)
180
- }
181
-
182
- let headerPathValue = headerPaths. map { $0. asString } . joined ( separator: " " )
183
177
184
- return ( headerPathKey, headerPathValue )
178
+ return ( headerPathKey, . array ( headerPaths . map { . string ( $0 . asString ) } ) )
185
179
}
186
180
187
181
func getDebugBuildSettings( _ options: XcodeprojOptions , xcodeProjectPath: AbsolutePath ) throws -> String {
188
182
var buildSettings = try getCommonBuildSettings ( options, xcodeProjectPath: xcodeProjectPath)
189
183
if let headerSearchPaths = headerSearchPaths {
190
184
buildSettings [ headerSearchPaths. key] = headerSearchPaths. value
191
185
}
192
- // FIXME: Need to honor actual quoting rules here.
193
- return buildSettings. map { " \( $0) = ' \( $1) '; " } . joined ( separator: " " )
186
+ return Plist . dictionary ( buildSettings) . quoteStrings ( ) . serialize ( )
194
187
}
195
188
196
189
func getReleaseBuildSettings( _ options: XcodeprojOptions , xcodeProjectPath: AbsolutePath ) throws -> String {
197
190
var buildSettings = try getCommonBuildSettings ( options, xcodeProjectPath: xcodeProjectPath)
198
191
if let headerSearchPaths = headerSearchPaths {
199
192
buildSettings [ headerSearchPaths. key] = headerSearchPaths. value
200
193
}
201
- // FIXME: Need to honor actual quoting rules here.
202
- return buildSettings. map { " \( $0) = ' \( $1) '; " } . joined ( separator: " " )
194
+ return Plist . dictionary ( buildSettings) . quoteStrings ( ) . serialize ( )
203
195
}
204
196
205
- private func getCommonBuildSettings( _ options: XcodeprojOptions , xcodeProjectPath: AbsolutePath ) throws -> [ String : String ] {
206
- var buildSettings = [ String: String ] ( )
197
+ private func getCommonBuildSettings( _ options: XcodeprojOptions , xcodeProjectPath: AbsolutePath ) throws -> [ String : Plist ] {
198
+ var buildSettings = [ String: Plist ] ( )
207
199
let plistPath = xcodeProjectPath. appending ( component: infoPlistFileName)
208
200
209
201
if isTest {
@@ -212,15 +204,15 @@ extension Module {
212
204
//FIXME this should not be required
213
205
buildSettings [ " LD_RUNPATH_SEARCH_PATHS " ] = " @loader_path/../Frameworks "
214
206
215
- buildSettings [ " INFOPLIST_FILE " ] = plistPath. relative ( to: xcodeProjectPath. parentDirectory) . asString
207
+ buildSettings [ " INFOPLIST_FILE " ] = . string ( plistPath. relative ( to: xcodeProjectPath. parentDirectory) . asString)
216
208
} else {
217
209
// We currently force a search path to the toolchain, since we
218
210
// cannot establish an expected location for the Swift standard
219
211
// libraries.
220
212
//
221
213
// This means the built binaries are not suitable for distribution,
222
214
// among other things.
223
- buildSettings [ " LD_RUNPATH_SEARCH_PATHS " ] = " $(TOOLCHAIN_DIR)/usr/lib/swift/macosx "
215
+ let toolchainPath = " $(TOOLCHAIN_DIR)/usr/lib/swift/macosx "
224
216
if isLibrary {
225
217
buildSettings [ " ENABLE_TESTABILITY " ] = " YES "
226
218
@@ -239,12 +231,13 @@ extension Module {
239
231
// default behavior on all packages.
240
232
241
233
buildSettings [ " PRODUCT_NAME " ] = " $(TARGET_NAME:c99extidentifier) "
242
- buildSettings [ " INFOPLIST_FILE " ] = plistPath. relative ( to: xcodeProjectPath. parentDirectory) . asString
234
+ buildSettings [ " INFOPLIST_FILE " ] = . string ( plistPath. relative ( to: xcodeProjectPath. parentDirectory) . asString)
243
235
244
236
buildSettings [ " PRODUCT_MODULE_NAME " ] = " $(TARGET_NAME:c99extidentifier) "
245
237
246
238
// FIXME: This should be user speficiable
247
- buildSettings [ " PRODUCT_BUNDLE_IDENTIFIER " ] = c99name
239
+ buildSettings [ " PRODUCT_BUNDLE_IDENTIFIER " ] = . string( c99name)
240
+ buildSettings [ " LD_RUNPATH_SEARCH_PATHS " ] = . string( toolchainPath)
248
241
} else {
249
242
// override default behavior, instead link dynamically
250
243
buildSettings [ " SWIFT_FORCE_STATIC_LINK_STDLIB " ] = " NO "
@@ -259,13 +252,13 @@ extension Module {
259
252
// example would be `@executable_path/../lib` but there are
260
253
// other problems to solve first, e.g. how to deal with the
261
254
// Swift standard library paths).
262
- buildSettings [ " LD_RUNPATH_SEARCH_PATHS " ] = buildSettings [ " LD_RUNPATH_SEARCH_PATHS " ] ! + " @executable_path"
255
+ buildSettings [ " LD_RUNPATH_SEARCH_PATHS " ] = . array ( [ . string ( toolchainPath ) , " @executable_path " ] )
263
256
}
264
257
}
265
258
266
259
if let pkgArgs = try ? self . pkgConfigArgs ( ) {
267
- buildSettings [ " OTHER_LDFLAGS " ] = ( [ " $(inherited) " ] + pkgArgs. libs) . joined ( separator : " " )
268
- buildSettings [ " OTHER_SWIFT_FLAGS " ] = ( [ " $(inherited) " ] + pkgArgs. cFlags) . joined ( separator : " " )
260
+ buildSettings [ " OTHER_LDFLAGS " ] = . array ( [ " $(inherited) " ] + pkgArgs. libs. map ( Plist . string ) )
261
+ buildSettings [ " OTHER_SWIFT_FLAGS " ] = . array ( [ " $(inherited) " ] + pkgArgs. cFlags. map ( Plist . string ) )
269
262
}
270
263
271
264
// Add framework search path to build settings.
@@ -286,7 +279,7 @@ extension Module {
286
279
moduleMapPath = path. appending ( component: moduleMapFilename)
287
280
}
288
281
289
- buildSettings [ " MODULEMAP_FILE " ] = moduleMapPath. relative ( to: xcodeProjectPath. parentDirectory) . asString
282
+ buildSettings [ " MODULEMAP_FILE " ] = . string ( moduleMapPath. relative ( to: xcodeProjectPath. parentDirectory) . asString)
290
283
}
291
284
292
285
// At the moment, set the Swift version to 3 (we will need to make this dynamic), but for now this is necessary.
@@ -298,3 +291,25 @@ extension Module {
298
291
return buildSettings
299
292
}
300
293
}
294
+
295
+ extension Plist {
296
+ // FIXME: This is only internal for unit testing.
297
+ /// Quotes the strings in the Plist.
298
+ func quoteStrings( ) -> Plist {
299
+ switch self {
300
+ case . string( let str) :
301
+ // Only quote if string has a space character.
302
+ guard str. utf8. contains ( UInt8 ( ascii: " " ) ) else {
303
+ return . string( str)
304
+ }
305
+ return . string( " \" " + str + " \" " )
306
+ case . array( let items) :
307
+ return . array( items. map { $0. quoteStrings ( ) } )
308
+ case . dictionary( var items) :
309
+ for (k, v) in items {
310
+ items [ k] = v. quoteStrings ( )
311
+ }
312
+ return . dictionary( items)
313
+ }
314
+ }
315
+ }
0 commit comments