Skip to content

Commit

Permalink
Add support for compiler_flags and ability to override objc_copts, sw…
Browse files Browse the repository at this point in the history
…ift_copts, cc_copts and linkopts via user options (#149)
  • Loading branch information
sergeykhliustin authored May 29, 2024
1 parent 954633e commit e487073
Show file tree
Hide file tree
Showing 20 changed files with 182 additions and 89 deletions.
8 changes: 6 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,9 @@ integration-generate-static:
--patches bundle_deduplicate arm64_to_sim_forced missing_sdks \
-a -d \
--color yes \
--log-level debug
--log-level debug \
--user-options \
"MMKVCore.cc_copts += -fno-objc-arc"

integration-generate-dynamic:
bazel run :bazelpods $(CONFIG) -- \
Expand All @@ -117,7 +119,9 @@ integration-generate-dynamic:
--color yes \
--log-level debug \
--patches bundle_deduplicate arm64_to_sim_forced missing_sdks user_options \
--user-options "CocoaLumberjack.platform_ios.sdk_frameworks += CoreGraphics"
--user-options \
"CocoaLumberjack.platform_ios.sdk_frameworks += CoreGraphics" \
"MMKVCore.cc_copts += -fno-objc-arc"

integration-build-x86_64:
bazel build $(CONFIG) //IntegrationTests:TestApp_iOS --ios_multi_cpus=x86_64
Expand Down
18 changes: 10 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,11 @@ OPTIONS:
--patches <patches> Patches. It will be applied in the order listed here.
Available options: bundle_deduplicate, arm64_to_sim, arm64_to_sim_forced, missing_sdks, user_options.
user_options requires --user-options configured.
If 'user_options' not specified, but --user_options exist, user_options patch are applied automatically.
If 'user_options' not specified, but --user_options exist, user_options patch are applied automatically. (values: bundle_deduplicate, arm64_to_sim, arm64_to_sim_forced, missing_sdks, user_options)
--user-options <user-options>
User extra options.
Supported fields: 'sdk_frameworks', 'sdk_dylibs', 'weak_sdk_frameworks', 'vendored_libraries', 'vendored_frameworks', 'vendored_xcframeworks', 'testonly', 'link_dynamic', 'data', 'objc_defines', 'runner', 'test_host', 'timeout'.
Supported fields: 'sdk_frameworks', 'sdk_dylibs', 'weak_sdk_frameworks', 'vendored_libraries', 'vendored_frameworks', 'vendored_xcframeworks', 'testonly', 'link_dynamic', 'data', 'objc_defines', 'runner', 'test_host', 'timeout',
'objc_copts', 'swift_copts', 'cc_copts', 'linkopts'.
Supported operators: '+=' (append), '-=' (delete), ':=' (replace).
Example:
'SomePod.sdk_dylibs += something,something'
Expand All @@ -115,10 +116,10 @@ OPTIONS:
--pods-root <pods-root> Pods root relative to workspace. Used for headers search paths (default: Pods)
-f, --frameworks Packaging pods in dynamic frameworks if possible (same as `use_frameworks!`)
--no-concurrency Disable concurrency.
--log-level <log-level> Log level (debug|info|warning|error|none) (default: info)
--log-level <log-level> Log level (debug|info|warning|error|none) (values: debug, info, warning, error, none; default: info)
--use-bundler Option to use `bundle exec` for `pod` calls
--tests-timeout <tests-timeout>
(Optional) Default timeout for test targets (short|moderate|long|eternal)
(Optional) Default timeout for test targets (short|moderate|long|eternal) (values: short, moderate, long, eternal)
--pods-json <pods-json> Pods.json (default: Pods/Pods.json)
--print-output Print BUILD files contents to terminal output
--dry-run Dry run. Files will not be written
Expand All @@ -141,10 +142,11 @@ OPTIONS:
--patches <patches> Patches. It will be applied in the order listed here.
Available options: bundle_deduplicate, arm64_to_sim, arm64_to_sim_forced, missing_sdks, user_options.
user_options requires --user-options configured.
If 'user_options' not specified, but --user_options exist, user_options patch are applied automatically.
If 'user_options' not specified, but --user_options exist, user_options patch are applied automatically. (values: bundle_deduplicate, arm64_to_sim, arm64_to_sim_forced, missing_sdks, user_options)
--user-options <user-options>
User extra options.
Supported fields: 'sdk_frameworks', 'sdk_dylibs', 'weak_sdk_frameworks', 'vendored_libraries', 'vendored_frameworks', 'vendored_xcframeworks', 'testonly', 'link_dynamic', 'data', 'objc_defines', 'runner', 'test_host', 'timeout'.
Supported fields: 'sdk_frameworks', 'sdk_dylibs', 'weak_sdk_frameworks', 'vendored_libraries', 'vendored_frameworks', 'vendored_xcframeworks', 'testonly', 'link_dynamic', 'data', 'objc_defines', 'runner', 'test_host', 'timeout',
'objc_copts', 'swift_copts', 'cc_copts', 'linkopts'.
Supported operators: '+=' (append), '-=' (delete), ':=' (replace).
Example:
'SomePod.sdk_dylibs += something,something'
Expand All @@ -160,10 +162,10 @@ OPTIONS:
--pods-root <pods-root> Pods root relative to workspace. Used for headers search paths (default: Pods)
-f, --frameworks Packaging pods in dynamic frameworks if possible (same as `use_frameworks!`)
--no-concurrency Disable concurrency.
--log-level <log-level> Log level (debug|info|warning|error|none) (default: info)
--log-level <log-level> Log level (debug|info|warning|error|none) (values: debug, info, warning, error, none; default: info)
--use-bundler Option to use `bundle exec` for `pod` calls
--tests-timeout <tests-timeout>
(Optional) Default timeout for test targets (short|moderate|long|eternal)
(Optional) Default timeout for test targets (short|moderate|long|eternal) (values: short, moderate, long, eternal)
--podspec <podspec> podspec.json
--subspecs <subspecs> Subspecs list
-h, --help Show help information.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,7 @@ struct BuildSettingsAnalyzer<S: XCConfigRepresentable> {
}

private func run() -> Result {
let xcconfig = spec.collectAttribute(with: subspecs, keyPath: \.xcconfig).platform(platform) ?? [:]
let podTargetXcconfig = spec.collectAttribute(with: subspecs, keyPath: \.podTargetXcconfig).platform(platform) ?? [:]
let userTargetXcconfig = spec.collectAttribute(with: subspecs, keyPath: \.userTargetXcconfig).platform(platform) ?? [:]
let mergedConfig = xcconfig
.merging(podTargetXcconfig, uniquingKeysWith: { $1 })
.merging(userTargetXcconfig, uniquingKeysWith: { $1 })
let parser = XCConfigParser(mergedConfig, options: options)
let parser = XCConfigParser(spec: spec, subspecs: subspecs, platform: platform, options: options)

return Result(
swiftCopts: parser.swiftCopts,
Expand Down
17 changes: 17 additions & 0 deletions Sources/BazelPodsCore/Core/UserOption.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ public struct UserOption {
case runner(String)
case test_host(String)
case timeout(TestsTimeout)
case objc_copts([String])
case swift_copts([String])
case cc_copts([String])
case linkopts([String])
}
public enum KeyPath: String, CaseIterable {
case sdk_frameworks
Expand All @@ -73,6 +77,10 @@ public struct UserOption {
case runner
case test_host
case timeout
case objc_copts
case swift_copts
case cc_copts
case linkopts
}

public init?(_ string: String) {
Expand Down Expand Up @@ -216,11 +224,20 @@ public struct UserOption {
let timeout = TestsTimeout(rawValue: last)
else {
log_error(
// swiftlint:disable:next line_length
"Incorrect value for \(string). Should be one of \(TestsTimeout.allCases.map({ $0.rawValue }).joined(separator: ", "))). Skipping..."
)
return nil
}
attribute = .timeout(timeout)
case .objc_copts:
attribute = .objc_copts(value)
case .swift_copts:
attribute = .swift_copts(value)
case .cc_copts:
attribute = .cc_copts(value)
case .linkopts:
attribute = .linkopts(value)
}
self.name = name
self.opt = opt
Expand Down
2 changes: 2 additions & 0 deletions Sources/BazelPodsCore/Models/Specs/AppSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public final class AppSpec: AppSpecRepresentable {
let xcconfig: [String: String]
let podTargetXcconfig: [String: String]
let userTargetXcconfig: [String: String]
let compilerFlags: [String]

let vendoredLibraries: [String]
let vendoredFrameworks: [String]
Expand Down Expand Up @@ -70,6 +71,7 @@ public final class AppSpec: AppSpecRepresentable {
xcconfig = Self.xcconfig(json: json)
podTargetXcconfig = Self.podTargetXcconfig(json: json)
userTargetXcconfig = Self.userTargetXcconfig(json: json)
compilerFlags = Self.compilerFlags(json: json)
vendoredLibraries = Self.vendoredLibraries(json: json)
vendoredFrameworks = Self.vendoredFrameworks(json: json)
infoPlist = Self.infoPlist(json: json)
Expand Down
5 changes: 2 additions & 3 deletions Sources/BazelPodsCore/Models/Specs/PodSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ enum PodSpecField: String {
case prefixHeaderFile = "prefix_header_file"
case prefixHeaderContents = "prefix_header_contents"
case preservePaths = "preserve_paths"
case compilerFlags = "compiler_flags"
case subspecs
case source
case license
Expand Down Expand Up @@ -145,9 +144,9 @@ public final class PodSpec: PodSpecRepresentable {
let podTargetXcconfig: [String: String]
let userTargetXcconfig: [String: String]
let xcconfig: [String: String]
let compilerFlags: [String]

let subspecs: [PodSpec]
let compilerFlags: [String]
let source: PodSpecSource?
let license: PodSpecLicense
let defaultSubspecs: [String]
Expand Down Expand Up @@ -221,6 +220,7 @@ public final class PodSpec: PodSpecRepresentable {
xcconfig = Self.xcconfig(json: json)
podTargetXcconfig = Self.podTargetXcconfig(json: json)
userTargetXcconfig = Self.userTargetXcconfig(json: json)
compilerFlags = Self.compilerFlags(json: json)

// VendoredDependenciesRepresentable
vendoredLibraries = Self.vendoredLibraries(json: json)
Expand All @@ -235,7 +235,6 @@ public final class PodSpec: PodSpecRepresentable {
prefixHeaderContents = fieldMap[.prefixHeaderContents] as? String

preservePaths = strings(fromJSON: fieldMap[.preservePaths])
compilerFlags = strings(fromJSON: fieldMap[.compilerFlags])

defaultSubspecs = strings(fromJSON: fieldMap[.defaultSubspecs])

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ protocol XCConfigRepresentable: BaseRepresentable {
var podTargetXcconfig: [String: String] { get }
var userTargetXcconfig: [String: String] { get }
var xcconfig: [String: String] { get }
var compilerFlags: [String] { get }
}

extension XCConfigRepresentable {
Expand All @@ -23,6 +24,7 @@ private enum Keys: String {
case pod_target_xcconfig
case user_target_xcconfig
case xcconfig
case compiler_flags
}

extension XCConfigRepresentable {
Expand All @@ -37,4 +39,9 @@ extension XCConfigRepresentable {
static func xcconfig(json: JSONDict) -> [String: String] {
return extractValue(fromJSON: json[Keys.xcconfig.rawValue], default: [:])
}

static func compilerFlags(json: JSONDict) -> [String] {
let stringFlags = extractValue(fromJSON: json[Keys.compiler_flags.rawValue], default: "")
return stringFlags.split(separator: " ").map { String($0) }
}
}
2 changes: 2 additions & 0 deletions Sources/BazelPodsCore/Models/Specs/TestSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public final class TestSpec: TestSpecRepresentable {
let xcconfig: [String: String]
let podTargetXcconfig: [String: String]
let userTargetXcconfig: [String: String]
let compilerFlags: [String]

let vendoredLibraries: [String]
let vendoredFrameworks: [String]
Expand Down Expand Up @@ -84,6 +85,7 @@ public final class TestSpec: TestSpecRepresentable {
xcconfig = Self.xcconfig(json: json)
podTargetXcconfig = Self.podTargetXcconfig(json: json)
userTargetXcconfig = Self.userTargetXcconfig(json: json)
compilerFlags = Self.compilerFlags(json: json)
vendoredLibraries = Self.vendoredLibraries(json: json)
vendoredFrameworks = Self.vendoredFrameworks(json: json)
infoPlist = Self.infoPlist(json: json)
Expand Down
36 changes: 36 additions & 0 deletions Sources/BazelPodsCore/Patches/UserOptionsPatch.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,42 @@ struct UserOptionsPatch: Patch, TestSpecSpecificPatch {
case .timeout:
// test spec specific option
break
case .objc_copts(let value):
switch option.opt {
case .append:
buildSettings.objcCopts += value
case .delete:
buildSettings.objcCopts.removeAll(where: { value.contains($0) })
case .replace:
buildSettings.objcCopts = value
}
case .swift_copts(let value):
switch option.opt {
case .append:
buildSettings.swiftCopts += value
case .delete:
buildSettings.swiftCopts.removeAll(where: { value.contains($0) })
case .replace:
buildSettings.swiftCopts = value
}
case .cc_copts(let value):
switch option.opt {
case .append:
buildSettings.ccCopts += value
case .delete:
buildSettings.ccCopts.removeAll(where: { value.contains($0) })
case .replace:
buildSettings.ccCopts = value
}
case .linkopts(let value):
switch option.opt {
case .append:
buildSettings.linkOpts += value
case .delete:
buildSettings.linkOpts.removeAll(where: { value.contains($0) })
case .replace:
buildSettings.linkOpts = value
}
}
}
}
Expand Down
33 changes: 21 additions & 12 deletions Sources/BazelPodsCore/XCConfig/XCConfigParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import Foundation

final class XCConfigParser {
final class XCConfigParser<S: XCConfigRepresentable> {
private(set) var xcconfig: [String: StarlarkNode] = [:]
private(set) var swiftCopts: [String] = []
private(set) var objcCopts: [String] = []
Expand All @@ -16,7 +16,7 @@ final class XCConfigParser {
private(set) var ccCopts: [String] = []
private let transformers: [String: XCConfigSettingTransformer]
private let options: BuildOptions
private static let defaultTransformers: [XCConfigSettingTransformer] = [
private let defaultTransformers: [XCConfigSettingTransformer] = [
HeaderSearchPathTransformer(),
UserHeaderSearchPathTransformer(),
ApplicationExtensionAPIOnlyTransformer(),
Expand All @@ -27,21 +27,23 @@ final class XCConfigParser {
ObjcDefinesListTransformer("GCC_PREPROCESSOR_DEFINITIONS")
]

convenience init(spec: PodSpec, subspecs: [PodSpec] = [], options: BuildOptions) {
let resolved =
spec.collectAttribute(with: subspecs, keyPath: \.xcconfig) <>
spec.collectAttribute(with: subspecs, keyPath: \.podTargetXcconfig) <>
spec.collectAttribute(with: subspecs, keyPath: \.userTargetXcconfig)
convenience init(spec: S, subspecs: [S] = [], platform: Platform, options: BuildOptions) {
let xcconfig = spec.collectAttribute(with: subspecs, keyPath: \.xcconfig).platform(platform) ?? [:]
let podTargetXcconfig = spec.collectAttribute(with: subspecs, keyPath: \.podTargetXcconfig).platform(platform) ?? [:]
let userTargetXcconfig = spec.collectAttribute(with: subspecs, keyPath: \.userTargetXcconfig).platform(platform) ?? [:]
let mergedConfig = xcconfig
.merging(podTargetXcconfig, uniquingKeysWith: { $1 })
.merging(userTargetXcconfig, uniquingKeysWith: { $1 })

self.init(resolved.multi.ios ?? [:], options: options)
let compilerFlags = spec.collectAttribute(with: subspecs, keyPath: \.compilerFlags).platform(platform) ?? []

self.init(mergedConfig, compilerFlags: compilerFlags, options: options)
}

init(_ config: [String: String],
options: BuildOptions,
transformers: [XCConfigSettingTransformer] = defaultTransformers) {
private init(_ config: [String: String], compilerFlags: [String], options: BuildOptions) {
self.options = options

self.transformers = transformers.reduce([String: XCConfigSettingTransformer](), { result, transformer in
self.transformers = defaultTransformers.reduce([String: XCConfigSettingTransformer](), { result, transformer in
var result = result
result[transformer.key] = transformer
return result
Expand Down Expand Up @@ -82,6 +84,13 @@ final class XCConfigParser {
log_debug("unhandled xcconfig \(key)")
}
}

for flag in compilerFlags {
let normalized = replacePodsEnvVars(flag, options: options, absolutePath: false)
if !normalized.isEmpty {
ccCopts.append(normalized)
}
}
}

private func replaceEnvVars(in config: [String: String]) -> [String: String] {
Expand Down
7 changes: 2 additions & 5 deletions TestTools/Pods.json
Original file line number Diff line number Diff line change
Expand Up @@ -388,13 +388,10 @@
"version": "3.7.6"
},
"MMKV": {
"version": "1.3.3"
"version": "1.3.5"
},
"MMKVAppExtension": {
"version": "1.3.3"
},
"MMKVCore": {
"version": "1.3.3"
"version": "1.3.5"
},
"MTHawkeye": {
"version": "0.12.8"
Expand Down
6 changes: 6 additions & 0 deletions TestTools/Pods_Integration.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@
"LTMorphingLabel": {
"version": "0.9.3"
},
"MMKV": {
"version": "1.3.5"
},
"Material": {
"version": "3.1.8"
},
Expand Down Expand Up @@ -182,6 +185,9 @@
"Kingfisher": {
"version": "7.6.2"
},
"MMKV": {
"version": "1.3.5"
},
"Moya": {
"version": "15.0.0"
},
Expand Down
3 changes: 3 additions & 0 deletions Tests/Recorded/KSCrash/BUILD.bazel

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit e487073

Please sign in to comment.