[cmake-developers] Generating buildsystem metadata from CMake

Anton Makeev Anton.Makeev at jetbrains.com
Thu Mar 19 11:06:03 EDT 2015


Hi Stephen, everyone.

First of all, many thanks for pushing this forward and spending your time to prepare the proposal.
My comments are inline.

> Goals include:
> 
> * Make it possible for IDEs to access the compile-related information for
>  autocompletion and code navigation etc purposes.
> 
> * Remove the need for IDEs to parse generated Makefiles or Ninja files to
>  access compile-related information.  The structure of those files is not
>  'stable', while the content of the metadata file is stable.
>    http://thread.gmane.org/gmane.comp.programming.tools.cmake.user/48412 <http://thread.gmane.org/gmane.comp.programming.tools.cmake.user/48412>
> 
> http://thread.gmane.org/gmane.comp.programming.tools.cmake.devel/10711/focus=11081 <http://thread.gmane.org/gmane.comp.programming.tools.cmake.devel/10711/focus=11081>
> 
> * Remove the need for users to create a new build directory and new build
>  in order to use or switch IDEs.  QtCreator requires that
>  the C::B 'extra generator is used as it parses compile information from
>  that.  Other 'extra generators' such as for eclipse, sublime, kate etc
>  also require fresh/new build directories, although the actual buildsystem
>  they create is identical (assuming using all Makefile based or
>  all Ninja based 'extra generators')
> 
> * Make it possible to write a plugin for the editors/IDEs such as sublime
>  which consumes the metadata file and invokes the build using whatever
>  buildsystem the user already has a build directory for, instead of
>  writing an 'extra generator' and maintaining it in the cmake repo.
>    http://thread.gmane.org/gmane.comp.programming.tools.cmake.devel/9004 <http://thread.gmane.org/gmane.comp.programming.tools.cmake.devel/9004>
> 
> * Make it possible for editors/IDEs to allow specifying the configuration
>  at build-time, where the IDE has that feature, and where a multi-config
>  generator is available.  That is, QtCreator provides user-interface for
>  choosing debug/release config to build.  Currently it can't offer that
>  when using cmake, because it only allows the use of Makefile or Ninja
>  generators, in order to make use of the C::B file.  QtCreator should be
>  able to use the Xcode or Visual Studio generators, generate the metadata
>  file(s), and invoke `cmake --build . --config ${CONFIG}` as
>  appropriate.  Eclipse, Sublime and other editors have similar abilities
>  to invoke config-specific builds after generation.
> 
> * Provide a list of 'build targets', which can be listed and invoked in
>  IDE/editor user interface.  Build targets for all linked binaries
>  and utilties are provided.  The tooling is expected to perform filtering
>  on the target types to show only executables and utilities for
>  execution, for example.
> 
> * Provide a list of source files per target per type of source file, eg
>  object sources, header files, generated files, files excluded from the
>  active configuration/platform/compiler, non-compiled files.

Agree with Tobias here (if I understood correctly):

cmake-metadata-generation page suggests that there should be the following property:
 sources: the list of sources with specific extra build properties specified. Each object in this property has properties described in Source File Properties <http://www.steveire.com/cmake-future/manual/cmake-metadata-generation.7.html#source-file-properties>.

This list seems to be more logical as a property of a target: this way we could easily handle per-file-per-target settings (not sure if it’’s currently supported), and make it easier for IDE to handle this information. But I’m not sure about the details so may be wrong here.

The other thing that seems troubling to me is that since file, target, language compiler options are split into different parts of metadata, the IDE need to know exactly how to assemble them back into the compiler’s command line (e.g. what flags go first file’s or language’s), duplicating CMake's logic that may be different from version to version and from compiler to compiler.
The exact command line is needed to get the actual and precise defines, include search paths etc. from the compiler.

> * Make it more easy for an IDE to support actions such as 'remove file
>  from the project', which requires removing it from the CMakeLists.txt
>  at the appropriate place, and 'add new file/class to target', which
>  involves adding code to the CMakeLists.txt file at the appropriate
>  place.  Most likely the easiest way to do the latter is using the
>  target_sources() command, and to support the former, the location of
>  the declaration of the target, and all target_sources() calls would
>  need to be recorded.  Even that is not enough because of transitive
>  consumption of source files through the link interface, but that is
>  likely irrelevant.

This would be really helpful indeed, currently, we have to introspect CMakeLists.txt files in order to find the most probably place where new files should be placed (works only in basic cases now).
And being able to do so correctly is also crucial for refactoring (e.g. extract class).

> * Provide information about the entire build graph of link-dependencies
>  for visulization and dependency analysis
>    http://thread.gmane.org/gmane.comp.programming.tools.cmake.devel/4042 <http://thread.gmane.org/gmane.comp.programming.tools.cmake.devel/4042>
> 
> * Provide enough information about runtime link dependencies for IDEs to
>  be able to properly invoke targets with debuggers, profilers and other
>  tools.
> 
> http://thread.gmane.org/gmane.comp.programming.tools.cmake.devel/10711/focus=11011 <http://thread.gmane.org/gmane.comp.programming.tools.cmake.devel/10711/focus=11011>
> 
> 
> The CMAKE_EXPORT_COMPILE_COMMANDS variable already exists to generate
> compile command lines, but that is a file whose format is defined by
> Clang, not by CMake, and other tools in the Clang ecosystem also support
> it.  It is not extensible or versioned in the way that a CMake-defined
> file format is, so I don't propose using it as a starting point.
> 
> Notes:
> 
> * I deliberately didn't push an implementation to my repo, so that this
>  discussion can focus on the design of the feature and contents of the
>  file first.
> 
> * In the documentation and the test I didn't mention that the metadata file
>  is JSON.  I'm not opposed to it, but I think there should be some kind of
>  schema defining how to read the metadata file.  If we go with JSON
> (instead of xml, say), then we'd have to define our own schema format, which
>  is not impossible.  My proposal is to generate the schema beside the metadata
>  file instead of writing a metadata version into the metadata file
> itself.  Does
>  anyone feel strongly about the file being JSON?  I just want to record the
>  reason for everything in this design phase - we don't have to spend a lot
>  of time on it.
> 
> * I didn't document the location or directory.  I'm not clear on whether
>  it is supposed to be the build location, or the install location(s!),
>  or all of those.

It would be useful, though, to have a location of generated files for each target: in case metadata misses some information (and I think it won’t cover every possible need anytime soon), IDE will be able to get if from generated makefiles. 

> * I don't generate 'dependencies' (actually the list of files which the
>  buildsystem re-generation depends on) as Aleix did, because there is no
>  well-defined usefulness for that list yet.

As Tobias pointed, we at least need to know what files are the part of CMake project, that is, the list of all CMakeLists.txt and *.cmake files, used for generation (ideally, including missing ones, since in that case IDE could be able to tell when missing file is created and refresh the project)

> * I documented the 'name' for the targets, and the TARGET_FILE_NAME
>  etc information, and can push an implementation which generates them.
> 
> http://thread.gmane.org/gmane.comp.programming.tools.cmake.devel/10711/focus=12619 <http://thread.gmane.org/gmane.comp.programming.tools.cmake.devel/10711/focus=12619>
> 
> * If it is useful to preprocess/compile/assemble individual files from
>  IDEs, as made possible by the Makefiles and Ninja generators, we'll need
>  to design that.
> http://thread.gmane.org/gmane.comp.programming.tools.cmake.devel/10711/focus=12429 <http://thread.gmane.org/gmane.comp.programming.tools.cmake.devel/10711/focus=12429>

This is definitely useful, but I’m not sure what kind of information needed here,
as I see it, since we already know the files in the project, we can tell make/ninja to simply compile it.


> * Some more information from project() may be relevant, but it's not clear
>  yet. We will likely know more when we have decided the file format and
>  generated some 'interesting' metadata files.

Project name, list of the configurations are most needed ones.
We also use CMAKE_<lang>_SOURCEFILE_EXTENSIONS to determine if a given file is potentially source file or not.

> * We might need backtraces for not only all add_library and add_executable
>  calls, but also all target_sources() calls.

> 
> * We list the Generator used to configure the build.  That way IDEs know
>  which build output parser to use.
> 
> * I propose to generate one metadata file per configuration active in the
>  buildsystem.  That means that the Makefile and Ninja generators would
>  generate only one file, and the multi-config generators would generate
>  multiple files.  When changing the 'active configuration', IDEs would
>  then read whatever metadata file is relevant to the active configuration.

