DikobrAz
DikobrAz

Reputation: 3707

How to make CMake target executed whether specified file was changed?

I'm trying to use ANTLR in my C++ project. I made a target for running ANTLR generator for specified grammar and made main prjct dependent from it.

ADD_CUSTOM_TARGET(GenerateParser
    COMMAND ${ANTLR_COMMAND} ${PROJECT_SOURCE_DIR}/src/MyGrammar.g 
                             -o ${PROJECT_SOURCE_DIR}/src/MyGrammar
)

ADD_LIBRARY(MainProject ${LIBRARY_TYPE} ${TARGET_SOURCES} ${TARGET_OPTIONS})
ADD_DEPENDENCIES(MainProject GenerateParser)

The problem is that ANTLR generator running every time I build project and consumes enough time. How can I make it run only whether my grammar has been changed? Or may be it is possible to make ANTLR somehow generate parser only for out of date grammar.

Upvotes: 23

Views: 17523

Answers (4)

xaviersjs
xaviersjs

Reputation: 1737

I had the exact same question. After reading how the makefiles were generated (because cmake documentation leaves a lot to be desired), it looks like the best solution is to use add_custom_command of the OUTPUT form. Here's my example

add_custom_command(OUTPUT
                   # In my cmake file I list every file generated
                   ${PROJECT_SOURCE_DIR}/src/MyGrammar/file1
                   ${PROJECT_SOURCE_DIR}/src/MyGrammar/file2
                   COMMAND ${ANTLR_COMMAND} ${PROJECT_SOURCE_DIR}/src/MyGrammar.g
                   -o {PROJECT_SOURCE_DIR}/src/MyGrammar

                   # In my case I used a script checked into source control, 
                   # so I want to know when it changes too
                   DEPENDS ${ANTLR_COMMAND} ${PROJECT_SOURCE_DIR}/src/MyGrammar.g)

# cmake caches are problematic, so list the files in a variable
set(generated_sources src/MyGrammar/file1 src/MyGrammar/file2)
add_library(yourlib ${list_of_source_files} ${generated_sources})

Then when you build cmake will check the command and grammar files for changes before deciding to re-generate sources.

Upvotes: 2

DikobrAz
DikobrAz

Reputation: 3707

Besides proposed solution with custom target, if your target depends on some generated sources the common workflow is the following:

Add target that generates your source file. I recommend to use full paths to avoid mistakes.

add_custom_command(OUTPUT ${GENERATED_SOURCE_FILE}
    COMMAND ${GENERATION COMMAND}
    DEPENDS ${DEPENDENCIES}
)

Set GENERATED properties of your generated source file. So cmake won't complain about missing source file.

set_source_files_properties(${GENERATED_SOURCE_FILE} PROPERTIES
    GENERATED TRUE
)

Add generated source to your target as usual.

add_executable(${YOUR_TARGET} SOURCES ${GENERATED_SOURCE_FILE})

So in the proposed example ${GENERATION COMMAND} will only be launched if some of ${DEPENDENCIES} files were changed.

Upvotes: 6

DLRdave
DLRdave

Reputation: 14250

add_custom_command will do the trick, if you construct the call to it correctly.

Something like this should work:

ADD_CUSTOM_COMMAND(OUTPUT ${PROJECT_SOURCE_DIR}/src/MyGrammar
  COMMAND ${ANTLR_COMMAND} ${PROJECT_SOURCE_DIR}/src/MyGrammar.g
    -o ${PROJECT_SOURCE_DIR}/src/MyGrammar
  DEPENDS ${PROJECT_SOURCE_DIR}/src/MyGrammar.g
)

ADD_CUSTOM_TARGET(GenerateParser ALL
   DEPENDS ${PROJECT_SOURCE_DIR}/src/MyGrammar
)

ADD_LIBRARY(MainProject ${LIBRARY_TYPE} ${TARGET_SOURCES} ${TARGET_OPTIONS})
ADD_DEPENDENCIES(MainProject GenerateParser)

Here, the custom target will "build" every time, but the only thing it will do is build the custom command on whose output it depends, but if and only if the output of the custom command is out of date with respect to its DEPENDS file(s).

Upvotes: 18

Michael
Michael

Reputation: 3834

Would add_custom_command do the trick? Here you can specify the DEPENDS [depends...] which would make the command only execute when the dependent file changes.

http://www.cmake.org/cmake/help/cmake2.6docs.html#command:add_custom_command

add_custom_command(OUTPUT output1 [output2 ...]
                 COMMAND command1 [ARGS] [args1...]
                 [COMMAND command2 [ARGS] [args2...] ...]
                 [MAIN_DEPENDENCY depend]
                 [DEPENDS [depends...]]
                 [IMPLICIT_DEPENDS <lang1> depend1 ...]
                 [WORKING_DIRECTORY dir]
                 [COMMENT comment] [VERBATIM] [APPEND])

Upvotes: 4

Related Questions