build: Add GN build
authorMike Schuchardt <mikes@lunarg.com>
Sat, 20 Apr 2019 01:09:30 +0000 (18:09 -0700)
committerMike Schuchardt <mikes@lunarg.com>
Mon, 13 May 2019 14:49:39 +0000 (07:49 -0700)
Add support for GN, Google's meta-build system for Ninja:
https://gn.googlesource.com/gn/

Pull BUILD.gn and script dependencies from
https://chromium.googlesource.com/angle/angle

Add build_overrides for this project to enable both standalone and
component builds using GN.

Add GN configuration to Travis CI

.gn [new file with mode: 0644]
.travis.yml
BUILD.gn [new file with mode: 0644]
build-gn/DEPS [new file with mode: 0644]
build-gn/generate_vulkan_layers_json.py [new file with mode: 0755]
build-gn/secondary/build_overrides/build.gni [new file with mode: 0644]
build-gn/secondary/build_overrides/vulkan_tools.gni [new file with mode: 0644]
build-gn/update_deps.sh [new file with mode: 0755]

diff --git a/.gn b/.gn
new file mode 100644 (file)
index 0000000..e190259
--- /dev/null
+++ b/.gn
@@ -0,0 +1,22 @@
+# Copyright (C) 2019 LunarG, 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
+#
+#     https://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.
+
+buildconfig = "//build/config/BUILDCONFIG.gn"
+secondary_source = "//build-gn/secondary/"
+
+default_args = {
+    clang_use_chrome_plugins = false
+    use_custom_libcxx = false
+}
+
index 07b015c..6e09f66 100644 (file)
@@ -10,6 +10,7 @@ matrix:
   fast_finish: true
   allow_failures:
     - env: CHECK_COMMIT_FORMAT=ON
+    - env: VULKAN_BUILD_TARGET=GN
   include:
     # Android build.
     - os: linux
@@ -27,6 +28,9 @@ matrix:
     - os: linux
       compiler: clang
       env: VULKAN_BUILD_TARGET=LINUX
+    # Linux GN debug build
+    - os: linux
+      env: VULKAN_BUILD_TARGET=GN
     # Check for proper clang formatting in the pull request.
     - env: CHECK_FORMAT=ON
     # Check for proper commit message formatting for commits in PR
@@ -42,10 +46,10 @@ cache: ccache
 before_install:
   - set -e
   - |
-    if [[ "$VULKAN_BUILD_TARGET" == "LINUX" ]]; then
+    if [[ "$VULKAN_BUILD_TARGET" == "LINUX" ]] || [[ "$VULKAN_BUILD_TARGET" == "GN" ]]; then
       # Install the appropriate Linux packages.
       sudo apt-get -qq update
-      sudo apt-get -y install libxkbcommon-dev libwayland-dev libmirclient-dev libxrandr-dev libx11-xcb-dev
+      sudo apt-get -y install libxkbcommon-dev libwayland-dev libmirclient-dev libxrandr-dev libx11-xcb-dev python-pathlib
     fi
   - |
     if [[ "$VULKAN_BUILD_TARGET" == "ANDROID" ]]; then
@@ -100,6 +104,14 @@ script:
       popd
     fi
   - |
+    if [[ "$VULKAN_BUILD_TARGET" == "GN" ]]; then
+      git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git depot_tools
+      export PATH=$PATH:$PWD/depot_tools
+      ./build-gn/update_deps.sh
+      gn gen out/Debug
+      ninja -C out/Debug
+    fi
+  - |
     if [[ "$CHECK_FORMAT" == "ON" ]]; then
       if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then
         # Run the clang format check only for pull request builds because the
