# Copyright (c) 2013 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.

import("//build/config/compiler/compiler.gni")
import("//build/config/sanitizers/sanitizers.gni")
import("//build/config/win/visual_studio_version.gni")
import("//build/toolchain/toolchain.gni")

assert(is_win)

declare_args() {
  # Set this to true to enable static analysis through Visual Studio's
  # /analyze. This dramatically slows compiles and reports thousands of
  # warnings, so normally this is done on a build machine and only the new
  # warnings are examined.
  use_vs_code_analysis = false
}

# This is included by reference in the //build/config/compiler config that
# is applied to all targets. It is here to separate out the logic that is
# Windows-only.
config("compiler") {
  if (current_cpu == "x86") {
    asmflags = [
      # When /safeseh is specified, the linker will only produce an image if it
      # can also produce a table of the image's safe exception handlers. This
      # table specifies for the operating system which exception handlers are
      # valid for the image. Note that /SAFESEH isn't accepted on the command
      # line, only /safeseh. This is only accepted by ml.exe, not ml64.exe.
      "/safeseh",
    ]
  }

  cflags = [
    "/Gy",  # Enable function-level linking.
    "/FS",  # Preserve previous PDB behavior.
    "/bigobj",  # Some of our files are bigger than the regular limits.

    # Tell the compiler to crash on failures. This is undocumented
    # and unsupported but very handy.
    "/d2FastFail",
  ]

  # Force C/C++ mode for the given GN detected file type. This is necessary
  # for precompiled headers where the same source file is compiled in both
  # modes.
  cflags_c = [ "/TC" ]
  cflags_cc = [ "/TP" ]

  if (visual_studio_version == "2015") {
    cflags += [
      # Work around crbug.com/526851, bug in VS 2015 RTM compiler.
      "/Zc:sizedDealloc-",

      # Disable thread-safe statics to avoid overhead and because
      # they are disabled on other platforms. See crbug.com/587210
      # and -fno-threadsafe-statics.
      "/Zc:threadSafeInit-",
    ]
  }

  # Building with Clang on Windows is a work in progress and very
  # experimental. See crbug.com/82385.
  # Keep this in sync with the similar block in build/common.gypi
  if (is_clang) {
    cflags += [
      # Many files use intrinsics without including this header.
      # TODO(hans): Fix those files, or move this to sub-GYPs.
      "/FIIntrin.h",
    ]

    if (visual_studio_version == "2013") {
      cflags += [ "-fmsc-version=1800" ]
    } else if (visual_studio_version == "2015") {
      cflags += [ "-fmsc-version=1900" ]
    }

    if (current_cpu == "x86") {
      cflags += [ "-m32" ]
    } else {
      cflags += [ "-m64" ]
    }

    if (exec_script("//build/win/use_ansi_codes.py", [], "trim string") ==
        "True") {
      cflags += [
        # cmd.exe doesn't understand ANSI escape codes by default,
        # so only enable them if something emulating them is around.
        "-fansi-escape-codes",
      ]
    }

    # Clang runtime libraries, such as the sanitizer runtimes, live here.
    lib_dirs = [ "//third_party/llvm-build/Release+Asserts/lib/clang/$clang_version/lib/windows" ]
  }

  if (is_syzyasan) {
    # SyzyAsan needs /PROFILE turned on to produce appropriate pdbs.
    assert(!is_win_fastlink, "/PROFILE and /DEBUG:FASTLINK are incompatible")
    ldflags = [ "/PROFILE" ]
  }

  # arflags apply only to static_libraries. The normal linker configs are only
  # set for executable and shared library targets so arflags must be set
  # elsewhere. Since this is relatively contained, we just apply them in this
  # more general config and they will only have an effect on static libraries.
  arflags = [
    # "No public symbols found; archive member will be inaccessible." This
    # means that one or more object files in the library can never be
    # pulled in to targets that link to this library. It's just a warning that
    # the source file is a no-op.
    "/ignore:4221",
  ]
}

