# Copyright 2016 Google Inc.
#
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

declare_args() {
  extra_asmflags = []
  extra_cflags = []
  extra_cflags_c = []
  extra_cflags_cc = []
  extra_ldflags = []

  malloc = ""
}

if (is_ios) {
  if (is_tvos) {
    sdk = "appletvos"
    if (target_cpu == "x86" || target_cpu == "x64") {
      sdk = "appletvsimulator"
    }
  } else {
    sdk = "iphoneos"
    if (target_cpu == "x86" || target_cpu == "x64") {
      sdk = "iphonesimulator"
    }
  }
  ios_sysroot = exec_script("find_ios_sysroot.py", [ sdk ], "trim string")
}

config("default") {
  asmflags = []
  cflags = []
  cflags_c = []
  cflags_cc = []
  defines = []
  ldflags = []
  libs = []

  if (is_win) {
    cflags += [
      "/bigobj",  # Some of our files are bigger than the regular limits.
      "/WX",  # Treat warnings as errors.
      "/utf-8",  # Set Source and Executable character sets to UTF-8.
    ]
    if (is_clang) {
      cflags += [ "-fms-compatibility-version=19" ]  # 2015
    }
    defines += [
      "_CRT_SECURE_NO_WARNINGS",  # Disables warnings about sscanf().
      "_HAS_EXCEPTIONS=0",  # Disables exceptions in MSVC STL.
      "WIN32_LEAN_AND_MEAN",
      "NOMINMAX",
    ]

    if (msvc == 2015) {
      _include_dirs = [ "$win_vc/include" ]
    } else {  # 2017
      _include_dirs = [ "$win_vc/Tools/MSVC/$win_toolchain_version/include" ]
    }
    _include_dirs += [
      "$win_sdk/Include/$win_sdk_version/shared",
      "$win_sdk/Include/$win_sdk_version/ucrt",
      "$win_sdk/Include/$win_sdk_version/um",
      "$win_sdk/Include/$win_sdk_version/winrt",
    ]

    if (is_clang) {
      foreach(dir, _include_dirs) {
        cflags += [
          "-imsvc",
          dir,
        ]
      }
    } else {
      include_dirs = _include_dirs
    }

    lib_dirs = [
      "$win_sdk/Lib/$win_sdk_version/ucrt/$target_cpu",
      "$win_sdk/Lib/$win_sdk_version/um/$target_cpu",
    ]
    if (msvc == 2015) {
      if (target_cpu == "x86") {
        lib_dirs += [ "$win_vc/lib" ]
      } else {
        lib_dirs += [ "$win_vc/lib/amd64" ]
      }
    } else {  # 2017
      lib_dirs +=
          [ "$win_vc/Tools/MSVC/$win_toolchain_version/lib/$target_cpu" ]
    }
  } else {
    cflags += [
      "-fstrict-aliasing",
      "-fPIC",
      "-Werror",
    ]
    cflags_cc += [ "-std=c++11" ]

    # The main idea is to slim the exported API, but these flags also improve link time on Mac.
    # These would make stack traces worse on Linux, so we don't just set them willy-nilly.
    if (is_component_build || is_ios || is_mac) {
      cflags += [ "-fvisibility=hidden" ]
      cflags_cc += [ "-fvisibility-inlines-hidden" ]
    }
  }

  if (current_cpu == "arm") {
    cflags += [
      "-march=armv7-a",
      "-mfpu=neon",
      "-mthumb",
    ]
  } else if (current_cpu == "x86" && !is_win) {
    asmflags += [ "-m32" ]
    cflags += [
      "-m32",
      "-msse2",
      "-mfpmath=sse",
    ]
    ldflags += [ "-m32" ]
  }

  if (malloc != "" && !is_win) {
    cflags += [
      "-fno-builtin-malloc",
      "-fno-builtin-calloc",
      "-fno-builtin-realloc",
      "-fno-builtin-free",
    ]
    libs += [ malloc ]
  }

  if (is_android) {
    asmflags += [ "--target=$ndk_target" ]
    cflags += [
      "--sysroot=$ndk/sysroot",
      "-isystem$ndk/sysroot/usr/include/$ndk_target",
      "-D__ANDROID_API__=$ndk_api",
      "--target=$ndk_target",
    ]
    cflags_cc += [
      "-isystem$ndk/sources/cxx-stl/llvm-libc++/include",
      "-isystem$ndk/sources/cxx-stl/llvm-libc++abi/include",
      "-isystem$ndk/sources/android/support/include",
    ]
    ldflags += [
      "--sysroot=$ndk/platforms/$ndk_platform",
      "--target=$ndk_target",
      "-B$ndk/toolchains/$ndk_gccdir-4.9/prebuilt/$ndk_host/$ndk_target/bin",
    ]
    lib_dirs = [
      "$ndk/sources/cxx-stl/llvm-libc++/libs/$ndk_stdlib",
      "$ndk/toolchains/$ndk_gccdir-4.9/prebuilt/$ndk_host/lib/gcc/$ndk_target/4.9.x",
    ]

    libs += [
      "c++_static",
      "c++abi",
      "android_support",
    ]
  }

  if (is_ios) {
    _target = target_cpu
    if (target_cpu == "arm") {
      _target = "armv7"
    } else if (target_cpu == "x86") {
      _target = "i386"
    } else if (target_cpu == "x64") {
      _target = "x86_64"
    }
    asmflags += [
      "-isysroot",
      ios_sysroot,
      "-arch",
      _target,
    ]
    cflags += [
      "-isysroot",
      ios_sysroot,
      "-arch",
      _target,
    ]
    cflags_cc += [ "-stdlib=libc++" ]
    ldflags += [
      "-isysroot",
      ios_sysroot,
      "-arch",
      _target,
      "-stdlib=libc++",
    ]
    libs += [ "objc" ]
  }

  if (is_linux) {
    libs += [ "pthread" ]
  }
  if (is_mac) {
    # Disable linker warnings.  They're usually just annoyances like,
    #   ld: warning: text-based stub file
    #     /System/Library/Frameworks/foo.framework/foo.tbd and library file
    #     /System/Library/Frameworks/foo.framework/foo are out of sync.
    #     Falling back to library file for linking.
    ldflags += [ "-Wl,-w" ]
  }

  if (sanitize != "") {
    # You can either pass the sanitizers directly, e.g. "address,undefined",
    # or pass one of the couple common aliases used by the bots.
    sanitizers = sanitize
    if (sanitize == "ASAN" || sanitize == "UBSAN") {
      # ASAN implicitly runs all UBSAN checks also.
      sanitizers = "bool,float-cast-overflow,integer-divide-by-zero,nonnull-attribute,null,return,returns-nonnull-attribute,shift,signed-integer-overflow,unreachable,vla-bound"
      if (!is_mac && !is_win) {
        sanitizers += ",function"  # Not supported on Mac or Win.
      }
      if (!is_win) {
        sanitizers += ",vptr"  # Not supported on Win.
      }
      if (!is_debug && !is_win) {
        # No-op with somewhat annoying warning at -O0.
        # Seems to be broken on Win.
        sanitizers += ",object-size"
      }
      if (sanitize == "ASAN") {
        sanitizers += ",address"
      }
      if (is_android) {
        # Android only easily supports address for now
        # UBSAN runs into linking errors
        sanitizers = "address"

        # recommended by
        # https://github.com/google/sanitizers/wiki/AddressSanitizerOnAndroid
        cflags += [ "-fno-omit-frame-pointer" ]
      }
    } else if (sanitize == "TSAN") {
      sanitizers = "thread"
    } else if (sanitize == "MSAN") {
      sanitizers = "memory"
    }

    cflags += [
      "-fsanitize=$sanitizers",
      "-fno-sanitize-recover=$sanitizers",
    ]
    if (!is_win) {
      cflags += [ "-fno-omit-frame-pointer" ]
    }
    if (is_linux) {
      cflags_cc += [ "-stdlib=libc++" ]
      ldflags += [ "-stdlib=libc++" ]
    }
    ldflags += [ "-fsanitize=$sanitizers" ]
    if (sanitizers == "memory") {
      cflags += [ "-fsanitize-memory-track-origins" ]
    }
  }
}

