chromium/chrome/installer/mini_installer/BUILD.gn

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

import("//build/config/compiler/compiler.gni")
import("//build/config/features.gni")
import("//build/config/python.gni")
import("//build/config/ui.gni")
import("//build/timestamp.gni")
import("//chrome/process_version_rc_template.gni")
import("//third_party/dawn/scripts/dawn_features.gni")
import("//third_party/ffmpeg/ffmpeg_options.gni")
import("//third_party/icu/config.gni")
import("//tools/v8_context_snapshot/v8_context_snapshot.gni")
import("//ui/base/ui_features.gni")
import("//v8/gni/v8.gni")

declare_args() {
  # The Chrome archive is maximally compressed in official builds to reduce the
  # size of the installer. By default: non-official or component builds, build
  # modes targeting developers, use maximum-speed instead of maximum-compression
  # settings so as to provide quicker build-test cycles. Uncompressed archives
  # are not supported due to size constraints.
  fast_archive_compression = !is_official_build || is_component_build

  # Enables the //chrome/installer/mini_installer:mini_installer_uncompressed
  # target, which is a variant of the installer containing an uncompressed
  # Chrome archive and setup.exe. The Chrome archive is compressed by default in
  # official builds. This archive will then be used to produce both compressed
  # and uncompressed mini_installer executables. This is done during the signing
  # step to keep the signed binaries and signatures as close to identical as
  # possible. This must be ignored for debug builds and is only intended to
  # allow developers to test the uncompressed installer locally.
  enable_uncompressed_archive = false
}

config("mini_installer_compiler_flags") {
  # Disable buffer security checking.
  cflags = [ "/GS-" ]
}

source_set("lib") {
  sources = [
    "appid.h",
    "chrome_appid.cc",
    "configuration.cc",
    "configuration.h",
    "decompress.cc",
    "decompress.h",
    "delete_with_retry.cc",
    "delete_with_retry.h",
    "enumerate_resources.cc",
    "enumerate_resources.h",
    "memory_range.h",
    "mini_file.cc",
    "mini_file.h",
    "mini_installer.cc",
    "mini_installer.h",
    "mini_installer.rc",
    "mini_installer_constants.cc",
    "mini_installer_constants.h",
    "mini_installer_resource.h",
    "mini_string.cc",
    "mini_string.h",
    "path_string.h",
    "regkey.cc",
    "regkey.h",
    "write_to_disk.cc",
    "write_to_disk.h",
  ]

  deps = [ "//build:branding_buildflags" ]

  # Initialization may insert unexpected memset calls.
  configs -= [ "//build/config/compiler:default_init_stack_vars" ]
  configs += [ ":mini_installer_compiler_flags" ]
}

process_version_rc_template("version") {
  template_file = "mini_installer_exe_version.rc.version"
  output = "$root_out_dir/mini_installer_exe_version.rc"
}

source_set("unit_tests") {
  testonly = true

  sources = [
    "configuration_test.cc",
    "decompress_test.cc",
    "delete_with_retry_test.cc",
    "mini_file_test.cc",
    "mini_installer_unittest.cc",
    "mini_string_test.cc",
    "write_to_disk_unittest.cc",
  ]

  public_deps = [ ":lib" ]
  deps = [
    "//base",
    "//base/test:test_support",
    "//build:branding_buildflags",
    "//chrome/install_static:install_static_util",
    "//chrome/installer/util:with_no_strings",
    "//testing/gtest",
  ]
}

# The runtime deps are used to tell create_installer_archive what component
# DLLs need to be packaged in a component build.
chrome_runtime_deps = "$root_gen_dir/chrome_component.runtime_deps"
setup_runtime_deps = "$root_gen_dir/setup.runtime_deps"

group("chrome_runtime_deps") {
  write_runtime_deps = chrome_runtime_deps
  data_deps = [
    "//chrome",
    "//chrome/chrome_proxy",
  ]
}

