Expose a variable for rule outputs? (Use case: Qt moc file generation)

31 views
Skip to first unread message

Eddie Parker

unread,
Feb 26, 2018, 12:31:18 PM2/26/18
to gyp-developer
I'm new to moc, so pardon me if there's a better way of accomplishing this.

I hooked up a Qt project to gyp, and used gyp to generate it's 'moc' files as a separate target:


'targets':
[
{
    'target_name': 'editor_generate_mocs',
    'type': 'none',
    'sources': 
        [
            'src/editorwindow.h',
        ],
    'direct_dependent_settings':
        {
            'sources':
            [
                '<(SHARED_INTERMEDIATE_DIR)/editorwindow_moc.cpp',
            ]
        },
    'rules':
        [
            {
                'rule_name': 'generate_qt_mocs_rule',
                'extension': '.h',
                'msvs_cygwin_shell' : 0, # Don't run cygwin set_env to run a command.
                'inputs':
                    [
                        '>(qt_dir)/bin/moc.exe',
                    ],
                'outputs':
                    [
                        '<(SHARED_INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT)_moc.cpp',
                    ],
                'action':
                    [
                        '>(qt_dir)/bin/moc.exe',
                        '--compiler-flavor', 'msvc',
                        '<(RULE_INPUT_PATH)',
                        '-o', '<(SHARED_INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT)_moc.cpp'
                    ],
                'message': '<(SHARED_INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT)_moc.cpp'
            }
        ]
    },
# ..., rest of my targets
}
]


This works pretty great: however I don't like that in order to add another 'source' file, I'd have to add a line to the 'sources' section, as well as copy/paste the line in direct_dependent_settings for the output sources that are generated.

Ideally I'd love an automatic variable that the rule defines for the list of outputs ("<(RULE_OUTPUTS)"?), or possibly better would be a way to define a variable based on the list of sources; i.e., something like:

'targets':
[
{
    'target_name': 'editor_generate_mocs',
    'type': 'none',
    'sources': 
        [
            'src/editorwindow.h',
        ],

#  Pseudo code begin
'variables':
 {
   'generated_moc_files': [ "<(SHARED_INTERMEDIATE_DIR)/%s_moc.cpp"%( path.basename(x) ) for x in <@(SOURCES)],
 },
# End pseudo code

    'direct_dependent_settings':
        {
            'sources': <@(generated_moc_files)
        },
    'rules':
        [
            {
                'rule_name': 'generate_qt_mocs_rule',
                'extension': '.h',
                'msvs_cygwin_shell' : 0, # Don't run cygwin set_env to run a command.
                'inputs':
                    [
                        '>(qt_dir)/bin/moc.exe',
                    ],
                'outputs':
                    [
                        '<(SHARED_INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT)_moc.cpp',
                    ],
                'action':
                    [
                        '>(qt_dir)/bin/moc.exe',
                        '--compiler-flavor', 'msvc',
                        '<(RULE_INPUT_PATH)',
                        '-o', '<(SHARED_INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT)_moc.cpp'
                    ],
                'message': '<(SHARED_INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT)_moc.cpp'
            }
        ]
    },
# ..., rest of my targets
}
]

Is there a better way of accomplishing what I'm setting out to do?

TJ Grant

unread,
Feb 26, 2018, 1:07:36 PM2/26/18
to Eddie Parker, gyp-developer
Hi Eddie,

I've not used "command expressions" in GYP, but it looks like this is along the lines of what you're looking for:


Particularly noting this:

'variables' : [
  'foo': '<!(echo Build Date <!(date))',
],

And this:

'variables' : [
  'files': '<!(["ls", "-1", "Filename With Spaces"])',
],

With regards to the stack overflow thread you posted, the other answer listed looks like it could be written like this:

'variables' : [
  'files': '<!(moc numerickeypad.h -o moc_numerickeypad.cpp && echo moc_numerickeypad.cpp)',
],

Sources will then probably look like this, but I might have the syntax incorrect (it's variable expansion, but I don't know if you'd need to do something special for lists):

'sources': [
  '<@(files)',
  'other_files.cc',
],

Best regards,

--

---
You received this message because you are subscribed to the Google Groups "gyp-developer" group.
To unsubscribe from this group and stop receiving emails from it, send an email to gyp-developer+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Eddie Parker

unread,
Feb 26, 2018, 1:45:12 PM2/26/18
to tjg...@tatewake.com, gyp-developer
Thanks for the reply TJ!

I've not used command expressions either, but my assumption is that they only get executed when you execute gyp on the commandline.

If that's the case, then the moc file would only get generated if someone issued a 'gyp' command from the commandline, not if they were building from visual studio, like a rule would issue.

Is that the case?  Because unfortunately I'd need the moc compiler to run whenever the .h is newer than the moc_ file generated.

-e-

To unsubscribe from this group and stop receiving emails from it, send an email to gyp-develope...@googlegroups.com.

TJ Grant

unread,
Feb 26, 2018, 3:03:19 PM2/26/18
to Eddie Parker, gyp-developer
Ah, I see…

> I've not used command expressions either, but my assumption is that they only get executed when you execute gyp on the commandline.

Yeah, that's right. In the scenario I presented it would only execute when executing gyp on the command line.

I don't know "moc" but if I understand correctly, you could do something like this:

1. Create a GYP file specifically for "moc" parsing, and targeting a static library
2. Make a target dependency within your VS project based on the header changing, to:
2a. Re-create the gyp project from the GYP file on the command line
2b. Compile it to a static library via the command line
3. Make a target dependency on said static library

Sounds a little complex to me, but then again generating new source files for a project during a project compile seems a bit complex too.
(I can't imagine VS supports this out of the box.)

The only real trick here is ensuring the order is "dependency on h -> generate static lib -> compile main project", which may require a top-level project for the first dependency and a sub-project that contains your actual main project.

Alternatively… you could have a special header / source file that you generate after the "moc" parsing step that simply does a #include for every other header / source file in the "moc"'s target directory.
This wouldn't even require gyp, just a clever shell script.

Actually, I would probably do it that way instead.

Best regards,
To unsubscribe from this group and stop receiving emails from it, send an email to gyp-developer+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--

---
You received this message because you are subscribed to the Google Groups "gyp-developer" group.
To unsubscribe from this group and stop receiving emails from it, send an email to gyp-developer+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages