# 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/c++/c++.gni")
import("//build/config/sanitizers/sanitizers.gni")
import("//build/toolchain/toolchain.gni")
import("//arkweb/build/config/sanitizers/sanitizers.gni")
import("//buildtools/third_party/libc++/libcxx_headers.gni")
import("//buildtools/third_party/libc++/modules.gni")

if (is_mac) {
  import("//build/config/mac/mac_sdk.gni")
}

# Used by libc++ and libc++abi.
# See //build/config/c++:runtime_library for the config used by users of libc++.
config("config") {
  configs = [
    ":extra_flags",
    ":stdver",
  ]
}

config("extra_flags") {
  cflags = [
    "-fstrict-aliasing",
    "-Wundef",
  ]
  if (is_win) {
    cflags += [
      # libc++ wants to redefine the macros WIN32_LEAN_AND_MEAN and _CRT_RAND_S
      # in its implementation.
      "-Wno-macro-redefined",
    ]
  } else {
    cflags += [ "-fPIC" ]
  }
  defines = [ "_LIBCPP_BUILDING_LIBRARY" ]
}

config("stdver") {
  if (is_win) {
    cflags_cc = [
      # We want to use a uniform C++ version across all of chromium, but
      # upstream libc++ requires C++23 so we have to make an exception here.
      # No other target should override the default -std= flag.
      "-std:c++23preview",
    ]
  } else {
    cflags_cc = [ "-std=c++23" ]
  }
}

# Explicitly set version macros to Windows 7 to prevent libc++ from adding a
# hard dependency on GetSystemTimePreciseAsFileTime, which was introduced in
# Windows 8.
config("winver") {
  defines = [
    "NTDDI_VERSION=NTDDI_WIN7",
    "_WIN32_WINNT=_WIN32_WINNT_WIN7",
    "WINVER=_WIN32_WINNT_WIN7",
  ]
}

config("builtin_modulemap") {
  cflags_cc = [ clang_arg_prefix + "-fbuiltin-module-map" ]
}

modulemap_config("libcxx_modulemap") {
  source =
      "${root_build_dir}/gen/third_party/libc++/src/include/module.modulemap"
}

if (current_toolchain == default_toolchain) {
  # The Clang modules build requires libc++ headers, __assertion_handler, and
  # __config_site to be in the same directory.
  #
  # To avoid redundant work, the copy targets are declared only in the default
  # toolchain. This prevents unnecessary copies in multi-toolchain builds and
  # allows Siso to use its precomputed tree for the default toolchain's `gen`
  # directory.
  #
  # Note: there are setups where clang_modules is enabled for some, but not all,
  # toolchains (see https://crrev.com/c/6849070). So, this copy must happen
  # unconditionally.
  copy("copy_libcxx_headers") {
    sources = libcxx_headers
    outputs = [ "{{source_gen_dir}}/{{source_file_part}}" ]

    # Rely on `:libcxx_headers` instead: it abstract away the default toolchain
    # optimization and the internal copy.
    visibility = [ ":libcxx_headers" ]
  }

  # Note: there are setups where clang_modules is enabled for some, but not all,
  # toolchains (see https://crrev.com/c/6849070). So, this copy must happen
  # unconditionally.
  copy("copy_custom_headers") {
    sources = [
      "__assertion_handler",
      "__config_site",
    ]
    outputs = [
      "${root_gen_dir}/third_party/libc++/src/include/{{source_file_part}}",
    ]

    # Rely on `:custom_headers` instead: it abstract away the default toolchain
    # optimization and the internal copy.
    visibility = [ ":custom_headers" ]
  }
}

# TODO(https://crbug.com/440260716): This intermediate target can be removed
# once Cronet's gn2bp supports copy targets with multiple outputs.
group("libcxx_headers") {
  if (use_clang_modules) {
    deps = [ ":copy_libcxx_headers($default_toolchain)" ]
  }
}

# TODO(https://crbug.com/440260716): This intermediate target can be removed
# once Cronet's gn2bp supports copy targets with multiple outputs.
group("custom_headers") {
  if (use_clang_modules) {
    deps = [ ":copy_custom_headers($default_toolchain)" ]
  }
}

if (use_clang_modules && use_xcode_symlinks && !use_autogenerated_modules) {
  # sysroot_modulemaps can be inside the build directory. This no-op action
  # declares the modulemap files as outputs to satisfy GN's dependency
  # tracking when other targets use them as inputs.
  action("copy_sysroot_modulemaps") {
    script = "//build/noop.py"
    outputs = sysroot_modulemaps
  }
}