config("vs_code_analysis") {
  if (use_vs_code_analysis) {
    # When use_vs_code_analysis is specified add the /analyze switch to enable
    # static analysis. Specifying /analyze:WX- says that /analyze warnings
    # should not be treated as errors.
    cflags = [ "/analyze:WX-" ]

    # Also, disable various noisy warnings that have low value.
    cflags += [
      "/wd6011",  # Dereferencing NULL pointer

      # C6285 is ~16% of raw warnings and has low value
      "/wd6285",  # non-zero constant || non-zero constant
      "/wd6308",  # realloc might return null pointer

      # Possible infinite loop: use of the constant
      # EXCEPTION_CONTINUE_EXECUTION in the exception-filter
      "/wd6312",

      "/wd6322",  # Empty _except block
      "/wd6330",  # 'char' used instead of 'unsigned char' for istype() call

      # C6334 is ~80% of raw warnings and has low value
      "/wd6334",  # sizeof applied to an expression with an operator
      "/wd6326",  # Potential comparison of constant with constant
      "/wd6340",  # Sign mismatch in function parameter
      "/wd28159",  # Consider using 'GetTickCount64'
      "/wd28196",  # The precondition is not satisfied
      "/wd28204",  # Inconsistent SAL annotations
      "/wd28251",  # Inconsistent SAL annotations
      "/wd28252",  # Inconsistent SAL annotations
      "/wd28253",  # Inconsistent SAL annotations
      "/wd28278",  # Function appears with no prototype in scope
      "/wd28285",  # syntax error in SAL annotation (in algorithm)
      "/wd28301",  # Inconsistent SAL annotations
      "/wd28182",  # Dereferencing NULL pointer
    ]
  }
}

# This is included by reference in the //build/config/compiler:runtime_library
# config that is applied to all targets. It is here to separate out the logic
# that is Windows-only. Please see that target for advice on what should go in
# :runtime_library vs. :compiler.
config("runtime_library") {
  cflags = []

  # Defines that set up the CRT.
  defines = [
    "__STD_C",
    "_CRT_RAND_S",
    "_CRT_SECURE_NO_DEPRECATE",
    "_HAS_EXCEPTIONS=0",
    "_SCL_SECURE_NO_DEPRECATE",
  ]

  # Defines that set up the Windows SDK.
  defines += [
    "_ATL_NO_OPENGL",
    "_WINDOWS",
    "CERT_CHAIN_PARA_HAS_EXTRA_FIELDS",
    "NTDDI_VERSION=0x0A000000",
    "PSAPI_VERSION=1",
    "WIN32",
    "_SECURE_ATL",
  ]

  if (!use_vs_code_analysis) {
    # This is required for ATL to use XP-safe versions of its functions.
    # However it is prohibited when using /analyze
    defines += [ "_USING_V110_SDK71_" ]
  }

  if (is_component_build) {
    # Component mode: dynamic CRT. Since the library is shared, it requires
    # exceptions or will give errors about things not matching, so keep
    # exceptions on.
    if (is_debug) {
      cflags += [ "/MDd" ]
    } else {
      cflags += [ "/MD" ]
    }
  } else {
    if (current_os != "win") {
      # WindowsRT: use the dynamic CRT.
      if (is_debug) {
        cflags += [ "/MDd" ]
      } else {
        cflags += [ "/MD" ]
      }
    } else {
      # Desktop Windows: static CRT.
      if (is_debug) {
        cflags += [ "/MTd" ]
      } else {
        cflags += [ "/MT" ]
      }
    }
  }
}

# Sets the default Windows build version. This is separated because some
# targets need to manually override it for their compiles.
config("winver") {
  defines = [
    "_WIN32_WINNT=0x0A00",
    "WINVER=0x0A00",
  ]
}

# Linker flags for Windows SDK setup, this is applied only to EXEs and DLLs.
config("sdk_link") {
  if (current_cpu == "x64") {
    ldflags = [ "/MACHINE:X64" ]
    lib_dirs = [
      "$windows_sdk_path\Lib\winv6.3\um\x64",
      "$visual_studio_path\VC\lib\amd64",
      "$visual_studio_path\VC\atlmfc\lib\amd64",
    ]
  } else {
    ldflags = [
      "/MACHINE:X86",
      "/SAFESEH",  # Not compatible with x64 so use only for x86.
      "/largeaddressaware",
    ]
    lib_dirs = [
      "$windows_sdk_path\Lib\winv6.3\um\x86",
      "$visual_studio_path\VC\lib",
      "$visual_studio_path\VC\atlmfc\lib",
    ]
  }
}

