xref: /aosp_15_r20/external/pigweed/pw_build/cc_blob_library.cmake (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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