Understanding CMake Policy CMP0088 for Bison Parser Generation


What is CMP0088?

CMP0088 is a CMake policy that controls where the Bison parser generator is run and where it generates implicit files during the build process. It was introduced in CMake version 3.14 to address a change in how Bison is executed.

Understanding the Policy

  • CMake 3.14 and Later (Preferred Behavior)

    • To ensure build tree separation and avoid modifying the source tree, Bison is now preferred to run in the current build directory (CMAKE_CURRENT_BINARY_DIR).
    • The WORKING_DIRECTORY argument of the add_custom_command invocation is set to CMAKE_CURRENT_BINARY_DIR.
    • Implicit files are generated in the build directory, keeping the source tree clean.
    • The BISON_TARGET macro would run Bison in the current source directory (CMAKE_CURRENT_SOURCE_DIR).
    • Implicit files generated by Bison (like header files) would also be placed in the source directory.

Compatibility for Older Projects

  • The CMP0088 policy provides compatibility for projects that haven't been updated to expect the new behavior.
    • OLD Behavior (Deprecated)
      Uses the current source directory for both running Bison and generating implicit files. This is the default behavior if the policy is not explicitly set.
    • NEW Behavior (Recommended)
      Uses the current build directory for both running Bison and generating implicit files.

How to Set the Policy

Use the cmake_policy command in your CMakeLists.txt file to explicitly set the policy:

cmake_policy(CMP0088 NEW)  # Use the new behavior (recommended)
# OR
cmake_policy(CMP0088 OLD)  # Use the old behavior (for compatibility)

Important Note

  • While CMake 3.24.2 doesn't warn when the policy is not set, it defaults to the OLD behavior. This behavior is deprecated and might be removed in future CMake versions. It's strongly recommended to set the policy explicitly (ideally to NEW) to avoid potential issues and ensure consistent builds across different CMake versions.


Scenario 1: Using the New Behavior (Recommended)

# CMakeLists.txt

cmake_minimum_required(VERSION 3.14)  # Requires CMake 3.14 or later

# No need to set CMP0088 explicitly as NEW is the default for CMake 3.14+

find_package(BISON REQUIRED)  # Find and require Bison

bison_target(my_parser parser.y parser.c)

add_executable(my_program main.cpp parser.c)
target_link_libraries(my_program Bison::Bison)

In this example:

  • The bison.y file is processed in the build directory, and the generated parser.c file is placed there as well.
  • BISON_TARGET is used without setting CMP0088, as NEW is the default behavior for CMake 3.14 and later.
  • CMake version 3.14 or later is required.

Scenario 2: Using the Old Behavior (For Compatibility)

# CMakeLists.txt

cmake_minimum_required(VERSION 3.0)  # Requires CMake 3.0 or later

# Explicitly set CMP0088 to OLD for compatibility with older projects

cmake_policy(CMP0088 OLD)

find_package(BISON REQUIRED)  # Find and require Bison

bison_target(my_parser parser.y parser.c)

add_executable(my_program main.cpp parser.c)
target_link_libraries(my_program Bison::Bison)

Here:

  • The bison.y file and generated parser.c will be placed in the source directory.
  • The policy is explicitly set to OLD to match the behavior of older CMake versions.
  • While a lower CMake version is allowed, it's generally recommended to upgrade to benefit from newer features.
  • Consider migrating your project to use the NEW behavior for better build tree organization and reduced risk of modifying source code unintentionally.
  • If you're unsure about your project's compatibility, start with the NEW behavior and test thoroughly.


Custom Commands with Explicit Working Directory

If you're using a version of CMake older than 3.14 or have specific reasons to avoid the BISON_TARGET macro, you can use a custom command to run Bison:

find_package(BISON REQUIRED)
message(STATUS "Running Bison in ${CMAKE_CURRENT_SOURCE_DIR}")  # Informative message

add_custom_command(
    OUTPUT parser.c  # Output file
    COMMAND ${BISON_EXECUTABLE} -d -o parser.c parser.y
    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}  # Set working directory
    COMMENT "Generating parser.c"
)

add_executable(my_program main.cpp parser.c)
target_link_libraries(my_program Bison::Bison)
  • Be aware that manually managing the working directory requires more code compared to BISON_TARGET.
  • This approach lets you control the exact command arguments passed to Bison and the working directory.

CMake Generator Expressions (CMake 3.13 or newer)

If your project uses CMake 3.13 or later, you can leverage generator expressions with BISON_TARGET to influence the behavior:

find_package(BISON REQUIRED)

set(OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")  # Set output directory

bison_target(my_parser
    parser.y
    ${OUTPUT_DIR}/parser.c  # Use generator expression for output path
)

add_executable(my_program main.cpp ${OUTPUT_DIR}/parser.c)
target_link_libraries(my_program Bison::Bison)
  • It keeps the code cleaner compared to custom commands, but requires a slightly newer CMake version.
  • This approach allows you to specify the output directory for the generated file within the BISON_TARGET invocation.
  • For more granular control over output locations (CMake 3.13+), generator expressions with BISON_TARGET are an option.
  • If compatibility with older CMake versions is critical, consider the custom command approach.
  • Use CMP0088 with the NEW behavior whenever possible for recommended build practice.