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