1# Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2# file Copyright.txt or https://cmake.org/licensing for details. 3 4#[=======================================================================[.rst: 5FindFLEX 6-------- 7 8Find Fast Lexical Analyzer (Flex) executable and provides a macro 9to generate custom build rules 10 11 12 13The module defines the following variables: 14 15:: 16 17 FLEX_FOUND - True is flex executable is found 18 FLEX_EXECUTABLE - the path to the flex executable 19 FLEX_VERSION - the version of flex 20 FLEX_LIBRARIES - The flex libraries 21 FLEX_INCLUDE_DIRS - The path to the flex headers 22 23 24 25The minimum required version of flex can be specified using the 26standard syntax, e.g. :command:`find_package(FLEX 2.5.13)` 27 28 29 30If flex is found on the system, the module provides the macro: 31 32:: 33 34 FLEX_TARGET(Name FlexInput FlexOutput 35 [COMPILE_FLAGS <string>] 36 [DEFINES_FILE <string>] 37 ) 38 39which creates a custom command to generate the ``FlexOutput`` file from 40the ``FlexInput`` file. Name is an alias used to get details of this custom 41command. If ``COMPILE_FLAGS`` option is specified, the next 42parameter is added to the flex command line. 43 44.. versionadded:: 3.5 45 If flex is configured to 46 output a header file, the ``DEFINES_FILE`` option may be used to specify its 47 name. 48 49.. versionchanged:: 3.17 50 When :policy:`CMP0098` is set to ``NEW``, ``flex`` runs in the 51 :variable:`CMAKE_CURRENT_BINARY_DIR` directory. 52 53The macro defines the following variables: 54 55:: 56 57 FLEX_${Name}_DEFINED - true is the macro ran successfully 58 FLEX_${Name}_OUTPUTS - the source file generated by the custom rule, an 59 alias for FlexOutput 60 FLEX_${Name}_INPUT - the flex source file, an alias for ${FlexInput} 61 FLEX_${Name}_OUTPUT_HEADER - the header flex output, if any. 62 63 64 65Flex scanners often use tokens defined by Bison: the code generated 66by Flex depends of the header generated by Bison. This module also 67defines a macro: 68 69:: 70 71 ADD_FLEX_BISON_DEPENDENCY(FlexTarget BisonTarget) 72 73which adds the required dependency between a scanner and a parser 74where ``FlexTarget`` and ``BisonTarget`` are the first parameters of 75respectively ``FLEX_TARGET`` and ``BISON_TARGET`` macros. 76 77:: 78 79 ==================================================================== 80 Example: 81 82 83 84:: 85 86 find_package(BISON) 87 find_package(FLEX) 88 89 90 91:: 92 93 BISON_TARGET(MyParser parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp) 94 FLEX_TARGET(MyScanner lexer.l ${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp) 95 ADD_FLEX_BISON_DEPENDENCY(MyScanner MyParser) 96 97 98 99:: 100 101 include_directories(${CMAKE_CURRENT_BINARY_DIR}) 102 add_executable(Foo 103 Foo.cc 104 ${BISON_MyParser_OUTPUTS} 105 ${FLEX_MyScanner_OUTPUTS} 106 ) 107 target_link_libraries(Foo ${FLEX_LIBRARIES}) 108 ==================================================================== 109#]=======================================================================] 110 111find_program(FLEX_EXECUTABLE NAMES flex win-flex win_flex DOC "path to the flex executable") 112mark_as_advanced(FLEX_EXECUTABLE) 113 114find_library(FL_LIBRARY NAMES fl 115 DOC "Path to the fl library") 116 117find_path(FLEX_INCLUDE_DIR FlexLexer.h 118 DOC "Path to the flex headers") 119 120mark_as_advanced(FL_LIBRARY FLEX_INCLUDE_DIR) 121 122set(FLEX_INCLUDE_DIRS ${FLEX_INCLUDE_DIR}) 123set(FLEX_LIBRARIES ${FL_LIBRARY}) 124 125if(FLEX_EXECUTABLE) 126 127 execute_process(COMMAND ${FLEX_EXECUTABLE} --version 128 OUTPUT_VARIABLE FLEX_version_output 129 ERROR_VARIABLE FLEX_version_error 130 RESULT_VARIABLE FLEX_version_result 131 OUTPUT_STRIP_TRAILING_WHITESPACE) 132 if(NOT ${FLEX_version_result} EQUAL 0) 133 if(FLEX_FIND_REQUIRED) 134 message(SEND_ERROR "Command \"${FLEX_EXECUTABLE} --version\" failed with output:\n${FLEX_version_output}\n${FLEX_version_error}") 135 else() 136 message("Command \"${FLEX_EXECUTABLE} --version\" failed with output:\n${FLEX_version_output}\n${FLEX_version_error}\nFLEX_VERSION will not be available") 137 endif() 138 else() 139 # older versions of flex printed "/full/path/to/executable version X.Y" 140 # newer versions use "basename(executable) X.Y" 141 get_filename_component(FLEX_EXE_NAME_WE "${FLEX_EXECUTABLE}" NAME_WE) 142 get_filename_component(FLEX_EXE_EXT "${FLEX_EXECUTABLE}" EXT) 143 string(REGEX REPLACE "^.*${FLEX_EXE_NAME_WE}(${FLEX_EXE_EXT})?\"? (version )?([0-9]+[^ ]*)( .*)?$" "\\3" 144 FLEX_VERSION "${FLEX_version_output}") 145 unset(FLEX_EXE_EXT) 146 unset(FLEX_EXE_NAME_WE) 147 endif() 148 149 #============================================================ 150 # FLEX_TARGET (public macro) 151 #============================================================ 152 # 153 macro(FLEX_TARGET Name Input Output) 154 155 set(FLEX_TARGET_PARAM_OPTIONS) 156 set(FLEX_TARGET_PARAM_ONE_VALUE_KEYWORDS 157 COMPILE_FLAGS 158 DEFINES_FILE 159 ) 160 set(FLEX_TARGET_PARAM_MULTI_VALUE_KEYWORDS) 161 162 cmake_parse_arguments( 163 FLEX_TARGET_ARG 164 "${FLEX_TARGET_PARAM_OPTIONS}" 165 "${FLEX_TARGET_PARAM_ONE_VALUE_KEYWORDS}" 166 "${FLEX_TARGET_MULTI_VALUE_KEYWORDS}" 167 ${ARGN} 168 ) 169 170 set(FLEX_TARGET_usage "FLEX_TARGET(<Name> <Input> <Output> [COMPILE_FLAGS <string>] [DEFINES_FILE <string>]") 171 172 if(NOT "${FLEX_TARGET_ARG_UNPARSED_ARGUMENTS}" STREQUAL "") 173 message(SEND_ERROR ${FLEX_TARGET_usage}) 174 else() 175 176 cmake_policy(GET CMP0098 _flex_CMP0098 177 PARENT_SCOPE # undocumented, do not use outside of CMake 178 ) 179 set(_flex_INPUT "${Input}") 180 if("x${_flex_CMP0098}x" STREQUAL "xNEWx") 181 set(_flex_WORKING_DIR "${CMAKE_CURRENT_BINARY_DIR}") 182 if(NOT IS_ABSOLUTE "${_flex_INPUT}") 183 set(_flex_INPUT "${CMAKE_CURRENT_SOURCE_DIR}/${_flex_INPUT}") 184 endif() 185 else() 186 set(_flex_WORKING_DIR "${CMAKE_CURRENT_SOURCE_DIR}") 187 endif() 188 unset(_flex_CMP0098) 189 190 set(_flex_OUTPUT "${Output}") 191 if(NOT IS_ABSOLUTE ${_flex_OUTPUT}) 192 set(_flex_OUTPUT "${_flex_WORKING_DIR}/${_flex_OUTPUT}") 193 endif() 194 set(_flex_TARGET_OUTPUTS "${_flex_OUTPUT}") 195 196 set(_flex_EXE_OPTS "") 197 if(NOT "${FLEX_TARGET_ARG_COMPILE_FLAGS}" STREQUAL "") 198 set(_flex_EXE_OPTS "${FLEX_TARGET_ARG_COMPILE_FLAGS}") 199 separate_arguments(_flex_EXE_OPTS) 200 endif() 201 202 set(_flex_OUTPUT_HEADER "") 203 if(NOT "${FLEX_TARGET_ARG_DEFINES_FILE}" STREQUAL "") 204 set(_flex_OUTPUT_HEADER "${FLEX_TARGET_ARG_DEFINES_FILE}") 205 if(IS_ABSOLUTE "${_flex_OUTPUT_HEADER}") 206 set(_flex_OUTPUT_HEADER_ABS "${_flex_OUTPUT_HEADER}") 207 else() 208 set(_flex_OUTPUT_HEADER_ABS "${_flex_WORKING_DIR}/${_flex_OUTPUT_HEADER}") 209 endif() 210 list(APPEND _flex_TARGET_OUTPUTS "${_flex_OUTPUT_HEADER_ABS}") 211 list(APPEND _flex_EXE_OPTS --header-file=${_flex_OUTPUT_HEADER_ABS}) 212 endif() 213 214 get_filename_component(_flex_EXE_NAME_WE "${FLEX_EXECUTABLE}" NAME_WE) 215 add_custom_command(OUTPUT ${_flex_TARGET_OUTPUTS} 216 COMMAND ${FLEX_EXECUTABLE} ${_flex_EXE_OPTS} -o${_flex_OUTPUT} ${_flex_INPUT} 217 VERBATIM 218 DEPENDS ${_flex_INPUT} 219 COMMENT "[FLEX][${Name}] Building scanner with ${_flex_EXE_NAME_WE} ${FLEX_VERSION}" 220 WORKING_DIRECTORY ${_flex_WORKING_DIR}) 221 222 set(FLEX_${Name}_DEFINED TRUE) 223 set(FLEX_${Name}_OUTPUTS ${_flex_TARGET_OUTPUTS}) 224 set(FLEX_${Name}_INPUT ${_flex_INPUT}) 225 set(FLEX_${Name}_COMPILE_FLAGS ${_flex_EXE_OPTS}) 226 set(FLEX_${Name}_OUTPUT_HEADER ${_flex_OUTPUT_HEADER}) 227 228 unset(_flex_EXE_NAME_WE) 229 unset(_flex_EXE_OPTS) 230 unset(_flex_INPUT) 231 unset(_flex_OUTPUT) 232 unset(_flex_OUTPUT_HEADER) 233 unset(_flex_OUTPUT_HEADER_ABS) 234 unset(_flex_TARGET_OUTPUTS) 235 unset(_flex_WORKING_DIR) 236 237 endif() 238 endmacro() 239 #============================================================ 240 241 242 #============================================================ 243 # ADD_FLEX_BISON_DEPENDENCY (public macro) 244 #============================================================ 245 # 246 macro(ADD_FLEX_BISON_DEPENDENCY FlexTarget BisonTarget) 247 248 if(NOT FLEX_${FlexTarget}_OUTPUTS) 249 message(SEND_ERROR "Flex target `${FlexTarget}' does not exist.") 250 endif() 251 252 if(NOT BISON_${BisonTarget}_OUTPUT_HEADER) 253 message(SEND_ERROR "Bison target `${BisonTarget}' does not exist.") 254 endif() 255 256 set_source_files_properties(${FLEX_${FlexTarget}_OUTPUTS} 257 PROPERTIES OBJECT_DEPENDS ${BISON_${BisonTarget}_OUTPUT_HEADER}) 258 endmacro() 259 #============================================================ 260 261endif() 262 263include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) 264FIND_PACKAGE_HANDLE_STANDARD_ARGS(FLEX REQUIRED_VARS FLEX_EXECUTABLE 265 VERSION_VAR FLEX_VERSION) 266