[cmake-developers] Generating buildsystem metadata from CMake

Tobias Hunger tobias.hunger at gmail.com
Sun Mar 22 15:45:28 EDT 2015


Hi Stephen,


On Sat, Mar 21, 2015 at 9:18 AM, Stephen Kelly <steveire at gmail.com> wrote:
>> Could you add have a "configuration list" key in the top level of each
>> file that lists all available configurations (including itself)? That
>> might be the lowest overhead solution that does not require parsing
>> extra files that I can think of right now.
>
> For Ninja and Makefile generators, CMake does not necessarily know 'all' of
> the configurations. It only knows what the user specified as the
> CMAKE_BUILD_TYPE. I could have a CMakeLists.txt with a condition like:
>
>  if (CMAKE_BUILD_TYPE STREQUAL Coverage)
>    # Foo
>  endif()
>
> and I could document to users/developers that they use it for coverage.
>
> CMake would not treat the above any differently to any other condition on
> any other variable. CMake can probably list its own built-in configurations,
> like Debug/Release/RelWithDebInfo/MinSizeRel, but that's not a generic
> solution. If you want though we can do that.

I understand and expect that.

>> I definitely will not hardcode cmake generator-A has configurations X
>> and Y while generator-A supports configurations X, Z and D into the
>> cmake plugin. I do prefer not to support configurations at all to
>> doing that.
>
> I think your position is reasonable. It is likely that you should consider
> Makefile and Ninja generators to be single-configuration, and we provide a
> way to give you the CMAKE_CONFIGURATION_TYPES for the multi-config
> generators.

I think that is fine.

>> What we do there is to check the default project build location for
>> folders that contain a build of the current sources.
>>
>> To do so we need to know which code was built in that directory
>
> I get this: The JSON file in the build dir would contain the path to the
> source and that part of the problem is solved, right?

Yes, that would already be a step into the right direction.

>> and
>> which kit (think set of compiler, Qt, some other settings) were used
>> to in the built in that directory.
>
> Is this hypothetical? Currently I can add a compiler location and a Qt
> location in QtCreator, and I can create a kit and give it a name and
> partcular compiler and Qt. However, the information I configure there and
> the kit that I choose is not passed to cmake when creator invokes that,
> right? CMake will do its own determination of the compiler to use, and will
> find Qt on its own, right? Unless the user manually sets those as arguments
> in the 'Run CMake' dialog page.

We do that for qmake projects at this time.

Nothing listed here is needed to get the level of cmake support we
have in Creator right *now*: That works fine already after all. I want
something better:-) So I bring up all the things I can think of to get
cmake to the same level that we currently have for qmake.

> My point is that you have to pass CMake this information before it can pass
> it back to you :). I might be looking at an old creator which doesn't have a
> relevant feature here though?

No, we do *nothing* to help with configuring a cmake project. That is
far from ideal, you are right there.

> Or are you thinking of scenarios such as 'the user creates a build outside
> of Creator and then tries to open it in creator'. Given that 'a kit' is
> something internal to Creator, there is no way CMake could tell you the kit
> in that scenario. Is that obvious or am I missing something? I think the
> best thing you can do there is find out which compiler was used, and what
> the value of Qt5Core_DIR is, and map that to things you know about available
> kits to find the match if there is one.

Yes, that is the same we do for qmake projects. In fact we just create
a new kit for configurations we had not seen before.

> In other words, this again collapses to 'we need a way to read cache
> values'.

Yeap.

>> We also need to figure out the
>> exact configuration (parameters passed to the "configure" step of the
>> build system) that was built there.
>
> My first question is 'Why?'. Running 'cmake .' in the build dir re-uses the
> options which were passed to it before.

In qmake it is perfectly save to do "rm -rf builddir" and then hit
"Build" in Creator. I would love to have the same for cmake projects.

> Aside from that, particular arguments can be retrieved from the cache. It
> seems that some stable interface to the cache is needed anyway. At most,
> this is just another reason to add a stable interface to it, right?

Yeap, that would be fine.

>> Since this is a feature our qmake users love I would also like to make
>> that possible with cmake. It would be great if I could get most
>> answers from the json file.
>
> I see. How do you determine which kit to use if you are imported an
> externally generated qmake build? Do you use heuristics like I described
> above?

We exctract as much data as we can from the qmake build (Qt version,
compiler, etc.) and then try to find an existing kit with those
characteristics.

If none is found we set up a new kit with all the settings.

>>>   Set up a filesystem watcher for each of the (very many) files.
>>>   If one of the files changes:
>>>     Run `cmake .` in the build dir
>>>   If the metadata file changes:
>>>     Reload the data it contains
>>
>> Yes, that's the scenario.
>
> In the 'one of the files changes' scenario, how do you imagine the change
> happened? Something the user did, either in creator, or a git checkout, or
> anything else?

All of them:-)

Git and other VCSes regularly touch the build system on updates. We
have users editing them in Creator, while others use some other means.
So I'll go with "all of the above":-)