# This default linker setup is provided separately from the SDK setup so
# targets who want different library configurations can remove this and specify
# their own.
config("common_linker_setup") {
  ldflags = [
    "/FIXED:NO",
    "/ignore:4199",
    "/ignore:4221",
    "/NXCOMPAT",

    # Suggested by Microsoft Devrel to avoid
    #   LINK : fatal error LNK1248: image size (80000000)
    #   exceeds maximum allowable size (80000000)
    # which started happening more regularly after VS2013 Update 4.
    # Needs to be a bit lower for VS2015, or else errors out.
    "/maxilksize:0x7ff00000",

    # Tell the linker to crash on failures.
    "/fastfail",
  ]

  # ASLR makes debugging with windbg difficult because Chrome.exe and
  # Chrome.dll share the same base name. As result, windbg will name the
  # Chrome.dll module like chrome_<base address>, where <base address>
  # typically changes with each launch. This in turn means that breakpoints in
  # Chrome.dll don't stick from one launch to the next. For this reason, we
  # turn ASLR off in debug builds.
  if (is_debug) {
    ldflags += [ "/DYNAMICBASE:NO" ]
  } else {
    ldflags += [ "/DYNAMICBASE" ]
  }

  # Delay loaded DLLs.
  ldflags += [
    "/DELAYLOAD:dbghelp.dll",
    "/DELAYLOAD:dwmapi.dll",
    "/DELAYLOAD:shell32.dll",
    "/DELAYLOAD:uxtheme.dll",
  ]
}

# Subsystem --------------------------------------------------------------------

# This is appended to the subsystem to specify a minimum version.
if (current_cpu == "x64") {
  # The number after the comma is the minimum required OS version.
  # 5.02 = Windows Server 2003.
  subsystem_version_suffix = ",5.02"
} else {
  # 5.01 = Windows XP.
  subsystem_version_suffix = ",5.01"
}

config("console") {
  ldflags = [ "/SUBSYSTEM:CONSOLE$subsystem_version_suffix" ]
}
config("windowed") {
  ldflags = [ "/SUBSYSTEM:WINDOWS$subsystem_version_suffix" ]
}

# Incremental linking ----------------------------------------------------------

incremental_linking_on_switch = [ "/INCREMENTAL" ]
incremental_linking_off_switch = [ "/INCREMENTAL:NO" ]

# Disable incremental linking for syzyasan
if (is_debug && !is_syzyasan) {
  default_incremental_linking_switch = incremental_linking_on_switch
} else {
  default_incremental_linking_switch = incremental_linking_off_switch
}

# Applies incremental linking or not depending on the current configuration.
config("default_incremental_linking") {
  ldflags = default_incremental_linking_switch
}

# Explicitly on or off incremental linking
config("incremental_linking") {
  ldflags = incremental_linking_on_switch
}
config("no_incremental_linking") {
  ldflags = incremental_linking_off_switch
}

# Some large modules can't handle incremental linking in some situations. This
# config should be applied to large modules to turn off incremental linking
# when it won't work.
config("default_large_module_incremental_linking") {
  if (symbol_level > 0 && (current_cpu == "x86" || !is_component_build)) {
    # When symbols are on, things get so large that the tools fail due to the
    # size of the .ilk files.
    ldflags = incremental_linking_off_switch
  } else {
    # Otherwise just do the default incremental linking for this build type.
    ldflags = default_incremental_linking_switch
  }
}

# Character set ----------------------------------------------------------------

# Not including this config means "ansi" (8-bit system codepage).
config("unicode") {
  defines = [
    "_UNICODE",
    "UNICODE",
  ]
}

# Lean and mean ----------------------------------------------------------------

# Some third party code might not compile with WIN32_LEAN_AND_MEAN so we have
# to have a separate config for it. Remove this config from your target to
# get the "bloaty and accomodating" version of windows.h.
config("lean_and_mean") {
  defines = [ "WIN32_LEAN_AND_MEAN" ]
}

# Nominmax --------------------------------------------------------------------

# Some third party code defines NOMINMAX before including windows.h, which
# then causes warnings when it's been previously defined on the command line.
# For such targets, this config can be removed.

config("nominmax") {
  defines = [ "NOMINMAX" ]
}

# Target WinRT ----------------------------------------------------------------

# When targeting Windows Runtime, certain compiler/linker flags are necessary.

config("target_winrt") {
  defines = [
    "WINRT",
    "WINAPI_FAMILY=WINAPI_FAMILY_PC_APP",
  ]
  cflags_cc = [
    "/ZW",
    "/EHsc",
  ]
}

# Internal stuff --------------------------------------------------------------

# Config used by the MIDL template to disable warnings.
config("midl_warnings") {
  if (is_clang) {
    # MIDL generates code like "#endif !_MIDL_USE_GUIDDEF_".
    cflags = [ "-Wno-extra-tokens" ]
  }
}