diff --git a/CMake/BuildFlatBuffers.cmake b/CMake/BuildFlatBuffers.cmake index ae3b235b985..2fb926eb2f6 100644 --- a/CMake/BuildFlatBuffers.cmake +++ b/CMake/BuildFlatBuffers.cmake @@ -12,6 +12,27 @@ # See the License for the specific language governing permissions and # limitations under the License. +# Include guard +if(DEFINED BUILD_FLATBUFFERS_CMAKE_INCLUDED) + return() +endif() +set(BUILD_FLATBUFFERS_CMAKE_INCLUDED TRUE) + +# Is this being included from FindFlatBuffers? +if(FlatBuffers_FOUND) + + # Sanity check that this version of flatc is compatible with this version of the library + include(${CMAKE_CURRENT_LIST_DIR}/FlatBuffersVersion.cmake) + if(${FLATBUFFERS_FLATC_VERSION} VERSION_EQUAL ${FLATBUFFERS_VERSION_NOCOMMIT}) + message(STATUS "Installed flatc version and flatbuffers library are compatible!") + else() + message(FATAL_ERROR "flatc version (${FLATBUFFERS_FLATC_VERSION}) does not match flatbuffers source \ +version (${FLATBUFFERS_VERSION_NOCOMMIT}). Please install the correct version of flatc. The flatc path can be changed \ +by modifying the FLATBUFFERS_FLATC_EXECUTABLE CMake variable.") + endif() + +endif() + # General function to create FlatBuffer build rules for the given list of # schemas. # @@ -154,15 +175,14 @@ function(build_flatbuffers flatbuffers_schemas endif() endfunction() -# Creates a target that can be linked against that generates flatbuffer headers. +# Creates a target that can be linked against that provides compiled versions of flatbuffer schemas. # -# This function takes a target name and a list of schemas. You can also specify -# other flagc flags using the FLAGS option to change the behavior of the flatc -# tool. +# This function takes a target name and a list of schemas. Custom commands will be created +# to generate the schemas, such that linking to the target passed as the TARGET argument +# will make the schema headers available. # -# When the target_link_libraries is done within a different directory than -# flatbuffers_generate_headers is called, then the target should also be dependent -# the custom generation target called GENERATE_. +# You can also specify other flagc flags using the FLAGS option to change the behavior of the flatc +# tool. # # Arguments: # TARGET: The name of the target to generate. @@ -176,6 +196,8 @@ endfunction() # files. Use this instead of the --include-prefix option. # FLAGS: Optional. A list of any additional flags that you would like to pass # to flatc. +# BINARY_SCHEMAS_FLAGS: Optional. Flags to pass to pass to flatc when generating +# binary schemas, if enabled. Note that FLAGS is not passed for generating binary schemas. # # Example: # @@ -190,8 +212,6 @@ endfunction() # PRIVATE my_generated_headers_target # ) # -# Optional (only needed within different directory): -# add_dependencies(app GENERATE_my_generated_headers_target) function(flatbuffers_generate_headers) # Parse function arguments. set(options) @@ -202,7 +222,8 @@ function(flatbuffers_generate_headers) set(multi_value_args "SCHEMAS" "INCLUDE" - "FLAGS") + "FLAGS" + "BINARY_SCHEMAS_FLAGS") cmake_parse_arguments( PARSE_ARGV 0 FLATBUFFERS_GENERATE_HEADERS @@ -212,13 +233,10 @@ function(flatbuffers_generate_headers) # Test if including from FindFlatBuffers if(FLATBUFFERS_FLATC_EXECUTABLE) - set(FLATC_TARGET "") set(FLATC ${FLATBUFFERS_FLATC_EXECUTABLE}) elseif(TARGET flatbuffers::flatc) - set(FLATC_TARGET flatbuffers::flatc) set(FLATC flatbuffers::flatc) else() - set(FLATC_TARGET flatc) set(FLATC flatc) endif() @@ -238,8 +256,9 @@ function(flatbuffers_generate_headers) list(APPEND FLATBUFFERS_GENERATE_HEADERS_FLAGS "--include-prefix" ${FLATBUFFERS_GENERATE_HEADERS_INCLUDE_PREFIX}) endif() + file(MAKE_DIRECTORY ${generated_include_dir}) - set(generated_custom_commands) + set(all_generated_files) # Create rules to generate the code for each schema. foreach(schema ${FLATBUFFERS_GENERATE_HEADERS_SCHEMAS}) @@ -264,26 +283,27 @@ function(flatbuffers_generate_headers) ${include_params} -c ${schema} ${FLATBUFFERS_GENERATE_HEADERS_FLAGS} - DEPENDS ${FLATC_TARGET} ${schema} + DEPENDS ${FLATC} ${schema} WORKING_DIRECTORY "${working_dir}" COMMENT "Building ${schema} flatbuffers...") list(APPEND all_generated_header_files ${generated_include}) list(APPEND all_generated_source_files ${generated_source_file}) - list(APPEND generated_custom_commands "${generated_include}" "${generated_source_file}") + list(APPEND all_generated_files "${generated_include}" "${generated_source_file}") - # Geneate the binary flatbuffers schemas if instructed to. + # Generate the binary flatbuffers schemas if instructed to. if (NOT ${FLATBUFFERS_GENERATE_HEADERS_BINARY_SCHEMAS_DIR} STREQUAL "") set(binary_schema "${FLATBUFFERS_GENERATE_HEADERS_BINARY_SCHEMAS_DIR}/${filename}.bfbs") add_custom_command( OUTPUT ${binary_schema} COMMAND ${FLATC} -b --schema - -o ${FLATBUFFERS_GENERATE_HEADERS_BINARY_SCHEMAS_DIR} + ${FLATBUFFERS_GENERATE_HEADERS_BINARY_SCHEMAS_FLAGS} + -o ${FLATBUFFERS_GENERATE_HEADERS_BINARY_SCHEMAS_DIR} ${include_params} ${schema} - DEPENDS ${FLATC_TARGET} ${schema} + DEPENDS ${FLATC} ${schema} WORKING_DIRECTORY "${working_dir}") - list(APPEND generated_custom_commands "${binary_schema}") + list(APPEND all_generated_files "${binary_schema}") list(APPEND all_generated_binary_files ${binary_schema}) endif() endforeach() @@ -291,21 +311,22 @@ function(flatbuffers_generate_headers) # Create an additional target as add_custom_command scope is only within same directory (CMakeFile.txt) set(generate_target GENERATE_${FLATBUFFERS_GENERATE_HEADERS_TARGET}) add_custom_target(${generate_target} ALL - DEPENDS ${generated_custom_commands} + DEPENDS ${all_generated_files} COMMENT "Generating flatbuffer target ${FLATBUFFERS_GENERATE_HEADERS_TARGET}") - # Set up interface library - add_library(${FLATBUFFERS_GENERATE_HEADERS_TARGET} INTERFACE) - target_sources( - ${FLATBUFFERS_GENERATE_HEADERS_TARGET} - INTERFACE - ${all_generated_header_files} - ${all_generated_binary_files} - ${all_generated_source_files} - ${FLATBUFFERS_GENERATE_HEADERS_SCHEMAS}) + # Set up interface library. + # This library is for users to link to, and depends on the custom target (so all the custom commands get run). + # It also adds the appropriate include paths. + # If there are no source files we use an interface library, otherwise compile the source files into a static lib. + if("${all_generated_source_files}" STREQUAL "") + add_library(${FLATBUFFERS_GENERATE_HEADERS_TARGET} INTERFACE) + else() + add_library(${FLATBUFFERS_GENERATE_HEADERS_TARGET} STATIC ${all_generated_source_files}) + endif() + add_dependencies( ${FLATBUFFERS_GENERATE_HEADERS_TARGET} - ${FLATC_TARGET}) + ${generate_target}) target_include_directories( ${FLATBUFFERS_GENERATE_HEADERS_TARGET} INTERFACE ${generated_target_dir}) @@ -324,8 +345,15 @@ function(flatbuffers_generate_headers) PREFIX "Flatbuffers/Schemas" FILES ${FLATBUFFERS_GENERATE_HEADERS_SCHEMAS}) if (NOT ${FLATBUFFERS_GENERATE_HEADERS_BINARY_SCHEMAS_DIR} STREQUAL "") + + # Resolve any relative paths for the source group call + get_filename_component(BINARY_SCHEMAS_DIR_ABSOLUTE_PATH + ${FLATBUFFERS_GENERATE_HEADERS_BINARY_SCHEMAS_DIR} + ABSOLUTE + BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + source_group( - TREE "${FLATBUFFERS_GENERATE_HEADERS_BINARY_SCHEMAS_DIR}" + TREE "${BINARY_SCHEMAS_DIR_ABSOLUTE_PATH}" PREFIX "Flatbuffers/Generated/Binary Schemas" FILES ${all_generated_binary_files}) endif() @@ -385,13 +413,10 @@ function(flatbuffers_generate_binary_files) # Test if including from FindFlatBuffers if(FLATBUFFERS_FLATC_EXECUTABLE) - set(FLATC_TARGET "") set(FLATC ${FLATBUFFERS_FLATC_EXECUTABLE}) elseif(TARGET flatbuffers::flatc) - set(FLATC_TARGET flatbuffers::flatc) set(FLATC flatbuffers::flatc) else() - set(FLATC_TARGET flatc) set(FLATC flatc) endif() @@ -414,7 +439,7 @@ function(flatbuffers_generate_binary_files) ${include_params} -b ${FLATBUFFERS_GENERATE_BINARY_FILES_SCHEMA} ${json_file} ${FLATBUFFERS_GENERATE_BINARY_FILES_FLAGS} - DEPENDS ${FLATC_TARGET} ${json_file} + DEPENDS ${FLATC} ${json_file} WORKING_DIRECTORY "${working_dir}" COMMENT "Building ${json_file} binary flatbuffers...") list(APPEND all_generated_binary_files ${generated_binary_file}) @@ -428,9 +453,6 @@ function(flatbuffers_generate_binary_files) ${all_generated_binary_files} ${FLATBUFFERS_GENERATE_BINARY_FILES_JSON_FILES} ${FLATBUFFERS_GENERATE_BINARY_FILES_SCHEMA}) - add_dependencies( - ${FLATBUFFERS_GENERATE_BINARY_FILES_TARGET} - ${FLATC}) # Organize file layout for IDEs. source_group( diff --git a/CMake/FindFlatBuffers.cmake b/CMake/FindFlatBuffers.cmake index 044cf7c9d27..78c21167000 100644 --- a/CMake/FindFlatBuffers.cmake +++ b/CMake/FindFlatBuffers.cmake @@ -16,24 +16,52 @@ # Find the flatbuffers schema compiler # # Output Variables: -# * FLATBUFFERS_FLATC_EXECUTABLE the flatc compiler executable -# * FLATBUFFERS_FOUND +# * FLATBUFFERS_FLATC_EXECUTABLE - The flatc compiler executable +# * FLATBUFFERS_FLATC_VERSION - The version of flatc found. +# * FlatBuffers_FOUND - Whether flatc was found. +# * FLATBUFFERS_FOUND - Legacy alias of the above (all caps). # -# Provides: -# * FLATBUFFERS_GENERATE_C_HEADERS(Name ) creates the C++ headers -# for the given flatbuffer schema files. -# Returns the header files in ${Name}_OUTPUTS +# If flatc is found, the following imported target is created: +# * flatbuffers::flatc - Imported target for the compiler +# +# If flatc is found, the following function is provided to compile the schemas into C headers: +# * flatbuffers_generate_headers() [see BuildFlatBuffers.cmake for signature] set(FLATBUFFERS_CMAKE_DIR ${CMAKE_CURRENT_LIST_DIR}) find_program(FLATBUFFERS_FLATC_EXECUTABLE NAMES flatc) -find_path(FLATBUFFERS_INCLUDE_DIR NAMES flatbuffers/flatbuffers.h) + +if(EXISTS ${FLATBUFFERS_FLATC_EXECUTABLE}) + # detect version + execute_process(COMMAND ${FLATBUFFERS_FLATC_EXECUTABLE} --version + RESULT_VARIABLE FLATBUFFERS_FLATC_VERSION_RESULT + OUTPUT_VARIABLE FLATBUFFERS_FLATC_VERSION_OUTPUT) + + if(FLATBUFFERS_FLATC_VERSION_RESULT EQUAL 0) + # The output looks like "flatc version 23.3.3", so use a regex to trim out the part we need + string(REGEX REPLACE "flatc version ([0-9]+\\.[0-9]+\\.[0-9]+).*" "\\1" FLATBUFFERS_FLATC_VERSION ${FLATBUFFERS_FLATC_VERSION_OUTPUT}) + else() + message(WARNING "Failed to execute flatc to check version") + endif() +endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(FlatBuffers - DEFAULT_MSG FLATBUFFERS_FLATC_EXECUTABLE FLATBUFFERS_INCLUDE_DIR) + VERSION_VAR FLATBUFFERS_FLATC_VERSION + REQUIRED_VARS FLATBUFFERS_FLATC_EXECUTABLE) -if(FLATBUFFERS_FOUND) +# CMake standard requires the found var to match the case of the filename. +# Provide legacy alias for all-caps. +set(FLATBUFFERS_FOUND ${FlatBuffers_FOUND}) + +if(FlatBuffers_FOUND AND NOT TARGET flatbuffers::flatc) + # Provide imported target for the executable + add_executable(flatbuffers::flatc IMPORTED GLOBAL) + set_property(TARGET flatbuffers::flatc PROPERTY IMPORTED_LOCATION ${FLATBUFFERS_FLATC_EXECUTABLE}) + + # LEGACY function for generating C headers from a flatbuffer. + # Deprecated, use flatbuffers_generate_headers() from BuildFlatBuffers.cmake instead, + # which allows passing options and generating library targets function(FLATBUFFERS_GENERATE_C_HEADERS Name) set(FLATC_OUTPUTS) foreach(FILE ${ARGN}) @@ -45,17 +73,12 @@ if(FLATBUFFERS_FOUND) add_custom_command(OUTPUT ${FLATC_OUTPUT} COMMAND ${FLATBUFFERS_FLATC_EXECUTABLE} ARGS -c -o "${CMAKE_CURRENT_BINARY_DIR}/" ${FILE} - DEPENDS ${FILE} + DEPENDS ${FILE} ${FLATBUFFERS_FLATC_EXECUTABLE} COMMENT "Building C++ header for ${FILE}" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) endforeach() set(${Name}_OUTPUTS ${FLATC_OUTPUTS} PARENT_SCOPE) endfunction() - set(FLATBUFFERS_INCLUDE_DIRS ${FLATBUFFERS_INCLUDE_DIR}) - include_directories(${CMAKE_BINARY_DIR}) -else() - set(FLATBUFFERS_INCLUDE_DIR) + include("${FLATBUFFERS_CMAKE_DIR}/BuildFlatBuffers.cmake") endif() - -include("${FLATBUFFERS_CMAKE_DIR}/BuildFlatBuffers.cmake") diff --git a/CMake/Version.cmake b/CMake/FlatBuffersVersion.cmake similarity index 75% rename from CMake/Version.cmake rename to CMake/FlatBuffersVersion.cmake index 21f47f637bc..d46eff59dbd 100644 --- a/CMake/Version.cmake +++ b/CMake/FlatBuffersVersion.cmake @@ -1,3 +1,9 @@ +# Include guard +if(DEFINED FLATBUFFERS_VERSION_CMAKE_INCLUDED) + return() +endif() +set(FLATBUFFERS_VERSION_CMAKE_INCLUDED TRUE) + set(VERSION_MAJOR 25) set(VERSION_MINOR 12) set(VERSION_PATCH 19) @@ -36,4 +42,8 @@ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git") endif() endif() -message(STATUS "Proceeding with version: ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}.${VERSION_COMMIT}") +set(FLATBUFFERS_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}.${VERSION_COMMIT}") +message(STATUS "Proceeding with FlatBuffers version: ${FLATBUFFERS_VERSION}") + +# The version reported by flatc does not include the commit number, so we also need a constant to compare to. +set(FLATBUFFERS_VERSION_NOCOMMIT "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") diff --git a/CMakeLists.txt b/CMakeLists.txt index 7bf48e6aecc..f1ea96648a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,10 @@ # This is the legacy minimum version flatbuffers supported for a while. -cmake_minimum_required(VERSION 3.8...3.25.2) +cmake_minimum_required(VERSION 3.10...3.25.2) +cmake_policy(VERSION 3.10) # Attempt to read the current version of flatbuffers by looking at the latest tag. -include(CMake/Version.cmake) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/CMake) +include(FlatBuffersVersion) project(FlatBuffers VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH} @@ -81,12 +83,20 @@ if(DEFINED FLATBUFFERS_COMPILATION_TIMINGS) set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "time -f 'Wall: %E User: %U Sys: %S | %C' -q -a -o ${FLATBUFFERS_COMPILATION_TIMINGS}") endif() -if(NOT FLATBUFFERS_BUILD_FLATC AND FLATBUFFERS_BUILD_TESTS) +if(NOT FLATBUFFERS_BUILD_FLATC) + # If we aren't supposed to build flatc, see if we can find it. + find_package(FlatBuffers ${FLATBUFFERS_VERSION_NOCOMMIT} EXACT) + set(FLATBUFFERS_FLATC_COMMAND ${FLATBUFFERS_FLATC_EXECUTABLE}) + + if(NOT FlatBuffers_FOUND AND FLATBUFFERS_BUILD_TESTS) message(WARNING - "Cannot build tests without building the compiler. Tests will be disabled.") + "Cannot build tests without building the compiler. Tests will be disabled.") set(FLATBUFFERS_BUILD_TESTS OFF) + endif() endif() +include(BuildFlatBuffers) + if(DEFINED FLATBUFFERS_MAX_PARSING_DEPTH) # Override the default recursion depth limit. add_definitions(-DFLATBUFFERS_MAX_PARSING_DEPTH=${FLATBUFFERS_MAX_PARSING_DEPTH}) @@ -471,6 +481,7 @@ if(FLATBUFFERS_BUILD_FLATC) endif() if(NOT FLATBUFFERS_FLATC_EXECUTABLE) set(FLATBUFFERS_FLATC_EXECUTABLE $) + set(FLATBUFFERS_FLATC_COMMAND flatc) endif() if(FLATBUFFERS_STATIC_FLATC AND NOT MSVC) target_link_libraries(flatc PRIVATE -static) @@ -508,7 +519,7 @@ function(compile_schema SRC_FBS OPT SUFFIX OUT_GEN_FILE) --filename-suffix ${SUFFIX} -o "${SRC_FBS_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}" - DEPENDS flatc ${SRC_FBS} + DEPENDS ${FLATBUFFERS_FLATC_COMMAND} ${SRC_FBS} COMMENT "flatc generation: `${SRC_FBS}` -> `${GEN_HEADER}`" ) set(${OUT_GEN_FILE} ${GEN_HEADER} PARENT_SCOPE) @@ -523,12 +534,6 @@ function(compile_schema_for_test_fbsh SRC_FBS OPT) compile_schema("${SRC_FBS}" "${OPT}" ".fbs" GEN_FILE) target_sources(flattests PRIVATE ${GEN_FILE}) endfunction() - -function(compile_schema_for_samples SRC_FBS OPT) - compile_schema("${SRC_FBS}" "${OPT}" "_generated" GEN_FILE) - target_sources(flatsample PRIVATE ${GEN_FILE}) -endfunction() - if(FLATBUFFERS_BUILD_TESTS) add_executable(flattests ${FlatBuffers_Tests_SRCS}) target_link_libraries(flattests PRIVATE $) @@ -572,14 +577,11 @@ if(FLATBUFFERS_BUILD_TESTS) # Add a library so there is a single target that the generated samples can # link too. - if(MSVC OR ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.20.0") - add_library(flatsample INTERFACE) - else() - add_library(flatsample STATIC) - endif() - - # Since flatsample has no sources, we have to explicitly set the linker lang. - set_target_properties(flatsample PROPERTIES LINKER_LANGUAGE CXX) + flatbuffers_generate_headers(TARGET flatsample + SCHEMAS samples/monster.fbs + BINARY_SCHEMAS_DIR samples/ + BINARY_SCHEMAS_FLAGS --bfbs-comments --bfbs-builtins + FLAGS ${FLATC_OPT_COMP}) target_link_libraries(flatsamplebinary PRIVATE $ flatsample) target_link_libraries(flatsampletext PRIVATE $ flatsample) @@ -704,8 +706,6 @@ if(FLATBUFFERS_BUILD_TESTS) endif() endif() -include(CMake/BuildFlatBuffers.cmake) - if(UNIX) # Use of CPack only supported on Linux systems. if(FLATBUFFERS_PACKAGE_DEBIAN)