config("no_exceptions") {
  # Exceptions are disabled by default on Windows.  (Use /EHsc to enable them.)
  if (!is_win) {
    cflags_cc = [ "-fno-exceptions" ]
  }
}

config("warnings") {
  cflags = []
  cflags_cc = []
  cflags_objc = []
  cflags_objcc = []
  if (is_win) {
    cflags += [
      "/W3",  # Turn on lots of warnings.

      # Disable a bunch of warnings:
      "/wd4244",  # conversion from 'float' to 'int', possible loss of data
      "/wd4267",  # conversion from 'size_t' to 'int', possible loss of data
      "/wd4800",  # forcing value to bool 'true' or 'false' (performance warning)

      # Probably only triggers when /EHsc is enabled.
      "/wd4291",  # no matching operator delete found;
                  # memory will not be freed if initialization throws an exception
    ]
  } else {
    cflags += [
      "-Wall",
      "-Wextra",
      "-Winit-self",
      "-Wpointer-arith",
      "-Wsign-compare",
      "-Wvla",

      "-Wno-deprecated-declarations",
      "-Wno-maybe-uninitialized",
    ]
    cflags_cc += [ "-Wnon-virtual-dtor" ]
  }

  if (is_clang) {
    cflags += [
      "-Weverything",
      "-Wno-unknown-warning-option",  # Let older Clangs ignore newer Clangs' warnings.
    ]

    if (target_cpu == "arm" && is_ios) {
      # Clang seems to think new/malloc will only be 4-byte aligned on 32-bit iOS.
      # We're pretty sure it's actually 8-byte alignment.
      cflags += [ "-Wno-over-aligned" ]
    }
    if (target_cpu == "x86" && is_android) {
      # Clang seems to think new/malloc will only be 4-byte aligned on 32-bit x86 Android builds.
      # We're pretty sure it's actually 8-byte alignment.  See OverAlignedTest.cpp for more info.
      cflags += [ "-Wno-over-aligned" ]
    }

    # Shouldn't be necessary for local builds. With distributed Windows builds, files may lose
    # their case during copy, causing case-sensitivity mismatch on remote machines.
    cflags += [
      "-Wno-nonportable-include-path",
      "-Wno-nonportable-system-include-path",
    ]

    # TODO: These would all be really great warnings to turn on.
    cflags += [
      "-Wno-cast-align",
      "-Wno-cast-qual",
      "-Wno-conversion",
      "-Wno-disabled-macro-expansion",
      "-Wno-documentation",
      "-Wno-documentation-unknown-command",
      "-Wno-double-promotion",
      "-Wno-exit-time-destructors",  # TODO: OK outside libskia
      "-Wno-float-equal",
      "-Wno-format-nonliteral",
      "-Wno-global-constructors",  # TODO: OK outside libskia
      "-Wno-missing-prototypes",
      "-Wno-missing-variable-declarations",
      "-Wno-pedantic",
      "-Wno-reserved-id-macro",
      "-Wno-shadow",
      "-Wno-shift-sign-overflow",
      "-Wno-signed-enum-bitfield",
      "-Wno-switch-enum",
      "-Wno-undef",
      "-Wno-unreachable-code",
      "-Wno-unreachable-code-break",
      "-Wno-unreachable-code-return",
      "-Wno-unused-macros",
      "-Wno-unused-member-function",
      "-Wno-unused-template",
      "-Wno-zero-as-null-pointer-constant",
    ]
    cflags_cc += [
      "-Wno-abstract-vbase-init",
      "-Wno-weak-vtables",
    ]

    # We are unlikely to want to fix these.
    cflags += [
      "-Wno-covered-switch-default",
      "-Wno-deprecated",
      "-Wno-missing-noreturn",
      "-Wno-old-style-cast",
      "-Wno-padded",
      "-Wno-newline-eof",
    ]
    cflags_cc += [
      "-Wno-c++98-compat",
      "-Wno-c++98-compat-pedantic",
      "-Wno-undefined-func-template",
    ]
    cflags_objc += [
      "-Wno-direct-ivar-access",
      "-Wno-objc-interface-ivars",
    ]
    cflags_objcc += [
      "-Wno-direct-ivar-access",
      "-Wno-objcc-interface-ivars",
    ]
  }
  if (!is_win || is_clang) {
    cflags += [ "-Wno-implicit-fallthrough" ]
  }
}
config("warnings_except_public_headers") {
  if (!is_win || is_clang) {
    cflags = [ "-Wno-unused-parameter" ]
  }
}

