haniceboy / gyp

Automatically exported from code.google.com/p/gyp
0 stars 0 forks source link

Adding a dependency into target_defaults produces a dependency loop elsewhere #409

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
The following GYP file (see the full repro with .c files attached) resembles 
the Chromium GYP config with the dummy 'main' target that depends on the 
'main_initial' executable. There's also a 'malloc' shared library that 
corresponds to libc++ in Chromium.
====================================================
{
  'variables': {
    'custom_malloc%' : 0,
  },
  'target_defaults': {
    'conditions': [
      ['custom_malloc==1', {
        'dependencies': [
          'malloc',
        ],
      }],
    ],
  },
  'targets': [
    {
      'target_name': 'main',
      'type': 'none',
      'dependencies': [ 'main_initial', ],
    },
    {
      'target_name': 'main_initial',
      'type': 'executable',
      'product_name': 'main',
      'sources': [ 'main.c' ],
    },
    {
      'target_name': 'malloc',
      'type': 'shared_library',
      'variables': {
        'prune_self_dependency': 1,
      },  
      'sources': [ 'mymalloc.c' ],
    },
  ],
}
====================================================
Normally (when custom_malloc==0) it's easy to build 'main':

$ GYP_DEFINES=custom_malloc=0 gyp --depth . -f ninja
$ ninja -C out/Default/ main
ninja: Entering directory `out/Default/'
[2/2] LINK main

When custom_malloc is set to 1, a dependency on libmalloc.so is added to each 
target in the config (this includes libmalloc.so itself, so the 
'prune_self_dependency' var is added to break the dependency cycle in GYP). 
This corresponds to the mode when each Chromium executable/shared library is 
built with libc++ instead of libstdc++ (it seems impossible to do the same in a 
cleaner fashion, ideas welcome). GYP is still able to generate ninja:
$ GYP_DEFINES=custom_malloc=1 gyp --depth . -f ninja
...

, but it's impossible to build 'main' because it now depends on itself:
$ ninja -C out/Default/ main
ninja: Entering directory `out/Default/'
ninja: warning: multiple rules generate main. builds involving this target will 
not be correct; continuing anyway
ninja: error: dependency cycle: main -> obj/main.actions_depends.stamp -> main

$ grep -R 'build main:' out/Default/
out/Default/obj/main_initial.ninja:build main: link obj/main_initial.main.o | 
lib/libmalloc.so.TOC
out/Default/build.ninja:build main: phony obj/main.actions_depends.stamp

For some reason in this case GYP adds a phony 'build main' target that depends 
on obj/main.actions_depends.stamp, which in turn is defined as:
$ cat out/Default/obj/main.ninja
build obj/main.actions_depends.stamp: stamp lib/libmalloc.so.TOC main

Original issue reported on code.google.com by gli...@chromium.org on 26 Feb 2014 at 3:25

Attachments:

GoogleCodeExporter commented 9 years ago

Original comment by gli...@chromium.org on 26 Feb 2014 at 3:26

GoogleCodeExporter commented 9 years ago
I find it inconvenient that GYP by design intermixes two different types of a 
dependency of a target on a static/shared library:
 - target is an executable or a shared library, and it must be linked to that shared library
 - target is a 'none' target, and it must be built only after the shared library dependency is built

The above example only needs the dependency to be added to executable and 
shared_library targets, but that's impossible in GYP right now. That's why the 
dependency is being added to every target which confuses the generator (I still 
think there's a bug in the generator). We can introduce a 'link_dependency' 
attribute for a static/shared library that doesn't allow 'none' targets to 
depend on this target:

    {   
      'target_name': 'malloc',
      'type': 'shared_library',
      'variables': {
        'prune_self_dependency': 1,
        'link_dependency': 1,
      },  
      'sources': [ 'mymalloc.c' ],
    }, 

A trivial patch supporting link_dependency in input.py lets me work around the 
problem described in #0.

Original comment by gli...@chromium.org on 27 Feb 2014 at 9:00

GoogleCodeExporter commented 9 years ago
The above example is actually equal to the following one:

{
  'targets': [
    {
      'target_name': 'main',
      'type': 'none',
      'dependencies': [ 'main_initial', 'malloc'],
    },
    {
      'target_name': 'main_initial',
      'type': 'executable',
      'product_name': 'main',
      'sources': [ 'main.c' ],
    },
    {
      'target_name': 'malloc',
      'type': 'shared_library',
      'sources': [ 'mymalloc.c' ],
    },
  ],
}

, which IIUC isn't valid GYP, because there's a target called 'main' and a 
binary with the same name.
Thus this isn't a bug in the Ninja generator, and we just need some knob to 
prevent GYP from generating invalid configs.

Original comment by gli...@chromium.org on 4 Mar 2014 at 12:10

GoogleCodeExporter commented 9 years ago
Mark has committed GYP r1860, which implements the link_dependency attribute.

Original comment by gli...@chromium.org on 5 Mar 2014 at 11:06