facebook / buck

A fast build system that encourages the creation of small, reusable modules over a variety of platforms and languages.
https://buck.build
Apache License 2.0
8.56k stars 1.16k forks source link

iOS minimum deployment target version per build rule #1803

Open mgrebenets opened 6 years ago

mgrebenets commented 6 years ago

Hi there.

How can I override ios min SDK version for a specific rule? For example, I have a monorepo with lots of frameworks and 2 apps: A and B. App A is built for iOS 9.0, app B is built for iOS 10.0.

So in my .buckconfig I specify default SDK versions:

iphonesimulator_target_sdk_version = 9.0
iphoneos_target_sdk_version = 9.0

now I need to build app B for iOS 10.0 as min supported version.

Is there a way to customize apple_binary rule for app B? Or do all projects in the repo have to be built for same min SDK?

mgrebenets commented 6 years ago

So it looks like [apple] section from .buckconfig is read once in buck source code and min SDK versions read from that section define the rest of the toolchain context, e.g. define the value of --minimum-deployment-target, -mios-version-min and so on.

There doesn't seem any place in the code where that min SDK version can be overridden.

Is it limitation of buck, e.g. it's caching mechanism can't allow having different targets with different min SDK versions?

Would it be possible to make min SDK version one of the flavors maybe?

mgrebenets commented 6 years ago

OK, so I was advised that I can use --config option to achieve this. E.g. in my case

buck build rule_name --config apple.iphonesimulator_target_sdk_version=10.0 --config apple.iphoneos_target_sdk_version=10.0

which will override the default 9.0 values.

Would it be the best approach? Do I still get all the benefits for buck's caching?

I've also noticed the following. I have a file which contains iOS 10-only code and will produce a compile error when built for iOS 9.0. So I do these steps:

Then I do this:

Is the observed behavior expected?

sdwilsh commented 6 years ago

If that's true, the target sdk version isn't in the rule key, which would cause it to be a cache hit and not get rebuilt. I would be surprised if that's intended, but I don't know Buck's iOS support very well.

mgrebenets commented 6 years ago

@sdwilsh it seems that min SDK does not impact the cache behavior indeed. So if I first build stuff for iOS 10 and then for iOS 9, it will simply try to reuse cached build artifacts.

It just means using --config option to override min deployment target for all buck targets is not the best way to go.

There seem to be some workarounds using things like this:

# app extensions require version 10.0
deployment_target_flags = [
  ('.*iphonesimulator.*', ['-mios-simulator-version-min=10.0']),
  ('.*iphoneos.*', ['-mios-version-min=10.0']),
]
kwargs['platform_compiler_flags'] = deployment_target_flags
kwargs['platform_linker_flags'] = deployment_target_flags

but it's not clear if this workaround works with latest master or with one of Uber's or AirBnB's forks and if it requires some changes to Buck's Java code (looks like it requires changes).

sdwilsh commented 6 years ago

@styurin, do you know who might be a good person to look at this?

mgrebenets commented 6 years ago

Just to add to use of platform_compiler_flags and platform_linker_flags. I've been told that currently these flags only apply to invocations of C/C++/Objective-C compiler. But they do not get added to invocations of Swift (swiftc) compiler. So if target has Swift code or is mix-n-match target, then Swift code will not respect -mios-simulator-version-min=10.0 flags passed this way.

I was suggested by people on slack channel that Buck may need to add swift_platform_compiler_flags and maybe swift_platform_linker_flags. Not sure about the linker flags, because if I understand it correctly the ld linker is same for object files coming from Swift and Objective-C.

Anyways, I was suggested that swift_platform_compiler_flags should be part of the Apple Generic Cxx rule so that they will then appear for apple_library, apple_binary and other Apple rules.

With that addition, it should be possible to do something like this:

# app extensions require version 10.0
deployment_target_flags = [
  ('.*iphonesimulator.*', ['-mios-simulator-version-min=10.0']),
  ('.*iphoneos.*', ['-mios-version-min=10.0']),
]
kwargs['platform_compiler_flags'] = deployment_target_flags
kwargs['swift_platform_compiler_flags'] = deployment_target_flags
kwargs['platform_linker_flags'] = deployment_target_flags

I tried to look into Buck's Java code but tbh on first read most of it went over my head.

Alternatively, maybe all Apple rules need an option like min_deployment_target? 🤷‍♂️

yiding commented 6 years ago

It's probably best to pass version-min set via buckconfig to swift compiler as well so the behavior is consistent. @milend and @robbertvanginkel are familiar with buck's swift integration.

mgrebenets commented 6 years ago

Digging further, I tried to utilize existing swift_compiler_flags option.

apple_binary(
  swift_compiler_flags=['-target', 'x86_64-apple-ios10.0']

this does the trick, -target x86_64-apple-ios10.0 is added at the end of swiftc commands for this particular target, while other targets are built with default min deployment iOS version.

However, this approach is not flexible. The very same buck rule will build different slices, e.g. x86_64 for simulator, arm64 and armv7 slices for device. But there's no way to decide which swift_compiler_flags to add inside the rule declaration.

What we need is a way to do this:

swift_platform_compiler_flags = [
  ('.*x86_64.*', ['-target', 'x86_64-apple-ios10.0']),
  ('.*arm64.*', ['-target', 'arm64-apple-ios10.0']),
  ('.*armv7.*', ['-target', 'armv7-apple-ios10.0']),
]

similar to the way buck already has platform_compiler_flags for Cxx languages.