# Copyright (C) 2018 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import("../gn/perfetto.gni") import("../gn/wasm.gni") import("../protos/perfetto/trace_processor/proto_files.gni") ui_dir = "$root_build_dir/ui" ui_gen_dir = "$target_out_dir/gen" nodejs_root = "../buildtools/nodejs" nodejs_bin = rebase_path("$nodejs_root/bin", root_build_dir) # +----------------------------------------------------------------------------+ # | The outer "ui" target to just ninja -C out/xxx ui | # +----------------------------------------------------------------------------+ group("ui") { deps = [ ":assets_dist", ":catapult_dist", ":controller_bundle_dist", ":engine_bundle_dist", ":frontend_bundle_dist", ":index_dist", ":scss", ":test_scripts", ":typefaces_dist", ":wasm_dist", ] } group("query") { deps = [ ":query_bundle_dist", ":query_dist", ":ui", ] } # +----------------------------------------------------------------------------+ # | Template used to run node binaries using the hermetic node toolchain. | # +----------------------------------------------------------------------------+ template("node_bin") { action(target_name) { forward_variables_from(invoker, [ "inputs", "outputs", "depfile", ]) deps = [ ":node_modules", ] if (defined(invoker.deps)) { deps += invoker.deps } script = "../gn/standalone/build_tool_wrapper.py" _node_cmd = invoker.node_cmd args = [] if (defined(invoker.suppress_stdout) && invoker.suppress_stdout) { args += [ "--suppress_stdout" ] } if (defined(invoker.suppress_stderr) && invoker.suppress_stderr) { args += [ "--suppress_stderr" ] } args += [ "--path=$nodejs_bin", "node", rebase_path("node_modules/.bin/$_node_cmd", root_build_dir), ] + invoker.args } } # +----------------------------------------------------------------------------+ # | Template for "sorcery" the source map resolver. | # +----------------------------------------------------------------------------+ template("sorcery") { node_bin(target_name) { assert(defined(invoker.input)) assert(defined(invoker.output)) forward_variables_from(invoker, [ "deps" ]) inputs = [ invoker.input, ] outputs = [ invoker.output, invoker.output + ".map", ] node_cmd = "sorcery" args = [ "-i", rebase_path(invoker.input, root_build_dir), "-o", rebase_path(invoker.output, root_build_dir), ] } } # +----------------------------------------------------------------------------+ # | Template for bundling js | # +----------------------------------------------------------------------------+ template("bundle") { node_bin(target_name) { assert(defined(invoker.input)) assert(defined(invoker.output)) forward_variables_from(invoker, [ "deps" ]) inputs = [ invoker.input, "rollup.config.js", ] outputs = [ invoker.output, invoker.output + ".map", ] node_cmd = "rollup" args = [ "-c", rebase_path("rollup.config.js", root_build_dir), rebase_path(invoker.input, root_build_dir), "-o", rebase_path(invoker.output, root_build_dir), "-f", "iife", "-m", "--silent", ] } } # +----------------------------------------------------------------------------+ # | Bundles all *.js files together resolving CommonJS require() deps. | # +----------------------------------------------------------------------------+ # Bundle together all js sources into a bundle.js file, that will ultimately be # included by the .html files. bundle("frontend_bundle") { deps = [ ":transpile_all_ts", ] input = "$target_out_dir/frontend/index.js" output = "$target_out_dir/frontend_bundle.js" } bundle("controller_bundle") { deps = [ ":transpile_all_ts", ] input = "$target_out_dir/controller/index.js" output = "$target_out_dir/controller_bundle.js" } bundle("engine_bundle") { deps = [ ":transpile_all_ts", ] input = "$target_out_dir/engine/index.js" output = "$target_out_dir/engine_bundle.js" } bundle("query_bundle") { deps = [ ":transpile_all_ts", ] input = "$target_out_dir/query/index.js" output = "$target_out_dir/query_bundle.js" } # +----------------------------------------------------------------------------+ # | Protobuf: gen rules to create .js and .d.ts files from protos. | # +----------------------------------------------------------------------------+ node_bin("protos_to_js") { inputs = [] foreach(proto, trace_processor_protos) { inputs += [ "../protos/perfetto/trace_processor/$proto.proto" ] } inputs += [ "../protos/perfetto/config/perfetto_config.proto" ] outputs = [ "$ui_gen_dir/protos.js", ] node_cmd = "pbjs" args = [ "-t", "static-module", "-w", "commonjs", "-p", rebase_path("../protos", root_build_dir), "-o", rebase_path(outputs[0], root_build_dir), ] + rebase_path(inputs, root_build_dir) } # Protobuf.js requires to first generate .js files from the .proto and then # create .ts definitions for them. node_bin("protos_to_ts") { deps = [ ":protos_to_js", ] inputs = [ "$ui_gen_dir/protos.js", ] outputs = [ "$ui_gen_dir/protos.d.ts", ] node_cmd = "pbts" args = [ "-p", rebase_path("../protos", root_build_dir), "-o", rebase_path(outputs[0], root_build_dir), rebase_path(inputs[0], root_build_dir), ] } # +----------------------------------------------------------------------------+ # | TypeScript: transpiles all *.ts into .js | # +----------------------------------------------------------------------------+ # Builds all .ts sources in the repo under |src|. node_bin("transpile_all_ts") { deps = [ ":dist_symlink", ":protos_to_ts", ":wasm_gen", ] inputs = [ "tsconfig.json", ] outputs = [ "$target_out_dir/frontend/index.js", "$target_out_dir/engine/index.js", "$target_out_dir/controller/index.js", "$target_out_dir/query/index.js", ] depfile = root_out_dir + "/tsc.d" exec_script("../gn/standalone/glob.py", [ "--root=" + rebase_path(".", root_build_dir), "--filter=*.ts", "--exclude=node_modules", "--exclude=dist", "--deps=obj/ui/frontend/index.js", "--output=" + rebase_path(depfile), ], "") node_cmd = "tsc" args = [ "--project", rebase_path(".", root_build_dir), "--outDir", rebase_path(target_out_dir, root_build_dir), ] } # +----------------------------------------------------------------------------+ # | Build css. | # +----------------------------------------------------------------------------+ scss_root = "src/assets/perfetto.scss" scss_srcs = [ "src/assets/typefaces.scss", "src/assets/sidebar.scss", "src/assets/topbar.scss", "src/assets/record.scss", "src/assets/common.scss", ] # Build css. node_bin("scss") { deps = [ ":dist_symlink", ] inputs = [ scss_root ] + scss_srcs outputs = [ "$ui_dir/perfetto.css", ] node_cmd = "node-sass" args = [ "--quiet", rebase_path(scss_root, root_build_dir), rebase_path(outputs[0], root_build_dir), ] } # +----------------------------------------------------------------------------+ # | Copy rules: create the final output directory. | # +----------------------------------------------------------------------------+ copy("index_dist") { sources = [ "index.html", ] outputs = [ "$ui_dir/index.html", ] } copy("typefaces_dist") { sources = [ "../buildtools/typefaces/GoogleSans-Medium.woff2", "../buildtools/typefaces/GoogleSans-Regular.woff2", "../buildtools/typefaces/MaterialIcons.woff2", "../buildtools/typefaces/Raleway-Regular.woff2", "../buildtools/typefaces/Raleway-Thin.woff2", "../buildtools/typefaces/RobotoMono-Regular.woff2", ] outputs = [ "$ui_dir/assets/{{source_file_part}}", ] } copy("query_dist") { sources = [ "query.html", ] outputs = [ "$ui_dir/query.html", ] } copy("assets_dist") { sources = [ "src/assets/logo-3d.png", "src/assets/logo.png", "src/assets/rec_atrace.png", "src/assets/rec_battery_counters.png", "src/assets/rec_board_voltage.png", "src/assets/rec_cpu_coarse.png", "src/assets/rec_cpu_fine.png", "src/assets/rec_cpu_freq.png", "src/assets/rec_cpu_voltage.png", "src/assets/rec_cpu_wakeup.png", "src/assets/rec_ftrace.png", "src/assets/rec_lmk.png", "src/assets/rec_logcat.png", "src/assets/rec_long_trace.png", "src/assets/rec_mem_hifreq.png", "src/assets/rec_meminfo.png", "src/assets/rec_one_shot.png", "src/assets/rec_ps_stats.png", "src/assets/rec_ring_buf.png", "src/assets/rec_vmstat.png", ] + [ scss_root ] + scss_srcs outputs = [ "$ui_dir/assets/{{source_file_part}}", ] } sorcery("frontend_bundle_dist") { deps = [ ":frontend_bundle", ] input = "$target_out_dir/frontend_bundle.js" output = "$ui_dir/frontend_bundle.js" } sorcery("controller_bundle_dist") { deps = [ ":controller_bundle", ] input = "$target_out_dir/controller_bundle.js" output = "$ui_dir/controller_bundle.js" } sorcery("engine_bundle_dist") { deps = [ ":engine_bundle", ] input = "$target_out_dir/engine_bundle.js" output = "$ui_dir/engine_bundle.js" } sorcery("query_bundle_dist") { deps = [ ":query_bundle", ] input = "$target_out_dir/query_bundle.js" output = "$ui_dir/query_bundle.js" } copy("wasm_dist") { deps = [ "//src/trace_processor:trace_processor.wasm($wasm_toolchain)", "//tools/trace_to_text:trace_to_text.wasm($wasm_toolchain)", ] sources = [ "$root_build_dir/wasm/trace_processor.wasm", "$root_build_dir/wasm/trace_to_text.wasm", ] outputs = [ "$ui_dir/{{source_file_part}}", ] } copy("wasm_gen") { deps = [ ":dist_symlink", # trace_processor "//src/trace_processor:trace_processor.d.ts($wasm_toolchain)", "//src/trace_processor:trace_processor.js($wasm_toolchain)", "//src/trace_processor:trace_processor.wasm($wasm_toolchain)", # trace_to_text "//tools/trace_to_text:trace_to_text.d.ts($wasm_toolchain)", "//tools/trace_to_text:trace_to_text.js($wasm_toolchain)", "//tools/trace_to_text:trace_to_text.wasm($wasm_toolchain)", ] sources = [ # trace_processor "$root_build_dir/wasm/trace_processor.d.ts", "$root_build_dir/wasm/trace_processor.js", "$root_build_dir/wasm/trace_processor.wasm", # trace_to_text "$root_build_dir/wasm/trace_to_text.d.ts", "$root_build_dir/wasm/trace_to_text.js", "$root_build_dir/wasm/trace_to_text.wasm", ] if (is_debug) { sources += [ "$root_build_dir/wasm/trace_processor.wasm.map", "$root_build_dir/wasm/trace_to_text.wasm.map", ] } outputs = [ "$ui_gen_dir/{{source_file_part}}", ] } # Copy over the vulcanized legacy trace viewer. copy("catapult_dist") { sources = [ "../buildtools/catapult_trace_viewer/catapult_trace_viewer.html", "../buildtools/catapult_trace_viewer/catapult_trace_viewer.js", ] outputs = [ "$ui_dir/assets/{{source_file_part}}", ] } # +----------------------------------------------------------------------------+ # | Node JS: Creates a symlink in the out directory to node_modules. | # +----------------------------------------------------------------------------+ action("check_node_exists") { script = "../gn/standalone/check_buildtool_exists.py" args = [ nodejs_bin, "--touch", rebase_path("$target_out_dir/node_exists", ""), ] inputs = [] outputs = [ "$target_out_dir/node_exists", ] } # Creates a symlink from out/xxx/ui/node_modules -> ../../../ui/node_modules. # This allows to run rollup and other node tools from the out/xxx directory. action("node_modules_symlink") { deps = [ ":check_node_exists", ] script = "../gn/standalone/build_tool_wrapper.py" stamp_file = "$target_out_dir/.$target_name.stamp" args = [ "--stamp", rebase_path(stamp_file, root_build_dir), "/bin/ln", "-fns", rebase_path("node_modules", target_out_dir), rebase_path("$target_out_dir/node_modules", root_build_dir), ] outputs = [ stamp_file, ] } group("node_modules") { deps = [ ":node_modules_symlink", ] } # Creates a symlink from //ui/dist -> ../../out/xxx/ui. Used only for # autocompletion in IDEs. The problem this is solving is that in tsconfig.json # we can't possibly know the path to ../../out/xxx for outDir. Instead, we set # outDir to "./dist" and create a symlink on the first build. action("dist_symlink") { script = "../gn/standalone/build_tool_wrapper.py" stamp_file = "$target_out_dir/.$target_name.stamp" args = [ "--stamp", rebase_path(stamp_file, root_build_dir), "/bin/ln", "-fns", rebase_path(target_out_dir, "."), rebase_path("dist", root_build_dir), ] inputs = [ "$root_build_dir", ] outputs = [ stamp_file, ] } group("test_scripts") { deps = [ ":copy_tests_script", ":copy_unittests_script", ] } copy("copy_unittests_script") { sources = [ "config/ui_unittests_template", ] outputs = [ "$root_build_dir/ui_unittests", ] } copy("copy_tests_script") { sources = [ "config/ui_tests_template", ] outputs = [ "$root_build_dir/ui_tests", ] }