# Copyright 2018 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/arm.gni")
import("//build/config/sysroot.gni")
import("//build_overrides/build.gni")

declare_args() {
  # Enable OSP_DCHECKs to be compiled in, even if it's not a debug build.
  dcheck_always_on = false

  # Enable address sanitizer.
  is_asan = false

  # Enable thread sanitizer.
  is_tsan = false

  # Enables clang's source-based coverage (requires is_clang=true).
  # NOTE: This will slow down the build and increase binary size
  # significantly. For more details, see:
  # https://chromium.googlesource.com/chromium/src/+/refs/heads/master/docs/clang_code_coverage_wrapper.md
  use_coverage = false
}

assert(!use_coverage || is_clang)

config("compiler_defaults") {
  cflags = []
  if (is_posix && !is_mac) {
    cflags += [ "-fPIC" ]
  }

  ldflags = []
  if (is_linux) {
    ldflags += [ "-pthread" ]
  }
  if (is_posix && !is_mac) {
    ldflags += [ "-Wl,--fatal-warnings" ]

    if (is_clang) {
      ldflags += [
        "-stdlib=libstdc++",
        "-latomic",
      ]
    }
  }
}

config("compiler_cpu_abi") {
  cflags = []
  ldflags = []

  if (current_cpu == "x64") {
    # These are explicitly specified in case of cross-compiling.
    cflags += [ "-m64" ]
    ldflags += [ "-m64" ]
  } else if (current_cpu == "x86") {
    cflags += [ "-m32" ]
    ldflags += [ "-m32" ]
  } else if (current_cpu == "arm") {
    cflags += [
      "--target=arm-linux-gnueabihf",
      "-march=$arm_arch",
      "-mfloat-abi=$arm_float_abi",
      "-mtune=$arm_tune",
    ]
    ldflags += [ "--target=arm-linux-gnueabihf" ]
  } else if (current_cpu == "arm64") {
    cflags += [ "--target=aarch64-linux-gnu" ]
    ldflags += [ "--target=aarch64-linux-gnu" ]
  }
}

config("no_exceptions") {
  # -fno-exceptions causes the compiler to choose the implementation of the STL
  # that uses abort() calls instead of throws, as well as issue compile errors
  # for throw calls in user ccode. The no*unwind-tables flags disable generation
  # of static unwind tables that are typically used for exceptions, resulting
  # in typically smaller object sizes. For some information, see:
  # https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#index-funwind-tables-1203
  cflags_cc = [
    "-fno-exceptions",
    "-fno-unwind-tables",
    "-fno-asynchronous-unwind-tables",
  ]

  cflags_objcc = [
    "-fno-exceptions",
    "-fno-unwind-tables",
    "-fno-asynchronous-unwind-tables",
  ]
}

config("no_rtti") {
  cflags_cc = [ "-fno-rtti" ]
  cflags_objcc = [ "-fno-rtti" ]
}

config("openscreen_code") {
  cflags = [
    "-Wall",
    "-Werror",
    "-fno-strict-aliasing",  # See http://crbug.com/32204
  ]

  cflags_cc = [ "-std=c++14" ]
  cflags_objcc = [ "-std=c++14" ]

  ldflags = [ "-Werror" ]

  if (is_gcc) {
    cflags += [ "-Wno-maybe-uninitialized" ]
    cflags_cc += [
      # GCC 7.2 reports noexcept errors that are not found in GCC 8.
      # TODO(crbug.com/openscreen/40): Remove this when bots are upgraded to
      # >= GCC 8.3.
      "-Wno-noexcept-type",
    ]
  }

  if (is_clang) {
    cflags += [
      "-Wextra",
      "-fcolor-diagnostics",

      # Warn on missing break statements at the end of switch cases.
      "-Wimplicit-fallthrough",

      # Unused function parameters are okay (e.g., empty virtual method
      # overrides).
      "-Wno-unused-parameter",

      # Permit code like "struct foo f = {0};".
      "-Wno-missing-field-initializers",

      # Warn on signed versus unsigned comparisons.
      "-Wsign-compare",

      # Warn on extra semi-colons.
      "-Wextra-semi",

      # Warn on unused results.
      "-Wunused-result",
    ]

    # Generate warning if code generates exit-time destructors, since such
    # things are in violation of Chromium C++ Don'ts.
    cflags_cc += [ "-Wexit-time-destructors" ]
    cflags_objcc += [ "-Wexit-time-destructors" ]

    ldflags += [ "-fcolor-diagnostics" ]
  }

  defines = []
  if (dcheck_always_on) {
    defines += [ "DCHECK_ALWAYS_ON" ]
  } else if (!is_debug) {
    # C-style assertions in the standard library should match the behavior of
    # OSP_DCHECKs. Thus, turn them off whenever OSP_DCHECKs would be turned off.
    defines += [ "NDEBUG" ]
  }
}

config("default_optimization") {
  cflags = []
  defines = []
  if (is_debug) {
    cflags += [
      "-O0",
      "-g3",  # Include extra debugging information.
      "-fstack-protector-strong",
    ]
    defines += [ "_DEBUG" ]
  } else {
    cflags += [
      "-O2",
      "-g1",  # Minimal symbols (enough for stack traces).
      "-fstack-protector",
    ]
  }
}

config("symbol_visibility_hidden") {
  cflags = [ "-fvisibility=hidden" ]
}

config("symbol_visibility_default") {
  cflags = [ "-fvisibility=default" ]
}

config("default_sanitizers") {
  # NOTE: This is not an artificial restriction; clang doesn't allow these to be
  # used together.
  assert(!is_asan || !is_tsan)

  cflags = []
  ldflags = []
  if (is_asan) {
    cflags += [ "-fsanitize=address" ]
    ldflags += [ "-fsanitize=address" ]
  } else if (is_tsan) {
    cflags += [ "-fsanitize=thread" ]
    ldflags += [ "-fsanitize=thread" ]
  }

  if (use_libfuzzer) {
    cflags += [ "-fsanitize=fuzzer-no-link" ]
    if (!is_asan) {
      ldflags += [ "-fsanitize=address" ]
    }
  }
}

config("default_coverage") {
  cflags = []
  ldflags = []

  # TODO(issuetracker.google.com/155348032): Limit the use of these flags
  if (use_coverage) {
    cflags += [
      "-fprofile-instr-generate",
      "-fcoverage-mapping",
    ]
    ldflags += [ "-fprofile-instr-generate" ]
  }
}

config("sysroot_runtime_libraries") {
  if (sysroot != "") {
    assert(is_clang)
    sysroot_path = rebase_path(sysroot, root_build_dir)
    flags = [ "--sysroot=" + sysroot_path ]
    hash = exec_script("//build/scripts/install-sysroot.py",
                       [
                         "--print-hash",
                         "$current_cpu",
                         "$sysroot_platform",
                       ],
                       "trim string",
                       [ "//build/scripts/sysroots.json" ])

    # GN uses this to know that the sysroot is "dirty"
    defines = [ "SYSROOT_HASH=$hash" ]
    ldflags = flags
    cflags = flags

    ld_paths = exec_script("//build/scripts/sysroot_ld_path.py",
                           [ sysroot_path ],
                           "list lines")
    foreach(ld_path, ld_paths) {
      ld_path = rebase_path(ld_path, root_build_dir)
      ldflags += [ "-L" + ld_path ]
    }
  }
}

config("operating_system_defines") {
  defines = []
  if (is_linux) {
    defines += [ "OS_LINUX" ]
  } else if (is_mac) {
    defines += [ "MAC_OSX" ]
  }
}
