# Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. #[=======================================================================[.rst: FindBISON --------- Find ``bison`` executable and provide a macro to generate custom build rules. The module defines the following variables: ``BISON_EXECUTABLE`` path to the ``bison`` program ``BISON_VERSION`` version of ``bison`` ``BISON_FOUND`` "True" if the program was found The minimum required version of ``bison`` can be specified using the standard CMake syntax, e.g. :command:`find_package(BISON 2.1.3)`. If ``bison`` is found, the module defines the macro:: BISON_TARGET( [COMPILE_FLAGS ] [DEFINES_FILE ] [VERBOSE []] [REPORT_FILE ] ) which will create a custom rule to generate a parser. ```` is the path to a yacc file. ```` is the name of the source file generated by bison. A header file is also be generated, and contains the token list. .. versionchanged:: 3.14 When :policy:`CMP0088` is set to ``NEW``, ``bison`` runs in the :variable:`CMAKE_CURRENT_BINARY_DIR` directory. The options are: ``COMPILE_FLAGS `` Specify flags to be added to the ``bison`` command line. ``DEFINES_FILE `` .. versionadded:: 3.4 Specify a non-default header ```` to be generated by ``bison``. ``VERBOSE []`` Tell ``bison`` to write a report file of the grammar and parser. .. deprecated:: 3.7 If ```` is given, it specifies path the report file is copied to. ``[]`` is left for backward compatibility of this module. Use ``VERBOSE REPORT_FILE ``. ``REPORT_FILE `` .. versionadded:: 3.7 Specify a non-default report ````, if generated. The macro defines the following variables: ``BISON__DEFINED`` ``True`` is the macro ran successfully ``BISON__INPUT`` The input source file, an alias for ``BISON__OUTPUT_SOURCE`` The source file generated by bison ``BISON__OUTPUT_HEADER`` The header file generated by bison ``BISON__OUTPUTS`` All files generated by bison including the source, the header and the report ``BISON__COMPILE_FLAGS`` Options used in the ``bison`` command line Example usage: .. code-block:: cmake find_package(BISON) BISON_TARGET(MyParser parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp DEFINES_FILE ${CMAKE_CURRENT_BINARY_DIR}/parser.h) add_executable(Foo main.cpp ${BISON_MyParser_OUTPUTS}) #]=======================================================================] find_program(BISON_EXECUTABLE NAMES bison win-bison win_bison DOC "path to the bison executable") mark_as_advanced(BISON_EXECUTABLE) if(BISON_EXECUTABLE) # the bison commands should be executed with the C locale, otherwise # the message (which are parsed) may be translated set(_Bison_SAVED_LC_ALL "$ENV{LC_ALL}") set(ENV{LC_ALL} C) execute_process(COMMAND ${BISON_EXECUTABLE} --version OUTPUT_VARIABLE BISON_version_output ERROR_VARIABLE BISON_version_error RESULT_VARIABLE BISON_version_result OUTPUT_STRIP_TRAILING_WHITESPACE) set(ENV{LC_ALL} ${_Bison_SAVED_LC_ALL}) if(NOT ${BISON_version_result} EQUAL 0) message(SEND_ERROR "Command \"${BISON_EXECUTABLE} --version\" failed with output:\n${BISON_version_error}") else() # Bison++ if("${BISON_version_output}" MATCHES "^bison\\+\\+ Version ([^,]+)") set(BISON_VERSION "${CMAKE_MATCH_1}") # GNU Bison elseif("${BISON_version_output}" MATCHES "^bison \\(GNU Bison\\) ([^\n]+)\n") set(BISON_VERSION "${CMAKE_MATCH_1}") elseif("${BISON_version_output}" MATCHES "^GNU Bison (version )?([^\n]+)") set(BISON_VERSION "${CMAKE_MATCH_2}") endif() endif() # internal macro # sets BISON_TARGET_cmdopt macro(BISON_TARGET_option_extraopts Options) set(BISON_TARGET_cmdopt "") set(BISON_TARGET_extraopts "${Options}") separate_arguments(BISON_TARGET_extraopts) list(APPEND BISON_TARGET_cmdopt ${BISON_TARGET_extraopts}) endmacro() # internal macro # sets BISON_TARGET_output_header and BISON_TARGET_cmdopt macro(BISON_TARGET_option_defines BisonOutput Header) if("${Header}" STREQUAL "") # default header path generated by bison (see option -d) string(REGEX REPLACE "^(.*)(\\.[^.]*)$" "\\2" _fileext "${BisonOutput}") string(REPLACE "c" "h" _fileext ${_fileext}) string(REGEX REPLACE "^(.*)(\\.[^.]*)$" "\\1${_fileext}" BISON_TARGET_output_header "${BisonOutput}") list(APPEND BISON_TARGET_cmdopt "-d") else() set(BISON_TARGET_output_header "${Header}") list(APPEND BISON_TARGET_cmdopt "--defines=${BISON_TARGET_output_header}") endif() endmacro() # internal macro # sets BISON_TARGET_verbose_file and BISON_TARGET_cmdopt macro(BISON_TARGET_option_report_file BisonOutput ReportFile) if("${ReportFile}" STREQUAL "") get_filename_component(BISON_TARGET_output_path "${BisonOutput}" PATH) get_filename_component(BISON_TARGET_output_name "${BisonOutput}" NAME_WE) set(BISON_TARGET_verbose_file "${BISON_TARGET_output_path}/${BISON_TARGET_output_name}.output") else() set(BISON_TARGET_verbose_file "${ReportFile}") list(APPEND BISON_TARGET_cmdopt "--report-file=${BISON_TARGET_verbose_file}") endif() if(NOT IS_ABSOLUTE "${BISON_TARGET_verbose_file}") cmake_policy(GET CMP0088 _BISON_CMP0088 PARENT_SCOPE # undocumented, do not use outside of CMake ) if("x${_BISON_CMP0088}x" STREQUAL "xNEWx") set(BISON_TARGET_verbose_file "${CMAKE_CURRENT_BINARY_DIR}/${BISON_TARGET_verbose_file}") else() set(BISON_TARGET_verbose_file "${CMAKE_CURRENT_SOURCE_DIR}/${BISON_TARGET_verbose_file}") endif() unset(_BISON_CMP0088) endif() endmacro() # internal macro # adds a custom command and sets # BISON_TARGET_cmdopt, BISON_TARGET_extraoutputs macro(BISON_TARGET_option_verbose Name BisonOutput filename) cmake_policy(GET CMP0088 _BISON_CMP0088 PARENT_SCOPE # undocumented, do not use outside of CMake ) set(_BISON_WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) if("x${_BISON_CMP0088}x" STREQUAL "xNEWx") set(_BISON_WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) endif() unset(_BISON_CMP0088) list(APPEND BISON_TARGET_cmdopt "--verbose") list(APPEND BISON_TARGET_outputs "${BISON_TARGET_verbose_file}") if (NOT "${filename}" STREQUAL "") if(IS_ABSOLUTE "${filename}") set(BISON_TARGET_verbose_extra_file "${filename}") else() set(BISON_TARGET_verbose_extra_file "${_BISON_WORKING_DIRECTORY}/${filename}") endif() add_custom_command(OUTPUT ${BISON_TARGET_verbose_extra_file} COMMAND ${CMAKE_COMMAND} -E copy "${BISON_TARGET_verbose_file}" "${filename}" VERBATIM DEPENDS "${BISON_TARGET_verbose_file}" COMMENT "[BISON][${Name}] Copying bison verbose table to ${filename}" WORKING_DIRECTORY ${_BISON_WORKING_DIRECTORY}) list(APPEND BISON_TARGET_extraoutputs "${BISON_TARGET_verbose_extra_file}") unset(BISON_TARGET_verbose_extra_file) unset(_BISON_WORKING_DIRECTORY) endif() endmacro() #============================================================ # BISON_TARGET (public macro) #============================================================ # macro(BISON_TARGET Name BisonInput BisonOutput) set(BISON_TARGET_outputs "${BisonOutput}") set(BISON_TARGET_extraoutputs "") # Parsing parameters set(BISON_TARGET_PARAM_OPTIONS ) set(BISON_TARGET_PARAM_ONE_VALUE_KEYWORDS COMPILE_FLAGS DEFINES_FILE REPORT_FILE ) set(BISON_TARGET_PARAM_MULTI_VALUE_KEYWORDS VERBOSE ) cmake_parse_arguments( BISON_TARGET_ARG "${BISON_TARGET_PARAM_OPTIONS}" "${BISON_TARGET_PARAM_ONE_VALUE_KEYWORDS}" "${BISON_TARGET_PARAM_MULTI_VALUE_KEYWORDS}" ${ARGN} ) if(NOT "${BISON_TARGET_ARG_UNPARSED_ARGUMENTS}" STREQUAL "") message(SEND_ERROR "Usage") elseif("${BISON_TARGET_ARG_VERBOSE}" MATCHES ";") # [VERBOSE [] hack: is non-multi value by usage message(SEND_ERROR "Usage") else() BISON_TARGET_option_extraopts("${BISON_TARGET_ARG_COMPILE_FLAGS}") BISON_TARGET_option_defines("${BisonOutput}" "${BISON_TARGET_ARG_DEFINES_FILE}") BISON_TARGET_option_report_file("${BisonOutput}" "${BISON_TARGET_ARG_REPORT_FILE}") if(NOT "${BISON_TARGET_ARG_VERBOSE}" STREQUAL "") BISON_TARGET_option_verbose(${Name} ${BisonOutput} "${BISON_TARGET_ARG_VERBOSE}") else() # [VERBOSE []] is used with no argument or is not used set(BISON_TARGET_args "${ARGN}") list(FIND BISON_TARGET_args "VERBOSE" BISON_TARGET_args_indexof_verbose) if(${BISON_TARGET_args_indexof_verbose} GREATER -1) # VERBOSE is used without BISON_TARGET_option_verbose(${Name} ${BisonOutput} "") endif() endif() list(APPEND BISON_TARGET_outputs "${BISON_TARGET_output_header}") cmake_policy(GET CMP0088 _BISON_CMP0088 PARENT_SCOPE # undocumented, do not use outside of CMake ) set(_BISON_WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) set(_BisonInput "${BisonInput}") if("x${_BISON_CMP0088}x" STREQUAL "xNEWx") set(_BISON_WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) if(NOT IS_ABSOLUTE "${_BisonInput}") set(_BisonInput "${CMAKE_CURRENT_SOURCE_DIR}/${_BisonInput}") endif() endif() unset(_BISON_CMP0088) add_custom_command(OUTPUT ${BISON_TARGET_outputs} COMMAND ${BISON_EXECUTABLE} ${BISON_TARGET_cmdopt} -o ${BisonOutput} ${_BisonInput} VERBATIM DEPENDS ${_BisonInput} COMMENT "[BISON][${Name}] Building parser with bison ${BISON_VERSION}" WORKING_DIRECTORY ${_BISON_WORKING_DIRECTORY}) unset(_BISON_WORKING_DIRECTORY) # define target variables set(BISON_${Name}_DEFINED TRUE) set(BISON_${Name}_INPUT ${_BisonInput}) set(BISON_${Name}_OUTPUTS ${BISON_TARGET_outputs} ${BISON_TARGET_extraoutputs}) set(BISON_${Name}_COMPILE_FLAGS ${BISON_TARGET_cmdopt}) set(BISON_${Name}_OUTPUT_SOURCE "${BisonOutput}") set(BISON_${Name}_OUTPUT_HEADER "${BISON_TARGET_output_header}") unset(_BisonInput) endif() endmacro() # #============================================================ endif() include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) FIND_PACKAGE_HANDLE_STANDARD_ARGS(BISON REQUIRED_VARS BISON_EXECUTABLE VERSION_VAR BISON_VERSION)