xref: /aosp_15_r20/external/perfetto/infra/perfetto.dev/BUILD.gn (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1# Copyright (C) 2022 The Android Open Source Project
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#      http://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
15import("../../gn/perfetto.gni")
16
17# Prevent that this file is accidentally included in embedder builds.
18assert(enable_perfetto_site)
19
20nodejs_bin = rebase_path("../../tools/node", root_build_dir)
21
22# The destination directory where the website will be built. GN pollutes
23# root_out_dir with all sorts of files, so we use a subdirectory.
24perfetto_website_out_dir = "$root_out_dir/site"
25
26# The directory containing all the markdown sources for the docs.
27src_doc_dir = "../../docs"
28
29group("site") {
30  deps = [
31    ":all_mdfiles",
32    ":assets",
33    ":gen_index",
34    ":gen_sql_stats_html",
35    ":gen_sql_tables_html",
36    ":gen_stdlib_docs_html",
37    ":gen_toc",
38    ":gen_trace_config_proto",
39    ":gen_trace_packet_proto",
40    ":node_assets",
41    ":readme",
42    ":style_scss",
43  ]
44}
45
46# Runs a nodejs script using the hermetic node toolchain.
47# Args:
48# * script: The .js script to execute
49# * inputs
50# * outputs
51# * deps
52# * depfile
53template("nodejs_script") {
54  assert(defined(invoker.script), "Need script in $target_name")
55
56  action(target_name) {
57    forward_variables_from(invoker,
58                           [
59                             "outputs",
60                             "depfile",
61                           ])
62    deps = [ ":node_modules" ]
63    if (defined(invoker.deps)) {
64      deps += invoker.deps
65    }
66    script = "../../gn/standalone/build_tool_wrapper.py"
67    inputs = [ invoker.script ]
68    inputs += invoker.inputs
69    args = [
70      nodejs_bin,
71      rebase_path(invoker.script, root_build_dir),
72    ]
73    args += invoker.args
74  }
75}
76
77# Installs the node modules specified in package.json
78action("node_modules") {
79  script = "../../gn/standalone/build_tool_wrapper.py"
80  stamp_file = "$target_out_dir/.$target_name.stamp"
81  cur_dir = rebase_path(".", root_build_dir)
82  args = [
83    "--stamp",
84    rebase_path(stamp_file, root_build_dir),
85    "--chdir=$cur_dir",
86    rebase_path("../../tools/pnpm", root_build_dir),
87    "install",
88    "--shamefully-hoist",
89    "--frozen-lockfile",
90  ]
91  inputs = [
92    "../../tools/npm",
93    "package.json",
94    "pnpm-lock.yaml",
95  ]
96  outputs = [ stamp_file ]
97}
98
99# Renders a markdown file into html.
100# Args:
101# * markdown: Optional. The source markdown file
102# * html_template: Optional. The html template to use
103# * out_html: The generated html, relative to `perfetto_website_out_dir`
104# * deps
105template("md_to_html") {
106  assert(defined(invoker.out_html), "Need out_html in $target_name")
107  assert(defined(invoker.html_template) || defined(invoker.markdown),
108         "Need html_template or markdown in $target_name")
109  nodejs_script(target_name) {
110    forward_variables_from(invoker, [ "deps" ])
111    script = "src/markdown_render.js"
112    inputs = []
113    if (defined(invoker.markdown)) {
114      inputs += [ invoker.markdown ]
115    }
116    depfile = "${target_gen_dir}/$target_name.d"
117    if (defined(invoker.html_template)) {
118      inputs += [ invoker.html_template ]
119    }
120    outputs = [ "${perfetto_website_out_dir}/${invoker.out_html}" ]
121    args = [
122      "--odir",
123      rebase_path(perfetto_website_out_dir, root_build_dir),
124      "-o",
125      rebase_path("${perfetto_website_out_dir}/${invoker.out_html}",
126                  root_build_dir),
127      "--depfile",
128      rebase_path(depfile, root_build_dir),
129    ]
130    if (defined(invoker.markdown)) {
131      args += [
132        "-i",
133        rebase_path(invoker.markdown, root_build_dir),
134      ]
135    }
136    if (defined(invoker.html_template)) {
137      args += [
138        "-t",
139        rebase_path(invoker.html_template, root_build_dir),
140      ]
141    }
142  }
143}
144
145md_to_html("gen_toc") {
146  markdown = "${src_doc_dir}/toc.md"
147  out_html = "docs/_nav.html"
148}
149
150md_to_html("gen_index") {
151  html_template = "src/template_index.html"
152  deps = [ ":gen_toc" ]
153  out_html = "index.html"
154}
155
156nodejs_script("style_scss") {
157  script = "node_modules/sass/sass.js"
158  input = "src/assets/style.scss"
159  inputs = [ input ]
160  output = "${perfetto_website_out_dir}/assets/style.css"
161  outputs = [ output ]
162  args = [
163    "--quiet",
164    rebase_path(input, root_build_dir),
165    rebase_path(output, root_build_dir),
166  ]
167  deps = [ ":node_modules" ]
168}
169
170sql_stats_md = "${target_gen_dir}/sql-stats.md"
171
172nodejs_script("gen_sql_stats_md") {
173  script = "src/gen_stats_reference.js"
174  input = "../../src/trace_processor/storage/stats.h"
175  inputs = [ input ]
176  outputs = [ sql_stats_md ]
177  args = [
178    "-i",
179    rebase_path(input, root_build_dir),
180    "-o",
181    rebase_path(sql_stats_md, root_build_dir),
182  ]
183}
184
185md_to_html("gen_sql_stats_html") {
186  markdown = sql_stats_md
187  html_template = "src/template_markdown.html"
188  deps = [
189    ":gen_sql_stats_md",
190    ":gen_toc",
191  ]
192  out_html = "docs/analysis/sql-stats"
193}
194
195# Generates a html reference for a proto
196# Args:
197# * proto: The path to a .proto file
198# * message_name: The proto message name
199# * out_html
200template("proto_reference") {
201  sql_stats_md = "${target_gen_dir}/${target_name}.md"
202  nodejs_script("${target_name}_md") {
203    script = "src/gen_proto_reference.js"
204    inputs = [ invoker.proto ]
205    outputs = [ sql_stats_md ]
206    args = [
207      "-i",
208      rebase_path(invoker.proto, root_build_dir),
209      "-p",
210      invoker.message_name,
211      "-o",
212      rebase_path(sql_stats_md, root_build_dir),
213    ]
214  }
215
216  md_to_html(target_name) {
217    markdown = sql_stats_md
218    html_template = "src/template_markdown.html"
219    deps = [
220      ":${target_name}_md",
221      ":gen_toc",
222    ]
223    out_html = invoker.out_html
224  }
225}
226
227proto_reference("gen_trace_config_proto") {
228  proto = "../../protos/perfetto/config/trace_config.proto"
229  message_name = "perfetto.protos.TraceConfig"
230  out_html = "docs/reference/trace-config-proto"
231}
232
233proto_reference("gen_trace_packet_proto") {
234  proto = "../../protos/perfetto/trace/trace_packet.proto"
235  message_name = "perfetto.protos.TracePacket"
236  out_html = "docs/reference/trace-packet-proto"
237}
238
239# WARNING: this does globbing at generation time. Incremental builds are not
240# going to work properly if files are added/removed. `gn gen` needs to be
241# rerun.
242sql_tables =
243    exec_script("../../gn/standalone/glob.py",
244                [
245                  "--root=" + rebase_path("../../src/trace_processor/tables",
246                                          root_build_dir),
247                  "--filter=*.h",
248                ],
249                "list lines")
250
251src_sql_tables = []
252
253foreach(i, sql_tables) {
254  src_sql_tables += [ rebase_path(i, ".", root_build_dir) ]
255}
256
257sql_tables_md = "${target_gen_dir}/sql-tables.md"
258stdlib_docs_md = "${target_gen_dir}/stdlib_docs.md"
259
260action("gen_stdlib_docs_md") {
261  script = "src/gen_stdlib_docs_md.py"
262  label_info = get_label_info(
263          "../../src/trace_processor/perfetto_sql/stdlib:stdlib_json_docs",
264          "target_gen_dir")
265  absolute_input_path = label_info + "/stdlib_docs.json"
266  deps = [
267    "../../python:trace_processor_stdlib_docs",
268    "../../src/trace_processor/perfetto_sql/stdlib:stdlib_json_docs",
269  ]
270  outputs = [ stdlib_docs_md ]
271  args = [
272    "--input",
273    rebase_path(absolute_input_path, root_build_dir),
274    "--output",
275    rebase_path(stdlib_docs_md, root_build_dir),
276  ]
277}
278
279md_to_html("gen_stdlib_docs_html") {
280  markdown = stdlib_docs_md
281  html_template = "src/template_markdown.html"
282  deps = [
283    ":gen_stdlib_docs_md",
284    ":gen_toc",
285  ]
286  out_html = "docs/analysis/stdlib-docs"
287}
288
289nodejs_script("gen_sql_tables_md") {
290  python_label = "../../src/trace_processor/tables:tables_python_docs"
291  python_docs_json = get_label_info(python_label, "target_gen_dir") + "/" +
292                     get_label_info(python_label, "name") + ".json"
293
294  script = "src/gen_sql_tables_reference.js"
295  inputs = src_sql_tables
296  deps = [ python_label ]
297  outputs = [ sql_tables_md ]
298  args = [
299    "-o",
300    rebase_path(sql_tables_md, root_build_dir),
301  ]
302  foreach(file, src_sql_tables) {
303    args += [
304      "-i",
305      rebase_path(file, root_build_dir),
306    ]
307  }
308  args += [
309    "-j",
310    rebase_path(python_docs_json, root_build_dir),
311  ]
312}
313
314md_to_html("gen_sql_tables_html") {
315  markdown = sql_tables_md
316  html_template = "src/template_markdown.html"
317  deps = [
318    ":gen_sql_tables_md",
319    ":gen_toc",
320  ]
321  out_html = "docs/analysis/sql-tables"
322}
323
324md_to_html("readme") {
325  markdown = "${src_doc_dir}/README.md"
326  html_template = "src/template_markdown.html"
327  out_html = "docs/index.html"
328  deps = [ ":gen_toc" ]
329}
330
331# WARNING: this does globbing at generation time. Incremental builds are not
332# going to work properly if files are added/removed. `gn gen` needs to be
333# rerun.
334mdfiles = exec_script("../../gn/standalone/glob.py",
335                      [
336                        "--root=" + rebase_path(src_doc_dir, root_build_dir),
337                        "--filter=*.md",
338                      ],
339                      "list lines")
340
341mdfiles -= [
342  rebase_path("../../docs/README.md", root_build_dir),
343  rebase_path("../../docs/toc.md", root_build_dir),
344]
345
346mdtargets = []
347
348foreach(source, mdfiles) {
349  filename = rebase_path(string_replace(source, ".md", ""),
350                         rebase_path("../../docs", root_build_dir))
351
352  md_to_html("mdfile_${source}") {
353    markdown = rebase_path(source, ".", root_build_dir)
354    html_template = "src/template_markdown.html"
355    out_html = "docs/${filename}"
356    deps = [ ":gen_toc" ]
357  }
358  mdtargets += [ ":mdfile_${source}" ]
359}
360
361# Files which have been removed/renamed/moved and now have HTTP redirections in
362# src/assets/script.js
363removed_renamed_moved_files = [ "analysis/common-queries.md" ]
364
365foreach(source, removed_renamed_moved_files) {
366  filename = rebase_path(string_replace(source, ".md", ""),
367                         rebase_path("../../docs", root_build_dir))
368  md_to_html("mdfile_${source}") {
369    markdown = "src/empty.md"
370    html_template = "src/template_markdown.html"
371    out_html = "docs/${filename}"
372    deps = [ ":gen_toc" ]
373  }
374  mdtargets += [ ":mdfile_${source}" ]
375}
376
377group("all_mdfiles") {
378  deps = mdtargets
379}
380
381copy("node_assets") {
382  sources = [
383    "node_modules/highlight.js/styles/tomorrow-night.css",
384    "node_modules/mermaid/dist/mermaid.min.js",
385  ]
386  deps = [ ":node_modules" ]
387
388  outputs = [ "${perfetto_website_out_dir}/assets/{{source_file_part}}" ]
389}
390
391# WARNING: this does globbing at generation time. Incremental builds are not
392# going to work properly if files are added/removed. `gn gen` needs to be
393# rerun.
394assets = exec_script("../../gn/standalone/glob.py",
395                     [
396                       "--root=" + rebase_path("src/assets", root_build_dir),
397                       "--filter=*.png",
398                       "--filter=*.js",
399                     ],
400                     "list lines")
401
402src_assets = []
403
404foreach(i, assets) {
405  src_assets += [ rebase_path(i, ".", root_build_dir) ]
406}
407
408copy("assets") {
409  sources = src_assets
410  outputs = [ "${perfetto_website_out_dir}/assets/{{source_file_part}}" ]
411}
412