Skip to content

Instantly share code, notes, and snippets.

@samdmarshall
Created October 29, 2015 15:09
Show Gist options
  • Save samdmarshall/a9f564bb8574e7ecaed0 to your computer and use it in GitHub Desktop.
Save samdmarshall/a9f564bb8574e7ecaed0 to your computer and use it in GitHub Desktop.

Xcode loads xcspec files (ascii plists) that specify everything (tools, buildphases, compilers, rules, etc) based on a set of conditions.

To evaluate these conditions you have to load these files and simulate the build process and construct your own "environment"

The target's build settings will help to resolve most of the environment variables by taking the basics from the particular platform you are using for the target (resolved from the SDKROOT value xcrun --show-sdk-platform-path --sdk)

when you load the spec of the compiler there is a key on it called "Options" which is an array of dictionaries that have a "Name" key that maps to a variable in the "environment"

When generating the flags to pass to the compiler you have to evaluate any conditional expression, for example:

{
                Name = "CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES";
                Type = Boolean;
                DefaultValue = NO;
                CommandLineArgs = {
                    YES = ();
                    NO = ("-Wnon-modular-include-in-framework-module",
                          "-Werror=non-modular-include-in-framework-module");
                };
                Condition = "$(CLANG_ENABLE_MODULES) == YES";
				        Category = LanguageModules;
                DisplayName = "Allow Non-modular Includes In Framework Modules";
            },

in this case the CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES option will only be evaluated if the value $(CLANG_ENABLE_MODULES) is enabled, otherwise this value is ignored.

To properly evaluate and generate the flags passed you must construct the base environment from the platform bundle. There are multiple levels to the environment and they must be stored as separate levels (not composed into a flat env) but resolve differently than how they are stored:

levels:

  • platform
  • project
  • config
  • target

resolution: see the explanation on build setting inheritance

NOTE: this process has to be done PER FILE because each file per phase is evaluated separately so the build rule can match the file type to the respective compiler and thus load the appropriate option variables

steps:

  1. load spec files from xcode core
  2. when a target is built an "environment" is created to house values
  3. when a target is built the platform it is built the platform is resolved from SDKROOT
  4. "environment" loads the defaults from the platform
  5. build settings will be loaded into the environment
  6. process build phases based on build rules, the phase specifies the type of action and will apply build rules
  7. each file in each phase will be evaluated by the rules by the phase
  8. build rule will use the file type to resolve what tool needs to be used
  9. each tool spec has a set of options which will be loaded into the "environment" now by evaluating their conditional values
  10. each Option variable is resolved based on the environment (eg: MY_SETTING = "FOO"; CC = $(MY_SETTING); translates to MY_SETTING = "FOO"; CC = "FOO";)
  11. each option may specify flags to pass to the tool based on the value the Option variable is assigned
  12. the Option variables that pass the conditional test (if one exists) are then collected and passed to the build system
  13. builds system takes the list of flags and invokes the tool passing those flags
  14. "environment" is cleared of variables resolved from the tool's spec, and is restored to the original state it had before loading the tool's spec

steps 7-14 will be repeated for each phase

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment