# file      : libcrypto/buildfile
# license   : Apache License 2.0; see accompanying LICENSE file

define inc: file
inc{*}: extension = inc

import imp_libs  = libz%lib{z}
import imp_libs += libzstd%lib{zstd}

tclass = $c.target.class
tsys   = $c.target.system

i686 = ($c.target.cpu == 'i686')

linux   = ($tclass == 'linux')
bsd     = ($tclass == 'bsd')
windows = ($tclass == 'windows')

# Exclude source code of unused features (engines, providers, disabled
# algorithms, etc).
#
# Note that crypto/LPdir_*.c, crypto/des/ncbc_enc.c,
# engines/e_{afalg,capi}_err.c, and
# providers/implementations/macs/blake2_mac_impl.c are actually headers.
#
lib{crypto}: {h      }{**               -buildinf-body -providers/**} \
             {h      }{buildinf-body                                } \
  downstream/{      c}{**                                           } \
   providers/{h inc c}{**               -fips/**                      \
                                        -**/securitycheck_fips        \
                                        -**_vms -**_vxworks           \
                                        -**/blake2_mac_impl           \
                                        -**/winstore_store            \
                                        -**/md2_prov                  \
                                        -**/mdc2_prov                 \
                                        -legacyprov                 } \
     engines/{      c}{e_capi e_padlock                             } \
      crypto/{      c}{**               -LPdir_* -*cap                \
                                        -**_ppc -**_riscv -**_sparc   \
                                        -aes/aes_x86core              \
                                        -bn/asm/x86_64-gcc            \
                                        -bn/rsaz_exp                  \
                                        -des/ncbc_enc                 \
                                        -ec/ecp_nistz*                \
                                        -ec/ecp_*nistp*               \
                                        -ec/ecp_sm2*                  \
                                        -ec/ecx_s390x                 \
                                        -evp/legacy_md2               \
                                        -evp/legacy_mdc2              \
                                        -md2/**                       \
                                        -mdc2/**                      \
                                        -poly1305/poly1305_ieee754    \
                                        -poly1305/poly1305_base2_44   \
                                        -rsa/rsa_acvp_test_params   }

lib{crypto}: engines/c{e_afalg}:                                include = $linux
lib{crypto}: engines/c{e_afalg_err e_capi_err}:                 include = adhoc
lib{crypto}: providers/implementations/macs/c{blake2_mac_impl}: include = adhoc
lib{crypto}: crypto/c{LPdir_* des/ncbc_enc}:                    include = adhoc

lib{crypto}: \
  providers/implementations/storemgmt/c{winstore_store}:        include = $windows

lib{crypto}: $imp_libs

# Symlinked where appropriate.
#
downstream/crypto/h{platform}@./downstream/crypto/: dist = false

libs{crypto}: file{libcrypto.ld}: include = ($linux || $bsd ? adhoc : false)
libs{crypto}: def{libcrypto}:     include = $windows

# Build options.
#
# Drop -DOPENSSL_PIC and -D{L|B}_ENDIAN preprocessor options and define
# OPENSSL_PIC and {L|B}_ENDIAN macros in downstream/openssl/configuration.h.
# Pass -DLIBCRYPTO_BUILD to define the above macros only while building the
# libcrypto library. Also drop -DOPENSSL_BUILDING_OPENSSL since the macro is
# not used in the library source code.
#
# Note that upstream also passes -DNDEBUG. Let's omit it for now to enable
# assertions to gain some extra confidence that we didn't break anything while
# packaging.
#
c.poptions += -DLIBCRYPTO_BUILD -DZLIB -DZSTD

if $windows
  c.poptions += -DWIN32_LEAN_AND_MEAN -DUNICODE -D_UNICODE

switch $tclass, $tsys
{
  case 'linux'
    c.poptions += -DOPENSSL_USE_NODELETE

  case 'windows', 'mingw32'
    c.poptions += -D_MT

  case 'windows'
  {
    # Note that upstream also adds Applink support if compiled with VC. This
    # is something about being able to use the library with application
    # compiled with a different compiler (see
    # ../../upstream/Configurations/10-main.conf for details). We drop this
    # for now as it requires ASM support. In particular, we don't pass
    # -DOPENSSL_USE_APPLINK preprocessor option no compile uplink.c and
    # auto-generated uplink-x86_64.asm.
    #
    c.poptions += -DOPENSSL_SYS_WIN32 -D_CRT_SECURE_NO_DEPRECATE \
                  -D_WINSOCK_DEPRECATED_NO_WARNINGS
  }
}

switch $c.class
{
  case 'gcc'
  {
    if $i686
      c.coptions += -fomit-frame-pointer

    # Disable warnings that pop up with -Wall -Wextra. Upstream doesn't seem
    # to care about these and it is not easy to disable specific warnings in a
    # way that works across compilers/versions (some -Wno-* options are only
    # recognized in newer versions). There are still some warnings left that
    # appear for certain platforms/compilers. We pass them through but disable
    # treating them as errors.
    #
    c.coptions += -Wno-all -Wno-extra -Wno-error
  }
  case 'msvc'
  {
    # Disable warnings that pop up with /W3.
    #
    c.coptions += /wd4028 /wd4090 /wd4133 /wd4244 /wd4267 /wd4334
  }
}

# Escape backslashes and quotes in the compilation flags and substitute them
# into buildinf-body.h as string literals, one per line.
#
# Note: the flag list will not reflect compiler options that build2 adds
# implicitly (-fPIC, etc).
#
cflags =
for f: $c.poptions $c.coptions
  cflags += $regex.replace($f, '(\\|")', '\\\1')

h{buildinf-body}: in{buildinf-body}
{
  cflags = $regex.merge($cflags, '(.+)', '\n  " \1"')
}

# Note that we have to add "-I$src_root" for the headers auto-generating
# machinery to work properly.
#
c.poptions =+ "-I$out_root" "-I$src_root"                     \
              "-I$src_base/downstream" "-I$src_base"          \
              "-I$src_base/providers/implementations/include" \
              "-I$src_base/providers/common/include"          \
              "-I$src_base/include"

crypto/evp/         c.poptions =+ "-I$src_root/libcrypto/crypto/modes"
crypto/rand/        c.poptions =+ "-I$src_root/libcrypto/crypto/modes"
crypto/ec/          c.poptions =+ "-I$src_root/libcrypto/crypto"
crypto/ec/curve448/ c.poptions =+ "-I$src_base" "-I$src_base/arch_32"

# Note that upstream defines OPENSSLDIR, ENGINESDIR, and MODULESDIR
# differently for different platforms/distributions. For example, it defines
# ENGINESDIR as /usr/local/lib64/engines-3 on Fedora and
# /usr/local/lib/engines-3 for MinGW GCC (which doesn't make much sense).
#
# Also note that Linux distributions may also define them differently. For
# example:
#
# Debian/Ubuntu: /usr/lib/ssl and /usr/lib/x86_64-linux-gnu/engines-3
# Fedora/RHEL:   /etc/pki/tls and /usr/lib64/engines-3
#
# We will not define these directories as there is no guarantee that they
# exist and contain data that is safe to use. Overall, the thinking is that if
# any of these directories are actually needed, then one should probably be
# using the system-installed OpenSSL or configure these directories manually
# at runtime (e.g., via environment variables, API, etc).
#
# Note that we cannot just leave the macros undefined as the project will fail
# to compile. Using empty paths may seem like a good idea but will end up in
# potentially existing filesystem entries (/certs, /cert.pem, etc; see
# upstream's cryptlib.h). Thus, we define them as "\0" which results in the
# empty string literal for the macros defined as follows:
#
# # define X509_CERT_DIR OPENSSLDIR "/certs"
#
# Also note that for the crypto/obj{cversion} target we instead need to leave
# OPENSSLDIR, ENGINESDIR, and MODULESDIR undefined not to break strings used
# by the OpenSSL_version() function (see crypto/cversion.c for details).
#
ns = $regex.apply({**.c -crypto/cversion.c}, '.c$', '')

obj{$ns}: c.poptions += -DOPENSSLDIR='"\0"' \
                        -DENGINESDIR='"\0"' \
                        -DMODULESDIR='"\0"'

crypto/obj{cversion info}: \
  c.poptions =+ "-I$src_root/libcrypto/downstream/crypto"

switch $tclass, $tsys
{
  case 'linux'
  {
    c.loptions += -Wl,-znodelete -Wl,-Bsymbolic                 \
                  "-Wl,--version-script=$src_base/libcrypto.ld"

    c.libs += -ldl -pthread
  }
  case 'bsd'
  {
    c.loptions += -Wl,-Bsymbolic                                \
                  "-Wl,--version-script=$src_base/libcrypto.ld"

    c.libs += -pthread
  }
  case 'windows', 'mingw32'
  {
    # Note that for MinGW GCC the upstream package also passes -static-libgcc.
    # We normally don't link GCC run-time statically when packaging other C
    # libraries, so let's not do that here either and see how it goes.
    #
    c.loptions += -Wl,--enable-auto-image-base

    c.libs += -lws2_32 -lgdi32 -lcrypt32
  }
  case 'windows'
  {
    # Suppress the 'object file does not define any public symbols' warning.
    #
    c.aoptions += /IGNORE:4221

    c.libs += ws2_32.lib gdi32.lib crypt32.lib advapi32.lib
  }
}

# Export options.
#
lib{crypto}: cc.export.poptions = "-I$src_base/downstream" \
                                  "-I$src_base/include"

# See bootstrap.build for details.
#
if $version.pre_release
  lib{crypto}: bin.lib.version = @"-$version.project_id"
else
  lib{crypto}: bin.lib.version = @"-$abi_version"

# Install headers from the upstream and downstream openssl/ subdirectories
# only.
#
h{*}:                                  install = false
include/openssl/h{*}:                  install = include/openssl/
downstream/openssl/h{*}:               install = include/openssl/
downstream/openssl/configuration/h{*}: install = include/openssl/configuration/
