Commit b971f499 by Tobin Ehlis Committed by Commit Bot

Migrating ANGLE to split LVL repos

Separated the Vulkan Validation Layers, Loader, Tools and Headers into separate dirs to map to the new separate repo structure. Bug: angleproject:2558 Change-Id: I422038f7dd7efe8c5b7a49dc5074de5caf40edfa Reviewed-on: https://chromium-review.googlesource.com/1071880 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent ad2ae93e
......@@ -33,6 +33,9 @@
/third_party/llvm-build
/third_party/spirv-headers/src
/third_party/spirv-tools/src
/third_party/vulkan-headers/src
/third_party/vulkan-loader/src
/third_party/vulkan-tools/src
/third_party/vulkan-validation-layers/src
/third_party/zlib
angle_internal
......
......@@ -433,7 +433,7 @@ if (angle_enable_vulkan) {
"$angle_root/third_party/glslang:glslang",
]
public_deps = [
"$angle_root/third_party/vulkan-validation-layers:vulkan_headers",
"$angle_root/third_party/vulkan-headers:vulkan_headers",
]
public_configs = [
"$angle_root/third_party/glslang:glslang_config",
......@@ -441,12 +441,10 @@ if (angle_enable_vulkan) {
]
data_deps = []
if (!is_android) {
deps += [ "$angle_root/third_party/vulkan-validation-layers:libvulkan" ]
data_deps +=
[ "$angle_root/third_party/vulkan-validation-layers:VkICD_mock_icd" ]
public_configs += [
"$angle_root/third_party/vulkan-validation-layers:vulkan_loader_config",
]
deps += [ "$angle_root/third_party/vulkan-loader:libvulkan" ]
data_deps += [ "$angle_root/third_party/vulkan-tools:VkICD_mock_icd" ]
public_configs +=
[ "$angle_root/third_party/vulkan-loader:vulkan_loader_config" ]
}
if (angle_enable_vulkan_validation_layers) {
......@@ -561,8 +559,7 @@ static_library("libANGLE") {
rebase_path(gles_gypi.libangle_vulkan_android_sources, ".", "src")
}
deps += [ ":angle_vulkan" ]
public_deps +=
[ "$angle_root/third_party/vulkan-validation-layers:vulkan_headers" ]
public_deps += [ "$angle_root/third_party/vulkan-headers:vulkan_headers" ]
# Include generated shaders.
import("src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.gni")
......
......@@ -20,8 +20,17 @@ vars = {
# Current revision of SPIRV-Tools for Vulkan.
'spirv_tools_revision': '9996173f363729b3a97309685dbd4d78547a63a7',
# Current revision of the Vulkan Validation Layers SDK.
'vulkan_revision': '25d5884746a2de7b51a8ef3ec88e1cd8066460e8',
# Current revision of Khronos Vulkan-Headers.
'vulkan_headers_revision': '634e3658d6fa8f95f9062a3a7831d5567baf0eb3',
# Current revision of Khronos Vulkan-Loader.
'vulkan_loader_revision': '1bd294a1ddb32e832916aa874d103618f4faf1b3',
# Current revision of Khronos Vulkan-Tools.
'vulkan_tools_revision': '84230dc24e866d887f6d856c6e12745292703d49',
# Current revision of Khronos Vulkan-ValidationLayers.
'vulkan_validation_revision': '571a886b62cc7092626064376a65c7654f5d9b39',
}
deps = {
......@@ -73,8 +82,20 @@ deps = {
'url': '{android_git}/platform/external/shaderc/spirv-tools@{spirv_tools_revision}',
},
'{angle_root}/third_party/vulkan-headers/src': {
'url': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Headers@{vulkan_headers_revision}',
},
'{angle_root}/third_party/vulkan-loader/src': {
'url': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Loader@{vulkan_loader_revision}',
},
'{angle_root}/third_party/vulkan-tools/src': {
'url': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Tools@{vulkan_tools_revision}',
},
'{angle_root}/third_party/vulkan-validation-layers/src': {
'url': '{android_git}/platform/external/vulkan-validation-layers@{vulkan_revision}',
'url': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@{vulkan_validation_revision}',
},
'{angle_root}/third_party/zlib': {
......
......@@ -11,6 +11,7 @@
vars = {
'android_git': 'https://android.googlesource.com',
'chromium_git': 'https://chromium.googlesource.com',
# Current revision of dEQP.
'deqp_revision': '4c0f2a4fba813e1046115c43c887eccb749b7bb3',
......@@ -24,8 +25,17 @@ vars = {
# Current revision of SPIRV-Tools for Vulkan.
'spirv_tools_revision': '9996173f363729b3a97309685dbd4d78547a63a7',
# Current revision of the Vulkan Validation Layers SDK.
'vulkan_revision': '25d5884746a2de7b51a8ef3ec88e1cd8066460e8',
# Current revision of the Vulkan Headers.
'vulkan_headers_revision': '634e3658d6fa8f95f9062a3a7831d5567baf0eb3',
# Current revision of the Vulkan Loader.
'vulkan_loader_revision': '1bd294a1ddb32e832916aa874d103618f4faf1b3',
# Current revision of the Vulkan Tools where Mock ICD is located.
'vulkan_tools_revision': '84230dc24e866d887f6d856c6e12745292703d49',
# Current revision of the Vulkan Validation Layers.
'vulkan_layers_revision': '571a886b62cc7092626064376a65c7654f5d9b39',
}
deps = {
......@@ -41,6 +51,15 @@ deps = {
'src/third_party/angle/third_party/spirv-tools/src':
Var('android_git') + '/platform/external/shaderc/spirv-tools@' + Var('spirv_tools_revision'),
'src/third_party/angle/third_party/vulkan-headers/src':
Var('chromium_git') + '/external/github.com/KhronosGroup/Vulkan-Headers@' + Var('vulkan_headers_revision'),
'src/third_party/angle/third_party/vulkan-loader/src':
Var('chromium_git') + '/external/github.com/KhronosGroup/Vulkan-Loader@' + Var('vulkan_loader_revision'),
'src/third_party/angle/third_party/vulkan-tools/src':
Var('chromium_git') + '/external/github.com/KhronosGroup/Vulkan-Tools@' + Var('vulkan_tools_revision'),
'src/third_party/angle/third_party/vulkan-validation-layers/src':
Var('android_git') + '/platform/external/vulkan-validation-layers@' + Var('vulkan_revision'),
Var('chromium_git') + '/external/github.com/KhronosGroup/Vulkan-ValidationLayers@' + Var('vulkan_layers_revision'),
}
......@@ -9,6 +9,9 @@ angle_dotfile_settings = {
exec_script_whitelist = [
get_path_info("BUILD.gn", "abspath"),
get_path_info("src/tests/BUILD.gn", "abspath"),
get_path_info("third_party/vulkan-headers/BUILD.gn", "abspath"),
get_path_info("third_party/vulkan-loader/BUILD.gn", "abspath"),
get_path_info("third_party/vulkan-tools/BUILD.gn", "abspath"),
get_path_info("third_party/vulkan-validation-layers/BUILD.gn", "abspath"),
]
}
# Copyright 2018 The ANGLE Project Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# BUILD settings for Vulkan Headers
# Headers repo is at
# https://github.com/KhronosGroup/Vulkan-Headers
import("../../gni/angle.gni")
config("vulkan_headers_config") {
include_dirs = [ "src/include" ]
}
# Vulkan headers only, no compiled sources.
source_set("vulkan_headers") {
sources = [
"src/include/vulkan/vk_icd.h",
"src/include/vulkan/vk_layer.h",
"src/include/vulkan/vk_platform.h",
"src/include/vulkan/vk_sdk_platform.h",
"src/include/vulkan/vulkan.h",
"src/include/vulkan/vulkan.hpp",
"src/include/vulkan/vulkan_core.h",
]
public_configs = [ ":vulkan_headers_config" ]
}
Name: Vulkan Header Components
Short Name: Vulkan Headers
Version: N/A
URL: https://github.com/KhronosGroup/Vulkan-Headers
SOURCE CODE: git clone https://github.com/KhronosGroup/Vulkan-Headers.git
Date: 06/12/2018
Revision: 634e3658d6fa8f95f9062a3a7831d5567baf0eb3
Security Critical: no
License: Apache 2.0
License File: LICENSE.txt
Description:
The Vulkan Headers Components are used to by Vulkan projects. This includes the Vulkan loader,
mock ICD in the Vulkan-Tools repo, and the Vulkan Validation layers.
# Copyright 2018 The ANGLE Project Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# BUILD settings for Vulkan Loader
# Loader repo is at
# https://github.com/KhronosGroup/Vulkan-Loader
import("../../gni/angle.gni")
if (!is_android) {
vulkan_undefine_configs = []
}
if (is_win) {
vulkan_undefine_configs += [
"//build/config/win:nominmax",
"//build/config/win:unicode",
]
}
vulkan_gen_dir = "$target_gen_dir/angle/vulkan"
raw_vulkan_gen_dir = rebase_path(vulkan_gen_dir, root_build_dir)
# Vulkan helper scripts
# ---------------------
helper_script_and_deps = [
[
"vulkan_gen_dispatch_table_helper_h",
"vk_dispatch_table_helper.h",
"dispatch_table_helper_generator.py",
],
[
"vulkan_gen_enum_string_helper",
"vk_enum_string_helper.h",
"helper_file_generator.py",
],
[
"vulkan_gen_extension_helper",
"vk_extension_helper.h",
"helper_file_generator.py",
],
[
"vulkan_gen_layer_dispatch_table_h",
"vk_layer_dispatch_table.h",
"loader_extension_generator.py",
],
[
"vulkan_gen_loader_extensions_c",
"vk_loader_extensions.c",
"loader_extension_generator.py",
],
[
"vulkan_gen_loader_extensions_h",
"vk_loader_extensions.h",
"loader_extension_generator.py",
],
[
"vulkan_gen_object_types_h",
"vk_object_types.h",
"helper_file_generator.py",
],
[
"vulkan_gen_safe_struct_cpp",
"vk_safe_struct.cpp",
"helper_file_generator.py",
],
[
"vulkan_gen_safe_struct_h",
"vk_safe_struct.h",
"helper_file_generator.py",
],
[
"vulkan_gen_typemap_helper",
"vk_typemap_helper.h",
"helper_file_generator.py",
],
]
# Python scripts needed for codegen, copy them to a temp dir
# so that all dependencies are together. The reg.py script from
# the headers repo is required input to loader_genvk.py.
copy("python_gen_deps") {
sources = [
"$angle_root/third_party/vulkan-headers/src/registry/cgenerator.py",
"$angle_root/third_party/vulkan-headers/src/registry/generator.py",
"$angle_root/third_party/vulkan-headers/src/registry/reg.py",
"$angle_root/third_party/vulkan-headers/src/registry/vk.xml",
"src/scripts/common_codegen.py",
"src/scripts/dispatch_table_helper_generator.py",
"src/scripts/helper_file_generator.py",
"src/scripts/loader_extension_generator.py",
"src/scripts/loader_genvk.py",
]
outputs = [
"$vulkan_gen_dir/{{source_file_part}}",
]
}
foreach(script_and_dep, helper_script_and_deps) {
target_name = script_and_dep[0]
file = script_and_dep[1]
dep = script_and_dep[2]
target("action", target_name) {
public_deps = [
":python_gen_deps",
]
script = "$vulkan_gen_dir/loader_genvk.py"
inputs = [
"$vulkan_gen_dir/$dep",
"$vulkan_gen_dir/common_codegen.py",
"$vulkan_gen_dir/reg.py",
"$vulkan_gen_dir/vk.xml",
"$vulkan_gen_dir/generator.py",
"$vulkan_gen_dir/cgenerator.py",
]
outputs = [
"$vulkan_gen_dir/$file",
]
args = [
"-o",
raw_vulkan_gen_dir,
"-registry",
"$raw_vulkan_gen_dir/vk.xml",
"-scripts",
raw_vulkan_gen_dir,
"$file",
"-quiet",
]
}
}
config("vulkan_generated_files_config") {
include_dirs = [ vulkan_gen_dir ]
}
group("vulkan_generate_helper_files") {
public_deps = [
"$angle_root/third_party/vulkan-headers:vulkan_headers",
]
public_configs = [ ":vulkan_generated_files_config" ]
foreach(script_and_dep, helper_script_and_deps) {
target_name = script_and_dep[0]
public_deps += [ ":$target_name" ]
}
}
config("vulkan_config") {
if (is_win) {
defines = [
"VK_USE_PLATFORM_WIN32_KHR",
"VK_USE_PLATFORM_WIN32_KHX",
]
}
if (is_linux) {
defines = [
"VK_USE_PLATFORM_XCB_KHR",
"VK_USE_PLATFORM_XCB_KHX",
]
}
if (is_android) {
defines = [
"VK_USE_PLATFORM_ANDROID_KHR",
"VK_USE_PLATFORM_ANDROID_KHX",
]
libs = [ "vulkan" ]
}
}
config("vulkan_internal_config") {
defines = [ "VULKAN_NON_CMAKE_BUILD" ]
if (is_clang || !is_win) {
cflags = [ "-Wno-unused-function" ]
}
if (is_linux) {
defines += [
"SYSCONFDIR=\"/etc\"",
"FALLBACK_CONFIG_DIRS=\"/etc/xdg\"",
"FALLBACK_DATA_DIRS=\"/usr/local/share:/usr/share\"",
]
}
}
# Vulkan loader
# -------------
config("vulkan_loader_config") {
include_dirs = [
vulkan_gen_dir,
"$angle_root/third_party/vulkan-headers/src/include",
"src/loader",
]
defines = [
"ANGLE_VK_DATA_DIR=\"$data_dir\"",
"ANGLE_VK_ICD_JSON=\"$data_dir/VkICD_mock_icd.json\"",
"API_NAME=\"Vulkan\"",
]
if (is_win) {
cflags = [ "/wd4201" ]
}
if (is_linux) {
# assume secure_getenv() is available
defines += [ "HAVE_SECURE_GETENV" ]
}
}
if (!is_android) {
if (angle_shared_libvulkan) {
library_type = "shared_library"
} else {
library_type = "static_library"
}
target(library_type, "libvulkan") {
sources = [
"src/loader/asm_offset.c",
"src/loader/cJSON.c",
"src/loader/cJSON.h",
"src/loader/debug_utils.c",
"src/loader/debug_utils.h",
"src/loader/dev_ext_trampoline.c",
"src/loader/extension_manual.c",
"src/loader/extension_manual.h",
"src/loader/gpa_helper.h",
"src/loader/loader.c",
"src/loader/loader.h",
"src/loader/murmurhash.c",
"src/loader/murmurhash.h",
"src/loader/phys_dev_ext.c",
"src/loader/trampoline.c",
# TODO(jmadill): Use assembler where available.
"src/loader/unknown_ext_chain.c",
"src/loader/vk_loader_platform.h",
"src/loader/wsi.c",
"src/loader/wsi.h",
]
if (is_win) {
sources += [
"src/loader/dirent_on_windows.c",
"src/loader/dirent_on_windows.h",
]
if (!is_clang) {
cflags = [
"/wd4054", # Type cast from function pointer
"/wd4055", # Type cast from data pointer
"/wd4100", # Unreferenced formal parameter
"/wd4152", # Nonstandard extension used (pointer conversion)
"/wd4201", # Nonstandard extension used: nameless struct/union
"/wd4214", # Nonstandard extension used: bit field types other than int
"/wd4232", # Nonstandard extension used: address of dllimport is not static
"/wd4305", # Type cast truncation
"/wd4706", # Assignment within conditional expression
"/wd4996", # Unsafe stdlib function
]
}
}
deps = [
":vulkan_generate_helper_files",
]
public_deps = [
"$angle_root/third_party/vulkan-headers:vulkan_headers",
]
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [ "//build/config/compiler:no_chromium_code" ]
configs += [ ":vulkan_internal_config" ]
public_configs = [
":vulkan_config",
":vulkan_loader_config",
]
configs -= vulkan_undefine_configs
}
}
Name: Vulkan Loader Components
Short Name: Vulkan Loader
Version: N/A
URL: https://github.com/KhronosGroup/Vulkan-Loader
SOURCE CODE: git clone https://github.com/KhronosGroup/Vulkan-Loader.git
Date: 05/24/2018
Revision: dba71dacd085918656a69e07fe8f37a71f5ebe2e
Security Critical: no
License: Apache 2.0
License File: LICENSE.txt
Description:
The Vulkan Loader Components are used to build the open-source desktop Vulkan loader. The loader
is a library that loads the Vulkan entry points and hooks them into the correct layers and the
client driver (ICD). This is required for using Vulkan layers and applications.
# Copyright 2018 The ANGLE Project Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# BUILD settings for Vulkan Tools where Mock ICD is located
# Tools repo is at
# https://github.com/KhronosGroup/Vulkan-Tools
import("../../gni/angle.gni")
vulkan_undefine_configs = []
if (is_win) {
vulkan_undefine_configs += [
"//build/config/win:nominmax",
"//build/config/win:unicode",
]
}
raw_vulkan_icd_dir = rebase_path("src", root_build_dir)
vulkan_gen_dir = "$target_gen_dir/angle/vulkan"
raw_vulkan_gen_dir = rebase_path(vulkan_gen_dir, root_build_dir)
# Vulkan helper scripts
# ---------------------
helper_script_and_deps = [
[
"vulkan_gen_typemap_helper",
"vk_typemap_helper.h",
"helper_file_generator.py",
],
[
"vulkan_mock_icd_cpp",
"mock_icd.cpp",
"mock_icd_generator.py",
],
[
"vulkan_mock_icd_h",
"mock_icd.h",
"mock_icd_generator.py",
],
]
foreach(script_and_dep, helper_script_and_deps) {
target_name = script_and_dep[0]
file = script_and_dep[1]
dep = script_and_dep[2]
target("action", target_name) {
script = "src/scripts/lvl_genvk.py"
inputs = [
"src/scripts/$dep",
"src/scripts/common_codegen.py",
"src/scripts/cgenerator.py",
"src/scripts/generator.py",
"src/scripts/reg.py",
"src/scripts/vk.xml",
]
outputs = [
"$vulkan_gen_dir/$file",
]
args = [
"-o",
raw_vulkan_gen_dir,
"-registry",
"$raw_vulkan_icd_dir/scripts/vk.xml",
"$file",
"-quiet",
]
}
}
config("vulkan_generated_files_config") {
include_dirs = [ vulkan_gen_dir ]
}
group("vulkan_generate_helper_files") {
public_deps = [
"$angle_root/third_party/vulkan-headers:vulkan_headers",
]
public_configs = [ ":vulkan_generated_files_config" ]
foreach(script_and_dep, helper_script_and_deps) {
target_name = script_and_dep[0]
public_deps += [ ":$target_name" ]
}
}
config("vulkan_config") {
if (is_win) {
defines = [
"VK_USE_PLATFORM_WIN32_KHR",
"VK_USE_PLATFORM_WIN32_KHX",
]
}
if (is_linux) {
defines = [
"VK_USE_PLATFORM_XCB_KHR",
"VK_USE_PLATFORM_XCB_KHX",
]
}
if (is_android) {
defines = [
"VK_USE_PLATFORM_ANDROID_KHR",
"VK_USE_PLATFORM_ANDROID_KHX",
]
libs = [ "vulkan" ]
}
}
config("vulkan_internal_config") {
defines = [ "VULKAN_NON_CMAKE_BUILD" ]
if (is_clang || !is_win) {
cflags = [ "-Wno-unused-function" ]
}
if (is_linux) {
defines += [
"SYSCONFDIR=\"/etc\"",
"FALLBACK_CONFIG_DIRS=\"/etc/xdg\"",
"FALLBACK_DATA_DIRS=\"/usr/local/share:/usr/share\"",
]
}
}
# Copy icd header to gen dir
copy("icd_header_dep") {
sources = [
"$angle_root/third_party/vulkan-headers/src/include/vulkan/vk_icd.h",
]
outputs = [
"$vulkan_gen_dir/vk_icd.h",
]
}
if (!is_android) {
# Vulkan Mock ICD
# ---------------
group("vulkan_generate_mock_icd_files") {
public_deps = [
":icd_header_dep",
":vulkan_generate_helper_files",
":vulkan_mock_icd_cpp",
":vulkan_mock_icd_h",
]
}
mock_icd_sources = [
"$vulkan_gen_dir/mock_icd.cpp",
"$vulkan_gen_dir/mock_icd.h",
]
shared_library("VkICD_mock_icd") {
configs -= vulkan_undefine_configs
public_configs = [ ":vulkan_config" ]
deps = [
":vulkan_generate_mock_icd_files",
]
data_deps = [
":vulkan_gen_icd_json_file",
]
sources = mock_icd_sources
if (is_win) {
sources += [ "src/icd/VkICD_mock_icd.def" ]
}
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [ "//build/config/compiler:no_chromium_code" ]
}
action("vulkan_gen_icd_json_file") {
script = "$angle_root/scripts/generate_vulkan_layers_json.py"
if (is_win) {
sources = [
"src/icd/windows/VkICD_mock_icd.json",
]
args = [ "$raw_vulkan_icd_dir/icd/windows" ]
}
if (is_linux) {
sources = [
"src/icd/linux/VkICD_mock_icd.json",
]
args = [ "$raw_vulkan_icd_dir/icd/linux" ]
}
# The layer JSON files are part of the necessary data deps.
outputs = [
"$root_out_dir/$data_dir/VkICD_mock_icd.json",
]
data = [
"$root_out_dir/$data_dir/VkICD_mock_icd.json",
]
args += [ rebase_path("$root_out_dir/$data_dir", root_build_dir) ]
}
}
Name: Khronos Vulkan Tools Components
Short Name: Vulkan Mock ICD
Version: N/A
URL: https://github.com/KhronosGroup/Vulkan-Tools
SOURCE CODE: git clone https://github.com/KhronosGroup/Vulkan-Tools.git
Date: 05/24/2018
Revision: 51dfb7b8a19820d6716190dd7e45cd6e861e1f1a
Security Critical: no
License: Apache 2.0
License File: LICENSE.txt
Description:
The Khronos Vulkan Tools Components contain the Vulkan Mock Installable
Client Driver (ICD) as well as the vulkaninfo utility. ANGLE is
primarily interested in the Mock ICD and uses it to run experiments
with the Mock ICD as a null driver.
......@@ -2,6 +2,10 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# BUILD settings for Vulkan Validation Layers
# Validation repo is at
# https://github.com/KhronosGroup/Vulkan-ValidationLayers
import("../../gni/angle.gni")
vulkan_undefine_configs = []
......@@ -12,7 +16,8 @@ if (is_win) {
]
}
raw_vulkan_layers_dir = rebase_path("src", root_build_dir)
raw_vulkan_headers_dir =
rebase_path("$angle_root/third_party/vulkan-headers/src", root_build_dir)
vulkan_gen_dir = "$target_gen_dir/angle/vulkan"
raw_vulkan_gen_dir = rebase_path(vulkan_gen_dir, root_build_dir)
......@@ -42,16 +47,6 @@ helper_script_and_deps = [
"loader_extension_generator.py",
],
[
"vulkan_gen_loader_extensions_c",
"vk_loader_extensions.c",
"loader_extension_generator.py",
],
[
"vulkan_gen_loader_extensions_h",
"vk_loader_extensions.h",
"loader_extension_generator.py",
],
[
"vulkan_gen_object_types_h",
"vk_object_types.h",
"helper_file_generator.py",
......@@ -91,33 +86,51 @@ helper_script_and_deps = [
"unique_objects_wrappers.h",
"unique_objects_generator.py",
],
[
"vulkan_mock_icd_cpp",
"mock_icd.cpp",
"mock_icd_generator.py",
],
[
"vulkan_mock_icd_h",
"mock_icd.h",
"mock_icd_generator.py",
],
]
# Python scripts needed for codegen, copy them to a temp dir
# so that all dependencies are together
copy("python_gen_deps") {
sources = [
"$angle_root/third_party/vulkan-headers/src/registry/cgenerator.py",
"$angle_root/third_party/vulkan-headers/src/registry/generator.py",
"$angle_root/third_party/vulkan-headers/src/registry/reg.py",
"$angle_root/third_party/vulkan-headers/src/registry/vk.xml",
"src/layers/vk_validation_error_messages.h",
"src/scripts/common_codegen.py",
"src/scripts/dispatch_table_helper_generator.py",
"src/scripts/helper_file_generator.py",
"src/scripts/loader_extension_generator.py",
"src/scripts/lvl_genvk.py",
"src/scripts/object_tracker_generator.py",
"src/scripts/parameter_validation_generator.py",
"src/scripts/threading_generator.py",
"src/scripts/unique_objects_generator.py",
"src/scripts/vuid_mapping.py",
]
outputs = [
"$vulkan_gen_dir/{{source_file_part}}",
]
}
foreach(script_and_dep, helper_script_and_deps) {
target_name = script_and_dep[0]
file = script_and_dep[1]
dep = script_and_dep[2]
target("action", target_name) {
script = "src/scripts/lvl_genvk.py"
public_deps = [
":python_gen_deps",
]
script = "$vulkan_gen_dir/lvl_genvk.py"
inputs = [
"src/scripts/$dep",
"src/scripts/cgenerator.py",
"src/scripts/common_codegen.py",
"src/scripts/generator.py",
"src/scripts/reg.py",
"src/scripts/vuid_mapping.py",
"src/layers/vk_validation_error_messages.h",
"src/scripts/vk.xml",
"$vulkan_gen_dir/$dep",
"$vulkan_gen_dir/cgenerator.py",
"$vulkan_gen_dir/common_codegen.py",
"$vulkan_gen_dir/generator.py",
"$vulkan_gen_dir/reg.py",
"$vulkan_gen_dir/vuid_mapping.py",
"$vulkan_gen_dir/vk_validation_error_messages.h",
"$vulkan_gen_dir/vk.xml",
]
outputs = [
"$vulkan_gen_dir/$file",
......@@ -126,31 +139,17 @@ foreach(script_and_dep, helper_script_and_deps) {
"-o",
raw_vulkan_gen_dir,
"-registry",
"$raw_vulkan_layers_dir/scripts/vk.xml",
"$raw_vulkan_headers_dir/registry/vk.xml",
"-scripts",
"$raw_vulkan_headers_dir/registry",
"$file",
"-quiet",
]
}
}
config("vulkan_headers_config") {
include_dirs = [ "src/include" ]
}
# Vulkan headers only, no compiled sources.
source_set("vulkan_headers") {
sources = [
"src/include/vulkan/vk_icd.h",
"src/include/vulkan/vk_layer.h",
"src/include/vulkan/vk_platform.h",
"src/include/vulkan/vk_sdk_platform.h",
"src/include/vulkan/vulkan.h",
"src/include/vulkan/vulkan.hpp",
]
public_configs = [ ":vulkan_headers_config" ]
}
raw_spirv_tools_dir = rebase_path("../spirv-tools/src", root_build_dir)
raw_spirv_tools_dir =
rebase_path("$angle_root/third_party/spirv-tools/src", root_build_dir)
spirv_git_is_present = exec_script("$angle_root/src/commit_id.py",
[
......@@ -198,7 +197,7 @@ config("vulkan_generated_files_config") {
group("vulkan_generate_helper_files") {
public_deps = [
":spirv_tools_external_revision_generate",
":vulkan_headers",
"$angle_root/third_party/vulkan-headers:vulkan_headers",
]
public_configs = [ ":vulkan_generated_files_config" ]
foreach(script_and_dep, helper_script_and_deps) {
......@@ -227,6 +226,7 @@ config("vulkan_config") {
]
libs = [ "vulkan" ]
}
defines += [ "API_NAME=\"Vulkan\"" ]
}
config("vulkan_internal_config") {
......@@ -243,97 +243,6 @@ config("vulkan_internal_config") {
}
}
# Vulkan loader
# -------------
config("vulkan_loader_config") {
include_dirs = [
vulkan_gen_dir,
"src/include",
"src/loader",
]
defines = [
"ANGLE_VK_DATA_DIR=\"$data_dir\"",
"ANGLE_VK_ICD_JSON=\"$data_dir/VkICD_mock_icd.json\"",
"API_NAME=\"Vulkan\"",
]
if (is_win) {
cflags = [ "/wd4201" ]
}
if (is_linux) {
# assume secure_getenv() is available
defines += [ "HAVE_SECURE_GETENV" ]
}
}
if (!is_android) {
if (angle_shared_libvulkan) {
library_type = "shared_library"
} else {
library_type = "static_library"
}
target(library_type, "libvulkan") {
sources = [
"src/loader/cJSON.c",
"src/loader/cJSON.h",
"src/loader/debug_utils.c",
"src/loader/debug_utils.h",
"src/loader/dev_ext_trampoline.c",
"src/loader/extension_manual.c",
"src/loader/extension_manual.h",
"src/loader/gpa_helper.h",
"src/loader/loader.c",
"src/loader/loader.h",
"src/loader/murmurhash.c",
"src/loader/murmurhash.h",
"src/loader/phys_dev_ext.c",
"src/loader/trampoline.c",
# TODO(jmadill): Use assembler where available.
"src/loader/unknown_ext_chain.c",
"src/loader/vk_loader_platform.h",
"src/loader/wsi.c",
"src/loader/wsi.h",
]
if (is_win) {
sources += [
"src/loader/dirent_on_windows.c",
"src/loader/dirent_on_windows.h",
]
if (!is_clang) {
cflags = [
"/wd4054", # Type cast from function pointer
"/wd4055", # Type cast from data pointer
"/wd4100", # Unreferenced formal parameter
"/wd4152", # Nonstandard extension used (pointer conversion)
"/wd4201", # Nonstandard extension used: nameless struct/union
"/wd4214", # Nonstandard extension used: bit field types other than int
"/wd4232", # Nonstandard extension used: address of dllimport is not static
"/wd4305", # Type cast truncation
"/wd4706", # Assignment within conditional expression
"/wd4996", # Unsafe stdlib function
]
}
}
deps = [
":vulkan_generate_helper_files",
]
public_deps = [
":vulkan_headers",
]
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [ "//build/config/compiler:no_chromium_code" ]
configs += [ ":vulkan_internal_config" ]
public_configs = [
":vulkan_config",
":vulkan_loader_config",
]
configs -= vulkan_undefine_configs
}
}
# The validation layers
# ---------------------
......@@ -354,8 +263,8 @@ source_set("vulkan_layer_table") {
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [ "//build/config/compiler:no_chromium_code" ]
sources = [
"$target_gen_dir/angle/vulkan/vk_dispatch_table_helper.h",
"$target_gen_dir/angle/vulkan/vk_enum_string_helper.h",
"$vulkan_gen_dir/vk_dispatch_table_helper.h",
"$vulkan_gen_dir/vk_enum_string_helper.h",
"src/layers/vk_layer_table.cpp",
"src/layers/vk_layer_table.h",
]
......@@ -434,6 +343,7 @@ layers = [
]
if (!is_android) {
raw_vulkan_layers_dir = rebase_path("src", root_build_dir)
vulkan_gen_json_files_outputs = [
"$root_out_dir/$data_dir/VkLayer_core_validation.json",
"$root_out_dir/$data_dir/VkLayer_object_tracker.json",
......@@ -473,61 +383,6 @@ if (!is_android) {
data = vulkan_gen_json_files_outputs
args += [ rebase_path("$root_out_dir/$data_dir", root_build_dir) ]
}
# Vulkan Mock ICD
# ---------------
group("vulkan_generate_mock_icd_files") {
public_deps = [
":vulkan_generate_helper_files",
":vulkan_mock_icd_cpp",
":vulkan_mock_icd_h",
]
}
mock_icd_sources = [
"$vulkan_gen_dir/mock_icd.cpp",
"$vulkan_gen_dir/mock_icd.h",
]
shared_library("VkICD_mock_icd") {
configs -= vulkan_undefine_configs
public_configs = [ ":vulkan_config" ]
deps = [ ":vulkan_generate_mock_icd_files" ]
data_deps = [
":vulkan_gen_icd_json_file",
]
sources = mock_icd_sources
if (is_win) {
sources += [ "src/icd/VkICD_mock_icd.def" ]
}
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [ "//build/config/compiler:no_chromium_code" ]
}
action("vulkan_gen_icd_json_file") {
script = "$angle_root/scripts/generate_vulkan_layers_json.py"
if (is_win) {
sources = [
"src/icd/windows/VkICD_mock_icd.json",
]
args = [ "$raw_vulkan_layers_dir/icd/windows" ]
}
if (is_linux) {
sources = [
"src/icd/linux/VkICD_mock_icd.json",
]
args = [ "$raw_vulkan_layers_dir/icd/linux" ]
}
# The layer JSON files are part of the necessary data deps.
outputs = [
"$root_out_dir/$data_dir/VkICD_mock_icd.json",
]
data = [
"$root_out_dir/$data_dir/VkICD_mock_icd.json",
]
args += [ rebase_path("$root_out_dir/$data_dir", root_build_dir) ]
}
}
source_set("vulkan_layer_utils") {
......@@ -543,7 +398,6 @@ source_set("vulkan_layer_utils") {
]
public_configs = [
":vulkan_config",
":vulkan_loader_config",
":vulkan_internal_config",
]
configs -= [ "//build/config/compiler:chromium_code" ]
......@@ -555,12 +409,12 @@ source_set("vulkan_layer_utils") {
}
config("vulkan_core_validation_config") {
include_dirs = [ "../glslang/src" ]
include_dirs = [ "$angle_root/third_party/glslang/src" ]
}
source_set("vulkan_core_validation_glslang") {
public_deps = [
"../spirv-tools:spirv_tools",
"$angle_root/third_party/spirv-tools:spirv_tools",
]
public_configs = [ ":vulkan_core_validation_config" ]
}
......
Name: Vulkan Ecosystem Components
Short Name: Vulkan Layers SDK
Name: Khronos Vulkan Validation Layers Components
Short Name: Vulkan Layers
Version: N/A
URL: https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers
SOURCE CODE: git clone https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers.git
Date: 06/07/2016
Revision: d9da90d92748c37962766868f8b0354637672c2a
URL: https://github.com/KhronosGroup/Vulkan-ValidationLayers
SOURCE CODE: git clone https://github.com/KhronosGroup/Vulkan-ValidationLayers.git
Date: 05/24/2018
Revision: 0fe5bfe66443b288ccf19b3d4c523af7e080672c
Security Critical: no
License: Apache 2.0
License File: LICENSE.txt
Description:
The Vulkan Ecosystem Components consist of the Vulkan loader and Validation Layers SDK. The layers help
validate Vulkan programs at runtime for development, and the loader is a utility for loading the Vulkan
entry points and hooking them into the correct layers. These are essential for developing Vulkan
applications.
The Khronos Vulkan Validation Layers Components consist of the Vulkan
Validation Layers. The layers help validate Vulkan programs at runtime
for development. When enabled the Vulkan loader will hook the layers
into the Vulkan APIs so that they evaluate Vulkan API calls and flag
the incorrect use of the API with callbacks. The layers are essential
for developing Vulkan applications.
#!/usr/bin/python3 -i
#
# Copyright (c) 2013-2018 The Khronos Group Inc.
#
# 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 io,os,pdb,re,string,sys,copy
import xml.etree.ElementTree as etree
from collections import defaultdict
# matchAPIProfile - returns whether an API and profile
# being generated matches an element's profile
# api - string naming the API to match
# profile - string naming the profile to match
# elem - Element which (may) have 'api' and 'profile'
# attributes to match to.
# If a tag is not present in the Element, the corresponding API
# or profile always matches.
# Otherwise, the tag must exactly match the API or profile.
# Thus, if 'profile' = core:
# <remove> with no attribute will match
# <remove profile='core'> will match
# <remove profile='compatibility'> will not match
# Possible match conditions:
# Requested Element
# Profile Profile
# --------- --------
# None None Always matches
# 'string' None Always matches
# None 'string' Does not match. Can't generate multiple APIs
# or profiles, so if an API/profile constraint
# is present, it must be asked for explicitly.
# 'string' 'string' Strings must match
#
# ** In the future, we will allow regexes for the attributes,
# not just strings, so that api="^(gl|gles2)" will match. Even
# this isn't really quite enough, we might prefer something
# like "gl(core)|gles1(common-lite)".
def matchAPIProfile(api, profile, elem):
"""Match a requested API & profile name to a api & profile attributes of an Element"""
match = True
# Match 'api', if present
if ('api' in elem.attrib):
if (api == None):
raise UserWarning("No API requested, but 'api' attribute is present with value '" +
elem.get('api') + "'")
elif (api != elem.get('api')):
# Requested API doesn't match attribute
return False
if ('profile' in elem.attrib):
if (profile == None):
raise UserWarning("No profile requested, but 'profile' attribute is present with value '" +
elem.get('profile') + "'")
elif (profile != elem.get('profile')):
# Requested profile doesn't match attribute
return False
return True
# BaseInfo - base class for information about a registry feature
# (type/group/enum/command/API/extension).
# required - should this feature be defined during header generation
# (has it been removed by a profile or version)?
# declared - has this feature been defined already?
# elem - etree Element for this feature
# resetState() - reset required/declared to initial values. Used
# prior to generating a new API interface.
# compareElem(info) - return True if self.elem and info.elem have the
# same definition.
class BaseInfo:
"""Represents the state of a registry feature, used during API generation"""
def __init__(self, elem):
self.required = False
self.declared = False
self.elem = elem
def resetState(self):
self.required = False
self.declared = False
def compareElem(self, info):
# Just compares the tag and attributes.
# @@ This should be virtualized. In particular, comparing <enum>
# tags requires special-casing on the attributes, as 'extnumber' is
# only relevant when 'offset' is present.
selfKeys = sorted(self.elem.keys())
infoKeys = sorted(info.elem.keys())
if selfKeys != infoKeys:
return False
# Ignore value of 'extname', as this will inherently be different
# when redefining the same interface in different feature and/or
# extension blocks.
for key in selfKeys:
if (key != 'extname' and key != 'extnumber' and
(self.elem.get(key) != info.elem.get(key))):
return False
return True
# TypeInfo - registry information about a type. No additional state
# beyond BaseInfo is required.
class TypeInfo(BaseInfo):
"""Represents the state of a registry type"""
def __init__(self, elem):
BaseInfo.__init__(self, elem)
self.additionalValidity = []
self.removedValidity = []
def resetState(self):
BaseInfo.resetState(self)
self.additionalValidity = []
self.removedValidity = []
# GroupInfo - registry information about a group of related enums
# in an <enums> block, generally corresponding to a C "enum" type.
class GroupInfo(BaseInfo):
"""Represents the state of a registry <enums> group"""
def __init__(self, elem):
BaseInfo.__init__(self, elem)
# EnumInfo - registry information about an enum
# type - numeric type of the value of the <enum> tag
# ( '' for GLint, 'u' for GLuint, 'ull' for GLuint64 )
class EnumInfo(BaseInfo):
"""Represents the state of a registry enum"""
def __init__(self, elem):
BaseInfo.__init__(self, elem)
self.type = elem.get('type')
if (self.type == None):
self.type = ''
# CmdInfo - registry information about a command
class CmdInfo(BaseInfo):
"""Represents the state of a registry command"""
def __init__(self, elem):
BaseInfo.__init__(self, elem)
self.additionalValidity = []
self.removedValidity = []
def resetState(self):
BaseInfo.resetState(self)
self.additionalValidity = []
self.removedValidity = []
# FeatureInfo - registry information about an API <feature>
# or <extension>
# name - feature name string (e.g. 'VK_KHR_surface')
# version - feature version number (e.g. 1.2). <extension>
# features are unversioned and assigned version number 0.
# ** This is confusingly taken from the 'number' attribute of <feature>.
# Needs fixing.
# number - extension number, used for ordering and for
# assigning enumerant offsets. <feature> features do
# not have extension numbers and are assigned number 0.
# category - category, e.g. VERSION or khr/vendor tag
# emit - has this feature been defined already?
class FeatureInfo(BaseInfo):
"""Represents the state of an API feature (version/extension)"""
def __init__(self, elem):
BaseInfo.__init__(self, elem)
self.name = elem.get('name')
# Determine element category (vendor). Only works
# for <extension> elements.
if (elem.tag == 'feature'):
self.category = 'VERSION'
self.version = elem.get('name')
self.versionNumber = elem.get('number')
self.number = "0"
self.supported = None
else:
self.category = self.name.split('_', 2)[1]
self.version = "0"
self.versionNumber = "0"
self.number = elem.get('number')
self.supported = elem.get('supported')
self.emit = False
from generator import write, GeneratorOptions, OutputGenerator
# Registry - object representing an API registry, loaded from an XML file
# Members
# tree - ElementTree containing the root <registry>
# typedict - dictionary of TypeInfo objects keyed by type name
# groupdict - dictionary of GroupInfo objects keyed by group name
# enumdict - dictionary of EnumInfo objects keyed by enum name
# cmddict - dictionary of CmdInfo objects keyed by command name
# apidict - dictionary of <api> Elements keyed by API name
# extensions - list of <extension> Elements
# extdict - dictionary of <extension> Elements keyed by extension name
# gen - OutputGenerator object used to write headers / messages
# genOpts - GeneratorOptions object used to control which
# fetures to write and how to format them
# emitFeatures - True to actually emit features for a version / extension,
# or False to just treat them as emitted
# breakPat - regexp pattern to break on when generatng names
# Public methods
# loadElementTree(etree) - load registry from specified ElementTree
# loadFile(filename) - load registry from XML file
# setGenerator(gen) - OutputGenerator to use
# breakOnName() - specify a feature name regexp to break on when
# generating features.
# parseTree() - parse the registry once loaded & create dictionaries
# dumpReg(maxlen, filehandle) - diagnostic to dump the dictionaries
# to specified file handle (default stdout). Truncates type /
# enum / command elements to maxlen characters (default 80)
# generator(g) - specify the output generator object
# apiGen(apiname, genOpts) - generate API headers for the API type
# and profile specified in genOpts, but only for the versions and
# extensions specified there.
# apiReset() - call between calls to apiGen() to reset internal state
# Private methods
# addElementInfo(elem,info,infoName,dictionary) - add feature info to dict
# lookupElementInfo(fname,dictionary) - lookup feature info in dict
class Registry:
"""Represents an API registry loaded from XML"""
def __init__(self):
self.tree = None
self.typedict = {}
self.groupdict = {}
self.enumdict = {}
self.cmddict = {}
self.apidict = {}
self.extensions = []
self.requiredextensions = [] # Hack - can remove it after validity generator goes away
self.validextensionstructs = defaultdict(list)
self.extdict = {}
# A default output generator, so commands prior to apiGen can report
# errors via the generator object.
self.gen = OutputGenerator()
self.genOpts = None
self.emitFeatures = False
self.breakPat = None
# self.breakPat = re.compile('VkFenceImportFlagBits.*')
def loadElementTree(self, tree):
"""Load ElementTree into a Registry object and parse it"""
self.tree = tree
self.parseTree()
def loadFile(self, file):
"""Load an API registry XML file into a Registry object and parse it"""
self.tree = etree.parse(file)
self.parseTree()
def setGenerator(self, gen):
"""Specify output generator object. None restores the default generator"""
self.gen = gen
self.gen.setRegistry(self)
# addElementInfo - add information about an element to the
# corresponding dictionary
# elem - <type>/<enums>/<enum>/<command>/<feature>/<extension> Element
# info - corresponding {Type|Group|Enum|Cmd|Feature}Info object
# infoName - 'type' / 'group' / 'enum' / 'command' / 'feature' / 'extension'
# dictionary - self.{type|group|enum|cmd|api|ext}dict
# If the Element has an 'api' attribute, the dictionary key is the
# tuple (name,api). If not, the key is the name. 'name' is an
# attribute of the Element
def addElementInfo(self, elem, info, infoName, dictionary):
# self.gen.logMsg('diag', 'Adding ElementInfo.required =',
# info.required, 'name =', elem.get('name'))
if ('api' in elem.attrib):
key = (elem.get('name'),elem.get('api'))
else:
key = elem.get('name')
if key in dictionary:
if not dictionary[key].compareElem(info):
self.gen.logMsg('warn', 'Attempt to redefine', key,
'with different value (this may be benign)')
#else:
# self.gen.logMsg('warn', 'Benign redefinition of', key,
# 'with identical value')
else:
dictionary[key] = info
#
# lookupElementInfo - find a {Type|Enum|Cmd}Info object by name.
# If an object qualified by API name exists, use that.
# fname - name of type / enum / command
# dictionary - self.{type|enum|cmd}dict
def lookupElementInfo(self, fname, dictionary):
key = (fname, self.genOpts.apiname)
if (key in dictionary):
# self.gen.logMsg('diag', 'Found API-specific element for feature', fname)
return dictionary[key]
elif (fname in dictionary):
# self.gen.logMsg('diag', 'Found generic element for feature', fname)
return dictionary[fname]
else:
return None
def breakOnName(self, regexp):
self.breakPat = re.compile(regexp)
def parseTree(self):
"""Parse the registry Element, once created"""
# This must be the Element for the root <registry>
self.reg = self.tree.getroot()
#
# Create dictionary of registry types from toplevel <types> tags
# and add 'name' attribute to each <type> tag (where missing)
# based on its <name> element.
#
# There's usually one <types> block; more are OK
# Required <type> attributes: 'name' or nested <name> tag contents
self.typedict = {}
for type in self.reg.findall('types/type'):
# If the <type> doesn't already have a 'name' attribute, set
# it from contents of its <name> tag.
if (type.get('name') == None):
type.attrib['name'] = type.find('name').text
self.addElementInfo(type, TypeInfo(type), 'type', self.typedict)
#
# Create dictionary of registry enum groups from <enums> tags.
#
# Required <enums> attributes: 'name'. If no name is given, one is
# generated, but that group can't be identified and turned into an
# enum type definition - it's just a container for <enum> tags.
self.groupdict = {}
for group in self.reg.findall('enums'):
self.addElementInfo(group, GroupInfo(group), 'group', self.groupdict)
#
# Create dictionary of registry enums from <enum> tags
#
# <enums> tags usually define different namespaces for the values
# defined in those tags, but the actual names all share the
# same dictionary.
# Required <enum> attributes: 'name', 'value'
# For containing <enums> which have type="enum" or type="bitmask",
# tag all contained <enum>s are required. This is a stopgap until
# a better scheme for tagging core and extension enums is created.
self.enumdict = {}
for enums in self.reg.findall('enums'):
required = (enums.get('type') != None)
for enum in enums.findall('enum'):
enumInfo = EnumInfo(enum)
enumInfo.required = required
self.addElementInfo(enum, enumInfo, 'enum', self.enumdict)
# self.gen.logMsg('diag', 'parseTree: marked req =',
# required, 'for', enum.get('name'))
#
# Create dictionary of registry commands from <command> tags
# and add 'name' attribute to each <command> tag (where missing)
# based on its <proto><name> element.
#
# There's usually only one <commands> block; more are OK.
# Required <command> attributes: 'name' or <proto><name> tag contents
self.cmddict = {}
# List of commands which alias others. Contains
# [ aliasName, element ]
# for each alias
cmdAlias = []
for cmd in self.reg.findall('commands/command'):
# If the <command> doesn't already have a 'name' attribute, set
# it from contents of its <proto><name> tag.
name = cmd.get('name')
if name == None:
name = cmd.attrib['name'] = cmd.find('proto/name').text
ci = CmdInfo(cmd)
self.addElementInfo(cmd, ci, 'command', self.cmddict)
alias = cmd.get('alias')
if alias:
cmdAlias.append([name, alias, cmd])
# Now loop over aliases, injecting a copy of the aliased command's
# Element with the aliased prototype name replaced with the command
# name - if it exists.
for (name, alias, cmd) in cmdAlias:
if alias in self.cmddict:
#@ pdb.set_trace()
aliasInfo = self.cmddict[alias]
cmdElem = copy.deepcopy(aliasInfo.elem)
cmdElem.find('proto/name').text = name
cmdElem.attrib['name'] = name
cmdElem.attrib['alias'] = alias
ci = CmdInfo(cmdElem)
# Replace the dictionary entry for the CmdInfo element
self.cmddict[name] = ci
#@ newString = etree.tostring(base, encoding="unicode").replace(aliasValue, aliasName)
#@elem.append(etree.fromstring(replacement))
else:
self.gen.logMsg('warn', 'No matching <command> found for command',
cmd.get('name'), 'alias', alias)
#
# Create dictionaries of API and extension interfaces
# from toplevel <api> and <extension> tags.
#
self.apidict = {}
for feature in self.reg.findall('feature'):
featureInfo = FeatureInfo(feature)
self.addElementInfo(feature, featureInfo, 'feature', self.apidict)
# Add additional enums defined only in <feature> tags
# to the corresponding core type.
# When seen here, the <enum> element, processed to contain the
# numeric enum value, is added to the corresponding <enums>
# element, as well as adding to the enum dictionary. It is
# *removed* from the <require> element it is introduced in.
# Not doing this will cause spurious genEnum()
# calls to be made in output generation, and it's easier
# to handle here than in genEnum().
#
# In lxml.etree, an Element can have only one parent, so the
# append() operation also removes the element. But in Python's
# ElementTree package, an Element can have multiple parents. So
# it must be explicitly removed from the <require> tag, leading
# to the nested loop traversal of <require>/<enum> elements
# below.
#
# This code also adds a 'version' attribute containing the
# api version.
#
# For <enum> tags which are actually just constants, if there's
# no 'extends' tag but there is a 'value' or 'bitpos' tag, just
# add an EnumInfo record to the dictionary. That works because
# output generation of constants is purely dependency-based, and
# doesn't need to iterate through the XML tags.
#
for elem in feature.findall('require'):
for enum in elem.findall('enum'):
addEnumInfo = False
groupName = enum.get('extends')
if (groupName != None):
# self.gen.logMsg('diag', 'Found extension enum',
# enum.get('name'))
# Add version number attribute to the <enum> element
enum.attrib['version'] = featureInfo.version
# Look up the GroupInfo with matching groupName
if (groupName in self.groupdict.keys()):
# self.gen.logMsg('diag', 'Matching group',
# groupName, 'found, adding element...')
gi = self.groupdict[groupName]
gi.elem.append(enum)
# Remove element from parent <require> tag
# This should be a no-op in lxml.etree
elem.remove(enum)
else:
self.gen.logMsg('warn', 'NO matching group',
groupName, 'for enum', enum.get('name'), 'found.')
addEnumInfo = True
elif (enum.get('value') or enum.get('bitpos') or enum.get('alias')):
# self.gen.logMsg('diag', 'Adding extension constant "enum"',
# enum.get('name'))
addEnumInfo = True
if (addEnumInfo):
enumInfo = EnumInfo(enum)
self.addElementInfo(enum, enumInfo, 'enum', self.enumdict)
self.extensions = self.reg.findall('extensions/extension')
self.extdict = {}
for feature in self.extensions:
featureInfo = FeatureInfo(feature)
self.addElementInfo(feature, featureInfo, 'extension', self.extdict)
# Add additional enums defined only in <extension> tags
# to the corresponding core type.
# Algorithm matches that of enums in a "feature" tag as above.
#
# This code also adds a 'extnumber' attribute containing the
# extension number, used for enumerant value calculation.
#
for elem in feature.findall('require'):
for enum in elem.findall('enum'):
addEnumInfo = False
groupName = enum.get('extends')
if (groupName != None):
# self.gen.logMsg('diag', 'Found extension enum',
# enum.get('name'))
# Add <extension> block's extension number attribute to
# the <enum> element unless specified explicitly, such
# as when redefining an enum in another extension.
extnumber = enum.get('extnumber')
if not extnumber:
enum.attrib['extnumber'] = featureInfo.number
enum.attrib['extname'] = featureInfo.name
enum.attrib['supported'] = featureInfo.supported
# Look up the GroupInfo with matching groupName
if (groupName in self.groupdict.keys()):
# self.gen.logMsg('diag', 'Matching group',
# groupName, 'found, adding element...')
gi = self.groupdict[groupName]
gi.elem.append(enum)
# Remove element from parent <require> tag
# This should be a no-op in lxml.etree
elem.remove(enum)
else:
self.gen.logMsg('warn', 'NO matching group',
groupName, 'for enum', enum.get('name'), 'found.')
addEnumInfo = True
elif (enum.get('value') or enum.get('bitpos') or enum.get('alias')):
# self.gen.logMsg('diag', 'Adding extension constant "enum"',
# enum.get('name'))
addEnumInfo = True
if (addEnumInfo):
enumInfo = EnumInfo(enum)
self.addElementInfo(enum, enumInfo, 'enum', self.enumdict)
# Construct a "validextensionstructs" list for parent structures
# based on "structextends" tags in child structures
for type in self.reg.findall('types/type'):
parentStructs = type.get('structextends')
if (parentStructs != None):
for parent in parentStructs.split(','):
# self.gen.logMsg('diag', type.get('name'), 'extends', parent)
self.validextensionstructs[parent].append(type.get('name'))
# Sort the lists so they don't depend on the XML order
for parent in self.validextensionstructs:
self.validextensionstructs[parent].sort()
def dumpReg(self, maxlen = 120, filehandle = sys.stdout):
"""Dump all the dictionaries constructed from the Registry object"""
write('***************************************', file=filehandle)
write(' ** Dumping Registry contents **', file=filehandle)
write('***************************************', file=filehandle)
write('// Types', file=filehandle)
for name in self.typedict:
tobj = self.typedict[name]
write(' Type', name, '->', etree.tostring(tobj.elem)[0:maxlen], file=filehandle)
write('// Groups', file=filehandle)
for name in self.groupdict:
gobj = self.groupdict[name]
write(' Group', name, '->', etree.tostring(gobj.elem)[0:maxlen], file=filehandle)
write('// Enums', file=filehandle)
for name in self.enumdict:
eobj = self.enumdict[name]
write(' Enum', name, '->', etree.tostring(eobj.elem)[0:maxlen], file=filehandle)
write('// Commands', file=filehandle)
for name in self.cmddict:
cobj = self.cmddict[name]
write(' Command', name, '->', etree.tostring(cobj.elem)[0:maxlen], file=filehandle)
write('// APIs', file=filehandle)
for key in self.apidict:
write(' API Version ', key, '->',
etree.tostring(self.apidict[key].elem)[0:maxlen], file=filehandle)
write('// Extensions', file=filehandle)
for key in self.extdict:
write(' Extension', key, '->',
etree.tostring(self.extdict[key].elem)[0:maxlen], file=filehandle)
# write('***************************************', file=filehandle)
# write(' ** Dumping XML ElementTree **', file=filehandle)
# write('***************************************', file=filehandle)
# write(etree.tostring(self.tree.getroot(),pretty_print=True), file=filehandle)
#
# typename - name of type
# required - boolean (to tag features as required or not)
def markTypeRequired(self, typename, required):
"""Require (along with its dependencies) or remove (but not its dependencies) a type"""
self.gen.logMsg('diag', 'tagging type:', typename, '-> required =', required)
# Get TypeInfo object for <type> tag corresponding to typename
type = self.lookupElementInfo(typename, self.typedict)
if (type != None):
if (required):
# Tag type dependencies in 'alias' and 'required' attributes as
# required. This DOES NOT un-tag dependencies in a <remove>
# tag. See comments in markRequired() below for the reason.
for attrib in [ 'requires', 'alias' ]:
depname = type.elem.get(attrib)
if depname:
self.gen.logMsg('diag', 'Generating dependent type',
depname, 'for', attrib, 'type', typename)
self.markTypeRequired(depname, required)
# Tag types used in defining this type (e.g. in nested
# <type> tags)
# Look for <type> in entire <command> tree,
# not just immediate children
for subtype in type.elem.findall('.//type'):
self.gen.logMsg('diag', 'markRequired: type requires dependent <type>', subtype.text)
self.markTypeRequired(subtype.text, required)
# Tag enums used in defining this type, for example in
# <member><name>member</name>[<enum>MEMBER_SIZE</enum>]</member>
for subenum in type.elem.findall('.//enum'):
self.gen.logMsg('diag', 'markRequired: type requires dependent <enum>', subenum.text)
self.markEnumRequired(subenum.text, required)
type.required = required
else:
self.gen.logMsg('warn', 'type:', typename , 'IS NOT DEFINED')
#
# enumname - name of enum
# required - boolean (to tag features as required or not)
def markEnumRequired(self, enumname, required):
self.gen.logMsg('diag', 'tagging enum:', enumname, '-> required =', required)
enum = self.lookupElementInfo(enumname, self.enumdict)
if (enum != None):
enum.required = required
# Tag enum dependencies in 'alias' attribute as required
depname = enum.elem.get('alias')
if depname:
self.gen.logMsg('diag', 'Generating dependent enum',
depname, 'for alias', enumname, 'required =', enum.required)
self.markEnumRequired(depname, required)
else:
self.gen.logMsg('warn', 'enum:', enumname , 'IS NOT DEFINED')
#
# cmdname - name of command
# required - boolean (to tag features as required or not)
def markCmdRequired(self, cmdname, required):
self.gen.logMsg('diag', 'tagging command:', cmdname, '-> required =', required)
cmd = self.lookupElementInfo(cmdname, self.cmddict)
if (cmd != None):
cmd.required = required
# Tag command dependencies in 'alias' attribute as required
depname = cmd.elem.get('alias')
if depname:
self.gen.logMsg('diag', 'Generating dependent command',
depname, 'for alias', cmdname)
self.markCmdRequired(depname, required)
# Tag all parameter types of this command as required.
# This DOES NOT remove types of commands in a <remove>
# tag, because many other commands may use the same type.
# We could be more clever and reference count types,
# instead of using a boolean.
if (required):
# Look for <type> in entire <command> tree,
# not just immediate children
for type in cmd.elem.findall('.//type'):
self.gen.logMsg('diag', 'markRequired: command implicitly requires dependent type', type.text)
self.markTypeRequired(type.text, required)
else:
self.gen.logMsg('warn', 'command:', name, 'IS NOT DEFINED')
#
# features - Element for <require> or <remove> tag
# required - boolean (to tag features as required or not)
def markRequired(self, features, required):
"""Require or remove features specified in the Element"""
self.gen.logMsg('diag', 'markRequired (features = <too long to print>, required =', required, ')')
# Loop over types, enums, and commands in the tag
# @@ It would be possible to respect 'api' and 'profile' attributes
# in individual features, but that's not done yet.
for typeElem in features.findall('type'):
self.markTypeRequired(typeElem.get('name'), required)
for enumElem in features.findall('enum'):
self.markEnumRequired(enumElem.get('name'), required)
for cmdElem in features.findall('command'):
self.markCmdRequired(cmdElem.get('name'), required)
#
# interface - Element for <version> or <extension>, containing
# <require> and <remove> tags
# api - string specifying API name being generated
# profile - string specifying API profile being generated
def requireAndRemoveFeatures(self, interface, api, profile):
"""Process <recquire> and <remove> tags for a <version> or <extension>"""
# <require> marks things that are required by this version/profile
for feature in interface.findall('require'):
if (matchAPIProfile(api, profile, feature)):
self.markRequired(feature,True)
# <remove> marks things that are removed by this version/profile
for feature in interface.findall('remove'):
if (matchAPIProfile(api, profile, feature)):
self.markRequired(feature,False)
def assignAdditionalValidity(self, interface, api, profile):
#
# Loop over all usage inside all <require> tags.
for feature in interface.findall('require'):
if (matchAPIProfile(api, profile, feature)):
for v in feature.findall('usage'):
if v.get('command'):
self.cmddict[v.get('command')].additionalValidity.append(copy.deepcopy(v))
if v.get('struct'):
self.typedict[v.get('struct')].additionalValidity.append(copy.deepcopy(v))
#
# Loop over all usage inside all <remove> tags.
for feature in interface.findall('remove'):
if (matchAPIProfile(api, profile, feature)):
for v in feature.findall('usage'):
if v.get('command'):
self.cmddict[v.get('command')].removedValidity.append(copy.deepcopy(v))
if v.get('struct'):
self.typedict[v.get('struct')].removedValidity.append(copy.deepcopy(v))
#
# generateFeature - generate a single type / enum group / enum / command,
# and all its dependencies as needed.
# fname - name of feature (<type>/<enum>/<command>)
# ftype - type of feature, 'type' | 'enum' | 'command'
# dictionary - of *Info objects - self.{type|enum|cmd}dict
def generateFeature(self, fname, ftype, dictionary):
#@ # Break to debugger on matching name pattern
#@ if self.breakPat and re.match(self.breakPat, fname):
#@ pdb.set_trace()
self.gen.logMsg('diag', 'generateFeature: generating', ftype, fname)
f = self.lookupElementInfo(fname, dictionary)
if (f == None):
# No such feature. This is an error, but reported earlier
self.gen.logMsg('diag', 'No entry found for feature', fname,
'returning!')
return
#
# If feature isn't required, or has already been declared, return
if (not f.required):
self.gen.logMsg('diag', 'Skipping', ftype, fname, '(not required)')
return
if (f.declared):
self.gen.logMsg('diag', 'Skipping', ftype, fname, '(already declared)')
return
# Always mark feature declared, as though actually emitted
f.declared = True
# Determine if this is an alias, and of what, if so
alias = f.elem.get('alias')
if alias:
self.gen.logMsg('diag', fname, 'is an alias of', alias)
#
# Pull in dependent declaration(s) of the feature.
# For types, there may be one type in the 'required' attribute of
# the element, one in the 'alias' attribute, and many in
# imbedded <type> and <enum> tags within the element.
# For commands, there may be many in <type> tags within the element.
# For enums, no dependencies are allowed (though perhaps if you
# have a uint64 enum, it should require that type).
genProc = None
if (ftype == 'type'):
genProc = self.gen.genType
# Generate type dependencies in 'alias' and 'required' attributes
if alias:
self.generateFeature(alias, 'type', self.typedict)
requires = f.elem.get('requires')
if requires:
self.generateFeature(requires, 'type', self.typedict)
# Generate types used in defining this type (e.g. in nested
# <type> tags)
# Look for <type> in entire <command> tree,
# not just immediate children
for subtype in f.elem.findall('.//type'):
self.gen.logMsg('diag', 'Generating required dependent <type>',
subtype.text)
self.generateFeature(subtype.text, 'type', self.typedict)
# Generate enums used in defining this type, for example in
# <member><name>member</name>[<enum>MEMBER_SIZE</enum>]</member>
for subtype in f.elem.findall('.//enum'):
self.gen.logMsg('diag', 'Generating required dependent <enum>',
subtype.text)
self.generateFeature(subtype.text, 'enum', self.enumdict)
# If the type is an enum group, look up the corresponding
# group in the group dictionary and generate that instead.
if (f.elem.get('category') == 'enum'):
self.gen.logMsg('diag', 'Type', fname, 'is an enum group, so generate that instead')
group = self.lookupElementInfo(fname, self.groupdict)
if alias != None:
# An alias of another group name.
# Pass to genGroup with 'alias' parameter = aliased name
self.gen.logMsg('diag', 'Generating alias', fname,
'for enumerated type', alias)
# Now, pass the *aliased* GroupInfo to the genGroup, but
# with an additional parameter which is the alias name.
genProc = self.gen.genGroup
f = self.lookupElementInfo(alias, self.groupdict)
elif group == None:
self.gen.logMsg('warn', 'Skipping enum type', fname,
': No matching enumerant group')
return
else:
genProc = self.gen.genGroup
f = group
#@ The enum group is not ready for generation. At this
#@ point, it contains all <enum> tags injected by
#@ <extension> tags without any verification of whether
#@ they're required or not. It may also contain
#@ duplicates injected by multiple consistent
#@ definitions of an <enum>.
#@ Pass over each enum, marking its enumdict[] entry as
#@ required or not. Mark aliases of enums as required,
#@ too.
enums = group.elem.findall('enum')
self.gen.logMsg('diag', 'generateFeature: checking enums for group', fname)
# Check for required enums, including aliases
# LATER - Check for, report, and remove duplicates?
enumAliases = []
for elem in enums:
name = elem.get('name')
required = False
extname = elem.get('extname')
version = elem.get('version')
if extname is not None:
# 'supported' attribute was injected when the <enum> element was
# moved into the <enums> group in Registry.parseTree()
if self.genOpts.defaultExtensions == elem.get('supported'):
required = True
elif re.match(self.genOpts.addExtensions, extname) is not None:
required = True
elif version is not None:
required = re.match(self.genOpts.emitversions, version) is not None
else:
required = True
self.gen.logMsg('diag', '* required =', required, 'for', name)
if required:
# Mark this element as required (in the element, not the EnumInfo)
elem.attrib['required'] = 'true'
# If it's an alias, track that for later use
enumAlias = elem.get('alias')
if enumAlias:
enumAliases.append(enumAlias)
for elem in enums:
name = elem.get('name')
if name in enumAliases:
elem.attrib['required'] = 'true'
self.gen.logMsg('diag', '* also need to require alias', name)
elif (ftype == 'command'):
# Generate command dependencies in 'alias' attribute
if alias:
self.generateFeature(alias, 'command', self.cmddict)
genProc = self.gen.genCmd
for type in f.elem.findall('.//type'):
depname = type.text
self.gen.logMsg('diag', 'Generating required parameter type',
depname)
self.generateFeature(depname, 'type', self.typedict)
elif (ftype == 'enum'):
# Generate enum dependencies in 'alias' attribute
if alias:
self.generateFeature(alias, 'enum', self.enumdict)
genProc = self.gen.genEnum
# Actually generate the type only if emitting declarations
if self.emitFeatures:
self.gen.logMsg('diag', 'Emitting', ftype, fname, 'declaration')
genProc(f, fname, alias)
else:
self.gen.logMsg('diag', 'Skipping', ftype, fname,
'(should not be emitted)')
#
# generateRequiredInterface - generate all interfaces required
# by an API version or extension
# interface - Element for <version> or <extension>
def generateRequiredInterface(self, interface):
"""Generate required C interface for specified API version/extension"""
#
# Loop over all features inside all <require> tags.
for features in interface.findall('require'):
for t in features.findall('type'):
self.generateFeature(t.get('name'), 'type', self.typedict)
for e in features.findall('enum'):
self.generateFeature(e.get('name'), 'enum', self.enumdict)
for c in features.findall('command'):
self.generateFeature(c.get('name'), 'command', self.cmddict)
#
# apiGen(genOpts) - generate interface for specified versions
# genOpts - GeneratorOptions object with parameters used
# by the Generator object.
def apiGen(self, genOpts):
"""Generate interfaces for the specified API type and range of versions"""
#
self.gen.logMsg('diag', '*******************************************')
self.gen.logMsg('diag', ' Registry.apiGen file:', genOpts.filename,
'api:', genOpts.apiname,
'profile:', genOpts.profile)
self.gen.logMsg('diag', '*******************************************')
#
self.genOpts = genOpts
# Reset required/declared flags for all features
self.apiReset()
#
# Compile regexps used to select versions & extensions
regVersions = re.compile(self.genOpts.versions)
regEmitVersions = re.compile(self.genOpts.emitversions)
regAddExtensions = re.compile(self.genOpts.addExtensions)
regRemoveExtensions = re.compile(self.genOpts.removeExtensions)
regEmitExtensions = re.compile(self.genOpts.emitExtensions)
#
# Get all matching API feature names & add to list of FeatureInfo
# Note we used to select on feature version attributes, not names.
features = []
apiMatch = False
for key in self.apidict:
fi = self.apidict[key]
api = fi.elem.get('api')
if (api == self.genOpts.apiname):
apiMatch = True
if (regVersions.match(fi.name)):
# Matches API & version #s being generated. Mark for
# emission and add to the features[] list .
# @@ Could use 'declared' instead of 'emit'?
fi.emit = (regEmitVersions.match(fi.name) != None)
features.append(fi)
if (not fi.emit):
self.gen.logMsg('diag', 'NOT tagging feature api =', api,
'name =', fi.name, 'version =', fi.version,
'for emission (does not match emitversions pattern)')
else:
self.gen.logMsg('diag', 'Including feature api =', api,
'name =', fi.name, 'version =', fi.version,
'for emission (matches emitversions pattern)')
else:
self.gen.logMsg('diag', 'NOT including feature api =', api,
'name =', fi.name, 'version =', fi.version,
'(does not match requested versions)')
else:
self.gen.logMsg('diag', 'NOT including feature api =', api,
'name =', fi.name,
'(does not match requested API)')
if (not apiMatch):
self.gen.logMsg('warn', 'No matching API versions found!')
#
# Get all matching extensions, in order by their extension number,
# and add to the list of features.
# Start with extensions tagged with 'api' pattern matching the API
# being generated. Add extensions matching the pattern specified in
# regExtensions, then remove extensions matching the pattern
# specified in regRemoveExtensions
for (extName,ei) in sorted(self.extdict.items(),key = lambda x : x[1].number):
extName = ei.name
include = False
#
# Include extension if defaultExtensions is not None and if the
# 'supported' attribute matches defaultExtensions. The regexp in
# 'supported' must exactly match defaultExtensions, so bracket
# it with ^(pat)$.
pat = '^(' + ei.elem.get('supported') + ')$'
if (self.genOpts.defaultExtensions and
re.match(pat, self.genOpts.defaultExtensions)):
self.gen.logMsg('diag', 'Including extension',
extName, "(defaultExtensions matches the 'supported' attribute)")
include = True
#
# Include additional extensions if the extension name matches
# the regexp specified in the generator options. This allows
# forcing extensions into an interface even if they're not
# tagged appropriately in the registry.
if (regAddExtensions.match(extName) != None):
self.gen.logMsg('diag', 'Including extension',
extName, '(matches explicitly requested extensions to add)')
include = True
# Remove extensions if the name matches the regexp specified
# in generator options. This allows forcing removal of
# extensions from an interface even if they're tagged that
# way in the registry.
if (regRemoveExtensions.match(extName) != None):
self.gen.logMsg('diag', 'Removing extension',
extName, '(matches explicitly requested extensions to remove)')
include = False
#
# If the extension is to be included, add it to the
# extension features list.
if (include):
ei.emit = (regEmitExtensions.match(extName) != None)
features.append(ei)
if (not ei.emit):
self.gen.logMsg('diag', 'NOT tagging extension',
extName,
'for emission (does not match emitextensions pattern)')
# Hack - can be removed when validity generator goes away
# (Jon) I'm not sure what this does, or if it should respect
# the ei.emit flag above.
self.requiredextensions.append(extName)
else:
self.gen.logMsg('diag', 'NOT including extension',
extName, '(does not match api attribute or explicitly requested extensions)')
#
# Sort the extension features list, if a sort procedure is defined
if (self.genOpts.sortProcedure):
self.genOpts.sortProcedure(features)
#
# Pass 1: loop over requested API versions and extensions tagging
# types/commands/features as required (in an <require> block) or no
# longer required (in an <remove> block). It is possible to remove
# a feature in one version and restore it later by requiring it in
# a later version.
# If a profile other than 'None' is being generated, it must
# match the profile attribute (if any) of the <require> and
# <remove> tags.
self.gen.logMsg('diag', '*******PASS 1: TAG FEATURES **********')
for f in features:
self.gen.logMsg('diag', 'PASS 1: Tagging required and removed features for',
f.name)
self.requireAndRemoveFeatures(f.elem, self.genOpts.apiname, self.genOpts.profile)
self.assignAdditionalValidity(f.elem, self.genOpts.apiname, self.genOpts.profile)
#
# Pass 2: loop over specified API versions and extensions printing
# declarations for required things which haven't already been
# generated.
self.gen.logMsg('diag', '*******PASS 2: GENERATE INTERFACES FOR FEATURES **********')
self.gen.beginFile(self.genOpts)
for f in features:
self.gen.logMsg('diag', 'PASS 2: Generating interface for',
f.name)
emit = self.emitFeatures = f.emit
if (not emit):
self.gen.logMsg('diag', 'PASS 2: NOT declaring feature',
f.elem.get('name'), 'because it is not tagged for emission')
# Generate the interface (or just tag its elements as having been
# emitted, if they haven't been).
self.gen.beginFeature(f.elem, emit)
self.generateRequiredInterface(f.elem)
self.gen.endFeature()
self.gen.endFile()
#
# apiReset - use between apiGen() calls to reset internal state
#
def apiReset(self):
"""Reset type/enum/command dictionaries before generating another API"""
for type in self.typedict:
self.typedict[type].resetState()
for enum in self.enumdict:
self.enumdict[enum].resetState()
for cmd in self.cmddict:
self.cmddict[cmd].resetState()
for cmd in self.apidict:
self.apidict[cmd].resetState()
#
# validateGroups - check that group= attributes match actual groups
#
def validateGroups(self):
"""Validate group= attributes on <param> and <proto> tags"""
# Keep track of group names not in <group> tags
badGroup = {}
self.gen.logMsg('diag', 'VALIDATING GROUP ATTRIBUTES ***')
for cmd in self.reg.findall('commands/command'):
proto = cmd.find('proto')
funcname = cmd.find('proto/name').text
if ('group' in proto.attrib.keys()):
group = proto.get('group')
# self.gen.logMsg('diag', 'Command ', funcname, ' has return group ', group)
if (group not in self.groupdict.keys()):
# self.gen.logMsg('diag', 'Command ', funcname, ' has UNKNOWN return group ', group)
if (group not in badGroup.keys()):
badGroup[group] = 1
else:
badGroup[group] = badGroup[group] + 1
for param in cmd.findall('param'):
pname = param.find('name')
if (pname != None):
pname = pname.text
else:
pname = type.get('name')
if ('group' in param.attrib.keys()):
group = param.get('group')
if (group not in self.groupdict.keys()):
# self.gen.logMsg('diag', 'Command ', funcname, ' param ', pname, ' has UNKNOWN group ', group)
if (group not in badGroup.keys()):
badGroup[group] = 1
else:
badGroup[group] = badGroup[group] + 1
if (len(badGroup.keys()) > 0):
self.gen.logMsg('diag', 'SUMMARY OF UNRECOGNIZED GROUPS ***')
for key in sorted(badGroup.keys()):
self.gen.logMsg('diag', ' ', key, ' occurred ', badGroup[key], ' times')
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment