blob: e67e931125f69704aefe872bfbb704345567288a [file] [log] [blame]
Ryan Prichard7aea7e92022-01-13 17:30:17 -08001# 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)