# 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_dist_dir = "$root_build_dir/ui" 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 = [ ":bundle", ":index", ":wasm", ] } # +----------------------------------------------------------------------------+ # | Template used to run node binaries using the hermetic node toolchain. | # +----------------------------------------------------------------------------+ template("node_bin") { action(target_name) { forward_variables_from(invoker, [ "inputs", "outputs", ]) deps = [ ":node_modules", ] if (defined(invoker.deps)) { deps += invoker.deps } script = "../gn/standalone/build_tool_wrapper.py" _node_cmd = invoker.node_cmd args = [ "--path=$nodejs_bin", "node", rebase_path("node_modules/.bin/$_node_cmd", root_build_dir), ] + invoker.args } } # +----------------------------------------------------------------------------+ # | 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. node_bin("bundle") { deps = [ ":transpile_all_ts", ] node_cmd = "browserify" inputs = [ "$ui_dist_dir/main.js", ] outputs = [ "$ui_dist_dir/bundle.js", ] args = [ rebase_path(inputs[0], root_build_dir), "-d", "-o", rebase_path(outputs[0], root_build_dir), ] } # +----------------------------------------------------------------------------+ # | Protobuf: gen rules to create .js and .d.ts files from protos. | # +----------------------------------------------------------------------------+ proto_gen_dir = "$ui_dist_dir/gen" node_bin("protos_to_js") { inputs = [] foreach(proto, trace_processor_protos) { inputs += [ "../protos/perfetto/trace_processor/$proto.proto" ] } outputs = [ "$proto_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 = [ "$proto_gen_dir/protos.js", ] outputs = [ "$proto_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 that are reachable from |sources|. node_bin("transpile_all_ts") { sources = [ "main.ts", ] deps = [ ":dist_symlink", ":protos_to_ts", ] inputs = sources + [ "tsconfig.json" ] outputs = [ "$ui_dist_dir/main.js", ] # Find all *.ts files and pass them as input triggers. This does NOT affect # which files will get built. This defines only the set of files that, when # changes, will re-trigger this rule in ninja. The files that get transpiled # are the transitive dependencies of |sources|. all_ts_files = exec_script("../gn/standalone/glob.py", [ "--root=" + rebase_path(".", root_build_dir), "--filter=*.ts", "--exclude=node_modules", "--exclude=dist", ], "list lines", [ "." ]) inputs += all_ts_files node_cmd = "tsc" args = [ "--project", rebase_path(".", root_build_dir), "--outDir", rebase_path(ui_dist_dir, root_build_dir), ] } # +----------------------------------------------------------------------------+ # | Copy rules: copy assets into the dist directory. | # +----------------------------------------------------------------------------+ copy("index") { sources = [ "index.html", ] outputs = [ "$ui_dist_dir/index.html", ] } copy("wasm") { deps = [ "//src/trace_processor:trace_processor.js($wasm_toolchain)", "//src/trace_processor:trace_processor.wasm($wasm_toolchain)", ] sources = [ "$root_build_dir/wasm/trace_processor.js", "$root_build_dir/wasm/trace_processor.wasm", ] outputs = [ "$ui_dist_dir/wasm/{{source_file_part}}", ] } # +----------------------------------------------------------------------------+ # | Node JS: run npm install and creates a symlink in the out directory. | # +----------------------------------------------------------------------------+ 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 browserify and other node tools from the out/xxx directory. action("node_modules_symlink") { deps = [ ":check_node_exists", ] inputs = [ "node_modules", ] outputs = [ "$ui_dist_dir/node_modules", ] script = "../gn/standalone/build_tool_wrapper.py" args = [ "/bin/ln", "-fns", rebase_path(inputs[0], ui_dist_dir), rebase_path(outputs[0], root_build_dir), ] } # Runs npm install. action("node_modules") { script = "../gn/standalone/build_tool_wrapper.py" stamp_file = "$ui_dist_dir/.$target_name.stamp" args = [ "--chdir", rebase_path(".", root_build_dir), "--stamp", rebase_path(stamp_file, root_build_dir), ] args += [ "--path=$nodejs_bin", "node", rebase_path("$nodejs_root/bin/npm", "."), "install", "--no-save", "--silent", ] inputs = [ "package.json", "package-lock.json", ] outputs = [ stamp_file, ] 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 = "$ui_dist_dir/.$target_name.stamp" args = [ "--stamp", rebase_path(stamp_file, root_build_dir), "/bin/ln", "-fns", rebase_path(ui_dist_dir, "."), rebase_path("dist", root_build_dir), ] inputs = [ "$root_build_dir", ] outputs = [ stamp_file, ] }