>>> Is it a problem if the value of 'very many' above is in the hundreds?
>>
>> I would probably trim down the list to those actually in the project
>> or build directories, but I would prefer having too much information
>> than too little:-)
>
> I don't see any reason to watch anything in the build dir. It is 'owned' by
> cmake and the user has no business messing with any files there.
> Additionally, any messing around they do there would immediately be
> overwritten by Creator running in the background.

True. So watching the files in the source dir should be enough.

> It seems that the relevant locations are 'within the source tree' and 'some
> external site of cmake files', such as the cmake installation itself, or
> cmake helper files shipped by a 'platform' like KDE.
>
> What do you think? Are changes to files outside of the source tree relevant
> at all? Is the 'you update your system cmake' scenario important enough that
> Creator should immediately update the content it shows without user
> interaction?

I think the files in the cmake files in the source dir are what I will
end up watching.

I do need to offer a way to force cmake to regenerate everything
anyway, so that is fine for the few cases where somebody updates cmake
or globally installed cmake files.

> FWIW I think the IDE should not do this 'regeneration in the background' for
> me when I edit files outside of the IDE. If I have Creator open in the
> background and then I go to the console and edit some files (possibly
> outside of the source dir of the project which is open in Creator), and save
> multiple times over a few seconds, I don't want Creator to be constantly re-
> running cmake for me. Or I'm doing a 'rebase -i' or anything else which is
> not for Creator to worry about. I also wonder how cmake would react if I
> edited those files and I ran 'cmake .' myself, and Creator did the same
> thing at the same time. I don't know that cmake currently defends against
> that.
>
> I only want the IDE to re-generate when I'm actually working in the IDE. If
> I edit any file and hit Ctrl+B, the IDE runs 'cmake --build .' and cmake
> regenerates if needed at that point. It's 'ok' if the project tree is
> technically 'stale' after I edit a file and before I hit Ctrl+B. It's 'ok'
> in the sense that the alternative is 'worse' as far as my opinion goes. You
> also have the option of running 'cmake .' any time any file is saved in the
> IDE, if that improves the experience, but I strongly believe you shouldn't
> be watching the files for outside changes and re-generating in response.

That might be ok for you, but we do get a lot of bug reports whenever
we have the project tree not update directly. So it is *not* ok for a
large number of users, particularly those that come from a proprietary
IDE that comes with a built-in build system.

We do *not* update creator while it is not in use. When the window
gets focus again we go "Things have changed outside Creator, do you
want to update?".

> That's not to say we won't 'give you the rope'. But before we would do that,
> cmake would have to be defensive against concurrent runs in the same build
> dir.

A simple lock file should suffice. I would be surprised if that was
not there already, but I never checked.

>>>> I would love to have something like ccmake built into Qt Creator at
>>>> some point, and having this information would spare me poking around
>>>> CMakeCache.txt and whatnot:-)
>>>
>>> If you mean you would like a fully-featured cache editor in Creator, then
>>> reading CMakeCache.txt is unavoidable, but you'd probably fork some of
>>> the Source/QtDialog code as a starting point.
>>
>> Is CMakeCache.txt considered to be a implementation detail of cmake,
>> or is it expected that external applications will parse it?
>
> As far as I know the file is an implementation detail. So, I guess if we add
> some stable interface for reading it, you wouldn't really have to read the
> CMakeCache.txt file directly and could 'write' it by invoking cmake with -D
> arguments.
>
>>>  $ cmake -E read_cache Qt5Core_DIR Boost_ROOT KF5Archive_DIR ZLIB_LIBRARY
>>>  {
>>>    "Qt5Core_DIR": "/opt/qt5/...",
>>>    "BOOST_ROOT": "/opt/boost/1.58/...",
>>>    "KF5Archive_DIR": "/opt/kf5/karchive/...",
>>>    "ZLIB_LIBRARY": "/opt/zlib/..."
>>>  }
>>
>> Yes, that would be nice, but once you add "cmake -E list_cache" you
>> could just as well just add the whole config into the json file and
>> let its users worry whether or not to actually read the section.
>
> When you wrote 'config' you meant 'cache key value pairs' or simply 'cache'.
>
> The key difference is that my proposal is only requested values, so is
> minimal.

Yes. But then you need to add "cmake -E list_cache" that lists all
values. Or how can I find out which values are there in a project?

Maybe also "cmake -E check_cache KEY" to check whether a key exists,
etc. And "cmake -E query_cache KEY" to get the type and advanced flag
for the KEY.

In the end it is probably easier to either put all that stuff into the
json file or to declare CMakeCache.txt to be a stable read-only file
for the configuration.

> As you suggest, we could write all of the cache data into the generated
> cmake-metadata.json file. Alternatively, we could design the interface such
> that you specify not only what version of the metadata you want, but also
> which cache values
>
>  $ cmake . -DCMAKE_GENERATE_METADATA=3.3 -DCMAKE_METADATA_CACHE="Foo;Bar"
>
> to generate a cache section in the metadata file with the 'Foo' and 'Bar'
> key-value pairs.
>
> Is there any particular reason you want "everything" instead of specifying
> what you want?

