# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# Chrome elf targets (excepting tests) should only link in kernel32.
# Please don't add dependencies on any other system libraries.

import("//build/config/compiler/compiler.gni")
import("//build/config/win/manifest.gni")
import("//chrome/process_version_rc_template.gni")
import("//testing/test.gni")

##------------------------------------------------------------------------------
## chrome_elf
##------------------------------------------------------------------------------

process_version_rc_template("chrome_elf_resources") {
  sources = [
    "chrome_elf.ver",
  ]
  output = "$target_gen_dir/chrome_elf_version.rc"
}

# This manifest matches what GYP produces. It may not even be necessary.
windows_manifest("chrome_elf_manifest") {
  sources = [
    as_invoker_manifest,
  ]
}

# Users of chrome_elf exports can depend on this target, which doesn't
# pin them to linking either chrome_elf.dll or test_stubs.
source_set("chrome_elf_main_include") {
  sources = [
    "chrome_elf_main.h",
  ]
}

# We should move chrome_result_codes.h to another target which does not bring
# in the world.
shared_library("chrome_elf") {
  sources = [
    "chrome_elf_main.cc",
    "chrome_elf_main.h",
  ]
  if (target_cpu == "x86") {
    sources += [ "chrome_elf_x86.def" ]
  } else {
    sources += [ "chrome_elf_x64.def" ]
  }

  deps = [
    ":blacklist",
    ":chrome_elf_manifest",
    ":chrome_elf_resources",
    ":constants",
    ":crash",
    ":hook_util",
    ":nt_registry",
    ":security",
    "//build/config:exe_and_shlib_deps",
    "//chrome/install_static:install_static_util",
    "//chrome/install_static:primary_module",
    "//components/crash/content/app:crash_export_thunks",
  ]
  configs += [ "//build/config/win:windowed" ]
  configs -= [ "//build/config/win:console" ]

  # Delay loads in this list will prevent user32.dll
  # from loading too early.
  ldflags = [
    "/DELAYLOAD:advapi32.dll",
    "/DELAYLOAD:dbghelp.dll",
    "/DELAYLOAD:rpcrt4.dll",
    "/DELAYLOAD:winmm.dll",
  ]
  if (current_cpu == "x86") {
    # Don"t set an x64 base address (to avoid breaking HE-ASLR).
    ldflags += [ "/BASE:0x01c20000" ]
  }
}

# For code that isn't Chrome-the browser, like test binaries, these stubs stand
# in for chrome_elf.;
static_library("test_stubs") {
  testonly = true

  sources = [
    "chrome_elf_main.h",
    "chrome_elf_test_stubs.cc",
  ]

  deps = [
    "//base",
    "//chrome/common:constants",
  ]
}

##------------------------------------------------------------------------------
## source sets
##------------------------------------------------------------------------------

source_set("security") {
  sources = [
    "chrome_elf_security.cc",
    "chrome_elf_security.h",
  ]
  deps = [
    ":constants",
    ":nt_registry",
    "//chrome/install_static:install_static_util",
  ]
}

source_set("constants") {
  sources = [
    "chrome_elf_constants.cc",
    "chrome_elf_constants.h",
  ]
}

source_set("dll_hash") {
  deps = [
    "//base",
  ]
  sources = [
    "dll_hash/dll_hash.cc",
    "dll_hash/dll_hash.h",
  ]
}

##------------------------------------------------------------------------------
## chrome_elf sub targets
##------------------------------------------------------------------------------

executable("dll_hash_main") {
  sources = [
    "dll_hash/dll_hash_main.cc",
  ]
  deps = [
    ":dll_hash",
    "//build/config:exe_and_shlib_deps",
    "//build/win:default_exe_manifest",
  ]
}

static_library("blacklist") {
  sources = [
    "blacklist/blacklist.cc",
    "blacklist/blacklist.h",
    "blacklist/blacklist_interceptions.cc",
    "blacklist/blacklist_interceptions.h",
  ]
  public_deps = [
    "//sandbox",
  ]
  deps = [
    ":constants",
    ":crash",
    ":hook_util",
    ":nt_registry",
    "//base:base_static",  # pe_image
    "//chrome/install_static:install_static_util",
  ]
}

static_library("crash") {
  sources = [
    "../chrome/app/chrome_crash_reporter_client_win.cc",
    "../chrome/app/chrome_crash_reporter_client_win.h",
    "../chrome/common/chrome_result_codes.h",
    "crash/crash_helper.cc",
    "crash/crash_helper.h",
  ]
  deps = [
    ":hook_util",
    "//base",  # This needs to go.  DEP of app, crash_keys, client.
    "//base:base_static",  # pe_image
    "//chrome/install_static:install_static_util",
    "//components/crash/content/app",
    "//components/crash/core/common",  # crash_keys
    "//components/version_info:channel",
    "//content/public/common:result_codes",
    "//gpu/config:crash_keys",
    "//third_party/crashpad/crashpad/client",  # DumpWithoutCrash
  ]
}

static_library("hook_util") {
  sources = [
    "../base/macros.h",
    "hook_util/hook_util.cc",
    "hook_util/hook_util.h",
  ]
  deps = [
    ":nt_registry",  # utils
    "//base:base_static",  # pe_image
    "//sandbox",
  ]
}