if (use_autogenerated_modules && use_clang_modules) {
  group("all_modules") {
    # If this doesn't exist, you'll need to run build/modules/modularize.py for that platform.
    public_deps = [ "//build/modules/${module_platform}:all_modules" ]
    public_configs = [ "//build/config/compiler:libcxx_module" ]
  }

  config("all_modulemap_configs") {
    configs = [ "//build/modules/${module_platform}:all_modulemap_configs" ]
  }
} else if (use_clang_modules) {
  if (is_apple) {
    DarwinBasic_module("MachO") {
      public_deps = [
        ":_Builtin_stdbool",
        ":_Builtin_stdint",
        ":_DarwinFoundation3",
        ":std_string_h",
      ]
    }

    DarwinFoundation1_module("_DarwinFoundation1") {
      public_deps = [ ":_AvailabilityInternal" ]
    }
    DarwinFoundation1_module("_AvailabilityInternal") {
    }
    DarwinFoundation2_module("_DarwinFoundation2") {
      public_deps = [
        ":_Builtin_stdarg",
        ":_Builtin_stddef",
        ":_DarwinFoundation1",
      ]
    }
    DarwinFoundation2_module("alloca") {
      public_deps = [ ":_DarwinFoundation2" ]
    }
    DarwinFoundation3_module("_DarwinFoundation3") {
      public_deps = [
        ":_Builtin_stdint",
        ":_DarwinFoundation2",
        ":std_ctype_h",
      ]
    }
    DarwinFoundation3_module("xlocale") {
      public_deps = [
        ":_DarwinFoundation1",
        ":_DarwinFoundation2",
      ]
    }

    group("all_sysroot") {
      public_deps = [
        ":MachO",
        ":_AvailabilityInternal",
        ":_DarwinFoundation1",
        ":_DarwinFoundation2",
        ":_DarwinFoundation3",
        ":alloca",
        ":xlocale",
      ]
    }

    group("sysroot_ctype") {
      public_deps = [ ":_DarwinFoundation2" ]
    }
    group("sysroot_errno") {
      public_deps = [ ":_DarwinFoundation1" ]
    }
    group("sysroot_fenv") {
      public_deps = [ ":_DarwinFoundation1" ]
    }
    group("sysroot_inttypes") {
      public_deps = [ ":_DarwinFoundation3" ]
    }
    group("sysroot_limits") {
      public_deps = [ ":_DarwinFoundation1" ]
    }
    group("sysroot_locale") {
    }
    group("sysroot_math") {
    }
    group("sysroot_pthread") {
    }
    group("sysroot_stdatomic") {
      public_deps = []
    }
    group("sysroot_stdint") {
      public_deps = [ ":_DarwinFoundation2" ]
    }
    group("sysroot_stdlib") {
      public_deps = [ ":_DarwinFoundation3" ]
    }
    group("sysroot_string") {
      public_deps = [ ":_DarwinFoundation2" ]
    }
    group("sysroot_uchar") {
      public_deps = []
    }
    group("sysroot_wchar") {
      public_deps = [ ":_DarwinFoundation3" ]
    }
    group("sysroot_wctype") {
      public_deps = [ ":_DarwinFoundation3" ]
    }
  }

  builtin_module("_Builtin_float") {
  }

  builtin_module("_Builtin_intrinsics") {
    public_deps = [
      ":std_core",
      ":sysroot_stdlib",
    ]
    if (current_cpu == "arm" || current_cpu == "arm64") {
      # <arm_acle.h> includes <stdint.h> which requires _Builtin_stdint module.
      public_deps += [ ":_Builtin_stdint" ]
    }
  }

  builtin_module("_Builtin_inttypes") {
    public_deps = [ ":sysroot_inttypes" ]
  }

  builtin_module("_Builtin_limits") {
    public_deps = [
      ":std_float_h",
      ":sysroot_limits",
    ]
  }

  builtin_module("_Builtin_stdalign") {
  }

  builtin_module("_Builtin_stdarg") {
  }

  builtin_module("_Builtin_stdatomic") {
    public_deps = [
      ":_Builtin_stddef",
      ":_Builtin_stdint",
      ":sysroot_stdatomic",
    ]
  }

  builtin_module("_Builtin_stdbool") {
  }

  builtin_module("_Builtin_stddef") {
  }

  builtin_module("_Builtin_stdint") {
    public_deps = [ ":sysroot_stdint" ]
  }

  builtin_module("_Builtin_unwind") {
    public_deps = [ ":_Builtin_stdint" ]
  }

  builtin_module("ptrauth") {
  }

  group("all_builtins") {
    public_deps = [
      "//buildtools/third_party/libc++:_Builtin_float",
      "//buildtools/third_party/libc++:_Builtin_intrinsics",
      "//buildtools/third_party/libc++:_Builtin_inttypes",
      "//buildtools/third_party/libc++:_Builtin_limits",
      "//buildtools/third_party/libc++:_Builtin_stdalign",
      "//buildtools/third_party/libc++:_Builtin_stdarg",
      "//buildtools/third_party/libc++:_Builtin_stdatomic",
      "//buildtools/third_party/libc++:_Builtin_stdbool",
      "//buildtools/third_party/libc++:_Builtin_stddef",
      "//buildtools/third_party/libc++:_Builtin_stdint",
      "//buildtools/third_party/libc++:_Builtin_unwind",
      "//buildtools/third_party/libc++:ptrauth",
    ]
  }

  libcxx_module("std") {
    public_deps = [
      ":_Builtin_limits",
      ":_Builtin_stdalign",
      ":std_core",
      ":std_ctype_h",
      ":std_errno_h",
      ":std_fenv_h",
      ":std_float_h",
      ":std_inttypes_h",
      ":std_math_h",
      ":std_private_mbstate_t",
      ":std_string_h",
      ":std_uchar_h",
      ":std_wctype_h",
      ":sysroot_locale",
      ":sysroot_pthread",
    ]
    if (is_apple) {
      public_deps += [
        # __locale_dir/support/apple.h includes __locale_dir/support/bsd_like.h,
        #  which includes xlocale.h.
        ":xlocale",
      ]
    }
  }

  textual_module("std_config") {
  }

  libcxx_module("std_core") {
    public_deps = [
      ":_Builtin_stddef",
      ":_Builtin_stdint",
      ":std_config",
    ]
  }

  libcxx_module("std_ctype_h") {
    public_deps = [
      ":std_config",
      ":sysroot_ctype",
    ]
  }

  libcxx_module("std_errno_h") {
    public_deps = [
      ":std_config",
      ":sysroot_errno",
    ]
  }

  libcxx_module("std_fenv_h") {
    public_deps = [
      ":std_config",
      ":sysroot_fenv",
    ]
  }

  libcxx_module("std_float_h") {
    public_deps = [
      ":_Builtin_float",
      ":std_config",
    ]
  }

  libcxx_module("std_inttypes_h") {
    public_deps = [
      ":_Builtin_inttypes",
      ":std_config",
    ]
  }

  libcxx_module("std_math_h") {
    public_deps = [
      ":std_core",
      ":sysroot_math",
      ":sysroot_stdlib",
    ]
  }

  libcxx_module("std_private_mbstate_t") {
    public_deps = [
      ":std_config",
      ":sysroot_wchar",
    ]
  }

  libcxx_module("std_stdatomic_h") {
    public_deps = [
      ":_Builtin_stdatomic",
      ":std_config",
      ":sysroot_stdint",
    ]
  }

  libcxx_module("std_string_h") {
    public_deps = [
      ":std_config",
      ":sysroot_string",
    ]
  }

  libcxx_module("std_uchar_h") {
    public_deps = [
      ":std_private_mbstate_t",
      ":sysroot_uchar",
    ]
  }

  libcxx_module("std_wctype_h") {
    public_deps = [
      ":std_config",
      ":sysroot_wctype",
    ]
  }

  group("all_std") {
    # There are more modules than this, but since the others are purely
    # textual, they don't need to be compiled to a pcm.
    public_deps = [
      ":std",
      ":std_core",
      ":std_ctype_h",
      ":std_errno_h",
      ":std_fenv_h",
      ":std_float_h",
      ":std_inttypes_h",
      ":std_math_h",
      ":std_private_mbstate_t",
      ":std_stdatomic_h",
      ":std_string_h",
      ":std_uchar_h",
      ":std_wctype_h",
    ]
  }

  config("sysroot_modulemaps") {
    cflags_cc = []
    foreach(modulemap, sysroot_modulemaps) {
      cflags_cc +=
          [ "-fmodule-map-file=" + rebase_path(modulemap, root_build_dir) ]
    }
  }

  group("all_modules") {
    public_deps = [
      ":all_builtins",
      ":all_std",
      ":all_sysroot",
    ]
    public_configs = [ "//build/config/compiler:libcxx_module" ]
  }
} else {
  # This is a no-op target for when use_clang_modules = false. It is
  # still referenced in BUILDCONFIG.gn.
  group("all_modules") {
  }
}

