1# Copyright 2019 Google LLC 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15# Creates an alias for SOURCE, called DESTINATION. 16# 17# On platforms that support them, this rule will effectively create a symlink. 18# 19# SOURCE may be relative to CMAKE_CURRENT_SOURCE_DIR, or absolute. 20# DESTINATION may relative to CMAKE_CURRENT_BINARY_DIR, or absolute. 21# 22# Adapted from https://github.com/google/binexport/blob/master/util.cmake 23function(create_directory_symlink SOURCE DESTINATION) 24 get_filename_component(_destination_parent "${DESTINATION}" DIRECTORY) 25 file(MAKE_DIRECTORY "${_destination_parent}") 26 27 if(WIN32) 28 file(TO_NATIVE_PATH "${SOURCE}" _native_source) 29 file(TO_NATIVE_PATH "${DESTINATION}" _native_destination) 30 execute_process(COMMAND $ENV{ComSpec} /c 31 mklink /J "${_native_destination}" "${_native_source}" ERROR_QUIET) 32 else() 33 execute_process(COMMAND ${CMAKE_COMMAND} -E 34 create_symlink "${SOURCE}" "${DESTINATION}") 35 endif() 36endfunction() 37 38# Helper function that behaves just like Protobuf's protobuf_generate_cpp(), 39# except that it strips import paths. This is necessary, because CMake's 40# protobuf rules don't work well with imports across different directories. 41function(sapi_protobuf_generate_cpp SRCS HDRS) 42 cmake_parse_arguments(PARSE_ARGV 2 _pb "" "EXPORT_MACRO" "") 43 if(NOT _pb_UNPARSED_ARGUMENTS) 44 message(FATAL_ERROR "sapi_protobuf_generate_cpp() missing proto files") 45 return() 46 endif() 47 48 foreach(_file IN LISTS _pb_UNPARSED_ARGUMENTS) 49 get_filename_component(_abs_file_orig "${_file}" ABSOLUTE) 50 get_filename_component(_abs_file_repl 51 "${CMAKE_CURRENT_BINARY_DIR}/${_file}" ABSOLUTE) 52 53 # Add a CMake script that replaces the actual import paths. An extra 54 # script file is necessary so that this happens at build time. 55 set(_cmake_gen "${CMAKE_CURRENT_BINARY_DIR}/${_file}.gen.cmake") 56 file(WRITE "${_cmake_gen}" "\ 57file(READ \"${_abs_file_orig}\" _pb_orig) 58string(REGEX REPLACE \"import \\\".*/([^/]+\\\\.proto)\\\"\"\ 59 \"import \\\"\\\\1\\\"\" _pb_repl \"\${_pb_orig}\") 60file(WRITE \"${_abs_file_repl}\" \"\${_pb_repl}\")\ 61") 62 add_custom_command(OUTPUT "${_abs_file_repl}" 63 COMMAND "${CMAKE_COMMAND}" 64 ARGS -P "${_cmake_gen}" 65 DEPENDS "${_abs_file_orig}") 66 67 list(APPEND _pb_files "${_abs_file_repl}") 68 endforeach() 69 70 set(_outvar) 71 sapi_protobuf_generate(APPEND_PATH 72 LANGUAGE cpp 73 EXPORT_MACRO ${_pb_EXPORT_MACRO} 74 OUT_VAR _outvar 75 PROTOS ${_pb_files}) 76 set(${SRCS}) 77 set(${HDRS}) 78 foreach(_file IN LISTS _outvar) 79 if(_file MATCHES "cc$") 80 list(APPEND ${SRCS} ${_file}) 81 else() 82 list(APPEND ${HDRS} ${_file}) 83 endif() 84 endforeach() 85 set(${SRCS} ${${SRCS}} PARENT_SCOPE) 86 set(${HDRS} ${${HDRS}} PARENT_SCOPE) 87endfunction() 88 89# Runs the protocol buffer compiler on the given proto files. Compatible 90# with the upstream version and included here so we can add_subdirectory() 91# the protobuf source tree. 92# One difference to the protobuf version is that this function handles 93# relative paths differently, which is relevant when Sandboxed API is 94# embedded in another project. 95# TODO(cblichmann): We should try and upstream this behavior. 96function(sapi_protobuf_generate) 97 set(_options APPEND_PATH) 98 set(_singleargs LANGUAGE OUT_VAR EXPORT_MACRO PROTOC_OUT_DIR TARGET) 99 set(_multiargs PROTOS IMPORT_DIRS GENERATE_EXTENSIONS) 100 cmake_parse_arguments(_pb "${_options}" "${_singleargs}" "${_multiargs}" 101 "${ARGN}") 102 103 if(NOT _pb_PROTOS AND NOT _pb_TARGET) 104 message(FATAL_ERROR "sapi_protobuf_generate missing targets or sources") 105 return() 106 endif() 107 108 if(NOT _pb_OUT_VAR AND NOT _pb_TARGET) 109 message(FATAL_ERROR "sapi_protobuf_generate missing target or output var") 110 return() 111 endif() 112 113 if(NOT _pb_LANGUAGE) 114 set(_pb_LANGUAGE cpp) 115 else() 116 string(TOLOWER ${_pb_LANGUAGE} _pb_LANGUAGE) 117 endif() 118 119 if(NOT _pb_PROTOC_OUT_DIR) 120 set(_pb_PROTOC_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) 121 endif() 122 123 if(_pb_EXPORT_MACRO AND _pb_LANGUAGE STREQUAL cpp) 124 set(_dll_export_decl "dllexport_decl=${_pb_EXPORT_MACRO}:") 125 endif() 126 127 if(NOT _pb_GENERATE_EXTENSIONS) 128 if(_pb_LANGUAGE STREQUAL cpp) 129 set(_pb_GENERATE_EXTENSIONS .pb.h .pb.cc) 130 elseif(_pb_LANGUAGE STREQUAL python) 131 set(_pb_GENERATE_EXTENSIONS _pb2.py) 132 else() 133 message(FATAL_ERROR 134 "sapi_protobuf_generate given unknown language ${_pb_LANGUAGE}") 135 return() 136 endif() 137 endif() 138 139 if(_pb_TARGET) 140 get_target_property(_source_list ${_pb_TARGET} SOURCES) 141 foreach(_file IN LISTS _source_list) 142 if(_file MATCHES "proto$") 143 list(APPEND _pb_PROTOS "${_file}") 144 endif() 145 endforeach() 146 endif() 147 148 if(NOT _pb_PROTOS) 149 message(FATAL_ERROR 150 "sapi_protobuf_generate could not find any .proto files") 151 return() 152 endif() 153 154 # Create an include path for each file specified 155 foreach(_file ${_pb_PROTOS}) 156 get_filename_component(_abs_file "${_file}" ABSOLUTE) 157 get_filename_component(_abs_path "${_abs_file}" PATH) 158 list(FIND _protobuf_include_path "${_abs_path}" _contains_already) 159 if(${_contains_already} EQUAL -1) 160 list(APPEND _protobuf_include_path -I ${_abs_path}) 161 endif() 162 endforeach() 163 164 foreach(_dir IN LISTS _pb_IMPORT_DIRS) 165 get_filename_component(_abs_path "${_dir}" ABSOLUTE) 166 list(FIND _protobuf_include_path "${_abs_path}" _contains_already) 167 if(${_contains_already} EQUAL -1) 168 list(APPEND _protobuf_include_path -I "${_abs_path}") 169 endif() 170 endforeach() 171 172 set(_generated_srcs_all) 173 foreach(_proto IN LISTS _pb_PROTOS) 174 get_filename_component(_abs_file "${_proto}" ABSOLUTE) 175 get_filename_component(_abs_dir "${_abs_file}" DIRECTORY) 176 get_filename_component(_basename "${_proto}" NAME_WE) 177 178 set(_generated_srcs) 179 foreach(_ext ${_pb_GENERATE_EXTENSIONS}) 180 # Use _pb_PROTOC_OUT_DIR directly without computing a relative path 181 list(APPEND _generated_srcs "${_pb_PROTOC_OUT_DIR}/${_basename}${_ext}") 182 endforeach() 183 list(APPEND _generated_srcs_all ${_generated_srcs}) 184 185 add_custom_command(OUTPUT ${_generated_srcs} 186 COMMAND protobuf::protoc 187 ARGS --${_pb_LANGUAGE}_out 188 ${_dll_export_decl}${_pb_PROTOC_OUT_DIR} 189 ${_protobuf_include_path} 190 ${_abs_file} 191 DEPENDS ${_abs_file} protobuf::protoc 192 COMMENT "Running ${_pb_LANGUAGE} protoc on ${_proto}" 193 VERBATIM) 194 endforeach() 195 196 set_source_files_properties(${_generated_srcs_all} PROPERTIES 197 GENERATED TRUE 198 INCLUDE_DIRECTORIES "${absl_SOURCE_DIR}" 199 ) 200 if(_pb_OUT_VAR) 201 set(${_pb_OUT_VAR} ${_generated_srcs_all} PARENT_SCOPE) 202 endif() 203 if(_pb_TARGET) 204 target_sources(${_pb_TARGET} PRIVATE ${_generated_srcs_all}) 205 endif() 206endfunction() 207 208# Adds a sub-directory from Sandboxed API to the build. This is a simple macro 209# that calls `add_subdirectory()` with Sandboxed API's source and binary 210# directories and `EXCLUDE_FROM_ALL`. 211# This is useful in embedding projects to be able to refer to pre-sandboxed 212# libraries easily. 213# In order to be able build everything in one go, this macro also accepts a 214# `INCLUDE_FROM_ALL` option. It is expected that this will only be used from 215# `contrib/CMakeLists.txt`. 216macro(add_sapi_subdirectory) 217 cmake_parse_arguments(_sd "INCLUDE_FROM_ALL" "" "" ${ARGN}) 218 if(NOT ${_sd_INCLUDE_FROM_ALL}) 219 set(_sd_exclude_from_all EXCLUDE_FROM_ALL) 220 endif() 221 add_subdirectory("${SAPI_SOURCE_DIR}/${ARGV0}" "${SAPI_BINARY_DIR}/${ARGV0}" 222 ${_sd_exclude_from_all}) 223endmacro() 224