import intf_libs    = cuda-crt%lib{crt}
import libnvvm = libnvvm%dir{nvvm}

define [see_through] import: group

name = $string.replace($project, 'cuda-', '')
win  = [bool] ($cc.target.class == 'windows')

source redist.build

# Exclude the archive's nvcc.profile from extraction: we generate a build-time
# profile with absolute paths to libnvvm. update-for-install regenerates it
# with $(TOP)-relative paths (correct once both packages share the same
# install prefix).
extract_exclude = [cmdline] --exclude "*/bin/nvcc.profile"

json{$name-manifest}: $src_root/manifest manifest.json

manifest_json = [json_object] $json.load($src_base/manifest.json)
package_ver   = "$(version.major).$(version.minor).$(version.patch)"

pub_hdrs = [strings]
for d: [json_array] ($manifest_json["includeDirs"])
{
  dir = [string] $d
  pub_hdrs += "-I$out_base/$dir"
}

for plat: [json_object] ($manifest_json["platforms"])
{
  plat_key = $member_name($plat)
  plat_val = $member_value($plat)
  enabled  = [bool] ($cc.target.cpu-$cc.target.class == $plat_key)
  platform = [string] ($plat_val["platform"])
  archive{$name-$platform-$package_ver}: json{$name-manifest} manifest.json: include = $enabled
  extract{$name}: archive{$name-$platform-$package_ver}: include = $enabled
}

import{$name-headers}: extract{$name}: update = match
import{$name-legals}:  extract{$name}: update = match

import{$name-legals}:
{{
  o = $directory($>[0])
  d = $o/$name($>[0]).files

  legal = [path] "$out_base/LICENSE"

  depdb dyndep \
    --dyn-target \
    --target-cwd "$o" \
    --target-what 'imported files' \
    --target-default-type 'legal' \
    --format lines \
    --file $d \
    -- \
      echo $legal >$d

  diag import $>

  for t : $filter_out($>, group)
  {
    touch $path($t)
  }
}}

import{$name-headers}:
{{
  o = $directory($>[0])
  d = $o/$name($>[0]).files

  find "$out_base/include/" -type f -name "*" \
    | set -n f [paths]

  depdb dyndep \
    --dyn-target \
    --target-cwd "$o" \
    --target-what 'headers' \
    --target-default-type 'h' \
    --target-extension-type '=h' \
    --format lines \
    -- echo $regex.merge($f, '(.+)', '\1\n')

  diag import $>

  for f : $filter($>, h)
  {
    touch $path($f)
  }
}}

./: json{package}
json = [json_object] $json.load($src_base/package.json)
for plat: [json_object] ($json["platforms"])
{
  plat_key = $member_name($plat)
  enabled  = [bool] ($cc.target.cpu-$cc.target.class == $plat_key)
  plat_val = [json_object] $member_value($plat)

  for m: [json_object] ($plat_val["libs"])
  {
    n = $member_name($m)

    ./: lib{$n}:
    {
      include = $enabled
      clean   = false
    }
    [rule_hint=cxx] \
    lib{$n}: import{$name-legals} import{$name-headers}: \
             extract{$name}:
    {
      include = $enabled
      update  = match
    }

    lib{$n}: $intf_libs: include = $enabled

    lib{$n}:
    {
      cc.type            = cc
      cc.export.poptions = $pub_hdrs
      cc.export.libs     = $intf_libs
    }
  }

  for m: [json_object] ($plat_val["exes"])
  {
    v = [json_object] ($member_value($m))
    p = [string] ($v["path"])

    ./: exe{$(p)...}: include = $enabled
    exe{$(p)...}: import{$name-headers}: extract{$name}: include = $enabled

    exe{$(p)...}:
    {
      install.subdirs = true
    }

    for d2: [json_array] ($v["depends"])
    {
      dep = [name] $d2
      exe{$(p)...}: libs{$dep}:
      {
        include = $enabled
        clean = false
      }
    }
  }
}

exe{~'/(.+)/'}:
{{
  diag import $> $<
  touch $path($>)

  # NVIDIA's cuda-nvcc/libnvvm executables link only against system libs
  # (confirmed via ldd/readelf against the real built binaries), so no
  # patchelf/rpath fix needed here, unlike nvidia-tensorrt's trtexec.
}}

lib/liba{**}: install = false

include/h{**}:
{
  install         = include/$project/
  install.subdirs = true
}

# Generate bin/nvcc.profile for the build-time layout. CICC_PATH and
# NVVMIR_LIBRARY_DIR point to libnvvm's build directory. The % install body
# regenerates it with $(TOP)-relative paths directly into the install prefix.
bin/exe{nvcc}: bin/file{nvcc.profile}

bin/file{nvcc.profile}: in{nvcc.profile.win.in}: include = $win
bin/file{nvcc.profile}: in{nvcc.profile.posix.in}: include = (!$win)
bin/file{nvcc.profile}: extract{$name} $libnvvm

bin/file{nvcc.profile}:
{
  in.symbol          = '@'
  cicc_path          = $posix_representation($path($libnvvm))bin
  nvvmir_library_dir = $posix_representation($path($libnvvm))libdevice
}

bin/file{nvcc.profile}:
{
  install = bin/
}
% install
{{
  dst = $install.resolve($install.bin)
  p   = $dst/nvcc.profile

  diag gen-install $> -> $p

  mkdir --no-cleanup -p "$dst"

  if ($win)
  {
    cat <<='EOF' >"$p" &!$p

    TOP              = $(_HERE_)/..

    CICC_PATH        = $(TOP)/nvvm/bin
    NVVMIR_LIBRARY_DIR = $(TOP)/nvvm/libdevice

    PATH            += $(CICC_PATH);$(_HERE_);$(TOP)/lib;

    INCLUDES        += "-I$(TOP)/include" "-I$(TOP)/include/cccl" $(_SPACE_)
    SYSTEM_INCLUDES +=  $(_SPACE_)

    LIBRARIES        =+ $(_SPACE_) "/LIBPATH:$(TOP)/lib/$(_WIN_PLATFORM_)"

    CUDAFE_FLAGS    +=
    PTXAS_FLAGS     +=

    EOF
  }
  else
  {
    cat <<='EOF' >"$p" &!$p

    TOP              = $(_HERE_)/..

    CICC_PATH        = $(TOP)/nvvm/bin
    NVVMIR_LIBRARY_DIR = $(TOP)/nvvm/libdevice

    LD_LIBRARY_PATH += $(TOP)/lib:
    PATH            += $(CICC_PATH):$(_HERE_):

    INCLUDES        += "-I$(TOP)/include" "-I$(TOP)/include/cccl" $(_SPACE_)
    SYSTEM_INCLUDES +=  $(_SPACE_)

    LIBRARIES        =+ $(_SPACE_) "-L$(TOP)/lib"

    CUDAFE_FLAGS    +=
    PTXAS_FLAGS     +=

    EOF
  }
}}