group("setup_runtime_deps") {
  write_runtime_deps = setup_runtime_deps
  data_deps = [ "//chrome/installer/setup" ]
}

packed_files_rc_file = "$target_gen_dir/mini_installer/packed_files.rc"

# Debug builds must not exceed the 2GB limit in order to avoid corrupting the
# mini_installer, and therefore must be compressed.
# The `enable_uncompressed_archive` arg is only intended for uncompressed
# targets, so we assert that this flag is only set when not building for debug:
# https://crbug.com/1408213.
assert(!is_debug || !enable_uncompressed_archive)

if (enable_uncompressed_archive) {
  packed_files_rc_file_uncompressed =
      "$target_gen_dir/mini_installer/packed_files_uncompressed.rc"
}

action("mini_installer_archive") {
  script = "//chrome/tools/build/win/create_installer_archive.py"

  release_file = "chrome.release"

  inputs = [
    "$root_out_dir/chrome.dll",
    "$root_out_dir/chrome.exe",
    "$root_out_dir/locales/en-US.pak",
    "$root_out_dir/setup.exe",
    "//chrome/tools/build/win/makecab.py",
    release_file,
  ]

  outputs = [
    "$root_out_dir/chrome.7z",
    "$root_out_dir/chrome.packed.7z",
    "$root_out_dir/setup.ex_",
    packed_files_rc_file,
  ]
  args = [
    "--build_dir",
    rebase_path(root_out_dir, root_build_dir),
    "--staging_dir",
    rebase_path("$target_gen_dir/mini_installer", root_build_dir),
    "--input_file",
    rebase_path(release_file, root_build_dir),
    "--resource_file_path",
    rebase_path(packed_files_rc_file, root_build_dir),
    "--target_arch=$current_cpu",
    "--distribution=_${branding_path_product}",
    "--output_dir",
    rebase_path(root_out_dir, root_build_dir),
    "--chrome_runtime_deps",
    rebase_path(chrome_runtime_deps, root_build_dir),
    "--setup_runtime_deps",
    rebase_path(setup_runtime_deps, root_build_dir),
    "--build_time",
    build_timestamp,

    # Optional arguments to generate diff installer.
    #'--last_chrome_installer=C:/Temp/base',
    #'--setup_exe_format=DIFF',
    #'--diff_algorithm=ZUCCHINI',

    # Optional argument for verbose archiving output.
    #"--verbose",
  ]

  deps = [
    ":chrome_runtime_deps",
    ":setup_runtime_deps",
    "//chrome",
    "//chrome:chrome_dll",
    "//chrome/browser/extensions/default_extensions",
    "//chrome/common/win:eventlog_provider",
    "//chrome/installer/setup",
    "//third_party/icu:icudata",
  ]

  if (enable_hidpi) {
    args += [ "--enable_hidpi=1" ]
  }
  if (is_component_build) {
    args += [ "--component_build=1" ]
  }

  if (is_component_ffmpeg) {
    args += [ "--component_ffmpeg_build=1" ]
  }

  if (fast_archive_compression) {
    args += [ "--fast_archive_compression" ]
  }

  if (enable_uncompressed_archive) {
    outputs += [ packed_files_rc_file_uncompressed ]
    args += [
      "--resource_file_path_uncompressed",
      rebase_path(packed_files_rc_file_uncompressed, root_build_dir),
    ]
  }

  if (icu_use_data_file) {
    inputs += [ "$root_out_dir/icudtl.dat" ]
  } else {
    inputs += [ "$root_out_dir/icudt.dll" ]
  }

  if (v8_use_external_startup_data) {
    deps += [ "//v8" ]
    if (use_v8_context_snapshot) {
      inputs += [ "$root_out_dir/$v8_context_snapshot_filename" ]
      deps += [ "//tools/v8_context_snapshot" ]
    }
    if (!use_v8_context_snapshot || include_both_v8_snapshots) {
      inputs += [ "$root_out_dir/snapshot_blob.bin" ]
      args += [ "--include_snapshotblob=1" ]
    }
  }

  if (dawn_use_built_dxc) {
    args += [ "--include_dxc=1" ]
  }

  depfile = "$target_gen_dir/archive.d"
  args += [
    "--depfile",
    rebase_path(depfile, root_build_dir),
  ]
}