# This target contains utility functions which must only depend on
# kernel32. Please don't add dependencies on other system libraries.
static_library("nt_registry") {
  sources = [
    "../sandbox/win/src/nt_internals.h",
    "nt_registry/nt_registry.cc",
    "nt_registry/nt_registry.h",
  ]
  if (is_official_build && full_wpo_on_official == true) {
    # This library doen't build with WPO enabled due to a MSVC compiler bug.
    # TODO(pennymac|sebmarchand): Remove this once MS has fixed this compiler
    # bug: https://connect.microsoft.com/VisualStudio/feedback/details/3104499
    configs -= [ "//build/config/compiler:default_optimization" ]
    configs += [ "//build/config/compiler:optimize_no_wpo" ]
  }

  libs = [ "kernel32.lib" ]
}

##------------------------------------------------------------------------------
## tests
##------------------------------------------------------------------------------

test("chrome_elf_unittests") {
  output_name = "chrome_elf_unittests"
  sources = [
    "blacklist/test/blacklist_test.cc",
    "chrome_elf_util_unittest.cc",
    "hook_util/test/hook_util_test.cc",
    "nt_registry/nt_registry_unittest.cc",
    "run_all_unittests.cc",
  ]
  include_dirs = [ "$target_gen_dir" ]
  deps = [
    ":blacklist",
    ":blacklist_test_main_dll",
    ":constants",
    ":crash",
    ":hook_util",
    ":hook_util_test_dll",
    ":nt_registry",
    ":security",
    "//base",
    "//base/test:test_support",
    "//chrome/common:version_header",
    "//chrome/install_static:install_static_util",
    "//chrome/install_static/test:test_support",
    "//components/crash/content/app:test_support",
    "//sandbox",
    "//testing/gtest",
  ]
  data_deps = [
    ":blacklist_test_dll_1",
    ":blacklist_test_dll_2",
    ":blacklist_test_dll_3",
    ":chrome_elf",
  ]
}

test("chrome_elf_import_unittests") {
  output_name = "chrome_elf_import_unittests"
  sources = [
    "elf_imports_unittest.cc",
  ]
  include_dirs = [ "$target_gen_dir" ]
  deps = [
    "//base",
    "//base/test:test_support",
    "//chrome",
    "//chrome/install_static:install_static_util",
    "//chrome/install_static/test:test_support",
    "//testing/gtest",
  ]

  # It's not easily possible to have //chrome in data_deps without changing
  # the //chrome target to bundle up both initial/chrome.exe and chrome.exe.
  # As a workaround, explicitly include a data dep on just chrome.exe, and
  # add //chrome to deps above to make sure it's been built.
  data = [
    "$root_out_dir/chrome.exe",
  ]
  data_deps = [
    ":chrome_elf",
  ]

  # Don't want the test-specific dependencies to affect ChromeElfLoadSanityTest.
  # In particular, a few system DLLs cause user32 to be loaded, which is bad.
  ldflags = [
    "/DELAYLOAD:advapi32.dll",
    "/DELAYLOAD:ole32.dll",
    "/DELAYLOAD:shell32.dll",
    "/DELAYLOAD:shlwapi.dll",
    "/DELAYLOAD:user32.dll",
    "/DELAYLOAD:winmm.dll",
  ]
}

shared_library("blacklist_test_main_dll") {
  testonly = true
  sources = [
    "blacklist/test/blacklist_test_main_dll.cc",
    "blacklist/test/blacklist_test_main_dll.def",
    "blacklist/test/blacklist_test_main_dll.h",
  ]
  deps = [
    ":blacklist",
    ":nt_registry",
    "//base",
    "//build/config:exe_and_shlib_deps",
    "//chrome/install_static:install_static_util",
    "//components/crash/content/app:test_support",
  ]
}

loadable_module("blacklist_test_dll_1") {
  testonly = true
  sources = [
    "blacklist/test/blacklist_test_dll_1.cc",
    "blacklist/test/blacklist_test_dll_1.def",
  ]
  deps = [
    "//build/config:exe_and_shlib_deps",
  ]
}

loadable_module("blacklist_test_dll_2") {
  testonly = true
  sources = [
    "blacklist/test/blacklist_test_dll_2.cc",
    "blacklist/test/blacklist_test_dll_2.def",
  ]
  deps = [
    "//build/config:exe_and_shlib_deps",
  ]
}

# As-is, this does not generate a .lib file because there are no exports and no
# .def file. The current definition of loadable_module does not declare a .lib
# file as an output, so this is OK. If it did (or if this used shared_library
# which does), Ninja would get confused and always rebuild this target because
# it sees a declared output file but that file doesn't exist on disk.
loadable_module("blacklist_test_dll_3") {
  testonly = true
  sources = [
    "blacklist/test/blacklist_test_dll_3.cc",
  ]
  deps = [
    "//build/config:exe_and_shlib_deps",
  ]
}

shared_library("hook_util_test_dll") {
  testonly = true
  sources = [
    "hook_util/test/hook_util_test_dll.cc",
    "hook_util/test/hook_util_test_dll.h",
  ]
  deps = [
    "//build/config:exe_and_shlib_deps",
  ]
}