# Public interface headers.
#
pub = [dir_path] ../include/GLFW/

include $pub

pub_hdrs = $pub/{$($pub/ pub_hdrs)}

# Platform-independent internal headers and source files.
#
cmn_hdrs = h{internal       \
             platform       \
             mappings       \
             null_platform  \
             null_joystick}

cmn_srcs = c{context        \
             init           \
             input          \
             monitor        \
             platform       \
             vulkan         \
             window         \
             egl_context    \
             osmesa_context \
             null_init      \
             null_monitor   \
             null_window    \
             null_joystick}

# Common GLFW library target.
#
lib{glfw}: $cmn_hdrs $pub_hdrs $cmn_srcs

# Platform-specific implementation components.
#

# macOS (Cocoa + NSGL)
#
lib{glfw}: m{cocoa_joystick \
             cocoa_monitor  \
             cocoa_init     \
             cocoa_window   \
             nsgl_context}  \
           c{posix_thread   \
             posix_module   \
             cocoa_time}    \
           h{cocoa_platform \
             cocoa_joystick \
             cocoa_time     \
             posix_thread}: include = $macos

# Windows (Win32 + WGL)
#
lib{glfw}: c{wgl_context    \
             win32_init     \
             win32_joystick \
             win32_module   \
             win32_monitor  \
             win32_thread   \
             win32_time     \
             win32_window}  \
           h{win32_joystick \
             win32_platform \
             win32_thread   \
             win32_time}: include = $windows

# Unix (generic POSIX components)
#
lib{glfw}: c{posix_time    \
             posix_thread  \
             posix_module  \
             posix_poll    \
             xkb_unicode}  \
           h{posix_time    \
             posix_thread  \
             posix_poll    \
             xkb_unicode}: include = ($linux || $freebsd)

# Unix - X11 backend
#
lib{glfw}: c{x11_init       \
             x11_monitor    \
             x11_window     \
             glx_context}   \
           h{x11_platform}: include = ($build_x11)

# Unix - Wayland backend
#
lib{glfw}: c{wl_init       \
             wl_monitor    \
             wl_window}    \
           h{wl_platform}: include = ($build_wayland)

# Linux-specific joystick support
#
lib{glfw}: {h c}{linux_joystick}: include = $linux

# Preprocessor include directories for both headers and sources.
#

out_pfx_inc = [dir_path] $out_root/include/
src_pfx_inc = [dir_path] $src_root/include/
out_pfx_src = [dir_path] $out_root/src/
src_pfx_src = [dir_path] $src_root/src/

c.poptions =+ "-I$out_pfx_src" \
              "-I$src_pfx_src" \
              "-I$out_pfx_inc" \
              "-I$src_pfx_inc"

# Backend-specific configuration and library linkage.
#
gl_libs =

# Linux-specific configuration
#
if ($linux || $freebsd)
{
  # Required system libraries for Linux/FreeBSD.
  #
  gl_libs += -lm  \
             -lrt \
             -ldl \
             -lpthread
}

# Windows-specific configuration
#
if ($windows)
{
  c.poptions += -D_GLFW_WIN32 \
                -D_CRT_SECURE_NO_WARNINGS

  switch $c.target.system: path.match
  {
    case '*msvc*'
      gl_libs += gdi32.lib

    default
      gl_libs += -lgdi32
  }
}

# macOS-specific configuration for Clang
#
if ($macos)
{
  # macOS requires Clang compiler, so we check for it.
  #
  # Note that we use 'switch ...: path.match' instead of a traditional 'if'
  # because 'if ($c.id == "*clang*")' performs literal comparison, not pattern
  # matching. This causes false negatives on CI or cross-toolchains where the
  # compiler ID may include a prefix or suffix (e.g., 'arm64-apple-clang').
  #
  switch $c.id: path.match
  {
    case "*clang*"
      c.coptions += # no-op
    default
      fail "Unsupported compiler toolchain detected. macOS builds require Clang compiler."
  }

  # Add Cocoa-specific compiler options.
  #
  c.poptions += -D_GLFW_COCOA

  # Required system libraries for macOS.
  #
  gl_libs += -framework Cocoa          \
             -framework IOKit          \
             -framework CoreFoundation
}

