# Copyright (c) 2020-now by the Zeek Project. See LICENSE for details. ### A collection of small helpers for the HILTI/Spicy build system. # Add the likely Bison include directory to Bison sources to avoid version mismatches. function (bison_source src output_dir) string(REGEX REPLACE "/bin/bison" "/include" bison_include "${BISON_EXECUTABLE}") set_source_files_properties( ${src} PROPERTIES INCLUDE_DIRECTORIES "${bison_include};${FLEX_INCLUDE_DIR};${output_dir}") endfunction () # Install a set of header files from a directory location. function (install_headers src dst) if (NOT IS_ABSOLUTE "${src}") set(src "${CMAKE_CURRENT_SOURCE_DIR}/${src}") endif () if (NOT IS_ABSOLUTE "${dst}") set(dst_msg "${CMAKE_INSTALL_FULL_INCLUDEDIR}/${dst}") set(dst "${CMAKE_INSTALL_INCLUDEDIR}/${dst}") endif () if (ARGN) foreach (i ${ARGN}) install(FILES ${src}/${i} DESTINATION ${dst}) endforeach () else () install(CODE "message(STATUS \"Installing: ${dst_msg}/*\")") install( DIRECTORY ${src}/ DESTINATION ${dst} MESSAGE_NEVER FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp" PATTERN "*.hh" PATTERN "3rdparty*" EXCLUDE) endif () endfunction () # Add a symlink at installation time. function (install_symlink filepath sympath) install(CODE "message(\"-- Creating symbolic link: ${sympath} -> ${filepath}\")") install( CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${filepath} ${sympath})") endfunction (install_symlink) # Initialize a variable that'll go into a {hilti,spicy}/config.cc # file. This performs some normalization: turn lists into # space-separated strings and strip/reduce whitespace. function (set_config_val dst val) if (NOT "${val}" STREQUAL "") string(REPLACE ";" " " _x "${val}") string(STRIP "${_x}" _x) string(REGEX REPLACE " *" " " _x "${_x}") set(${dst} "${_x}" PARENT_SCOPE) else () set(${dst} "" PARENT_SCOPE) endif () endfunction () # Sets an appropriate RPATH for the system. function (make_install_rpath dst relative_from relative_to) # The following is from "Professional CMake" to set target's RPATH relative to their location. if (APPLE) set(base_point "@loader_path") else () set(base_point "$ORIGIN") endif () file(RELATIVE_PATH relative_lib_path ${relative_from} ${relative_to}) set(${dst} "${base_point};${base_point}/${relative_lib_path}" PARENT_SCOPE) endfunction () # Warn or abort if we don't a given version isn't recent enough. function (require_version name found have need require) if (NOT ${found}) if (require) message(FATAL_ERROR "${name} required, but not found") else () set(${found} no PARENT_SCOPE) set(${have} "not found") endif () else () if (${have} VERSION_LESS "${need}") if (require) message(FATAL_ERROR "Need ${name} version >= ${need}, found ${${have}}") endif () message(STATUS "Warning: Need ${name} version >= ${need}, found ${${have}}") set(${found} no PARENT_SCOPE) set(${have} "${${have}} (error: too old, must be at least ${need})" PARENT_SCOPE) endif () endif () endfunction () # Internal helper to link in all object libraries that libhilti needs. function (hilti_link_object_libraries_in_tree lib) if (HAVE_TOOLCHAIN) target_link_libraries(${lib} "${ARGN}" hilti-objects) endif () if (CMAKE_BUILD_TYPE STREQUAL "Debug") target_link_libraries(${lib} "${ARGN}" hilti-rt-debug-objects) else () target_link_libraries(${lib} "${ARGN}" hilti-rt-objects) endif () set(_private "") if (NOT "${ARGN}" STREQUAL "") set(_private "PRIVATE") endif () target_link_libraries(${lib} ${_private} reproc++) target_link_libraries(${lib} ${_private} jrx-objects) target_link_libraries(${lib} ${_private} fiber) endfunction () # Link a library against libhilti. This picks the right version of # libhilti (shared or object) based on the build configuration. function (hilti_link_libraries_in_tree lib) if (BUILD_SHARED_LIBS) target_link_libraries(${lib} "${ARGN}" hilti) else () hilti_link_object_libraries_in_tree(${lib} "${ARGN}") endif () endfunction () # Link an executable against libhilti. This picks the right version of # libhilti (shared or object) based on the build configuration. function (hilti_link_executable_in_tree exec) # Ideally, we'd just link against the static hilti library here. However, # ENABLE_EXPORTS doesn't seem to apply through to that, and we'd get # missing symbol errors at runtime. So instead we link directly # against our set of objects libraries by calling hilti_link_libraries_in_tree(). hilti_link_libraries_in_tree(${exec} "${ARGN}") set_property(TARGET ${exec} PROPERTY ENABLE_EXPORTS true) endfunction () # Internal helper to link in all object libraries that libspicy needs. function (spicy_link_object_libraries_in_tree lib) if (HAVE_TOOLCHAIN) target_link_libraries(${lib} "${ARGN}" spicy-objects) endif () if (CMAKE_BUILD_TYPE STREQUAL "Debug") target_link_libraries(${lib} "${ARGN}" spicy-rt-debug-objects) else () target_link_libraries(${lib} "${ARGN}" spicy-rt-objects) endif () endfunction () # Link a library against libspicy. This picks the right version of # libspicy (shared or object) based on the build configuration. function (spicy_link_libraries_in_tree lib) if (BUILD_SHARED_LIBS) target_link_libraries(${lib} "${ARGN}" spicy) else () spicy_link_object_libraries_in_tree(${lib} "${ARGN}") endif () endfunction () # Link an executable against libspicy. This picks the right version of # libspicy (shared or object) based on the build configuration. function (spicy_link_executable_in_tree exec) # Similar comment here as hilti_link_executable_in_tree(). hilti_link_libraries_in_tree(${exec} "${ARGN}") spicy_link_libraries_in_tree(${exec} "${ARGN}") set_property(TARGET ${exec} PROPERTY ENABLE_EXPORTS true) endfunction () include(CheckCXXCompilerFlag) # Wrapper around `BISON_TARGET` with Spicy-specific preprocessing. macro (BISON_TARGET_PP Name BisonInput BisonOutput) # Name of the preprocessed Bison input. string(JOIN "." BisonInputPP "${BisonOutput}" "pp") # Preprocess the input file: # # - in versions ${BisonInputPP} WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} COMMENT "Preprocessing Bison file ${BisonInput}") else () add_custom_command( OUTPUT ${BisonInputPP} DEPENDS ${BisonInput} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${BisonInput} ${BisonInputPP} WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} COMMENT "Preprocessing Bison file ${BisonInput}") endif () # Pass preprocessed file to `BISON_TARGET`. # # TODO(bbannier): Since `ARGV` is a list of lists normal list manipulations like # `list(REPLACE_AT ...)` do not seem to work so we create a new output list. set(i 0) foreach (arg ${ARGV}) if (i EQUAL 1) list(APPEND args "${BisonInputPP}") else () list(APPEND args "${arg}") endif () math(EXPR i "${i}+1") endforeach () # Invoke the actual Bison processing. if (BISON_VERSION VERSION_GREATER_EQUAL "3.7.0") bison_target( ${args} COMPILE_FLAGS "--file-prefix-map=${BisonInputPP}=${CMAKE_CURRENT_SOURCE_DIR}/${BisonInput}") else () # This works but will leave locations in compiler error messages point to the preprocessed file. bison_target(${args}) endif () check_cxx_compiler_flag("-Wunused-but-set-variable" have_unused_but_set_variable) if (have_unused_but_set_variable) # Suppress warnings in generated code. # cmake-format: off # (cmake-format and cmake-lint don't agree on how this line should be formatted). set_source_files_properties(${BisonOutput} PROPERTIES COMPILE_FLAGS "-Wno-unused-but-set-variable") # cmake-format: on endif () endmacro ()