1717import static com .google .devtools .build .lib .analysis .config .CoreOptionConverters .BUILD_SETTING_CONVERTERS ;
1818import static com .google .devtools .build .lib .packages .RuleClass .Builder .STARLARK_BUILD_SETTING_DEFAULT_ATTR_NAME ;
1919import static com .google .devtools .build .lib .packages .Type .BOOLEAN ;
20+ import static java .util .stream .Collectors .joining ;
2021
2122import com .google .common .annotations .VisibleForTesting ;
2223import com .google .common .base .Preconditions ;
2728import com .google .devtools .build .lib .cmdline .Label ;
2829import com .google .devtools .build .lib .cmdline .TargetParsingException ;
2930import com .google .devtools .build .lib .packages .BuildSetting ;
30- import com .google .devtools .build .lib .packages .Rule ;
31+ import com .google .devtools .build .lib .packages .BuildType ;
3132import com .google .devtools .build .lib .packages .Target ;
3233import com .google .devtools .build .lib .packages .Type ;
3334import com .google .devtools .build .lib .packages .Types ;
3839import java .util .ArrayList ;
3940import java .util .Collection ;
4041import java .util .HashMap ;
42+ import java .util .LinkedHashSet ;
4143import java .util .List ;
4244import java .util .Map ;
4345import java .util .Objects ;
46+ import java .util .SequencedSet ;
4447import java .util .TreeMap ;
48+ import java .util .stream .Stream ;
4549import javax .annotation .Nullable ;
4650
4751/**
@@ -282,7 +286,7 @@ private boolean parseArg(String arg, Multimap<String, Pair<String, Target>> unpa
282286 }
283287
284288 /**
285- * Returns the given build setting's {@link Target}.
289+ * Returns the given build setting's {@link Target}, following (unconfigured) aliases if needed .
286290 *
287291 * @return the target, or null if the {@link BuildSettingLoader} needs to do more work to retrieve
288292 * the target
@@ -293,23 +297,71 @@ private Target loadBuildSetting(String targetToBuild) throws OptionsParsingExcep
293297 return buildSettings .get (targetToBuild );
294298 }
295299
296- Target buildSetting ;
297- try {
298- buildSetting = buildSettingLoader .loadBuildSetting (targetToBuild );
299- if (buildSetting == null ) {
300- return null ;
300+ Target target ;
301+ String targetToLoadNext = targetToBuild ;
302+ SequencedSet <Label > aliasChain = new LinkedHashSet <>();
303+ while (true ) {
304+ try {
305+ target = buildSettingLoader .loadBuildSetting (targetToLoadNext );
306+ if (target == null ) {
307+ return null ;
308+ }
309+ } catch (InterruptedException | TargetParsingException e ) {
310+ Thread .currentThread ().interrupt ();
311+ throw new OptionsParsingException (
312+ "Error loading option " + targetToBuild + ": " + e .getMessage (), targetToBuild , e );
313+ }
314+ if (!aliasChain .add (target .getLabel ())) {
315+ throw new OptionsParsingException (
316+ String .format (
317+ "Failed to load build setting '%s' due to a cycle in alias chain: %s" ,
318+ targetToBuild ,
319+ formatAliasChain (Stream .concat (aliasChain .stream (), Stream .of (target .getLabel ())))),
320+ targetToBuild );
321+ }
322+ if (target .getAssociatedRule () == null ) {
323+ throw new OptionsParsingException (
324+ String .format ("Unrecognized option: %s" , formatAliasChain (aliasChain .stream ())),
325+ targetToBuild );
326+ }
327+ if (target .getAssociatedRule ().isBuildSetting ()) {
328+ break ;
329+ }
330+ // Follow the unconfigured values of aliases.
331+ if (target .getAssociatedRule ().getRuleClass ().equals ("alias" )) {
332+ targetToLoadNext =
333+ switch (target .getAssociatedRule ().getAttr ("actual" )) {
334+ case Label label -> label .getUnambiguousCanonicalForm ();
335+ case BuildType .SelectorList <?> ignored ->
336+ throw new OptionsParsingException (
337+ String .format (
338+ "Failed to load build setting '%s' as it resolves to an alias with an"
339+ + " actual value that uses select(): %s. This is not supported as"
340+ + " build settings are needed to determine the configuration the"
341+ + " select is evaluated in." ,
342+ targetToBuild , formatAliasChain (aliasChain .stream ())),
343+ targetToBuild );
344+ case null , default ->
345+ throw new IllegalStateException (
346+ String .format (
347+ "Alias target '%s' with 'actual' attr value not equals to a label or a"
348+ + " selectorlist" ,
349+ target .getLabel ()));
350+ };
351+ continue ;
301352 }
302- } catch (InterruptedException | TargetParsingException e ) {
303- Thread .currentThread ().interrupt ();
304353 throw new OptionsParsingException (
305- "Error loading option " + targetToBuild + ": " + e .getMessage (), targetToBuild , e );
306- }
307- Rule associatedRule = buildSetting .getAssociatedRule ();
308- if (associatedRule == null || associatedRule .getRuleClassObject ().getBuildSetting () == null ) {
309- throw new OptionsParsingException ("Unrecognized option: " + targetToBuild , targetToBuild );
354+ String .format ("Unrecognized option: %s" , formatAliasChain (aliasChain .stream ())),
355+ targetToBuild );
310356 }
311- buildSettings .put (targetToBuild , buildSetting );
312- return buildSetting ;
357+ ;
358+
359+ buildSettings .put (targetToBuild , target );
360+ return target ;
361+ }
362+
363+ private static String formatAliasChain (Stream <Label > aliasChain ) {
364+ return aliasChain .map (Label ::getCanonicalForm ).collect (joining (" -> " ));
313365 }
314366
315367 @ VisibleForTesting
0 commit comments