1# Copyright 2022 The Pigweed Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); you may not 4# use this file except in compliance with the License. You may obtain a copy of 5# 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, WITHOUT 11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# License for the specific language governing permissions and limitations under 13# the License. 14 15include_guard(GLOBAL) 16 17cmake_minimum_required(VERSION 3.20) # string(JSON) 18 19include("$ENV{PW_ROOT}/pw_build/pigweed.cmake") 20 21# Turns binary blobs into a C++ library of hard-coded byte arrays. The byte 22# arrays are constant initialized and are safe to access at any time, including 23# before main(). 24# 25# Args: 26# 27# HEADER 28# 29# The header file to generate. Users will include this file exactly as it is 30# written here to reference the byte arrays. 31# 32# NAMESPACE 33# 34# The C++ namespace in which to place the generated blobs. 35# 36# BLOB 37# 38# A blob to be transformed from file to byte array. Multiple blobs may be 39# specified. 40# 41# Blob args: 42# 43# SYMBOL_NAME 44# 45# The C++ symbol name for the byte array. 46# 47# PATH 48# 49# The file path for the binary blob. 50# 51# LINKER_SECTION [optional] 52# 53# If present, places the byte array in the specified linker section. 54# 55# ALIGNAS [optional] 56# 57# If present, the byte array is aligned as specified. The value of this 58# argument is used verbatim in an alignas() specifier for the blob 59# byte array. 60# 61function(pw_cc_blob_library NAME) 62 cmake_parse_arguments(PARSE_ARGV 1 arg "" "HEADER;NAMESPACE" "") 63 64 set(blobs ${arg_UNPARSED_ARGUMENTS}) 65 set(blob_files "") 66 set(blob_index 0) 67 set(json_blobs "[]") # Create a JSON list of blobs 68 69 pw_require_args("" arg_ HEADER NAMESPACE) 70 71 while(NOT "${blobs}" STREQUAL "") 72 list(POP_FRONT blobs first_arg) 73 74 if(NOT "${first_arg}" STREQUAL BLOB) 75 message(FATAL_ERROR "Invalid syntax in pw_cc_blob_library: " 76 "Expected 'BLOB', found '${first_arg}'.") 77 endif() 78 79 list(FIND blobs BLOB blob_end) 80 list(SUBLIST blobs 0 "${blob_end}" current_blob) 81 82 cmake_parse_arguments( 83 blob_arg "" "SYMBOL_NAME;PATH;LINKER_SECTION;ALIGNAS" "" "${current_blob}" 84 ) 85 86 if(NOT "${blob_arg_UNPARSED_ARGUMENTS}" STREQUAL "") 87 message(FATAL_ERROR "Unexpected BLOB arguments in pw_cc_blob_library: " 88 "${blob_arg_UNPARSED_ARGUMENTS}") 89 endif() 90 91 pw_require_args("BLOB args for ${CMAKE_CURRENT_FUNCTION}" 92 blob_arg_ PATH SYMBOL_NAME) 93 94 cmake_path(ABSOLUTE_PATH blob_arg_PATH) 95 list(APPEND blob_files "${blob_arg_PATH}") 96 97 set(json_blob "{}") 98 _pw_json_set_string_key(json_blob file_path "${blob_arg_PATH}") 99 _pw_json_set_string_key(json_blob symbol_name "${blob_arg_SYMBOL_NAME}") 100 101 if(NOT "${blob_arg_ALIGNAS}" STREQUAL "") 102 _pw_json_set_string_key(json_blob alignas "${blob_arg_ALIGNAS}") 103 endif() 104 105 if(NOT "${blob_arg_LINKER_SECTION}" STREQUAL "") 106 _pw_json_set_string_key( 107 json_blob linker_section "${blob_arg_LINKER_SECTION}") 108 endif() 109 110 string(JSON json_blobs SET "${json_blobs}" "${blob_index}" "${json_blob}") 111 112 if("${blob_end}" EQUAL -1) 113 break() 114 endif() 115 116 list(SUBLIST blobs "${blob_end}" -1 blobs) 117 math(EXPR blob_index "${blob_index}+1") 118 endwhile() 119 120 set(out_dir "${CMAKE_CURRENT_BINARY_DIR}/${NAME}") 121 set(blob_json_file "${out_dir}/blobs.json") 122 123 file(WRITE "${blob_json_file}" "${json_blobs}") 124 set_property( # Ensure the file is regenerated by CMake if it is deleted. 125 DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${blob_json_file}") 126 127 set(generated_header "${out_dir}/public/${arg_HEADER}") 128 129 cmake_path(GET arg_HEADER STEM filename) 130 set(generated_source "${out_dir}/${filename}.cc") 131 132 add_custom_command( 133 COMMAND 134 python3 135 "$ENV{PW_ROOT}/pw_build/py/pw_build/generate_cc_blob_library.py" 136 --blob-file "${blob_json_file}" 137 --header-include "${arg_HEADER}" 138 --out-header "${generated_header}" 139 --out-source "${generated_source}" 140 --namespace "${arg_NAMESPACE}" 141 DEPENDS 142 "$ENV{PW_ROOT}/pw_build/py/pw_build/generate_cc_blob_library.py" 143 "${blob_json_file}" 144 ${blob_files} 145 OUTPUT 146 "${generated_header}" 147 "${generated_source}" 148 ) 149 150 add_custom_target("${NAME}._gen" 151 DEPENDS 152 "${generated_header}" 153 "${generated_source}" 154 ) 155 156 pw_add_library_generic("${NAME}" OBJECT 157 SOURCES 158 "${generated_source}" 159 PUBLIC_INCLUDES 160 "${out_dir}/public" 161 PUBLIC_DEPS 162 pw_polyfill 163 pw_preprocessor 164 ) 165 add_dependencies("${NAME}" "${NAME}._gen") 166endfunction(pw_cc_blob_library) 167 168# Sets a key with a string value in a JSON object. 169macro(_pw_json_set_string_key json_var key value) 170 string(JSON "${json_var}" SET "${${json_var}}" "${key}" "\"${value}\"") 171endmacro() 172