target(libcxx_target_type, "libc++") {
  # Most things that need to depend on libc++ should do so via the implicit
  # 'common_deps' dependency below.  Some targets that package libc++.so may
  # need to explicitly depend on libc++.
  visibility = [
    "//build/config:common_deps",
    "//third_party/catapult/devil",
  ]
  if (is_linux) {
    # This target packages libc++.so, so must have an explicit dependency on
    # libc++.
    visibility +=
        [ "//remoting/host/linux:remoting_me2me_host_copy_user_session" ]
  }
  if (build_with_chromium && is_win && is_component_build) {
    # PartitionAlloc uses no_default_deps=true when is_win && is_component_build
    # but it depends on libc++. So need to add an explicit dependency on
    # libc++.
    visibility +=
        [ "//base/allocator/partition_allocator/src/partition_alloc:*" ]
  }
  if (libcxx_is_shared) {
    no_default_deps = true
  }

  if (is_linux && !is_clang) {
    libs = [ "atomic" ]
  }

  inputs = [
    "__assertion_handler",
    "__config_site",
  ]

  # TODO(crbug.com/40273848): Move this build file to third_party/libc++/BUILD.gn
  # once submodule migration is done.
  sources = [
    "//third_party/libc++/src/src/algorithm.cpp",
    "//third_party/libc++/src/src/any.cpp",
    "//third_party/libc++/src/src/atomic.cpp",
    "//third_party/libc++/src/src/barrier.cpp",
    "//third_party/libc++/src/src/bind.cpp",
    "//third_party/libc++/src/src/call_once.cpp",
    "//third_party/libc++/src/src/charconv.cpp",
    "//third_party/libc++/src/src/chrono.cpp",
    "//third_party/libc++/src/src/condition_variable.cpp",
    "//third_party/libc++/src/src/condition_variable_destructor.cpp",
    "//third_party/libc++/src/src/error_category.cpp",
    "//third_party/libc++/src/src/exception.cpp",
    "//third_party/libc++/src/src/filesystem/directory_iterator.cpp",
    "//third_party/libc++/src/src/filesystem/filesystem_error.cpp",
    "//third_party/libc++/src/src/filesystem/operations.cpp",
    "//third_party/libc++/src/src/filesystem/path.cpp",
    "//third_party/libc++/src/src/functional.cpp",
    "//third_party/libc++/src/src/future.cpp",
    "//third_party/libc++/src/src/hash.cpp",
    "//third_party/libc++/src/src/ios.cpp",
    "//third_party/libc++/src/src/ios.instantiations.cpp",
    "//third_party/libc++/src/src/iostream.cpp",
    "//third_party/libc++/src/src/locale.cpp",
    "//third_party/libc++/src/src/memory.cpp",
    "//third_party/libc++/src/src/mutex.cpp",
    "//third_party/libc++/src/src/mutex_destructor.cpp",
    "//third_party/libc++/src/src/new_handler.cpp",
    "//third_party/libc++/src/src/new_helpers.cpp",
    "//third_party/libc++/src/src/optional.cpp",
    "//third_party/libc++/src/src/random.cpp",
    "//third_party/libc++/src/src/random_shuffle.cpp",
    "//third_party/libc++/src/src/regex.cpp",
    "//third_party/libc++/src/src/ryu/d2fixed.cpp",
    "//third_party/libc++/src/src/ryu/d2s.cpp",
    "//third_party/libc++/src/src/ryu/f2s.cpp",
    "//third_party/libc++/src/src/shared_mutex.cpp",
    "//third_party/libc++/src/src/stdexcept.cpp",
    "//third_party/libc++/src/src/string.cpp",
    "//third_party/libc++/src/src/strstream.cpp",
    "//third_party/libc++/src/src/system_error.cpp",
    "//third_party/libc++/src/src/thread.cpp",
    "//third_party/libc++/src/src/typeinfo.cpp",
    "//third_party/libc++/src/src/valarray.cpp",
    "//third_party/libc++/src/src/variant.cpp",
    "//third_party/libc++/src/src/vector.cpp",
    "//third_party/libc++/src/src/verbose_abort.cpp",
  ]

  if (is_apple || (!is_asan && !is_tsan && !is_msan)) {
    # In {a,t,m}san configurations, operator new and operator delete will be
    # provided by the sanitizer runtime library.  Since libc++ defines these
    # symbols with weak linkage, and the *san runtime uses strong linkage, it
    # should technically be OK to include this file, but it's removed to be
    # explicit.
    sources += [ "//third_party/libc++/src/src/new.cpp" ]
  }

  if (is_linux) {
    # These sources are necessary for the Centipede fuzzer,
    # which currently only needs to run on Linux.
    sources += [
      "//third_party/libc++/src/src/filesystem/directory_entry.cpp",
      "//third_party/libc++/src/src/filesystem/filesystem_clock.cpp",
    ]
  }

  include_dirs = [ "//third_party/libc++/src/src" ]
  if (is_win) {
    sources += [
      "//third_party/libc++/src/src/support/win32/locale_win32.cpp",
      "//third_party/libc++/src/src/support/win32/support.cpp",
      "//third_party/libc++/src/src/support/win32/thread_win32.cpp",
    ]
    configs -= [ "//build/config/win:winver" ]
    configs += [ ":winver" ]
    if (libcxx_natvis_include) {
      inputs += [
        # libc++.natvis listed as an input here instead of in
        # //build/config/c++:runtime_library to prevent unnecessary size
        # increase in generated build files.
        "//build/config/c++/libc++.natvis",
      ]
    }
  }

  # Enable exceptions and rtti for libc++, but disable them in modules targets
  # so that modules can be used for other chromium targets which don't enable
  # exception and rtti.
  configs -= configs_to_remove + [
               "//build/config/compiler:no_exceptions",
               "//build/config/compiler:no_rtti",
             ]
  configs += configs_to_add + [
               "//build/config/compiler:exceptions",
               "//build/config/compiler:rtti",
             ]

  deps = [
    ":custom_headers",
    ":libcxx_headers",
    "//third_party/llvm-libc:llvm-libc-shared",
  ]

  if(use_custom_libcxx && enable_cfi_protection) {
    configs -= [ 
      "//arkweb/build/config/sanitizers:ptrauth_base",
      "//arkweb/build/config/sanitizers:armv83a",
    ]
  }

  if (use_clang_modules) {
    # TODO(https://github.com/llvm/llvm-project/issues/127012): We don't enable
    # Clang modules for libc++ as libc++'s iostream.cpp has ODR issue
    # (https://crbug.com/40440396#comment81). Also we don't take care about the
    # libc++'s build performance much.
    # (https://crrev.com/c/6248376/4#message-0ddf8e6a0f3ce1eb1654f7025280d8ed75cf2e81)
    # This removes deps to libc++'s modules from libc++'s build as libc++
    # doesn't support modules build itself.
    use_libcxx_modules = false
  }

  if ((is_android || is_apple) && libcxx_is_shared) {
    # Use libc++_chrome to avoid conflicting with system libc++
    output_name = "libc++_chrome"
    if (is_android) {
      # See crbug.com/1076244#c11 for more detail.
      configs -= [ "//build/config/android:hide_all_but_jni_onload" ]
    }
  }

  if (libcxx_is_shared && !is_win) {
    configs -= [ "//build/config/gcc:symbol_visibility_hidden" ]
    configs += [ "//build/config/gcc:symbol_visibility_default" ]
  }

  defines = []
  cflags = []

  if (!libcxx_is_shared && !is_win) {
    if (is_apple && is_clang) {
      # We want operator new/delete to be private on Mac, but these functions
      # are implicitly created by the compiler for each translation unit, as
      # specified in the C++ spec 3.7.4p2, which makes them always have default
      # visibility.  This option is needed to force hidden visibility since
      # -fvisibility=hidden doesn't have the desired effect.
      cflags += [ "-fvisibility-global-new-delete=force-hidden" ]
    } else {
      # This resets the visibility to default only for the various
      # flavors of operator new and operator delete.  These symbols
      # are weak and get overriden by Chromium-provided ones, but if
      # these symbols had hidden visibility, this would make the
      # Chromium symbols hidden too because elf visibility rules
      # require that linkers use the least visible form when merging.
      # We want operator new to be public, so that our allocator is
      # able to intercept allocations from other shared libraries.
      # TODO(lld): Ask lld for a --force-public-visibility flag or
      # similar to that overrides the default elf merging rules, and
      # make the allocator's gn config pass that to all its dependencies,
      # then remove this override here.
      defines += [ "_LIBCPP_OVERRIDABLE_FUNC_VIS=__attribute__((__visibility__(\"default\")))" ]
    }
  }

  if (!is_win) {
    defines += [ "LIBCXX_BUILDING_LIBCXXABI" ]
    if (!export_libcxxabi_from_executables) {
      deps += [ "//buildtools/third_party/libc++abi" ]
    }
  }

  # Disabling -Wexit-time-destructors, as libc++ uses `static string` objects
  # for locale code.
  configs += [ "//build/config/compiler:no_exit_time_destructors" ]
}