source_set("mini_installer_sources") {
  sources = [ "mini_installer_exe_main.cc" ]
  deps = [
    ":lib",
    "//base:clang_profiling_buildflags",
  ]
  configs -= [ "//build/config/compiler:default_init_stack_vars" ]
  configs += [ ":mini_installer_compiler_flags" ]
}

# Generates a mini_installer executable containing the resources provided in the
# caller's `rc_file`.
template("generate_mini_installer") {
  executable(target_name) {
    sources = [ invoker.rc_file ]

    # This target is special so we manually override most linker flags and
    # specify our own to keep the size down.
    configs -= [
      "//build/config/compiler:cet_shadow_stack",
      "//build/config:executable_config",
      "//build/config/win:console",
    ]
    configs += [
      "//build/config/sanitizers:link_executable",
      "//build/config/win:sdk_link",
      "//build/config/win:windowed",
    ]

    ldflags = [
      "/FIXED:NO",
      "/ignore:4199",
      "/NXCOMPAT",
    ]

    libs = [ "setupapi.lib" ]

    deps = [
      ":lib",
      ":mini_installer_archive",
      ":mini_installer_sources",
      ":version",
      "//build/win:default_exe_manifest",
    ]

    # In general, mini_installer tries to avoid depending on the C++ standard
    # library for size reasons. This is achieved by:
    #   1. setting a custom entry point which avoids pulling in the standard
    #      library via a link dependency.
    #   2. setting no_default_deps=true to avoid including the implicit
    #      dependency on //buildtools/third_party/libc++ in builds that set
    #      use_custom_libcxx=true.
    #
    # The net result is similar to linking with /NODEFAULTLIB, but more precise
    # as it just excludes the CRT.
    #
    # But in asan and clang profiling builds we need to link against a runtime
    # library, which in turn depends on the standard library and relies on it
    # to run initializers.
    if (!is_asan && !use_clang_profiling) {
      no_default_deps = true
      ldflags += [ "/ENTRY:MainEntryPoint" ]
    }
  }
}

generate_mini_installer("mini_installer") {
  rc_file = packed_files_rc_file
}

if (enable_uncompressed_archive) {
  generate_mini_installer("mini_installer_uncompressed") {
    rc_file = packed_files_rc_file_uncompressed
  }
}

# previous_version_mini_installer.exe can't be generated in an x86 Debug
# component build because it requires too much memory.
# TODO(thakis): Enable this in cross builds, https://crbug.com/799827
if (!(is_component_build && is_debug && target_cpu == "x86") &&
    host_os == "win") {
  action("previous_version_mini_installer") {
    script = "generate_previous_version_mini_installer.py"
    testonly = true
    if (target_cpu == "arm64") {
      select_toolchain = host_toolchain
    } else {
      select_toolchain = current_toolchain
    }
    alternate_version_generator_target =
        "//chrome/installer/test:alternate_version_generator($select_toolchain)"
    alternate_version_generator_rel_path =
        rebase_path(
            get_label_info(alternate_version_generator_target, "root_out_dir") +
                "/alternate_version_generator.exe",
            root_out_dir)
    inputs = [
      "$root_out_dir/" + alternate_version_generator_rel_path,
      "$root_out_dir/mini_installer.exe",
    ]
    outputs = [ "$root_out_dir/$target_name.exe" ]
    args = [
      "--alternate_version_generator",
      alternate_version_generator_rel_path,
      "--mini_installer",
      "mini_installer.exe",
      "--out",
      "$target_name.exe",
      "--path_7za",
      "../../third_party/lzma_sdk/bin/win64",
    ]
    deps = [
      ":mini_installer",
      alternate_version_generator_target,
    ]
  }
}