Mostly because I want to be able to rm -rf "builddir" and still be
able to build:-)

> You don't know how to understand 'everything'. Is it just
> because of the idea you wrote above about a cache editor within Creator?

... and because of a cache editor.

> Why not just run cmake-gui as an external process?

My hope is to get good cmake support into creator, not to add a more
fancy set of clutches:-)

That is one more thing that needs configuring, it is ugly to have yet
another window pop up and I can not embed that where I want the
information to be visible.

> Note also that nothing in the cache tells you the path to qmake for Qt 5 or
> anything like that. The Qt5Core_DIR is a path to
> `qt_installation/lib/cmake/Qt5Core`. Depending on how Qt was built, qmake
> may or may not be in `../../bin`. I don't know if that's relevant to
> Creator. At any rate, the content of the Qt5Core_DIR variable is what
> identifies Qt to CMake. qmake does not identify Qt 5 for CMake. However, if
> you run `qmake -query QT_INSTALL_LIBS` for each of your available Qts, you
> can map to the right one easily enough.

Thanks for the tip! It is appreciated.

>>>> Having the full configuration available would also remove the need to
>>>> have special flags in the "Metadata Contents" section for the compiler
>>>> used.
>>>
>>> I don't know what you mean. You mean '-g', '-O3' etc? Or are you
>>> referring to what I wrote about the pattern of the compile command line,
>>> and the order of where includes definitions and compile flags appear?
>>
>> You documented a couple of keys in the top level that deal with the
>> compiler (See "Metadata Contents/Optional Properties", e.g.
>> "<lang>_compiler").
>>
>> I will need more information than just the compiler used: The Qt
>> version used is obviously important to us,  as are all settings
>> related to cross-compilation.
>
> By 'important to us', do you mean 'we provide interface allowing the user to
> edit the values, and we pass those values to CMake on behalf of the user'?
> Is that currently the case? If it is not currently the case, does the fact
> that the metadata file does not currently exist somehow block that? If so,
> how? That feature seems completely orthogonal to the metadata file to me. It
> could be added to Creator at any time if it is not there already.

We do not do that *yet*: Currently the configuration inside Qt Creator
and that of cmake are two entirely separate beasts, and that is a huge
part of why I consider our cmake support to be in dire need of
improvement. We need to feed information into cmake when we first set
up a build directory and we need to retrieve that information back
from cmake when we read make use of a build directory.

I would really appreciate getting all possible information from CMake
mostly since I doubt you can decide what each and every IDE will need
that wants to integrate cmake.

We need the Qt version used for the code model as well as for the help
system. CLion will most likely not be so concerned about that piece of
information but will need something else instead.

Please do not try to second-guess which information might be relevant
to any IDE, that is bound to fail.

>>> Yes, so far this is possible, and doesn't carry a requirement to not
>>> generate an actual buildsystem...
>>
>> I agree with Anton that it would be nice not to have to ask for a
>> build directory and generator first thing.
>
> Adding a way to make cmake dump the metadata to stdout would be possible,
> but it wouldn't help...

Why not? We could set a temporary build dir and you give us the data you can.

We have people that want to look into projects and moan when we ask
them to configure a build dir since they do not understand why they
need that: They want to browse the code only.

We do need the information from the build system to set up the code
model correctly and thus need to put them through that -- from their
point useless -- setup.

>> Many users just want to
>> browse some project and an IDE should support that use case as well as
>> possible. Nagging those users about a build directory or generator is
>> not the best user experience.
>
> ... CMake needs a directory to run in. It needs to generate files to compile
> to test the compiler features, determine the platform etc. The content of
> the project depends on the outcome of those configure-time tests. You need
> to give cmake a temp directory in this scenario *anyway*. A temp directory
> from your OS is fine, and you can read the metadata file from there.
>
> This doesn't change the scope or requirements afaics.
>
>>>  $ cmake -E list_generators
>>>  {
>>>    "generators": ["Unix Makefiles", "Ninja", "Xcode"]
>>>  }
>>>
>>> etc.
>>
>> That would be *really* nice to have once this metadata file is in place:-)
>
> It is also orthogonal to the metadata of the build itself and can be
> designed separately.

I agree.

> I filed
>
>  http://public.kitware.com/Bug/view.php?id=15462
>
> if you want to engage in the design or implementation of that.

Thanks. Bookmarked:-)

> So, requirements gathered in this email:
>
>  * Being able to read cache values is of primary importance
>  * * Open question whether values should be 'on demand' or 'always all'

I vote for "always all". That should be simpler.

>  * Knowing which CMake files in the source directory need to be watched for
> changes is very important.

Yes.

>  * Knowing which CMake files outside of the source directory need to be
> watched for changes is very important.

I'd say that is just important.


More information about the cmake-developers mailing list