30 pts.
 CMake – Automatically regenerate a file using an external tool and custom target upon “make”
Hi. I'm working on a project and I use cmake for generating "projects", that is, under Linux, a Makefile. I also use an external tool (re2c) to generate the scanner, and an included tool to generate the parser (lemon, part of sqlite). The problem is I need to "cmake" every time I change something in the grammar (lemon_parser.y) or in the scanner (scanner.re). The cmake files are: ./CMakeLists.txt: 1 cmake_minimum_required(VERSION 2.6) 2 project(Calc C) 3 #set(CMAKE_USE_RELATIVE_PATHS ON FORCE) 4 set(CMAKE_BUILD_TYPE Debug) 5 #set(CMAKE_VERBOSE_MAKEFILE true) 6 include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR}/parser) 7 8 IF ( ${CMAKE_SOURCE_DIR} EQUAL ${CMAKE_BINARY_DIR} AND NOT ${ACCEPT_SOURCE_DIR} ) 9 MESSAGE( FATAL "Please choose a different directory for building" ) 10 ENDIF( ${CMAKE_SOURCE_DIR} EQUAL ${CMAKE_BINARY_DIR} AND NOT ${ACCEPT_SOURCE_DIR} ) 11 12 add_subdirectory(lemon) 13 add_subdirectory(hash) 14 add_subdirectory(parser) 15 #memory safety 16 #add_subdirectory(memory_safety) 17 18 add_executable(calc main.c) 19 target_link_libraries(calc hash parser) ./parser/CMakeLists.txt and a file irrelevant to the problem: ./hash/CMakeLists.txt: 1 add_library(hash STATIC hash_table.c hash_functions.c)

Software/Hardware used:
ASKED: December 5, 2008  11:01 AM
UPDATED: December 8, 2008  12:09 PM

Answer Wiki:
Fixed it in the meanwhile: <pre> 1 set(parser_odir "${CMAKE_CURRENT_BINARY_DIR}/") 2 include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${parser_odir}) 3 4 #The right way to me would be to use the commands (2) and (4) 5 #but it seems one needs (1) and (3) instead, if regeneration 6 #of the scanner.re and parser.y is desired with only a "make" 7 #command. 8 # 9 #Why I think that would be the right way? Because commands 10 #have output (in cmake terms) and targets don't. 11 12 add_custom_target(lemon_parser 13 COMMAND ${CMAKE_COMMAND} -E copy "lemon_parser.y" "${parser_odir}lemon_parser.y" 14 #(1): 15 COMMAND ${PROJECT_BINARY_DIR}/lemon/lemon d="${CMAKE_CURRENT_SOURCE_DIR}/lempar.c" "${parser_odir}lemon_parser.y" 16 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 17 COMMENT "add_custom_target(lemon_parser)" 18 ) 19 add_custom_command(OUTPUT "${parser_odir}lemon_parser.c" 20 #(2): 21 # COMMAND ${PROJECT_BINARY_DIR}/lemon/lemon d="${CMAKE_CURRENT_SOURCE_DIR}/lempar.c" "${parser_odir}lemon_parser.y" 22 COMMENT "add_custom_command(parser)" 23 ) 24 25 add_custom_target(re2c_scanner 26 #(3): 27 COMMAND re2c -i "${CMAKE_CURRENT_SOURCE_DIR}/scanner.re" > "${parser_odir}scanner.c" 28 COMMENT "add_custom_target(re2c_scanner)" 29 ) 30 add_custom_command(OUTPUT "${parser_odir}scanner.c" 31 #(4): 32 # COMMAND re2c -i "${CMAKE_CURRENT_SOURCE_DIR}/scanner.re" > "${parser_odir}scanner.c" 33 COMMENT "add_custom_command(scanner)" 34 ) 35 add_library(parser STATIC parser.c ast.c "${parser_odir}scanner.c" "${parser_odir}lemon_parser.c") 36 add_dependencies(parser lemon_parser re2c_scanner) 37 add_dependencies(lemon_parser lemon)</pre> Hopefully this will help someone else.
Last Wiki Answer Submitted:  December 8, 2008  12:09 pm  by  OriginalCopy   30 pts.
All Answer Wiki Contributors:  OriginalCopy   30 pts.
To see all answers submitted to the Answer Wiki: View Answer History.


Discuss This Question:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _


 

OOps, I’ve forgot to paste the parser/CMakeLists.txt:

     1	set(parser_odir "${CMAKE_CURRENT_BINARY_DIR}/")
     2	include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${parser_odir})
     3	
     4	add_custom_command(
     5			OUTPUT "${parser_odir}lemon_parser.c" "${parser_odir}lemon_parser.h" "${parser_odir}lemon_parser.out"
     6			#COMMAND ${PROJECT_BINARY_DIR}/lemon/lemon d="${CMAKE_CURRENT_SOURCE_DIR}/lempar.c" "${CMAKE_CURRENT_BINARY_DIR}/lemon_parser.y"
     7			COMMAND ${PROJECT_BINARY_DIR}/lemon/lemon d="${CMAKE_CURRENT_SOURCE_DIR}/lempar.c" "${parser_odir}lemon_parser.y"
     8			DEPENDS lemon "${CMAKE_CURRENT_SOURCE_DIR}/lemon_parser.y"
     9		)
    10	#add_custom_target(lemon_parser)
    11	file(READ lemon_parser.y parser_content)
    12	file(WRITE "${parser_odir}lemon_parser.y" "${parser_content}")
    13	
    14	add_custom_command(
    15			OUTPUT "${parser_odir}scanner.c" 
    16			COMMAND re2c -i "${CMAKE_CURRENT_SOURCE_DIR}/scanner.re" > "${parser_odir}scanner.c"
    17			DEPENDS "${parser_odir}lemon_parser.h" "${CMAKE_CURRENT_SOURCE_DIR}/scanner.re"
    18		)
    19	#add_custom_target(re2c_scanner)
    20	
    21	#add_custom_target(lemon_parser ALL DEPENDS "${parser_odir}lemon_parser.c" "${parser_odir}lemon_parser.h")
    22	add_library(parser STATIC "${parser_odir}lemon_parser.c" "${parser_odir}scanner.c" parser.c ast.c)

Is there any feedback area? The small “ask a question” textarea on the right is hard to use.

 30 pts.