# file      : libbuild2/buildfile
# license   : MIT; see accompanying LICENSE file

# NOTE: remember to update bundled_modules in libbuild2/module.cxx if adding a
#       new module.
#
bundled_modules = bash/ bin/ c/ cc/ cxx/ in/ version/

./: lib{build2} $bundled_modules

# Note that we have to load these buildfiles explicitly in order to have their
# imports processed before the $config.save() call below. Failed that, we will
# get a warning about saving unused config.import.* values.
#
include $bundled_modules

# A module should treat lib{build2} as an "implied interface dependency"
# meaning that it can link it as an implementation dependency and assume that
# whomever imports and links this module will also import and link lib{build2}
# explicitly. A module should also assume that lib{butl} will always be an
# interface dependency of lib{build2} and therefore need not be explicitly
# imported or linked.

# NOTE: shared imports should go into root.build.
#
intf_libs = $libbutl

lib{build2}: libul{build2}:                                            \
  {hxx ixx txx cxx}{* -utility-*installed -config -version -*.test...} \
  {hxx}{config version}

libul{build2}: script/{hxx ixx txx cxx}{** -*-options -**.test...} \
               script/{hxx ixx cxx}{builtin-options}

libul{build2}: build/{hxx ixx txx cxx}{** -**.test...}

# Note that this won't work in libul{} since it's not installed.
#
lib{build2}: cxx{utility-installed}:   for_install = true
lib{build2}: cxx{utility-uninstalled}: for_install = false

# These are "core modules" that come bundled with libbuild2 (see also unit
# tests loop below). Note that the build system core can still function
# without them or with their alternative implementations. Also note that
# config/utility.?xx are part of the build system core (see comments in the
# header for details).
#
# NOTE: remember to update import_modules() in libbuild2/modules.cxx if adding
#       a new such module.
#
libul{build2}: config/{hxx ixx txx cxx}{** -host-config -**.test...} \
               config/cxx{host-config}

# This will of course blow up spectacularly if we are cross-compiling. But
# let's wait and enjoy the fireworks (and get a sense of why someone would
# want to cross-compile a build system).
#
config/cxx{host-config}: config/in{host-config}
{
  # For the ~host configuration we only want c/cxx/cc and bin that they load.
  # For ~build2 we want to keep everything except dist.
  #
  # We also remove comment lines which could be confused with preprocessor
  # directives by some lesser compilers.
  #
  # For ~build2 also filter out config.install.chroot -- we definitely don't
  # want it carried through.
  #
  # Finally, for both ~host and ~build2 we keep config.config.environment
  # but strip config.config.hermetic* (we shouldn't be forcing hermiticity
  # on the users of ~host/~build2; they can decide for themselves if they
  # want it).
  #
  build2_config = $regex.replace_lines(                              \
    $config.save(),                                                  \
    '^ *(#|(config\.(dist\.|install\.chroot|config\.hermetic))).*$', \
    [null],                                                          \
    return_lines)

  # Also preserve config.version and blank lines between groups of options.
  #
  host_config = $regex.replace_lines(                                             \
    $build2_config,                                                               \
    '^( *config\.(c[. ]|cxx[. ]|cc[.]|bin[.]|config.environment |version ).*|)$', \
    '$&',                                                                         \
    format_no_copy return_lines)
}

libul{build2}: dist/{hxx ixx txx cxx}{** -**.test...}

libul{build2}: install/{hxx ixx txx cxx}{** -**.test...}

libul{build2}: test/{hxx ixx txx cxx}{** -**.test...}

libul{build2}: $intf_libs

# Include the generated config and version headers into the distribution (so
# that we don't pick up installed ones) and don't remove them when cleaning in
# src (so that clean results in a state identical to distributed).
#
hxx{config}: in{config}
hxx{version}: in{version} $src_root/manifest

hxx{config version}:
{
  dist  = true
  clean = ($src_root != $out_root)
}

# Unit tests.
#
exe{*.test}:
{
  test = true
  install = false
}

for t:         cxx{ *.test...} \
        script/cxx{**.test...} \
         build/cxx{**.test...} \
        config/cxx{**.test...} \
          dist/cxx{**.test...} \
       install/cxx{**.test...} \
          test/cxx{**.test...}
{
  d = $directory($t)
  n = $name($t)...
  b = $path.base($name($t))

  ./: $d/exe{$n}: $t $d/{hxx ixx txx}{+$n} $d/testscript{+$n +$b+*.test...}
  $d/exe{$n}: libul{build2}: bin.whole = false
  $d/exe{$n}: cxx{utility-uninstalled}
}

