Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make build rules in cmake to preprocess lazy C++ .lzz files that generate .h and .cpp files?

Tags:

cmake

lazy-c++

What I'd like to do is write just Lazy C++ .lzz files and then have lzz run before a build to generate .cpp and .h files that will be built into the final application, sort of like how moc works with Qt.

Is there any way to do this?

like image 959
jjacksonRIAB Avatar asked Apr 21 '10 23:04

jjacksonRIAB


2 Answers

Here is an example of how to do this... First you need to find the lzz program, for that use the find_program command:

find_program(LZZ_COMMAND lzz)

This sets LZZ_COMMAND to the path of the compiler. Then use a CMake custom command to compile the LZZ file to their C++ header/implementation files:

add_custom_command(
    OUTPUT ${output}
    COMMAND ${LZZ_COMMAND} -o ${CMAKE_CURRENT_BINARY_DIR} ${filename})

That generates the files in the current build directory, in case you do out-of-source builds. You will also need to specify that the outputs are generated files:

set_source_files_properties(${output} PROPERTIES GENERATED TRUE)

Put that all together and you get a CMakeLists.txt file something like this:

cmake_minimum_required(VERSION 2.8)
project(lazy_test)
find_program(LZZ_COMMAND lzz)
function(lazy_compile filename)
    get_filename_component(base ${filename} NAME_WE)
    set(base_abs ${CMAKE_CURRENT_BINARY_DIR}/${base})
    set(output ${base_abs}.cpp ${base_abs}.h)
    add_custom_command(
        OUTPUT ${output}
        COMMAND ${LZZ_COMMAND} -o ${CMAKE_CURRENT_BINARY_DIR} ${filename})
    set_source_files_properties(${output} PROPERTIES GENERATED TRUE)
endfunction()
lazy_compile(${CMAKE_CURRENT_SOURCE_DIR}/example.lzz)
add_executable(test example.cpp example.h)

You would probably also want to add include path and other options to lzz eventually. If you placed all the Lazy C++ stuff into a module file and included that from the CMakeLists.txt it would be a bit cleaner. But this is the basic idea.

like image 160
richq Avatar answered Nov 15 '22 01:11

richq


I just wanted to share my CMakeLists.txt, which builds upon richq's script. The *.cpp and *.hpp files now properly depend on the *.lzz files. The *.lzz files are added to the project (which answers absense's question above) but kept separate from the generated files using the source_group command.

The only remaining dealbreaker for me is the inability to compile the current file for *.lzz files.

cmake_minimum_required(VERSION 2.8)

PROJECT(LzzTest)

find_program(LZZ_COMMAND lzz.exe)

# Syntax: 
#   add_lzz_file(<output> <lzz file>)
# Adds a build rule for the specified lzz file. The absolute paths of the generated 
# files are added to the <output> list. The files are generated in the binary dir.
# 
# TODO: Support for generating template files etc.
function(add_lzz_file output filename)
  # Only process *.lzz files
  get_filename_component(ext ${filename} EXT)
  if(NOT ext STREQUAL ".lzz")
    return()
  endif()

  set(header_extension "hpp")
  get_filename_component(base ${filename} NAME_WE)
  set(base_abs ${CMAKE_CURRENT_BINARY_DIR}/${base})
  set(outfiles ${base_abs}.cpp ${base_abs}.${header_extension})
  set(${output} ${${output}} ${outfiles} PARENT_SCOPE)

  #message("outfiles=${outfiles}, DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${filename}")
  add_custom_command(
    OUTPUT ${outfiles}
    COMMAND ${LZZ_COMMAND} 
      -o ${CMAKE_CURRENT_BINARY_DIR} # output dir
      -hx ${header_extension}
      -sl -hl -il -tl -nl -x # insert #line commands w/ absolute paths
      -sd -hd -id -td -nd # don't output files that didn't change
      ${CMAKE_CURRENT_SOURCE_DIR}/${filename}
    DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${filename}"
  )

  set_source_files_properties(${outfiles} PROPERTIES GENERATED TRUE)
endfunction()

include_directories(${CMAKE_CURRENT_BINARY_DIR})

set(SOURCES
  A.lzz
  B.lzz
  main.cpp
)

foreach(file ${SOURCES})
  add_lzz_file(GENERATED_SOURCES ${file})
endforeach()

source_group("" FILES ${SOURCES})
source_group(generated FILES ${GENERATED_SOURCES})

add_executable(LzzTest ${SOURCES} ${GENERATED_SOURCES})
like image 29
Andreas Haferburg Avatar answered Nov 15 '22 01:11

Andreas Haferburg