This has already been discussed but I give our usage scenario:

in CLion we retrieve the list of all build types (aka configurations, Debug, Release etc) and then generate project using Makefiles generator for each of them.
This is necessary because of several reasons:
1) To be able to correctly build language model, we need to know, when a file is used in several configurations, which means, it's compiler settings and macros are different.
    E.g. some branches of code may not be available in Debug or Release and we give user an option to quickly switch between them in the editor.
2) Though, the case is rare, the list of the targets may be different in configurations, and we want to show all the targets (with an options to change configuration during build time).

There is also another issue with Makefiles/Ninja generator: if CMAKE_BUILD_TYPE is not specified, an unnamed configuration is generated, that is neither Debug nor Release.
And we don’t know in advance what configurations are available, since the list of them may be redefined.

I don’t know if it’s possible at all, but it would be great if we could have info for all configurations generated in one go (not only for multi-config, but for single-config generators as well like Ninja and Makefiles).

As a side note, it seems more natural to me to have one json file with one or several configurations listed, providing that there is also shared project info that should be in that files.
something like that:

project: ProjectName
configurations: {
 {
   name: Debug
   targets: {...}
 },
 { 
  name: Release
   targets: {...}
 }
 ...
}

>  This also means that conditions don't need to be added inside the metadata
>  file for configurations in order to show files 'excluded' by being part of
>  a non-active configuration.  The code implementing discovery of excluded
>  files is in the generate-metadata branch in my clone.
> 
> 
> http://thread.gmane.org/gmane.comp.programming.tools.cmake.devel/10711/focus=11323 <http://thread.gmane.org/gmane.comp.programming.tools.cmake.devel/10711/focus=11323>
>    "At least Qt Creator does not need information on which conditions to
>     be met for a file to become part of the current build."
> 
> * I propose generating language-specific source lists, because CMake can
>  build files with compilers which do not match their file extension.
> 
> * I propose generating language-specific compile properties in the metadata
>  file if there a language specific variant groups.  For example if the
>  compile options themselves are language-specific (the feature enabling that
>  was merged to CMake master this week), then a property for each language
>  is specified.  Otherwise only a language-agnostic property is generated. This
>  can vary per-configuration for a multi-config generator, so each metadata
>  file for a multi-config generator could have different properties present.
>  Consumers read the language specific property if it is present, and read
>  the language agnostic version otherwise.
> 
> * Generating metadata only (without generating buildsystem files) is not
>  currently in scope.  This was requested several times, but it is not
>  clear why.

It’s simply to be able to get this the information as quickly as possible.
I’m not sure which part is most slow, but, say, InsightToolKit 4.5 (http://www.itk.org/Wiki/ITK/Source <http://www.itk.org/Wiki/ITK/Source>), generates in couple of minutes. The regeneration, even when nothing was changes, a few dozens of seconds.

Plus, we’d prefer being able to open the project without any questions to user, e.g. not asking, which generator he/she prefers. If we generate using ‘wrong’ default generator we’ll need to regenerate everything again when user decides to change it.

Another benefit of skipping actual generation is possibly better error recoverability.
That is, some generators may fail here and there if the project is incorrectly configured (e.g. source files are missing). Skipping the generation phase will (probably) help getting the project metadata even in that case.

But anyway, it seems a little outside of the scope of the discussion.

> * How much information does tooling need about installation?  Targets
>  can use different include directories and compile definitions in their
>  install locations compared to their build locations.  If IDEs want to
>  provide some user interface related to the project files in their
>  install location, perhaps a separate solution based on cmExportFile*
>  is needed.  For future investigation.


An additional though: here only the 'project information' aspect is discussed; though, to be fully machine-frienly, cmake should be able to also generate parseable output (error reports etc), provide the progress, etc. So, just to mull over, probably the discussed design should consider such future direction.


Regards,
Anton Makeev
JetBrains
http://www.jetbrains.com <http://www.jetbrains.com/>
"Develop with pleasure!"

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/cmake-developers/attachments/20150319/edfbfa58/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 2856 bytes
Desc: not available
URL: <http://public.kitware.com/pipermail/cmake-developers/attachments/20150319/edfbfa58/attachment-0001.bin>


More information about the cmake-developers mailing list