# Build options.
#
# NOTE: this scope happens to be outer to the bundled modules which means they
#       will inherit any scope-wide options. So we should normally only set
#       them on targets.
#
obja{*}: cxx.poptions += -DLIBBUILD2_STATIC_BUILD
objs{*}: cxx.poptions += -DLIBBUILD2_SHARED_BUILD

# Pass our compiler target to be used as build2 host and our out_root to be
# used as the build system import path (unless cross-compiling and not
# forgetting to escape backslashes on Windows).
#
{obja objs}{context}: cxx.poptions += "-DBUILD2_HOST_TRIPLET=\"$cxx.target\""

# Note that we used to compare complete target triplets but that proved too
# strict. For example, we may be running on x86_64-apple-darwin17.7.0 while
# the compiler is targeting x86_64-apple-darwin17.3.0.
#
cross = ($cxx.target.cpu != $build.host.cpu || \
         $cxx.target.system != $build.host.system)

if! $cross
{
  {obja objs}{context}: cxx.poptions += \
    -DBUILD2_IMPORT_PATH=\"$regex.replace($out_root, '\\', '\\\\')\"

  # While this object file should only be linked when we are installing, it
  # will be compiled even in the uninstalled case.
  #
  if ($install.root != [null])
    {obja objs}{utility-installed}: cxx.poptions += \
      -DBUILD2_INSTALL_LIB=\"$regex.replace(\
        $install.resolve($install.lib), '\\', '\\\\')\"
}

if ($cxx.target.class != 'windows')
{
  libul{build2}: cxx.libs += -lpthread

  # Note: only linking libdl in shared build.
  #
  if ($cxx.target.class != "bsd")
    libus{build2}: cxx.libs += -ldl
}
else
{
  # @@ TMP work around Clang bug #45021.
  #
  if ($cxx.id == 'clang' && $cxx.target.system == 'win32-msvc')
  {
    if ($regex.find_match($cc.coptions $cxx.coptions, '-O[23]'))
      script/obj{run}: cxx.coptions += -O1
  }
}

# Export options.
#
lib{build2}:
{
  cxx.export.poptions = "-I$out_root" "-I$src_root"
  cxx.export.libs = $intf_libs
}

# While we don't call any pthread_*() functions in our API, this appears to be
# needed for some std::thread implementations (like libstdc++).
#
if ($cxx.target.class != 'windows')
  lib{build2}: cxx.export.libs += -lpthread

liba{build2}: cxx.export.poptions += -DLIBBUILD2_STATIC
libs{build2}: cxx.export.poptions += -DLIBBUILD2_SHARED

# 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.
#
if $version.pre_release
  lib{build2}: bin.lib.version = @"-$version.project_id"
else
  lib{build2}: bin.lib.version = @"-$version.major.$version.minor"

# Generated options parser.
#
script/
{
  if $cli.configured
  {
    cli.cxx{builtin-options}: cli{builtin}

    cli.options += --std c++11 -I $src_root --include-with-brackets \
--include-prefix libbuild2/script --guard-prefix LIBBUILD2_SCRIPT \
--cli-namespace build2::script::cli --generate-vector-scanner \
--generate-modifier --generate-specifier --suppress-usage

    cli.cxx{*}:
    {
      # Include the generated cli files into the distribution and don't remove
      # them when cleaning in src (so that clean results in a state identical
      # to distributed). But don't install their headers since they are only
      # used internally in the testscript implementation.
      #
      dist  = true
      clean = ($src_root != $out_root)
      install = false

      # We keep the generated code in the repository so copy it back to src in
      # case of a forwarded configuration.
      #
      backlink = overwrite
    }
  }
  else
    # No install for the pre-generated case.
    #
    hxx{builtin-options}@./ ixx{builtin-options}@./: install = false
}

# Install into the libbuild2/ subdirectory of, say, /usr/include/
# recreating subdirectories.
#
{hxx ixx txx}{*}:
{
  install         = include/libbuild2/
  install.subdirs = true
}