run a shell command (ctags) in cmake and make
Asked Answered
P

3

15

I'm coding a c++ project in vim.

I'd like to run a ctags command (ctags -R --c++-kinds=+p --fields=+iaS --extra=+q .) to generate references when I run make.

I think the way to do it is to use add_custom_command but I get confused on how to integrate it into CMakeLists.txt .

Palatable answered 22/3, 2012 at 17:16 Comment(1)
I'm not testing these answers anymore. ctags takes time on my ultra low power i5 so i just call it from vim once in a while.Palatable
K
16

The most basic way to do this is:

set_source_files_properties( tags PROPERTIES GENERATED true)
add_custom_command ( OUTPUT tags
    COMMAND ctags -R --c++-kinds=+p --fields=+iaS --extra=+q . 
    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} )
add_executable ( MyProjectOutput tags )

The first line tells CMake that tags will be generated. The add_custom_command is CMake will generate tags when needed, and finally, some target needs to depend on tags. The default working directory is in the build tree, so WORKING_DIRECTORY must be set to your source tree. This is equivalent a Makefile entry:

tags:
    ctags -R --c++-kinds=+p --fields=+iaS --extra=+q .

MyProjectOutput: tags
    # Whatever here...
Kaleb answered 23/3, 2012 at 15:34 Comment(4)
just to make sure, CMAKE_SOURCE_DIR is specified by default. I don't need to specify it. right?Palatable
Yes, CMAKE_SOURCE_DIR is automatically set to the current source directory (may be a subdirectory, if you are recursively adding source files). CMAKE_SOURCE_DIR is usually the directory where the CMakeLists.txt file is located.Kaleb
CMAKE_SOURCE_DIR is the path to the top level of the source tree.Chrystalchryste
Note that set_source_files_properties(tags PROPERTIES GENERATED true) is redundant. Quote from CMake documentation: OUTPUT: (...) Each output file will be marked with the GENERATED source file property automatically.Johniejohnna
K
9

New solution:

I think CMake changed since the previous answer was given.
Here is the lines I added in my CMakeLists.txt (tested with version 2.8.12):

# Add "tags" target and make my_project depending on this target.
set_source_files_properties(tags PROPERTIES GENERATED true)
add_custom_target(tags
    COMMAND ctags -R --c++-kinds=+p --fields=+iaS --extra=+q .
    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
add_dependencies(my_project tags)

And it works perfectly now!

Kalfas answered 6/11, 2013 at 1:4 Comment(3)
Hi Creak, this got flagged as not an answer. Did this solve your problem or are you asking a question. If solving a problem, can you edit your post and clarify so other people don't accidentally flag it? If asking a question, can you remove this and see How to Ask for more details? Hope this helps, and good luck! :)Whomp
@jmort253 : Sorry Creak , I didn't read your post correctly. I have no idea on how to undo flagging (You've made an error and you don't want to attract a moderator attention anymore....).Etoile
@jmort253: I changed my comment, it is definitely an answer and not a question.Kalfas
V
8

Daniel's and Creak's answers got me started, but I ended up with a more complex solution that I thought I'd share:

# Add a top-level "tags" target which includes all files in both
# the build and source versions of src/*.
set_source_files_properties(tags PROPERTIES GENERATED true)
add_custom_target(tags
    COMMAND ctags -R --c++-kinds=+p --fields=+iaS --extra=+q 
        ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
    COMMAND ln -sf ${CMAKE_CURRENT_BINARY_DIR}/tags ${CMAKE_BINARY_DIR}
    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})

# ...but only make it a dependency of the project if the ctags program
# is available, else it will fail to build on Windows.
find_program(CTAGS_PATH ctags)
if(CTAGS_PATH)
    message(STATUS "Found ctags: ${CTAGS_PATH}")
    add_dependencies(MyProjecct tags)
endif(CTAGS_PATH)

It does several things that the simpler solutions do not:

  1. It only adds "tags" as a dependency of the primary build product (MyProject) if there is actually a ctags program on the system. We don't want to break the build just because this is Windows, or because ctags simply hasn't been installed yet on the build system.

  2. It extracts symbols from source files in both the build and source directories. This matters in a couple of cases.

    First, you might be using configure_file() and come from an Autotools background, so you've named your true source files *.in, which means ctags -R won't scan them. You need it to scan the generated versions in the build directory. For example, you might have src/mainheader.h.in in your source tree, with the project version number automatically subbed into it as build/src/mainheader.h.

    Second, some of your "source" files might be generated by other tools. In my current project, I have a couple of C++ header files that are generated by Perl scripts. I want symbols from both the generated headers and the Perl scripts in the tags file.

  3. It works in a subdirectory.

    In the project I'm working on right now, the primary build product is made from src/* relative to the project root, and I only want symbols from that subtree in the tags file. I don't want it to include symbols from the unit tests, the examples, or the utility scripts.

    Because it is designed to run in a subdirectory, it creates a symlink to the src/tags file in the top of the build directory, so that vi -t TagName works. (I'm assuming here that if ctags exists, ln does, too.)

Visceral answered 23/9, 2014 at 19:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.