# Wayland-specific configuration
#
# Note that we distinguish between development and consumption builds to avoid
# requiring `wayland-scanner` or protocol XMLs for downstream consumers.
#
# In development builds (`$develop == true`), we generate protocol headers and
# code using `wayland-scanner` from upstream XML definitions under
# `deps/wayland/`. Any regenerated files are compared against committed
# pregenerated versions and copied into `pregenerated/glfw/` if changed.
#
# In consumption builds (`$develop == false`), we use only the pregenerated
# protocol sources.
#
if ($build_wayland)
{
  # Path to upstream Wayland protocol definitions.
  #
  wayland = $src_root/../upstream/deps/wayland

  # Wayland support and baseline feature macros.
  #
  c.poptions += -D_GLFW_WAYLAND -D_DEFAULT_SOURCE

  # Required system and user-space client libraries for Wayland.
  #
  # NOTE: libwayland should eventually be packaged as a build2 package. For now,
  #       we assume it's installed in the system or user environment.
  #
  gl_libs += -lwayland-client \
             -lwayland-cursor \
             -lwayland-egl


  # Wayland protocols used for code generation.
  #
  protocols = wayland-client-protocol                         \
              viewporter-client-protocol                      \
              xdg-shell-client-protocol                       \
              idle-inhibit-unstable-v1-client-protocol        \
              pointer-constraints-unstable-v1-client-protocol \
              relative-pointer-unstable-v1-client-protocol    \
              fractional-scale-v1-client-protocol             \
              xdg-activation-v1-client-protocol               \
              xdg-decoration-unstable-v1-client-protocol
}

# Wayland consumption build ($develop == false && $build_wayland == true).
#

# Use pregenerated protocol headers in the consumption build.
#
lib{glfw}: pregenerated/glfw/{h}{*}: include = (!$develop && $build_wayland)

# Pregenerated protocol headers must be found first in the include path.
#
if (!$develop && $build_wayland)
  c.poptions =+ "-I($src_base/pregenerated/glfw)"

# Always distribute pregenerated protocol headers in consumption builds.
#
# Consumption build must always include pregenerated headers, regardless of the
# current Wayland configuration to avoids failure cases where CI or other
# generates a distribution archive without X11 or Wayland enabled, then later
# attempts to consume that archive in a Wayland-enabled configuration. Without
# the pregenerated headers, such use would fail.
#
# https://github.com/build2-packaging/glfw/issues/15
#
pregenerated/glfw/{h}{**}: dist = (!$develop)

# Wayland development build ($develop == true && $build_wayland == true).
#

# Use protocol headers directly in the development build.
#
lib{glfw}: {h}{$protocols}: include = ($develop && $build_wayland)

# Import code generation tool from Wayland SDK.
#
if ($develop && $build_wayland)
  import! scanner = wayland-scanner%exe{wayland-scanner}

# Generate and track distribution for each protocol.
#
for f: $protocols
{
  d = $directory($f)
  p = pregenerated/glfw

  h{$f $f-code}:
  {
     dist = (($develop && $build_wayland) ? $relative([dir_path] "$p/$d", $d) : false)
  }
}

# NOTE:
#
# Each protocol is handled in an individual rule block on purpose: the XML
# filename, generated header, and generated code file names are not always
# derived uniformly.

# Wayland core protocol: base surface and input protocol.
#
<h{wayland-client-protocol} h{wayland-client-protocol-code}>: $scanner
%
if ($develop && $build_wayland)
{{
  diag wayland-scanner $>

  $scanner client-header $wayland/wayland.xml $path($>[0])
  $scanner private-code  $wayland/wayland.xml $path($>[1])

  # If the result differs from the pregenerated version, copy it over.
  #
  d = [dir_path] $src_base/pregenerated/glfw

  dh = $d/$leaf($path($>[0]))
  dc = $d/$leaf($path($>[1]))

  if diff $dh $path($>[0]) >- && \
     diff $dc $path($>[1]) >-
    exit
  end

  cp $path($>[0]) $dh
  cp $path($>[1]) $dc
}}