config("extra_flags") {
  asmflags = extra_asmflags
  cflags = extra_cflags
  cflags_c = extra_cflags_c
  cflags_cc = extra_cflags_cc
  ldflags = extra_ldflags
}

config("debug_symbols") {
  # It's annoying to wait for full debug symbols to push over
  # to Android devices.  -gline-tables-only is a lot slimmer.
  if (is_android) {
    cflags = [
      "-gline-tables-only",
      "-funwind-tables",  # Helps make in-process backtraces fuller.
    ]
  } else if (is_win) {
    cflags = [ "/Z7" ]
    ldflags = [ "/DEBUG:FASTLINK" ]
  } else {
    cflags = [ "-g" ]
  }
}

config("no_rtti") {
  if (sanitize != "ASAN") {  # -fsanitize=vptr requires RTTI
    if (is_win) {
      cflags_cc = [ "/GR-" ]
    } else {
      cflags_cc = [ "-fno-rtti" ]
    }
  }
}

config("release") {
  if (is_win) {
    cflags = [
      "/O2",
      "/Zc:inline",
    ]
    ldflags = [
      "/OPT:ICF",
      "/OPT:REF",
    ]
  } else {
    cflags = [
      "-O3",
      "-fdata-sections",
      "-ffunction-sections",
    ]
    if (is_mac || is_ios) {
      ldflags = [ "-dead_strip" ]
    } else {
      ldflags = [ "-Wl,--gc-sections" ]
    }
    if (target_cpu == "wasm") {
      # The compiler asks us to add an optimization flag to both cflags
      # and ldflags to cut down on the local variables,
      # for performance reasons.
      # The "linking" step is the conversion to javascript.
      ldflags += [ "-O3" ]
    }
  }
  defines = [ "NDEBUG" ]
}

config("executable") {
  if (is_android) {
    ldflags = [
      "-pie",
      "-rdynamic",
    ]
  } else if (is_mac) {
    ldflags = [ "-Wl,-rpath,@loader_path/." ]
  } else if (is_linux) {
    ldflags = [
      "-rdynamic",
      "-Wl,-rpath,\$ORIGIN",
    ]
  } else if (is_win) {
    ldflags = [
      "/SUBSYSTEM:CONSOLE",  # Quiet "no subsystem specified; CONSOLE assumed".
      "/INCREMENTAL:NO",  # Quiet warnings about failing to incrementally link by never trying to.
    ]
  }
}