blob: 0e26c717cf2cae19effefb4fb7eb920e6a2e04a9 [file] [log] [blame]
# Copyright 2019 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# These rules are only used by the Fuchsia platform build.
import("//build/package.gni")
import("//build/test/test_package.gni")
import("//build/testing/environments.gni")
import("//src/lib/vulkan/image_pipe_swapchain.gni")
import("//src/lib/vulkan/layers.gni")
import("build_settings.gni")
# A target providing access to Vulkan at compile time when added to deps.
graphics_compute_vulkan_loader_target = "//src/lib/vulkan"
# A target providing the GTest main() function.
# This version sets up logging appropriately for Fuchsia on startup.
graphics_compute_gtest_main_target = "//src/lib/fxl/test:gtest_main"
# Technical note:
#
# It might be useful to clarify what Fuchsia packages and components are
# because the documentation is still a bit fuzzy, and using GN build rules
# like package() incorrectly is very easy and leads to GN errors that are
# really hard to understand. This will also make the content of this file
# clearer for anyone wanting to understand how it works.
#
# In Fuchsia, a package is the unit of distribution, and a component is the
# unit of execution. More precisely:
#
# - A package is an archive with a specific filesystem layout, e.g.:
#
# - executables can go under bin/ or test/ (by convention).
# - shared libraries the executable(s) depend on will go under lib/
# - non-executable files used by the executables will go under data/
# - the meta/ directory contains metadata describing the package's
# content.
# - each package can contain one or more components, and each one of
# them has a corresponding manifest file under meta/<component>.cmx
#
# - A component's manifest describes how said component is run, i.e.:
#
# - which binary executable must be launched to start it.
# - which specific sandbox features, devices and services it requires.
#
# IMPORTANT: The format of component manifest file is going to change, which
# is why the documentation at fuchsia.dev does not match the
# descriptions below, which still correspond to the current format!
#
# As an example, the manifest for a trivial unit-test would look like:
#
# {
# "program": { "binary": "bin/foo_unittest" },
# "sandbox": {
# "features": [ "isolated-temp" ]
# "services": [ "fuchsia.logger.LogSink" ]
# }
# }
#
# Here the 'program' entry points to the actual executable.
# The 'sandbox' entry lists the "isolated-temp" feature (to ensure that /tmp
# exists when the program is run), and a service to ensure that logs can
# be sent to the syslog, instead of disappearing into the void.
#
# One can imagine that this manifest is stored as `meta/foo_component.cmx` in
# the `foo_package` package. In this case, one would invoke it with:
#
# fx shell run fuchsia-pkg://fuchsia.com/foo_package#meta/foo_component.cmx
#
# However, most of the time, the package and component will have the same name
# and the following will be equivalent (if there is no ambiguity):
#
# fx shell run foo_package
# # Same as using fuchsia-pkg://fuchsia.com/foo_package#meta/foo_package.cmx
#
# Note that components are started in the environment of their caller. I.e.
# foo_unittest will be connecting to the fuchsia.logger.LogSink service
# running inside the shell process when started with "fx shell run ...".
#
# Simple executable components were just described above, but Fuchsia also
# defines a different component type: a "test component". The difference
# between a regular and test component are the following:
#
# - Binaries are placed under test/ instead of bin/ (again, by convention).
#
# - Test components can be launched with the "run" shell command, in which
# case they are launched like regular executables, i.e. they inherit the
# environment of their caller (which will normally be the shell).
#
# - Test components can also be launched with the "runtests --names <name>" shell
# command. Compared to "run", the latter will first create a new hermetic
# Fuchsia process to run the test program inside, decoupled from the
# caller.
#
# Incidentally, this is what "fx run-test <component>" does too, after
# eventually rebuilding the package then updating it on the target device.
#
# - By default, said hermetic process environment is very limited, but the
# test component's manifest can also specify services to inject into the
# process before running it.
#
# This is done by adding an entry under the "facets" dictionary in the
# manifest, for example, for a test that uses Vulkan would have something
# like the following:
#
# {
# "facets": {
# "fuchsia.test": {
# "system-services": [
# "fuchsia.sysmem.Allocator",
# "fuchsia.vulkan.loader.Loader"
# ]
# }
# },
# "program": { "binary": "test/foo_vulkan_test" },
# "sandbox": {
# "features": [
# "vulkan"
# ],
# "services": [
# "fuchsia.sysmem.Allocator",
# "fuchsia.vulkan.loader.Loader",
# ]
# }
# }
#
# Notice how the same services appear twice in the manifest above.
# But the "system-services" part is only used by "runtests", and ignored
# when the test is launched with "run".
#
# Generate a Fuchsia package that contains a single component.
# The binary executable target must be defined before calling this rule.
# This will generate the component manifest automatically.
#
# Accept all variables from the GN executable() rule, as well as:
# Variables:
# needs_vulkan: set to true if Vulkan is required to run the component.
# test_package: optional flag. True to turn this into a test package
# that can run with 'fx run-test' or 'fx shell runtests'. Will force
# |testonly| to be true.
# test_environments: optional list of test environments. Requires
# |test_package| to be true. Used to run the test in the right environment
# on the continuous integration bots.
#
template("graphics_compute_single_component_package") {
_component_name = target_name
_test_package = defined(invoker.test_package) && invoker.test_package
_testonly = (defined(invoker.testonly) && invoker.testonly) || _test_package
_needs_vulkan = defined(invoker.needs_vulkan) && invoker.needs_vulkan
if (defined(invoker.test_environments)) {
assert(_test_package,
"Using test_environments requires test_package=true!!")
}
_binary_target = "bin_${target_name}"
# Generate executable target.
executable(_binary_target) {
testonly = _testonly
forward_variables_from(invoker,
"*",
[
# Avoid clobbering default configs
"configs",
"needs_vulkan",
"target_name",
"testonly",
"test_environments",
"test_package",
])
if (defined(invoker.configs)) {
configs += invoker.configs
}
if (_needs_vulkan) {
if (!defined(deps)) {
deps = []
}
deps += [ graphics_compute_vulkan_loader_target ]
}
# NOTE: The package() rule *requires* that for tests, the executable's
# name be the same as the component name. Otherwise, a very cryptic error
# will be displayed by GN.
output_name = _component_name
}
# Generate a component manifest automatically.
_component_manifest = "${target_gen_dir}/meta/${_component_name}.cmx"
_component_manifest_target = "${_component_name}__manifest"
action(_component_manifest_target) {
script = "${graphics_compute_dir}/scripts/generate_component_manifest.py"
outputs = [ _component_manifest ]
args = [
"--name",
_component_name,
"--output",
rebase_path(_component_manifest, root_build_dir),
]
if (_test_package) {
args += [
"--type",
"test",
]
}
if (_needs_vulkan) {
args += [
# For now, all graphics compute tests and programs rely on framebuffer
# display. This will change in the future when imagepipe swapchain
# support will be added, and --needs-vulkan will be used instead.
"--needs-vulkan-framebuffer",
]
}
}
# Create the package now.
package(target_name) {
testonly = _testonly
deps = [
":${_binary_target}",
":${_component_manifest_target}",
]
if (_needs_vulkan) {
deps += [ graphics_compute_vulkan_loader_target ]
public_deps = []
loadable_modules = []
resources = []
public_deps += vulkan_validation_layers.public_deps
public_deps += image_pipe_swapchain_fb.public_deps
public_deps += image_pipe_swapchain_fb_skip_present.public_deps
loadable_modules += vulkan_validation_layers.loadable_modules
loadable_modules += image_pipe_swapchain_fb.loadable_modules
loadable_modules += image_pipe_swapchain_fb_skip_present.loadable_modules
resources += vulkan_validation_layers.resources
resources += image_pipe_swapchain_fb.resources
resources += image_pipe_swapchain_fb_skip_present.resources
}
meta = [
{
path = _component_manifest
dest = "${_component_name}.cmx"
},
]
if (_test_package) {
tests = [
{
name = _component_name
dest = _component_name
manifest = _component_manifest
if (defined(invoker.test_environments)) {
environments = invoker.test_environments
}
},
]
} else {
binaries = [
{
name = _component_name
},
]
}
}
}
template("graphics_compute_executable_rule") {
graphics_compute_single_component_package(target_name) {
forward_variables_from(invoker,
"*",
[
"test_package",
"test_environments",
])
}
}
template("graphics_compute_test_rule") {
graphics_compute_single_component_package(target_name) {
forward_variables_from(invoker, "*")
test_package = true
if (defined(invoker.needs_vulkan) && invoker.needs_vulkan) {
test_environments = [ nuc_env ]
}
}
}
template("graphics_compute_unittests_rule") {
graphics_compute_test_rule(target_name) {
forward_variables_from(invoker, "*")
if (!defined(deps)) {
deps = []
}
deps += [
# This version sets up logging appropriately for Fuchsia on startup.
"//src/lib/fxl/test:gtest_main",
]
}
}