# Wayland viewport protocol: surface scaling and cropping.
#
<h{viewporter-client-protocol} h{viewporter-client-protocol-code}>: $scanner
%
if ($develop && $build_wayland)
{{
  diag wayland-scanner $>

  $scanner client-header $wayland/viewporter.xml $path($>[0])
  $scanner private-code  $wayland/viewporter.xml $path($>[1])

  # If the result differs from the pregenerated version, copy it over.
  #
  d = [dir_path] $src_base/pregenerated/glfw

  dh = $d/$leaf($path($>[0]))
  dc = $d/$leaf($path($>[1]))

  if diff $dh $path($>[0]) >- && \
     diff $dc $path($>[1]) >-
    exit
  end

  cp $path($>[0]) $dh
  cp $path($>[1]) $dc
}}

# XDG shell protocol: toplevel and popup window support.
#
<h{xdg-shell-client-protocol} h{xdg-shell-client-protocol-code}>: $scanner
%
if ($develop && $build_wayland)
{{
  diag wayland-scanner $>

  $scanner client-header $wayland/xdg-shell.xml $path($>[0])
  $scanner private-code  $wayland/xdg-shell.xml $path($>[1])

  # If the result differs from the pregenerated version, copy it over.
  #
  d = [dir_path] $src_base/pregenerated/glfw

  dh = $d/$leaf($path($>[0]))
  dc = $d/$leaf($path($>[1]))

  if diff $dh $path($>[0]) >- && \
     diff $dc $path($>[1]) >-
    exit
  end

  cp $path($>[0]) $dh
  cp $path($>[1]) $dc
}}

# Idle inhibit protocol: screen idle prevention for active surfaces.
#
<h{idle-inhibit-unstable-v1-client-protocol} h{idle-inhibit-unstable-v1-client-protocol-code}>: $scanner
%
if ($develop && $build_wayland)
{{
  diag wayland-scanner $>

  $scanner client-header $wayland/idle-inhibit-unstable-v1.xml $path($>[0])
  $scanner private-code  $wayland/idle-inhibit-unstable-v1.xml $path($>[1])

  # If the result differs from the pregenerated version, copy it over.
  #
  d = [dir_path] $src_base/pregenerated/glfw

  dh = $d/$leaf($path($>[0]))
  dc = $d/$leaf($path($>[1]))

  if diff $dh $path($>[0]) >- && \
     diff $dc $path($>[1]) >-
    exit
  end

  cp $path($>[0]) $dh
  cp $path($>[1]) $dc
}}

# Pointer constraints protocol: pointer lock and confinement.
#
<h{pointer-constraints-unstable-v1-client-protocol} h{pointer-constraints-unstable-v1-client-protocol-code}>: $scanner
%
if ($develop && $build_wayland)
{{
  diag wayland-scanner $>

  $scanner client-header $wayland/pointer-constraints-unstable-v1.xml $path($>[0])
  $scanner private-code  $wayland/pointer-constraints-unstable-v1.xml $path($>[1])

  # If the result differs from the pregenerated version, copy it over.
  #
  d = [dir_path] $src_base/pregenerated/glfw

  dh = $d/$leaf($path($>[0]))
  dc = $d/$leaf($path($>[1]))

  if diff $dh $path($>[0]) >- && \
     diff $dc $path($>[1]) >-
    exit
  end

  cp $path($>[0]) $dh
  cp $path($>[1]) $dc
}}

# Relative pointer protocol: input deltas from raw devices.
#
<h{relative-pointer-unstable-v1-client-protocol} h{relative-pointer-unstable-v1-client-protocol-code}>: $scanner
%
if ($develop && $build_wayland)
{{
  diag wayland-scanner $>

  $scanner client-header $wayland/relative-pointer-unstable-v1.xml $path($>[0])
  $scanner private-code  $wayland/relative-pointer-unstable-v1.xml $path($>[1])

  # If the result differs from the pregenerated version, copy it over.
  #
  d = [dir_path] $src_base/pregenerated/glfw

  dh = $d/$leaf($path($>[0]))
  dc = $d/$leaf($path($>[1]))

  if diff $dh $path($>[0]) >- && \
     diff $dc $path($>[1]) >-
    exit
  end

  cp $path($>[0]) $dh
  cp $path($>[1]) $dc
}}