diff --git a/BUILD.gn b/BUILD.gn
new file mode 100644 (file)
index 0000000..c6cc155
--- /dev/null
+++ b/BUILD.gn
@@ -0,0 +1,206 @@
+# Copyright (C) 2018-2019 The ANGLE Project Authors.
+# Copyright (C) 2019 LunarG, 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
+#
+#     https://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("//build_overrides/vulkan_tools.gni")
+
+vulkan_registry_script_files = [
+  "$vulkan_headers_dir/registry/cgenerator.py",
+  "$vulkan_headers_dir/registry/conventions.py",
+  "$vulkan_headers_dir/registry/generator.py",
+  "$vulkan_headers_dir/registry/reg.py",
+  "$vulkan_headers_dir/registry/vkconventions.py",
+  "$vulkan_headers_dir/registry/vk.xml",
+]
+
+# Vulkan-tools isn't ported to Fuchsia yet.
+# TODO(spang): Port mock ICD to Fuchsia.
+assert(!is_fuchsia)
+
+vulkan_undefine_configs = []
+if (is_win) {
+  vulkan_undefine_configs += [
+    "//build/config/win:nominmax",
+    "//build/config/win:unicode",
+  ]
+}
+
+raw_vulkan_icd_dir = rebase_path("icd", root_build_dir)
+raw_vulkan_headers_dir = rebase_path("$vulkan_headers_dir", root_build_dir)
+
+vulkan_gen_dir = "$target_gen_dir/$vulkan_gen_subdir"
+raw_vulkan_gen_dir = rebase_path(vulkan_gen_dir, root_build_dir)
+
+vulkan_data_dir = "$root_out_dir/$vulkan_data_subdir"
+raw_vulkan_data_dir = rebase_path(vulkan_data_dir, root_build_dir)
+
+# Vulkan helper scripts
+# ---------------------
+
+helper_script_and_deps = [
+  [
+    "vulkan_gen_typemap_helper",
+    "vk_typemap_helper.h",
+    "vulkan_tools_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",
+  ],
+]
+
+# Python scripts needed for codegen, copy them to a temp dir
+# so that all dependencies are together
+copy("python_gen_deps") {
+  sources = vulkan_registry_script_files + [
+              "scripts/common_codegen.py",
+              "scripts/kvt_genvk.py",
+              "scripts/mock_icd_generator.py",
+              "scripts/vulkan_tools_helper_file_generator.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/kvt_genvk.py"
+    inputs = [
+      "$vulkan_gen_dir/$dep",
+      "$vulkan_gen_dir/common_codegen.py",
+    ]
+    outputs = [
+      "$vulkan_gen_dir/$file",
+    ]
+    args = [
+      "-o",
+      raw_vulkan_gen_dir,
+      "-registry",
+      "$raw_vulkan_headers_dir/registry/vk.xml",
+      "-scripts",
+      "$raw_vulkan_headers_dir/registry",
+      "$file",
+      "-quiet",
+    ]
+  }
+}
+
+config("vulkan_generated_files_config") {
+  include_dirs = [ vulkan_gen_dir ]
+}
+
+group("vulkan_generate_helper_files") {
+  public_deps = [
+    "$vulkan_headers_dir: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_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 = [
+    "$vulkan_headers_dir/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
+    deps = [
+      ":vulkan_generate_mock_icd_files",
+    ]
+    data_deps = [
+      ":vulkan_gen_icd_json_file",
+    ]
+    sources = mock_icd_sources
+    if (is_win) {
+      sources += [ "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 = "build-gn/generate_vulkan_layers_json.py"
+    sources = [
+      "$vulkan_headers_dir/include/vulkan/vulkan_core.h",
+    ]
+    args = [ "--icd" ]
+    if (is_win) {
+      sources += [ "icd/windows/VkICD_mock_icd.json" ]
+      args += [ "$raw_vulkan_icd_dir/windows" ]
+    }
+    if (is_linux) {
+      sources += [ "icd/linux/VkICD_mock_icd.json" ]
+      args += [ "$raw_vulkan_icd_dir/linux" ]
+    }
+
+    # The layer JSON files are part of the necessary data deps.
+    outputs = [
+      "$vulkan_data_dir/VkICD_mock_icd.json",
+    ]
+    data = outputs
+    args += [ raw_vulkan_data_dir ] + rebase_path(sources, root_build_dir)
+  }
+}
diff --git a/build-gn/DEPS b/build-gn/DEPS
new file mode 100644 (file)
index 0000000..81cca43
--- /dev/null
@@ -0,0 +1,57 @@
+vars = {
+  'chromium_git': 'https://chromium.googlesource.com',
+}
+
+deps = {
+
+  './build': {
+    'url': '{chromium_git}/chromium/src/build.git@a660b0b9174e3a808f620222017566e8d1b2669b',
+  },
+
+  './buildtools': {
+    'url': '{chromium_git}/chromium/src/buildtools.git@459baaf66bee809f6eb288e0215cf524f4d2429a',
+  },
+
+  './testing': {
+    'url': '{chromium_git}/chromium/src/testing@083d633e752e7a57cbe62a468a06e51e28c49ee9',
+  },
+
+  './tools/clang': {
+    'url': '{chromium_git}/chromium/src/tools/clang.git@3114fbc11f9644c54dd0a4cdbfa867bac50ff983',
+  },
+
+}
+
+hooks = [
+  # Pull clang-format binaries using checked-in hashes.
+  {
+    'name': 'clang_format_linux',
+    'pattern': '.',
+    'condition': 'host_os == "linux"',
+    'action': [ 'download_from_google_storage',
+                '--no_resume',
+                '--platform=linux*',
+                '--no_auth',
+                '--bucket', 'chromium-clang-format',
+                '-s', './buildtools/linux64/clang-format.sha1',
+    ],
+  },
+  {
+    'name': 'sysroot_x64',
+    'pattern': '.',
+    'condition': 'checkout_linux and checkout_x64',
+    'action': ['python', './build/linux/sysroot_scripts/install-sysroot.py',
+               '--arch=x64'],
+  },
+  {
+    # Note: On Win, this should run after win_toolchain, as it may use it.
+    'name': 'clang',
+    'pattern': '.',
+    'action': ['python', './tools/clang/scripts/update.py'],
+  },
+]
+
+recursedeps = [
+  # buildtools provides clang_format.
+  './buildtools',
+]
diff --git a/build-gn/generate_vulkan_layers_json.py b/build-gn/generate_vulkan_layers_json.py
new file mode 100755 (executable)
index 0000000..2999cd8
--- /dev/null
@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2016 The ANGLE Project Authors.
+#
+# 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
+#
+#     https://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.
+
+"""Generate copies of the Vulkan layers JSON files, with no paths, forcing
+Vulkan to use the default search path to look for layers."""
+
+from __future__ import print_function
+
+import argparse
+import glob
+import json
+import os
+import platform
+import sys
+
+
+def glob_slash(dirname):
+    """Like regular glob but replaces \ with / in returned paths."""
+    return [s.replace('\\', '/') for s in glob.glob(dirname)]
+
+
+def main():
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument('--icd', action='store_true')
+    parser.add_argument('source_dir')
+    parser.add_argument('target_dir')
+    parser.add_argument('version_header', help='path to vulkan_core.h')
+    parser.add_argument('json_files', nargs='*')
+    args = parser.parse_args()
+
+    source_dir = args.source_dir
+    target_dir = args.target_dir
+
+    json_files = [j for j in args.json_files if j.endswith('.json')]
+    json_in_files = [j for j in args.json_files if j.endswith('.json.in')]
+
+    data_key = 'ICD' if args.icd else 'layer'
+
+    if not os.path.isdir(source_dir):
+        print(source_dir + ' is not a directory.', file=sys.stderr)
+        return 1
+
+    if not os.path.exists(target_dir):
+        os.makedirs(target_dir)
+
+    # Copy the *.json files from source dir to target dir
+    if (set(glob_slash(os.path.join(source_dir, '*.json'))) != set(json_files)):
+        print(glob.glob(os.path.join(source_dir, '*.json')))
+        print('.json list in gn file is out-of-date', file=sys.stderr)
+        return 1
+
+    for json_fname in json_files:
+        if not json_fname.endswith('.json'):
+            continue
+        with open(json_fname) as infile:
+            data = json.load(infile)
+
+        # Update the path.
+        if not data_key in data:
+            raise Exception(
+                "Could not find '%s' key in %s" % (data_key, json_fname))
+
+        # The standard validation layer has no library path.
+        if 'library_path' in data[data_key]:
+            prev_name = os.path.basename(data[data_key]['library_path'])
+            data[data_key]['library_path'] = prev_name
+
+        target_fname = os.path.join(target_dir, os.path.basename(json_fname))
+        with open(target_fname, 'wb') as outfile:
+            json.dump(data, outfile)
+
+    # Get the Vulkan version from the vulkan_core.h file
+    vk_header_filename = args.version_header
+    vk_version = None
+    with open(vk_header_filename) as vk_header_file:
+        for line in vk_header_file:
+            if line.startswith('#define VK_HEADER_VERSION'):
+                vk_version = line.split()[-1]
+                break
+    if not vk_version:
+        print('failed to extract vk_version', file=sys.stderr)
+        return 1
+
+    # Set json file prefix and suffix for generating files, default to Linux.
+    relative_path_prefix = '../lib'
+    file_type_suffix = '.so'
+    if platform.system() == 'Windows':
+        relative_path_prefix = r'..\\'  # json-escaped, hence two backslashes.
+        file_type_suffix = '.dll'
+
+    # For each *.json.in template files in source dir generate actual json file
+    # in target dir
+    if (set(glob_slash(os.path.join(source_dir, '*.json.in'))) !=
+            set(json_in_files)):
+        print('.json.in list in gn file is out-of-date', file=sys.stderr)
+        return 1
+    for json_in_name in json_in_files:
+        if not json_in_name.endswith('.json.in'):
+            continue
+        json_in_fname = os.path.basename(json_in_name)
+        layer_name = json_in_fname[:-len('.json.in')]
+        layer_lib_name = layer_name + file_type_suffix
+        json_out_fname = os.path.join(target_dir, json_in_fname[:-len('.in')])
+        with open(json_out_fname,'w') as json_out_file, \
+             open(json_in_name) as infile:
+            for line in infile:
+                line = line.replace('@RELATIVE_LAYER_BINARY@',
+                                    relative_path_prefix + layer_lib_name)
+                line = line.replace('@VK_VERSION@', '1.1.' + vk_version)
+                json_out_file.write(line)
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/build-gn/secondary/build_overrides/build.gni b/build-gn/secondary/build_overrides/build.gni
new file mode 100644 (file)
index 0000000..c6c11fa
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2019 LunarG, 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
+#
+#     https://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.
+
+build_with_chromium = false
+ignore_elf32_limitations = true
+linux_use_bundled_binutils_override = false
+use_system_xcode = true
diff --git a/build-gn/secondary/build_overrides/vulkan_tools.gni b/build-gn/secondary/build_overrides/vulkan_tools.gni
new file mode 100644 (file)
index 0000000..9f80846
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright (c) 2019 LunarG, 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
+#
+#     https://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.
+
+# Paths to vulkan tools dependencies
+vulkan_headers_dir = "//external/Vulkan-Headers"
+
+# Subdirectories for generated files
+vulkan_data_subdir = ""
+vulkan_gen_subdir = ""
+
diff --git a/build-gn/update_deps.sh b/build-gn/update_deps.sh
new file mode 100755 (executable)
index 0000000..41da2ab
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+# Copyright (c) 2019 LunarG, 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
+#
+#     https://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.
+
+# Execute at repo root
+cd "$(dirname $0)/.."
+
+# Use update_deps.py to update source dependencies from /scripts/known_good.json
+scripts/update_deps.py --dir="external" --no-build
+
+# Use gclient to update toolchain dependencies from /build-gn/DEPS (from chromium)
+cat << EOF >> .gclient
+solutions = [
+  { "name"        : ".",
+    "url"         : "https://github.com/KhronosGroup/Vulkan-Tools",
+    "deps_file"   : "build-gn/DEPS",
+    "managed"     : False,
+    "custom_deps" : {
+    },
+    "custom_vars": {},
+  },
+]
+EOF
+gclient sync
+