New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 862232 link

Starred by 2 users

Issue metadata

Status: WontFix
Owner: ----
Closed: Jul 12
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: ----
Pri: 3
Type: Bug



Sign in to add a comment

GN propagation of testonly variable problem when wrapping action() calls.

Project Member Reported by digit@google.com, Jul 10

Issue description

This issue with GN appeared while working on Android-related changes to the Chromium build rules. It can be reproduced with the following simple CL: https://chromium-review.googlesource.com/c/chromium/src/+/1131740

Essentially, the 'testonly' variable doesn't seem to be propagated correctly through template calls that wraps an action. As an example, first consider the following:

  template("my_template") {
    forward_variables_from(invoker, ["testonly"])
    ...
    action(first_target) {
       # This inherits the 'testonly' from the upper scope
       ...
    }
    action(second_target) {
       # This inherits 'testonly' from the upper scope too.
       ...
    }
  }

Here's things occur as designed, the value of 'testonly' that was forwarded into the |my_template| scope is propagated to the actions.

Now, let's write a template that wraps an action without doing anything else:

  template("action_wrapper") {
    action(target_name) {
      forward_variables_from(invoker, "*")
    }
  }

My understanding of the GN language and rules is that calling action() or action_wrapper() should be equivalent for 'testonly'. But that's not the case:

  template("my_template") {
    forward_variables_from(invoker, ["testonly"])
    ...
    action(first_target) {
       # This inherits the 'testonly' from the upper scope
       ...
    }
    action_wrapper(second_target) {
       # This DOES NOT inherit 'testonly' from the upper scope.
       ...
    }
  }

In the code above, |second_target| will never have the testonly flag set to true, and any target that depends on it, that is testonly, will actually generate an error at GN time.

This doesn't happen with a simple action() call.

I've tried to look at the GN sources, the FillTestonly() method in tools/gen/target_generator.cc sets the 'testonly' flag associated with each target by calling Scope::GetValue(), which performs a recursive lookup (i.e. it is supposed to find the 'testonly' value defined in the |my_template| scope).

We can work around by forwarding testonly explicitly, either with:

  action_wrapper(second_target) {
    testonly = defined(testonly) && testonly
    ...
  }

Or:

  action_wrapper(second_target) {
    if (defined(testonly)) {
      testonly = testonly
    }
    ...
  }

Also, note that the problem only arises when testonly is first forwarded in the outer template's scope, i.e. the following works correctly:

  template("my_template") {
    ...
    action(first_target) {
      # Inherit 'testonly' from the calling scope.
      forward_variables_from(invoker, ["testonly"])
       ...
    }
    action_wrapper(second_target) {
       # This DOES inherit 'testonly' from the calling scope.
      forward_variables_from(invoker, ["testonly"])
       ...
    }
  }

 
Cc: dpranke@chromium.org brettw@chromium.org
Labels: Build-Tools-GN
I've just stumbled upon https://bugs.chromium.org/p/chromium/issues/detail?id=594610 as well as a comment in https://cs.chromium.org/chromium/src/build/config/BUILDCONFIG.gn?q=BUILDCONFIG.gn&sq=package:chromium&g=0&l=703

It looks like the root of the issue is that forwarding all variables with "*" does not look in scopes recursively, but forwarding specific variables do.

I.e. it looks like the issue can be solved by doing something like:

  template("action_wrapper") {
    action(target_name) {
      # Forward testonly explicitly, which performs a recursive scope lookup.
      forward_variables_from(invoker, [ "testonly" ])

      # Forward all other variables, which does NOT!
      forward_variables_from(invoker, "*", [ "testonly" ])
    }
  }

I'll experiment with this and report here.
Status: WontFix (was: Available)
I confirm that this indeed works correctly, and is actually covered by the documentation for forward_variables_from(), which says:

"""
  As a special case, if the variable_list is a string with the value of "*",
  all variables from the given scope will be copied. "*" only copies variables
  set directly on the from_scope, not enclosing ones. Otherwise it would
  duplicate all global variables.
"""

So I guess this is working as intended, though a little bit unintuitive, regarding the role of testonly and visibility during GN target dependency resolution.

Making this as WontFix then. Sorry for the noise.

I wonder if we don't want to make "*" forward 'testonly' and 'visibility' recursively by default though. I suspect there are many parts of the builds where these are not forwarded correctly :-/


Sign in to add a comment