# Fractional scale protocol: non-integer surface scaling factor support.
#
<h{fractional-scale-v1-client-protocol} h{fractional-scale-v1-client-protocol-code}>: $scanner
%
if ($develop && $build_wayland)
{{
  diag wayland-scanner $>

  $scanner client-header $wayland/fractional-scale-v1.xml $path($>[0])
  $scanner private-code  $wayland/fractional-scale-v1.xml $path($>[1])

  # If the result differs from the pregenerated version, copy it over.
  #
  d = [dir_path] $src_base/pregenerated/glfw

  dh = $d/$leaf($path($>[0]))
  dc = $d/$leaf($path($>[1]))

  if diff $dh $path($>[0]) >- && \
     diff $dc $path($>[1]) >-
    exit
  end

  cp $path($>[0]) $dh
  cp $path($>[1]) $dc
}}

# XDG activation protocol: surface focus and activation triggers.
#
<h{xdg-activation-v1-client-protocol} h{xdg-activation-v1-client-protocol-code}>: $scanner
%
if ($develop && $build_wayland)
{{
  diag wayland-scanner $>

  $scanner client-header $wayland/xdg-activation-v1.xml $path($>[0])
  $scanner private-code  $wayland/xdg-activation-v1.xml $path($>[1])

  # If the result differs from the pregenerated version, copy it over.
  #
  d = [dir_path] $src_base/pregenerated/glfw

  dh = $d/$leaf($path($>[0]))
  dc = $d/$leaf($path($>[1]))

  if diff $dh $path($>[0]) >- && \
     diff $dc $path($>[1]) >-
    exit
  end

  cp $path($>[0]) $dh
  cp $path($>[1]) $dc
}}

# XDG decoration protocol: client-side and server-side decoration control.
#
<h{xdg-decoration-unstable-v1-client-protocol} h{xdg-decoration-unstable-v1-client-protocol-code}>: $scanner
%
if ($develop && $build_wayland)
{{
  diag wayland-scanner $>

  $scanner client-header $wayland/xdg-decoration-unstable-v1.xml $path($>[0])
  $scanner private-code  $wayland/xdg-decoration-unstable-v1.xml $path($>[1])

  # If the result differs from the pregenerated version, copy it over.
  #
  d = [dir_path] $src_base/pregenerated/glfw

  dh = $d/$leaf($path($>[0]))
  dc = $d/$leaf($path($>[1]))

  if diff $dh $path($>[0]) >- && \
     diff $dc $path($>[1]) >-
    exit
  end

  cp $path($>[0]) $dh
  cp $path($>[1]) $dc
}}

# X11-specific configuration
#
if ($build_x11)
{
  c.poptions += -D_GLFW_X11 -D_DEFAULT_SOURCE

  # Required system libraries for X11 backend.
  #
  gl_libs += -lX11
}

# Enable hybrid GPU support when requested
#
if ($use_hybrid_hpg)
  c.poptions += -D_GLFW_USE_HYBRID_HPG

# Default to static build or shared (DLL) build based on target type
#
obja{*}: c.poptions += -DGLFW_STATIC_BUILD
objs{*}: c.poptions += -D_GLFW_BUILD_DLL

# Export configuration
#
c.libs += $gl_libs

lib{glfw}:
{
  c.export.poptions = "-I$out_pfx_inc" "-I$src_pfx_inc"
  c.export.libs = $intf_libs $gl_libs
}

liba{glfw}: c.export.poptions += -DGLFW_STATIC
libs{glfw}: c.export.poptions += -D_GLFW_BUILD_DLL

# For pre-releases use the complete version to make sure they cannot be used
# in place of another pre-release or the final version. See the version module
# for details on the version.* variable values.
# Need to do it this way as windows@.. suffix is not yet supported

if $version.pre_release
  lib{glfw}: bin.lib.version = @"-$version.project_id"
else
{
  release_version_suffix = "$version.major.$version.minor"
  if($windows)
    release_version_suffix = "$version.major"
  lib{glfw}: bin.lib.version = @"-$release_version_suffix"
}

# Don't install private headers.
#
h{*}: install = false
