|
47 | 47 | find_program(LEMON_EXECUTABLE lemon DOC "path to the lemon executable") |
48 | 48 | mark_as_advanced(LEMON_EXECUTABLE) |
49 | 49 |
|
50 | | -if (LEMON_EXECUTABLE AND NOT LEMON_TEMPLATE) |
51 | | - # look for the template in share |
52 | | - if (DATA_DIR AND EXISTS "${DATA_DIR}/lemon/lempar.c") |
53 | | - set (LEMON_TEMPLATE "${DATA_DIR}/lemon/lempar.c") |
54 | | - elseif (EXISTS "share/lemon/lempar.c") |
55 | | - set (LEMON_TEMPLATE "share/lemon/lempar.c") |
56 | | - elseif (EXISTS "/usr/share/lemon/lempar.c") |
57 | | - set (LEMON_TEMPLATE "/usr/share/lemon/lempar.c") |
58 | | - endif (DATA_DIR AND EXISTS "${DATA_DIR}/lemon/lempar.c") |
59 | | -endif (LEMON_EXECUTABLE AND NOT LEMON_TEMPLATE) |
60 | | - |
61 | | -if (LEMON_EXECUTABLE AND NOT LEMON_TEMPLATE) |
62 | | - # look for the template in bin dir |
63 | | - get_filename_component(lemon_path ${LEMON_EXECUTABLE} PATH) |
64 | | - if (lemon_path) |
65 | | - if (EXISTS ${lemon_path}/lempar.c) |
66 | | - set (LEMON_TEMPLATE "${lemon_path}/lempar.c") |
67 | | - endif (EXISTS ${lemon_path}/lempar.c) |
68 | | - if (EXISTS /usr/share/lemon/lempar.c) |
69 | | - set (LEMON_TEMPLATE "/usr/share/lemon/lempar.c") |
70 | | - endif (EXISTS /usr/share/lemon/lempar.c) |
71 | | - endif (lemon_path) |
72 | | -endif(LEMON_EXECUTABLE AND NOT LEMON_TEMPLATE) |
73 | | - |
74 | | -if (LEMON_EXECUTABLE AND NOT LEMON_TEMPLATE) |
75 | | - # fallback |
76 | | - set (LEMON_TEMPLATE "lempar.c") |
77 | | - if (NOT EXISTS ${LEMON_TEMPLATE}) |
78 | | - message(WARNING "Lemon's lempar.c template file could not be found automatically, set LEMON_TEMPLATE") |
79 | | - endif (NOT EXISTS ${LEMON_TEMPLATE}) |
80 | | -endif (LEMON_EXECUTABLE AND NOT LEMON_TEMPLATE) |
81 | | - |
82 | | -mark_as_advanced(LEMON_TEMPLATE) |
| 50 | +if (LEMON_EXECUTABLE) |
| 51 | + if(NOT LEMON_TEMPLATE) |
| 52 | + # look for the template, if we've not already been told where it is |
| 53 | + if (DATA_DIR AND EXISTS "${DATA_DIR}/lemon/lempar.c") |
| 54 | + find_file(LEMON_TEMPLATE lempar.c |
| 55 | + PATHS "${DATA_DIR}/lemon/lempar.c" |
| 56 | + NO_DEFAULT_PATH) |
| 57 | + endif () |
| 58 | + |
| 59 | + # If the above did not succeed, check standard locations |
| 60 | + get_filename_component(lemon_dir ${LEMON_EXECUTABLE} DIRECTORY) |
| 61 | + find_file(LEMON_TEMPLATE lempar.c |
| 62 | + PATHS "${lemon_dir}" "/usr/share/lemon" |
| 63 | + NO_DEFAULT_PATH) |
| 64 | + mark_as_advanced(LEMON_TEMPLATE) |
| 65 | + endif() |
| 66 | + |
| 67 | + # We need a template to be able to use lemon correctly |
| 68 | + if(NOT LEMON_TEMPLATE) |
| 69 | + message(FATAL_ERROR "Failed to find lemon template file (lempar.c) - need to set LEMON_TEMPLATE") |
| 70 | + endif() |
| 71 | + |
| 72 | + # Define the function |
| 73 | + # LEMON_TARGET(<Name> <LemonInput> <LemonSource> <LemonHeader> |
| 74 | + # [<ArgString>]) |
| 75 | + # which will create a custom rule to generate a parser. <LemonInput> is |
| 76 | + # the path to a lemon file. <LemonSource> is the desired name for the |
| 77 | + # generated source file. <LemonHeader> is the desired name for the |
| 78 | + # generated header which contains the token list. Anything in the optional |
| 79 | + # <ArgString> parameter is appended to the lemon command line. |
| 80 | + # |
| 81 | + # ==================================================================== |
| 82 | + # Example: |
| 83 | + # |
| 84 | + # find_package(LEMON) |
| 85 | + # LEMON_TARGET(MyParser parser.y parser.c parser.h) |
| 86 | + # add_executable(Foo main.cpp ${LEMON_MyParser_OUTPUTS}) |
| 87 | + # ==================================================================== |
| 88 | + |
| 89 | + include(CMakeParseArguments) |
| 90 | + |
| 91 | + if(NOT COMMAND LEMON_TARGET) |
| 92 | + function(LEMON_TARGET Name LemonInput LemonOutput) |
| 93 | + set(LT_ARGS DEFINES_FILE COMPILE_FLAGS) |
| 94 | + cmake_parse_arguments(LEMON_TARGET_ARG "" "${LT_ARGS}" "" ${ARGN}) |
| 95 | + |
| 96 | + if(NOT "${LEMON_TARGET_ARG_COMPILE_FLAGS}" STREQUAL "") |
| 97 | + set(LEMON_EXECUTABLE_opts "${LEMON_TARGET_ARG_COMPILE_FLAGS}") |
| 98 | + separate_arguments(LEMON_EXECUTABLE_opts) |
| 99 | + else() |
| 100 | + set(LEMON_EXECUTABLE_opts "") |
| 101 | + endif() |
| 102 | + |
| 103 | + # check for LemonOutput |
| 104 | + get_filename_component(_basename ${LemonOutput} NAME_WE) |
| 105 | + get_filename_component(_out_src_file ${LemonOutput} NAME) |
| 106 | + get_filename_component(_out_dir ${LemonOutput} PATH) |
| 107 | + if(NOT "${_out_dir}" STREQUAL "") |
| 108 | + message(WARNING "Full path specified for LemonOutput - should be filename only") |
| 109 | + endif() |
| 110 | + |
| 111 | + # set report file |
| 112 | + set(_out_rpt_file "${_basename}.out") |
| 113 | + |
| 114 | + # check for DEFINES_FILE |
| 115 | + if ("${LEMON_TARGET_ARG_DEFINES_FILE}" STREQUAL "") |
| 116 | + set(_out_hdr_file "${_basename}.h") |
| 117 | + else() |
| 118 | + get_filename_component(_out_dir ${LEMON_TARGET_ARG_DEFINES_FILE} PATH) |
| 119 | + get_filename_component(_out_hdr_file ${LEMON_TARGET_ARG_DEFINES_FILE} NAME) |
| 120 | + if(NOT "${_out_dir}" STREQUAL "") |
| 121 | + message(WARNING "Full path specified for DEFINES_FILE - should be filename only") |
| 122 | + endif() |
| 123 | + endif() |
| 124 | + |
| 125 | + # input file |
| 126 | + get_filename_component(_in_y_path ${LemonInput} ABSOLUTE) |
| 127 | + get_filename_component(_in_y_file ${LemonInput} NAME) |
| 128 | + |
| 129 | + # TODO: is this really necessary? |
| 130 | + add_custom_command( |
| 131 | + OUTPUT ${_in_y_file} |
| 132 | + COMMAND ${CMAKE_COMMAND} -E copy ${_in_y_path} ${CMAKE_CURRENT_BINARY_DIR} |
| 133 | + ) |
83 | 134 |
|
84 | | -include(FindPackageHandleStandardArgs) |
85 | | -FIND_PACKAGE_HANDLE_STANDARD_ARGS(LEMON DEFAULT_MSG LEMON_EXECUTABLE LEMON_TEMPLATE) |
86 | | - |
87 | | -# Define the macro |
88 | | -# LEMON_TARGET(<Name> <LemonInput> <LemonSource> <LemonHeader> |
89 | | -# [<ArgString>]) |
90 | | -# which will create a custom rule to generate a parser. <LemonInput> is |
91 | | -# the path to a lemon file. <LemonSource> is the desired name for the |
92 | | -# generated source file. <LemonHeader> is the desired name for the |
93 | | -# generated header which contains the token list. Anything in the optional |
94 | | -# <ArgString> parameter is appended to the lemon command line. |
95 | | -# |
96 | | -# ==================================================================== |
97 | | -# Example: |
98 | | -# |
99 | | -# find_package(LEMON) |
100 | | -# LEMON_TARGET(MyParser parser.y parser.c parser.h) |
101 | | -# add_executable(Foo main.cpp ${LEMON_MyParser_OUTPUTS}) |
102 | | -# ==================================================================== |
103 | | - |
104 | | -include(CMakeParseArguments) |
105 | | - |
106 | | -if(NOT COMMAND LEMON_TARGET) |
107 | | - macro(LEMON_TARGET Name Input) |
108 | | - |
109 | | - get_filename_component(IN_FILE_WE ${Input} NAME_WE) |
110 | | - set(LVAR_PREFIX ${Name}_${IN_FILE_WE}) |
111 | | - |
112 | | - if(${ARGC} GREATER 3) |
113 | | - CMAKE_PARSE_ARGUMENTS(${LVAR_PREFIX} "" "OUT_SRC_FILE;OUT_HDR_FILE;WORKING_DIR;EXTRA_ARGS" "" ${ARGN}) |
114 | | - endif(${ARGC} GREATER 3) |
115 | | - |
116 | | - # Need a working directory |
117 | | - if("${${LVAR_PREFIX}_WORKING_DIR}" STREQUAL "") |
118 | | - set(${LVAR_PREFIX}_WORKING_DIR "${CMAKE_CURRENT_BINARY_DIR}/${LVAR_PREFIX}") |
119 | | - endif("${${LVAR_PREFIX}_WORKING_DIR}" STREQUAL "") |
120 | | - file(MAKE_DIRECTORY ${${LVAR_PREFIX}_WORKING_DIR}) |
121 | | - |
122 | | - # Output source file |
123 | | - if ("${${LVAR_PREFIX}_OUT_SRC_FILE}" STREQUAL "") |
124 | | - set(${LVAR_PREFIX}_OUT_SRC_FILE ${${LVAR_PREFIX}_WORKING_DIR}/${IN_FILE_WE}.c) |
125 | | - else ("${${LVAR_PREFIX}_OUT_SRC_FILE}" STREQUAL "") |
126 | | - get_filename_component(specified_out_dir ${${LVAR_PREFIX}_OUT_SRC_FILE} PATH) |
127 | | - if(NOT "${specified_out_dir}" STREQUAL "") |
128 | | - message(FATAL_ERROR "\nFull path specified for OUT_SRC_FILE - should be filename only.\n") |
129 | | - endif(NOT "${specified_out_dir}" STREQUAL "") |
130 | | - set(${LVAR_PREFIX}_OUT_SRC_FILE ${${LVAR_PREFIX}_WORKING_DIR}/${${LVAR_PREFIX}_OUT_SRC_FILE}) |
131 | | - endif ("${${LVAR_PREFIX}_OUT_SRC_FILE}" STREQUAL "") |
132 | | - |
133 | | - # Output header file |
134 | | - if ("${${LVAR_PREFIX}_OUT_HDR_FILE}" STREQUAL "") |
135 | | - set(${LVAR_PREFIX}_OUT_HDR_FILE ${${LVAR_PREFIX}_WORKING_DIR}/${IN_FILE_WE}.h) |
136 | | - else ("${${LVAR_PREFIX}_OUT_HDR_FILE}" STREQUAL "") |
137 | | - get_filename_component(specified_out_dir ${${LVAR_PREFIX}_OUT_HDR_FILE} PATH) |
138 | | - if(NOT "${specified_out_dir}" STREQUAL "") |
139 | | - message(FATAL_ERROR "\nFull path specified for OUT_HDR_FILE - should be filename only.\n") |
140 | | - endif(NOT "${specified_out_dir}" STREQUAL "") |
141 | | - set(${LVAR_PREFIX}_OUT_HDR_FILE ${${LVAR_PREFIX}_WORKING_DIR}/${${LVAR_PREFIX}_OUT_HDR_FILE}) |
142 | | - endif ("${${LVAR_PREFIX}_OUT_HDR_FILE}" STREQUAL "") |
143 | | - |
144 | | - # input file |
145 | | - get_filename_component(in_full ${Input} ABSOLUTE) |
146 | | - if("${in_full}" STREQUAL "${Input}") |
147 | | - set(lemon_in_file ${Input}) |
148 | | - else("${in_full}" STREQUAL "${Input}") |
149 | | - set(lemon_in_file "${CMAKE_CURRENT_SOURCE_DIR}/${Input}") |
150 | | - endif("${in_full}" STREQUAL "${Input}") |
151 | | - |
152 | | - |
153 | | - # names of lemon output files will be based on the name of the input file |
154 | | - set(LEMON_GEN_SOURCE ${${LVAR_PREFIX}_WORKING_DIR}/${IN_FILE_WE}.c) |
155 | | - set(LEMON_GEN_HEADER ${${LVAR_PREFIX}_WORKING_DIR}/${IN_FILE_WE}.h) |
156 | | - set(LEMON_GEN_OUT ${${LVAR_PREFIX}_WORKING_DIR}/${IN_FILE_WE}.out) |
157 | | - |
158 | | - # copy input to bin directory and run lemon |
159 | | - get_filename_component(INPUT_NAME ${Input} NAME) |
160 | | - add_custom_command( |
161 | | - OUTPUT ${LEMON_GEN_OUT} ${LEMON_GEN_SOURCE} ${LEMON_GEN_HEADER} |
162 | | - COMMAND ${CMAKE_COMMAND} -E copy ${lemon_in_file} ${${LVAR_PREFIX}_WORKING_DIR}/${INPUT_NAME} |
163 | | - COMMAND ${LEMON_EXECUTABLE} -T${LEMON_TEMPLATE} ${${LVAR_PREFIX}_WORKING_DIR}/${INPUT_NAME} ${${LVAR_PREFIX}__EXTRA_ARGS} |
164 | | - DEPENDS ${Input} ${LEMON_TEMPLATE} ${LEMON_EXECUTABLE_TARGET} |
165 | | - WORKING_DIRECTORY ${${LVAR_PREFIX}_WORKING_DIR} |
166 | | - COMMENT "[LEMON][${Name}] Building parser with ${LEMON_EXECUTABLE}" |
167 | | - ) |
168 | | - |
169 | | - # rename generated outputs |
170 | | - if(NOT "${${LVAR_PREFIX}_OUT_SRC_FILE}" STREQUAL "${LEMON_GEN_SOURCE}") |
| 135 | + # execute lemon |
171 | 136 | add_custom_command( |
172 | | - OUTPUT ${${LVAR_PREFIX}_OUT_SRC_FILE} |
173 | | - COMMAND ${CMAKE_COMMAND} -E copy ${LEMON_GEN_SOURCE} ${${LVAR_PREFIX}_OUT_SRC_FILE} |
174 | | - DEPENDS ${LemonInput} ${LEMON_EXECUTABLE_TARGET} ${LEMON_GEN_SOURCE} |
| 137 | + OUTPUT ${_out_src_file} |
| 138 | + COMMAND ${LEMON_EXECUTABLE} -T${LEMON_TEMPLATE} ${LEMON_EXECUTABLE_opts} ${_in_y_file} |
| 139 | + DEPENDS ${_in_y_file} |
| 140 | + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} |
| 141 | + COMMENT "[LEMON][${Name}] Building parser with ${LEMON_EXECUTABLE}" |
175 | 142 | ) |
176 | | - set(LEMON_${Name}_OUTPUTS ${${LVAR_PREFIX}_OUT_SRC_FILE} ${LEMON_${Name}_OUTPUTS}) |
177 | | - endif(NOT "${${LVAR_PREFIX}_OUT_SRC_FILE}" STREQUAL "${LEMON_GEN_SOURCE}") |
178 | | - if(NOT "${${LVAR_PREFIX}_OUT_HDR_FILE}" STREQUAL "${LEMON_GEN_HEADER}") |
| 143 | + |
| 144 | + # rename the header |
179 | 145 | add_custom_command( |
180 | | - OUTPUT ${${LVAR_PREFIX}_OUT_HDR_FILE} |
181 | | - COMMAND ${CMAKE_COMMAND} -E copy ${LEMON_GEN_HEADER} ${${LVAR_PREFIX}_OUT_HDR_FILE} |
182 | | - DEPENDS ${LemonInput} ${LEMON_EXECUTABLE_TARGET} ${LEMON_GEN_HEADER} |
| 146 | + OUTPUT ${_out_hdr_file} |
| 147 | + COMMAND ${CMAKE_COMMAND} ARGS -E rename ${_basename}.h ${_out_hdr_file} |
| 148 | + DEPENDS ${_out_src_file} |
| 149 | + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} |
183 | 150 | ) |
184 | | - set(LEMON_${Name}_OUTPUTS ${${LVAR_PREFIX}_OUT_HDR_FILE} ${LEMON_${Name}_OUTPUTS}) |
185 | | - endif(NOT "${${LVAR_PREFIX}_OUT_HDR_FILE}" STREQUAL "${LEMON_GEN_HEADER}") |
186 | 151 |
|
187 | | - set(LEMON_${Name}_OUTPUTS ${LEMON_${Name}_OUTPUTS} ${LEMON_GEN_OUT}) |
| 152 | + # set the return values |
| 153 | + # TODO: for generated sources even headers should be target dependencies |
| 154 | + set(LEMON_${Name}_DEFINED TRUE PARENT_SCOPE) |
| 155 | + set(LEMON_${Name}_OUTPUT_HEADER "${CMAKE_CURRENT_BINARY_DIR}/${_out_hdr_file}" PARENT_SCOPE) |
| 156 | + set(LEMON_${Name}_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}" PARENT_SCOPE) |
| 157 | + set(LEMON_${Name}_OUTPUTS "${_out_src_file}" PARENT_SCOPE) |
188 | 158 |
|
189 | | - # make sure we clean up generated output and copied input |
190 | | - set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${LEMON_${Name}_OUTPUTS}") |
191 | | - set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${${LVAR_PREFIX}_WORKING_DIR}/${INPUT_NAME}") |
| 159 | + # make sure we clean up generated output and copied input |
| 160 | + set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${LEMON_${Name}_OUTPUTS}") |
| 161 | + set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/${_in_y_file}") |
192 | 162 |
|
193 | | - # macro ran successfully |
194 | | - set(LEMON_${Name}_DEFINED TRUE) |
| 163 | + endfunction(LEMON_TARGET) |
| 164 | + endif(NOT COMMAND LEMON_TARGET) |
195 | 165 |
|
196 | | - set(LEMON_${Name}_SRC ${${LVAR_PREFIX}_OUT_SRC_FILE}) |
197 | | - set(LEMON_${Name}_HDR ${${LVAR_PREFIX}_OUT_HDR_FILE}) |
198 | | - set(LEMON_${Name}_INCLUDE_DIR ${${LVAR_PREFIX}_WORKING_DIR}) |
| 166 | +endif(LEMON_EXECUTABLE) |
199 | 167 |
|
200 | | - endmacro(LEMON_TARGET) |
201 | | -endif(NOT COMMAND LEMON_TARGET) |
| 168 | +include(FindPackageHandleStandardArgs) |
| 169 | +find_package_handle_standard_args(LEMON REQUIRED_VARS LEMON_EXECUTABLE LEMON_TEMPLATE) |
202 | 170 |
|
203 | 171 | #============================================================ |
204 | 172 | # FindLEMON.cmake ends here |
|
0 commit comments