How to create reliable command-line configured argument dependencies for custom commands?

I have a build system use case (building the 5 papers that currently
describe FreeEOS) where the custom commands that are run to generate
plots for the papers have a configurable argument (the name of the
PLplot device that generates those plots). Currently, that configured
argument appears in no file and does not affect the name of any
generated files. But I obviously want those custom commands that
create plots to rerun whenever that configured argument is changed.

For my complex use case where the above conditions apply, it appears
that CMake does have a default mechanism for figuring out when command
arguments are reconfigured for custom commands, but that mechanism
appears to be unreliable. That is, when I reconfigure the PLplot
device name, plots are rebuilt and the paper is rebuilt for four of my
papers but not the fifth. And I cannot spot any difference in the way
the PLplot device is specified for that fifth paper compared to the
rest.

I plan to solve this issue in a reliable way by configuring a file
containing the name of the PLplot device, and then making all custom
commands that depend on that configured argument, file-depend on that
configured file instead. But if someone has a better idea for
implementing configured argument dependencies for custom commands or
has knowledge of the current default way that CMake does that, please
comment.

Sorting out a missing file dependency makes the “solution” figures and paper rebuild properly
whenever the PLplot device is changed without going to the configured file approach I outlined.
So it appears that CMake does implement custom command argument dependencies reliably at
least for this example. Can build-system designers always depend on that capability?

Possibly, although you may find that CMake older than a certain release does things differently, so it partly depends on the range of possible versions you need to support. If you’ve got full control over the build environment and you can require CMake 3.16+ or 3.17+ or whatever, then if it works for you it should keep working, though I’d test hard for corner cases.

For instance, it’s possible the generated build system could operate as expected when you run make all (which is implicit in just make), but fail to trigger the right set of dependencies if you make $specific_target.

Practically the entire purpose of add_custom_command() is to generate files so that targets can depend on them. (“Generating Files” is even the section heading that covers 3/4 of the length of that command’s documentation page.) So, the official CMake position will probably be that it’s safer to write the configs to a file and set the necessary dependencies on that file, and there’s some wisdom in that.

Having add_custom_command() rules depend on the output of a previous add_custom_command() should be pretty safe and reliable. (As long as all of the necessary dependencies are in place, as you discovered.) It’s one of CMake’s core functions to manage those relationships between build rules.

But what does that first file depend on, that would ensure it’s always going to be regenerated anytime and everytime the configuration gets updated? The only files being modified during a config change, potentially, are the build scripts — relying entirely on implicit dependencies there feels a whole lot less safe.

It might work. But, probably far safer to explicitly generate a file during the build, something the first link in your dependency chain can be configured to depend on so that it’ll always get triggered to rebuild when that file is updated.

That’s my 2¢, anyway.

Hi Frank:

Thanks for your thoughts on this topic.

For at least my use case, CMake (version 3.13.4 is what I am testing
since that is the minimum CMake version I allow for this project)
appears to be doing exactly the right thing (once I implemented the
file and target dependency chains properly but with no special
provisions for argument dependencies). That is all commands previous
in the dependency chain to commands whose arguments are changed are
not rebuilt while the commands whose arguments changed as well as
all commands that depend on those changed argument commands are
rebuilt.

I am happy with that correct result for how argument changes
automatically (with no special provisions) propagate through existing
file and target dependency chains since it makes a big practical
difference for my particular use case. There it takes 13 minutes of
real time and ~80 minutes of cpu time to rebuild the papers from
scratch with virtually all that time spend on generating data files to
be plotted. But to just to rebuild the plots whose command-line
arguments changed, and papers that depend on those plots without
rebuilding those data files takes only ~10 seconds or so. Which
allows quick comparisons of the quality of the figures generated by
various combinations of PLplot options. So thanks to CMake knowing
exactly what to do with changed custom command arguments and their
associated dependency chains, those ~60 plot comparisons for different
sets of PLplot options are a near-interactive experience.

1 Like