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:
- load spec files from xcode core
- when a target is built an "environment" is created to house values
- when a target is built the platform it is built the platform is resolved from
SDKROOT
- "environment" loads the defaults from the platform
- build settings will be loaded into the environment
- process build phases based on build rules, the phase specifies the type of action and will apply build rules
- each file in each phase will be evaluated by the rules by the phase
- build rule will use the file type to resolve what tool needs to be used
- each tool spec has a set of options which will be loaded into the "environment" now by evaluating their conditional values
- each Option variable is resolved based on the environment (eg:
MY_SETTING = "FOO"; CC = $(MY_SETTING);
translates toMY_SETTING = "FOO"; CC = "FOO";
) - each option may specify flags to pass to the tool based on the value the Option variable is assigned
- the Option variables that pass the conditional test (if one exists) are then collected and passed to the build system
- builds system takes the list of flags and invokes the tool passing those flags
- "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