Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve variable substitution for xcconfig declared build settings #501

Merged
merged 6 commits into from
Aug 18, 2017
Merged

Resolve variable substitution for xcconfig declared build settings #501

merged 6 commits into from
Aug 18, 2017

Conversation

UnsafePointer
Copy link
Contributor

Currently, given an xcconfig like:

PRODUCT_BUNDLE_IDENTIFIER_Release = com.cocoapods.app
PRODUCT_BUNDLE_IDENTIFIER_Debug = com.cocoapods.app.dev
PRODUCT_BUNDLE_IDENTIFIER = $(PRODUCT_BUNDLE_IDENTIFIER_$(CONFIGURATION))

Using XCBuildConfiguration#resolve_build_setting for PRODUCT_BUNDLE_IDENTIFIER would return $(PRODUCT_BUNDLE_IDENTIFIER_$(CONFIGURATION)). With this change, it returns the proper value com.cocoapods.app or com.cocoapods.app.dev depending of the configuration.

expression = /\$\((.*)\)/
match_data = config_setting.match(expression)
if match_data.nil?
return name if config_setting.eql?('CONFIGURATION')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is an exhaustive way to resolve the value, would love feedback on this.

Copy link
Member

@segiddins segiddins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this only change the behavior when $(CONFIGURATION) needs to be expanded?

@@ -82,6 +82,7 @@ def type
def resolve_build_setting(key)
setting = build_settings[key]
config_setting = base_configuration_reference && config[key]
config_setting = resolve_variable_substitution(config_setting) if !config_setting.nil? && config_setting.is_a?(String)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need to check is_a?(String)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

xcconfig file parsing goes through XCBuildConfiguration#normalize_array_settings and we get array values from there. I'm completely ignoring those, as I believe it's mostly used for OTHER_LDFLAGS, but I don't fully understand why those have to be arrays, I assume this is expected in other parts of system.

@UnsafePointer
Copy link
Contributor Author

@segiddins not sure if I get the question correctly. Previously $(CONFIGURATION) was not expanded at all (at least not by this method), now it is correctly expanded; so yes, it does.

@segiddins
Copy link
Member

But does it effect any other setting names?

@UnsafePointer
Copy link
Contributor Author

UnsafePointer commented Jul 17, 2017

@segiddins Yes. It basically should capture anything between {()} and try to resolve the value of that, respecting the level rules in XCBuildConfiguration#resolve_build_setting, if no value is found it will just fallback to the config name.

Sorry about the rebase, someone reported a problem with my implementation, which should be fixed now. I'll add more tests to try to cover all the different scenarios.

@segiddins
Copy link
Member

This looks reasonable to me. 👍
I think I'd like @samdmarshall to chime in if there are known corner cases we should test against for variable expansion, and @dantoml to review the changes.
Thanks!

@samdmarshall
Copy link

The major thing to watch out for is that the variables you are attempting to expand are actually valid as xcconfig identifiers. Otherwise you are going to run into problems with invalid xcconfig files and people wondering why their unicode configuration names aren't working as expected.

@UnsafePointer
Copy link
Contributor Author

UnsafePointer commented Jul 18, 2017

Some changes I did after the last review:

  • Applied @samdmarshall suggestion, the regex now looks only for valid xcconfig identifiers.
  • Made the regex lazy so cases like $(USER_DEFINED)_$(CONFIGURATION) work now.
  • Added more tests.

Thanks to the feedback on fastlane/fastlane#9760 (comment) I realised that there's a problem with this approach:

If a build setting defined at a project level uses variable substitution referencing values at a target level the method won't work. I'm still looking into this. Ideally I'd like to jump to the target level from this point (if self == project.build_configuration_list[name]), but not sure if this is possible without passing a reference of the target from the root of the recursion which is something I want to avoid.

Update:

I think that problem can be avoided by using PBXNativeTarget#resolved_build_setting which will lookup on both levels separately and resolve the value. Will try this now.

@UnsafePointer
Copy link
Contributor Author

@segiddins @dantoml anything else I can do here to move forward this?

Copy link
Member

@segiddins segiddins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks 👍 other than the minor comments

setting = build_settings[key]
setting = resolve_variable_substitution(setting, root_target) if !setting.nil? && setting.is_a?(String)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checking both nil? and is_a? is redundant

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes totally sense!

config_setting = base_configuration_reference && config[key]
config_setting = resolve_variable_substitution(config_setting, root_target) if !config_setting.nil? && config_setting.is_a?(String)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checking both nil? and is_a? is redundant

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes totally sense!

@@ -103,6 +108,20 @@ def expand_build_setting(build_setting_value, config_value)
build_setting_value.map { |value| Constants::INHERITED_KEYWORDS.include?(value) ? inherited : value }.flatten
end

def resolve_variable_substitution(config_setting, root_target)
expression = /\$[{(]([^inherited][$(){}_a-zA-Z0-9]*?)[})]/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extract this into a constant and please comment the regexp

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@segiddins
Copy link
Member

I'll let @dantoml merge this one

@@ -96,13 +101,42 @@ def resolve_build_setting(key)

private

CAPTURE_VARIABLE_IN_BUILD_CONFIG = /
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for documenting the regex 👍

@endocrimes endocrimes merged commit 84ebf06 into CocoaPods:master Aug 18, 2017
@litalhassine
Copy link

Any plans for a new release with this commit?

@dnkoutso
Copy link
Contributor

dnkoutso commented Sep 6, 2017

@litalhassine you can use http://bundler.io/ and point to a specific SHA or branch to use this.

@UnsafePointer
Copy link
Contributor Author

@dnkoutso it would be really nice to have this as a patch release (probably nobody is using that API anyway) so we could submit a fix for the issue described here: fastlane/fastlane#9460 (comment).

@jetersen
Copy link

jetersen commented Sep 29, 2017

Thanks this resolved one of the issue I had in my sample for environment variables substitution
https://github.com/casz/xcodeproj-sample-env
the case The subtitues variables that are resolved by xcode build settings
written because I saw this PR and wanted to see that it kept working after environment variables variable substitutes was in xcodeproj 👍

So it did not work with xcodeproj 1.5.1

However it works in 1.5.2, great work 🚀

@epatel
Copy link

epatel commented Oct 21, 2017

This don't seem to work for me. I am using fastlane and it always fails on export now, did work earlier though (Xcode8? Xcode9 now).

I have $(TEST_GROUP) that can be defined as a couple of test groups and then a number of other variables, in a BUNDLE_ID that is a concatenation like $($(TEST_GROUP)_BUNDLE_ID) which then gets i.e. from EXTERNAL_BUNDLE_ID = com.myapp.external if TEST_GROUP is set to EXTERNAL.

I see $($(TEST_GROUP)_BUNDLE_ID) becomes TEST_GROUP_BUNDLE_ID

This worked for a while and now it does not...
http://dyna.mo/xcconfig/

@UnsafePointer
Copy link
Contributor Author

@epatel I'm happy to have a look if you could open an issue with a sample project to reproduce this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants