mesonbuild / meson

The Meson Build System
http://mesonbuild.com
Apache License 2.0
5.39k stars 1.55k forks source link

Suggestion: an option to make custom_target touch/create (empty) output file #11506

Open v1993 opened 1 year ago

v1993 commented 1 year ago

Motivation

I'm trying to integrate glslValidator into my build system for verifying shaders at compile time. The catch is that I'm using it as a validator (rather than compiler into SPIR-V), so its purpose is to simply exit successfully rather than produce any output files. This makes it apparently impossible to integrate well into meson right now:

shader_validation = custom_target(
    'shader_validation',
    output: 'shader_validation.txt',
    input: shader_files,
    command: [glslangValidator, '-t', '@INPUT@'],
    #capture: true,
    build_by_default: true, # I want to run it as part of a standard build to check for errors
)

This makes it re-run validator on every build since output file doesn't get created. Uncommenting capture: true fixes this particular problem (so glslangValidator is only invoked when I edit shaders), but instead leads to an even worse one: in case of an error stdout with errors gets lost, leaving me without vital information to diagnose the problem.

While my personal issue is specifically with glslangValidator, I imagine it would be pretty much the same with any other validator program out there.

Suggestion

Add a boolean keyword argument touch_output_files to custom_target that makes Meson create/update timestamp on output files after command successfully exits (much like touch).

Current workarounds

While a little messy, this does the job:

if (glslangValidator.found())
    touch = find_program('touch', required: true, native: true)
endif

shader_validation = custom_target(
    'shader_validation',
    output: 'shader_validation.txt',
    input: shader_files,
    command: [glslangValidator, '-t', '@INPUT@'],
    console: true,
)

custom_target(
    'shader_validation_toucher',
    output: 'shader_validation2.txt',
    depends: [shader_validation],
    command: [touch, 'shader_validation.txt', 'shader_validation2.txt'],
    build_by_default: true,
)

Nothing is done if shader files weren't modified and validator runs with proper stdout as well (console: true is not required, but is apparently nice to have).

Another, simpler but subopimal option, is to pass -E to glslangValidator and set capture: true, which causes it to print errors to stderr (which is dumped into console) and output preprocessed GLSL to stdout (which meson redirects to output file):

shader_validation = custom_target(
    'shader_validation',
    output: 'shader_validation.txt',
    input: shader_files,
    command: [glslangValidator, '-t', '-E', '@INPUT@'],
    build_by_default: true,
    capture: true,
)

Obviously, this forces glslValidator to do somewhat more work than actually needed, so it's still less than ideal. Additionally, option like this might as well be missing on other validators out there.

eli-schwartz commented 1 year ago

I'm trying to integrate glslValidator into my build system for verifying shaders at compile time.

But you only need this when the shader sources are edited during development, right?

Maybe the real solution here is to add this as a test() and run tests during your development workflow e.g. in CI?

v1993 commented 1 year ago

But you only need this when the shader sources are edited during development, right?

Correct, I have shader validation available as a feature-type option right now.

Maybe the real solution here is to add this as a test() and run tests during your development workflow e.g. in CI?

That's an interesting idea. However, when actively working on a game, it makes sense to make shader validation failure lead to build failure (like it would in case of using glslValidator to compile shaders into SPIR-V rather than just validate them) since invalid shaders will result in program that's not functional overall and will eventually encounter runtime error (from driver's own shader compiler). As such, failing as early as possible is important - and CI is pretty late.

eli-schwartz commented 1 year ago

Do you tend to run meson test as part of your local dev workflow before running the binary interactively?

v1993 commented 1 year ago

No - it's a game we're talking about, so basically all testing is either done as validation on compiler and linker's part or interactive (everything that could be tested otherwise is already a separate library). Moving shaders to first part of this flow is essentially what I'm trying to do.