Reputation: 3707
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
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
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
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
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