cdelledonne / vim-cmake

Vim/Neovim plugin for working with CMake projects
MIT License
259 stars 21 forks source link

Retrieve build targets using CMake's file API #62

Closed cdelledonne closed 1 year ago

cdelledonne commented 2 years ago

Vim-CMake uses the help target to retrieve a list of available build targets. When running cmake --build <build_dir> --target help, there are a few differences between the output for Makefile systems and that for Ninja systems—e.g. the format is different, and Ninja systems also return a lot more entries.

To make the retrieval of build targets consistent and build tool-independent, we could use CMake's file api. From https://github.com/cdelledonne/vim-cmake/issues/57#issuecomment-1203294478:

Fortunately CMake has a feature for this. It is called cmake-file-api(7) and is meant to be used by 'clients' to retrieve semantic information about the buildsystems CMake generates. So exactly what we want, especially with the Object Kind "codemodel".

Parsing JSON data should not be an issue, as both Vim and Neovim provide the function json_decode().

cdelledonne commented 2 years ago

@marwing we'd need to decide how to incorporate this into the architecture of Vim-CMake. Feel free to propose something, otherwise I'll take this up in a few weeks.

marwing commented 2 years ago

Integrating this into Vim-CMake seems simple enough:

We may want to create/update query files when running any CMake command, to create/update in existing build trees. We also may want to re-parse after a :CMakeGenerate or :CMakeBuild as this may regenerate the buildsystem and update the replies (e.g. after adding/removing a target to/from the project).

Depending on the complexity of parsing the files correctly this might warrant a separate file like cmake-api.vim (to not confuse with Vim-CMake's api). If we want to support CMake versions lower than 3.14 (where the file api was introduced) we should keep the current solution as a fallback for at least Makefile support, otherwise I would replace it to avoid duplicated responsibilities.

Have I missed something? If not I would work on this and open a pull request. With vim supporting json_decode() this should be pretty straightforward.

cdelledonne commented 2 years ago

We may want to create/update query files when running any CMake command, to create/update in existing build trees.

I'm not sure I understand why. Doesn't a query file only specify the information we'd like to receive from CMake? What parts of the query file are to be changed after generating the first query file?

We also may want to re-parse after a :CMakeGenerate or :CMakeBuild as this may regenerate the buildsystem and update the replies (e.g. after adding/removing a target to/from the project).

Yes, definitely.

Depending on the complexity of parsing the files correctly this might warrant a separate file like cmake-api.vim (to not confuse with Vim-CMake's api).

I leave this to your judgement, if the complexity of creating/parsing files warrants a new module, just create it. Perhaps fileapi.vim would be a fairly unambiguous name.

If we want to support CMake versions lower than 3.14 (where the file api was introduced) we should keep the current solution as a fallback for at least Makefile support, otherwise I would replace it to avoid duplicated responsibilities.

I would indeed get rid of the old solution, for easier maintenance. Perhaps we should check the CMake version when any of the API functions is invoked and issue an error if CMake < 3.14, or something along these lines.

Have I missed something? If not I would work on this and open a pull request. With vim supporting json_decode() this should be pretty straightforward.

Great! Just be aware that json_decode() only accepts strings in Vim, while it also accepts lists in Neovim. I found out this recently (I still need to fix the other calls to json_decode() throughout the code).

Thanks a lot for taking this up, looking forward to your PR, which I'll only be able to review in 2-3 weeks.

cdelledonne commented 2 years ago

By the way, somewhat related question. When running :CMakeGenerete, Vim-CMake also retrieves a list of CTest tests defined in the build tree by running ctest --show-only=json-v1, which returns a JSON string. Would you perhaps know whether there's a way to retrieve tests with the file API, so as to make our queries to CMake consistent?

cdelledonne commented 2 years ago

One more thing: when making a list of CMake targets, I believe we should filter out interface libraries, as they do not generate any build rules. Would you agree?

marwing commented 2 years ago

I'm not sure I understand why. Doesn't a query file only specify the information we'd like to receive from CMake? What parts of the query file are to be changed after generating the first query file?

If a user already has a build-tree generated our query won't be there. If we now want target completion to work we have to somehow get our query in and regenerate (to generate the replies). We could ask users to regenerate or just automatically regenerate if we don't find our query or we rely on the user doing something for CMake to regenerate during build. Unfortunately updating queries doesn't make CMake regenerate during build so that would be hit or miss.
Also we may want to update our query in the future to get additional information to support new features.

I would indeed get rid of the old solution, for easier maintenance. Perhaps we should check the CMake version when any of the API functions is invoked and issue an error if CMake < 3.14, or something along these lines.

Will do. On a related note, how does error management work. I know there is logger.vim but how do I abort out of nested calls? Are throws OK if I catch them at the module boundary?

Great! Just be aware that json_decode() only accepts strings in Vim, while it also accepts lists in NeoVim. I found out this recently (I still need to fix the other calls to json_decode() throughout the code).

Thanks for the tip. I assumed this behavior in neovim as well but missed that readfile() returns a list. That would have been fun to find...

Would you perhaps know whether there's a way to retrieve tests with the file API, so as to make our queries to CMake consistent?

I actually thought about this before but I can't find a way to query tests using the file api. With ctest returning JSON this is way more robust anyway though so this is no big issue IMHO.

One more thing: when making a list of CMake targets, I believe we should filter out interface libraries, as they do not generate any build rules. Would you agree?

I'm actually not sure about this as interface libraries may be used to group related targets. However this doesn't seem to be a question as (based on some initial tests) interface targets don't show up in the codemodel reply anyway.