cmake_minimum_required(VERSION 2.8.12)

project("libspdm" C)
FILE(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/VERSION.md CMAKE_INPUT_PROJECT_VERSION)
string(REPLACE " " "_" CMAKE_PROJECT_VERSION ${CMAKE_INPUT_PROJECT_VERSION})

#
# Build Configuration Macro Definition
#
MESSAGE("#########################")
MESSAGE("## Build Configuration ##")
MESSAGE("#########################")

SET(CMAKE_GENERATOR ${CMAKE_GENERATOR} CACHE STRING "Choose the generator of cmake")
SET(ARCH ${ARCH} CACHE STRING "Choose the arch of build: ia32 x64 arm aarch64 riscv32 riscv64 arc" FORCE)
SET(TOOLCHAIN ${TOOLCHAIN} CACHE STRING "Choose the toolchain of build: Windows: VS2015 VS2019 VS2022 CLANG ARM_DS2022 LIBFUZZER Linux: GCC ARM_DS2022 ARM_GNU ARM_GNU_BARE_METAL ARM_GCC AARCH64_GCC RISCV_GNU RISCV64_GCC RISCV_XPACK ARC_GCC CLANG CBMC AFL KLEE LIBFUZZER" FORCE)
SET(CMAKE_BUILD_TYPE ${TARGET} CACHE STRING "Choose the target of build: Debug Release" FORCE)
SET(CRYPTO ${CRYPTO} CACHE STRING "Choose the crypto of build: mbedtls openssl" FORCE)
SET(GCOV ${GCOV} CACHE STRING "Choose the target of Gcov: ON  OFF, and default is OFF" FORCE)
SET(STACK_USAGE ${STACK_USAGE} CACHE STRING "Choose the target of STACK_USAGE: ON  OFF, and default is OFF" FORCE)
SET(BUILD_LINUX_SHARED_LIB ${BUILD_LINUX_SHARED_LIB} CACHE STRING "Choose if libspdm shared library should be built for linux: ON OFF, and default is OFF" FORCE)
SET(X509_IGNORE_CRITICAL ${X509_IGNORE_CRITICAL} CACHE STRING "Choose if libspdm-provided cryptography libraries (OpenSSL and MbedTLS) ignore unsupported critical extensions in certificates : ON OFF, and default is OFF" FORCE)

if(NOT GCOV)
    SET(GCOV "OFF")
endif()

if(NOT STACK_USAGE)
    SET(STACK_USAGE "OFF")
endif()

if(NOT BUILD_LINUX_SHARED_LIB)
    SET(BUILD_LINUX_SHARED_LIB "OFF")
endif()

if(NOT X509_IGNORE_CRITICAL)
    SET(X509_IGNORE_CRITICAL "OFF")
endif()

SET(LIBSPDM_DIR ${PROJECT_SOURCE_DIR})

#
# OpenSSL specific compiled libraries.
#
SET(COMPILED_LIBCRYPTO_PATH ${COMPILED_LIBCRYPTO_PATH} CACHE STRING "Optionally provide a path to libcrypto" FORCE)
SET(COMPILED_LIBSSL_PATH ${COMPILED_LIBSSL_PATH} CACHE STRING "Optionally provide a path to libssl" FORCE)

MESSAGE("CMAKE_GENERATOR = ${CMAKE_GENERATOR}")

if(ARCH STREQUAL "x64")
    MESSAGE("ARCH = x64")
elseif(ARCH STREQUAL "ia32")
    MESSAGE("ARCH = ia32")
elseif(ARCH STREQUAL "arm")
    MESSAGE("ARCH = arm")
elseif(ARCH STREQUAL "aarch64")
    MESSAGE("ARCH = aarch64")
elseif(ARCH STREQUAL "riscv32")
    MESSAGE("ARCH = riscv32")
elseif(ARCH STREQUAL "riscv64")
    MESSAGE("ARCH = riscv64")
elseif(ARCH STREQUAL "arc")
    MESSAGE("ARCH = arc")
elseif(ARCH STREQUAL "nios2")
    MESSAGE("ARCH = nios2")
else()
    MESSAGE(FATAL_ERROR "Unknown ARCH")
endif()

if(CMAKE_SYSTEM_NAME MATCHES "Linux")
    if(TOOLCHAIN STREQUAL "GCC")
        MESSAGE("TOOLCHAIN = GCC")
    elseif(TOOLCHAIN STREQUAL "CLANG")
        MESSAGE("TOOLCHAIN = CLANG")
    elseif(TOOLCHAIN STREQUAL "CBMC")
        MESSAGE("TOOLCHAIN = CBMC")
    elseif(TOOLCHAIN STREQUAL "AFL")
        MESSAGE("TOOLCHAIN = AFL")
    elseif(TOOLCHAIN STREQUAL "KLEE")
        MESSAGE("TOOLCHAIN = KLEE")
    elseif(TOOLCHAIN STREQUAL "LIBFUZZER")
        MESSAGE("TOOLCHAIN = LIBFUZZER")
    elseif(TOOLCHAIN STREQUAL "ARM_DS2022")
        MESSAGE("TOOLCHAIN = ARM_DS2022")
    elseif(TOOLCHAIN STREQUAL "ARM_GNU")
        MESSAGE("TOOLCHAIN = ARM_GNU")
    elseif(TOOLCHAIN STREQUAL "ARM_GNU_BARE_METAL")
        MESSAGE("TOOLCHAIN = ARM_GNU_BARE_METAL")
    elseif(TOOLCHAIN STREQUAL "ARM_GCC")
        MESSAGE("TOOLCHAIN = ARM_GCC")
    elseif(TOOLCHAIN STREQUAL "AARCH64_GCC")
        MESSAGE("TOOLCHAIN = AARCH64_GCC")
    elseif(TOOLCHAIN STREQUAL "RISCV_GNU")
        MESSAGE("TOOLCHAIN = RISCV_GNU")
    elseif(TOOLCHAIN STREQUAL "RISCV64_GCC")
        MESSAGE("TOOLCHAIN = RISCV64_GCC")
    elseif(TOOLCHAIN STREQUAL "RISCV_NONE")
        MESSAGE("TOOLCHAIN = RISCV_NONE")
    elseif(TOOLCHAIN STREQUAL "RISCV_XPACK")
        MESSAGE("TOOLCHAIN = RISCV_XPACK")
    elseif(TOOLCHAIN STREQUAL "ARC_GCC")
        MESSAGE("TOOLCHAIN = ARC_GCC")
    elseif(TOOLCHAIN STREQUAL "NIOS2_GCC")
        MESSAGE("TOOLCHAIN = NIOS2_GCC")
    elseif(TOOLCHAIN STREQUAL "NONE")
        MESSAGE("TOOLCHAIN = NONE")
    else()
        MESSAGE(FATAL_ERROR "Unknown TOOLCHAIN")
    endif()
    if(GCOV STREQUAL "ON")
        MESSAGE("GCOV = ON")
    elseif(GCOV STREQUAL "OFF")
        MESSAGE("GCOV = OFF")
    else()
        MESSAGE(FATAL_ERROR "Unknown GCOV switch input")
    endif()
    if(STACK_USAGE STREQUAL "ON")
        MESSAGE("STACK_USAGE = ON")
    endif()
elseif(CMAKE_SYSTEM_NAME MATCHES "Windows")
    if(TOOLCHAIN STREQUAL "GCC")
        MESSAGE("TOOLCHAIN = GCC")
    elseif(TOOLCHAIN STREQUAL "VS2015")
        MESSAGE("TOOLCHAIN = VS2015")
    elseif(TOOLCHAIN STREQUAL "VS2019")
        MESSAGE("TOOLCHAIN = VS2019")
    elseif(TOOLCHAIN STREQUAL "VS2022")
        MESSAGE("TOOLCHAIN = VS2022")
    elseif(TOOLCHAIN STREQUAL "CLANG")
        MESSAGE("TOOLCHAIN = CLANG")
    elseif(TOOLCHAIN STREQUAL "CBMC")
        MESSAGE("TOOLCHAIN = CBMC")
    elseif(TOOLCHAIN STREQUAL "LIBFUZZER")
        MESSAGE("TOOLCHAIN = LIBFUZZER")
    elseif(TOOLCHAIN STREQUAL "ARM_DS2022")
        MESSAGE("TOOLCHAIN = ARM_DS2022")
    else()
        MESSAGE(FATAL_ERROR "Unknown TOOLCHAIN")
    endif()
else()
    MESSAGE(FATAL_ERROR "${CMAKE_SYSTEM_NAME} is not supportted")
endif()

if(CMAKE_BUILD_TYPE STREQUAL "Debug")
    MESSAGE("TARGET = Debug")
elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
    MESSAGE("TARGET = Release")
else()
    MESSAGE(FATAL_ERROR "Unknown build type")
endif()

if(CRYPTO STREQUAL "mbedtls")
    MESSAGE("CRYPTO = mbedtls")
    add_definitions(-DLIBSPDM_SHA3_256_SUPPORT=0)
    add_definitions(-DLIBSPDM_SHA3_384_SUPPORT=0)
    add_definitions(-DLIBSPDM_SHA3_512_SUPPORT=0)
    add_definitions(-DLIBSPDM_SM3_256_SUPPORT=0)
    add_definitions(-DLIBSPDM_EDDSA_ED25519_SUPPORT=0)
    add_definitions(-DLIBSPDM_EDDSA_ED448_SUPPORT=0)
    add_definitions(-DLIBSPDM_SM2_DSA_P256_SUPPORT=0)
    add_definitions(-DLIBSPDM_SM2_KEY_EXCHANGE_P256_SUPPORT=0)
    add_definitions(-DLIBSPDM_AEAD_SM4_128_GCM_SUPPORT=0)
elseif(CRYPTO STREQUAL "openssl")
    MESSAGE("CRYPTO = openssl")
    add_definitions(-DLIBSPDM_SM2_DSA_P256_SUPPORT=0)
    add_definitions(-DLIBSPDM_SM2_KEY_EXCHANGE_P256_SUPPORT=0)
    add_definitions(-DLIBSPDM_AEAD_SM4_128_GCM_SUPPORT=0)
else()
    MESSAGE(FATAL_ERROR "Unknown CRYPTO")
endif()

if (X509_IGNORE_CRITICAL STREQUAL "ON")
    if (CRYPTO STREQUAL "openssl")
        add_definitions(-DOPENSSL_IGNORE_CRITICAL=1)
    elseif(CRYPTO STREQUAL "mbedtls")
        add_definitions(-DMBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION)
    endif()
endif()

if(ENABLE_BINARY_BUILD STREQUAL "1")
    if(NOT CRYPTO STREQUAL "openssl")
        MESSAGE(FATAL_ERROR "enabling binary build not supported for non-openssl")
    endif()

    if(NOT COMPILED_LIBCRYPTO_PATH)
        MESSAGE(FATAL_ERROR "enabling binary build requires path to libcrypto.")
    endif()

    if(NOT COMPILED_LIBSSL_PATH)
        MESSAGE(FATAL_ERROR "enabling binary build requires path to libssl.")
    endif()

    # Disable EDDSA when binary builds are enabled. EDDSA may be enabled in the future.
    add_definitions(-DLIBSPDM_EDDSA_ED25519_SUPPORT=0)
    add_definitions(-DLIBSPDM_EDDSA_ED448_SUPPORT=0)

    MESSAGE("ENABLE_BINARY_BUILD=1")
    MESSAGE("COMPILED_LIBCRYPTO_PATH=${COMPILED_LIBCRYPTO_PATH}")
    MESSAGE("COMPILED_LIBSSL_PATH=${COMPILED_LIBSSL_PATH}")
    MESSAGE("Disabling EDDSA support due to ENABLE_BINARY_BUILD=1")

    SET(CRYPTO_LIB_PATHS ${COMPILED_LIBCRYPTO_PATH} ${COMPILED_LIBSSL_PATH})

else()
    SET(CRYPTO_LIB_PATHS ${CRYPTO}lib)
    MESSAGE("ENABLE_BINARY_BUILD=0; Building ${CRYPTO} library from source.")
endif()

if(ENABLE_CODEQL STREQUAL "ON")
    MESSAGE("Enable CodeQL scan.")
endif()

if(CMAKE_SYSTEM_NAME MATCHES "Linux")
    SET(CMAKE_EXE_EXPORTS_C_FLAG "")

    if(TOOLCHAIN STREQUAL "GCC")
        SET(CMAKE_C_COMPILER gcc)
        ADD_COMPILE_OPTIONS(-std=c99 -fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -Wno-address -fpie -fno-asynchronous-unwind-tables -DUSING_LTO  -Wno-maybe-uninitialized -Wno-uninitialized  -Wno-builtin-declaration-mismatch -Wno-nonnull-compare -Werror-implicit-function-declaration -Wcast-qual -Wcast-align)
        if (ARCH STREQUAL "x64")
            ADD_COMPILE_OPTIONS(-mno-red-zone)
        endif()
        if (ARCH STREQUAL "x64" OR "ia32")
            ADD_COMPILE_OPTIONS(-maccumulate-outgoing-args)
        endif()
        if(CMAKE_BUILD_TYPE STREQUAL "Debug")
            ADD_COMPILE_OPTIONS(-g)
        endif()
        if(STACK_USAGE STREQUAL "ON")
            ADD_COMPILE_OPTIONS(-fstack-usage)
        else()
            ADD_COMPILE_OPTIONS(-flto)
        endif()
        if(GCOV STREQUAL "ON")
        ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage)
        endif()
        SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual)
        if(STACK_USAGE STREQUAL "ON")
            SET(OPENSSL_FLAGS ${OPENSSL_FLAGS} -fstack-usage)
        endif()
        SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual)
        if(STACK_USAGE STREQUAL "ON")
            SET(CMOCKA_FLAGS ${CMOCKA_FLAGS} -fstack-usage)
        endif()

        SET(CMAKE_AR gcc-ar)

        if(NOT CMAKE_C_COMPILER_VERSION VERSION_GREATER 9.2)
                SET(CMAKE_C_ARCHIVE_FINISH true)
        endif()

        SET(CMAKE_LINKER gcc)
        SET(CMAKE_EXE_LINKER_FLAGS "-flto -Wno-error -no-pie" )
        if(GCOV STREQUAL "ON")
        SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}  --coverage -lgcov -fprofile-arcs -ftest-coverage")
        endif()
        SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--start-group <LINK_LIBRARIES> -Wl,--end-group")

    elseif(TOOLCHAIN STREQUAL "ARM_DS2022")
        if(ARCH STREQUAL "aarch64")
            SET(CMAKE_SYSTEM_NAME   Linux)
            SET(CMAKE_C_COMPILER    armclang)
            SET(CMAKE_AR            armar)
            SET(CMAKE_LINKER        armlink)
            SET(CMAKE_OBJCOPY       fromelf)

            SET(CMAKE_EXECUTABLE_SUFFIX ".elf")
            SET(CMAKE_LIBRARY_PATH_FLAG "--userlibpath=")
            ADD_COMPILE_OPTIONS(-fshort-wchar -fno-strict-aliasing  -ffunction-sections -fdata-sections -fno-common -fpie -fno-asynchronous-unwind-tables -flto -DUSING_LTO)
            SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic )
            SET(OPENSSL_FLAGS -include base.h)
            SET(CMAKE_C_CREATE_STATIC_LIBRARY "armar -r -s --create <TARGET> <LINK_FLAGS> <OBJECTS>")
            SET(CMAKE_SYSTEM_PROCESSOR aarch64v)
            ADD_COMPILE_OPTIONS(--target=aarch64-arm-none-eabi)
            SET(CMAKE_EXE_LINKER_FLAGS "--target=aarch64-arm-none-eabi -flto -Wl,--undefined=__udivti3")
        elseif(ARCH STREQUAL "arm")
            SET(CMAKE_SYSTEM_NAME   Linux)
            SET(CMAKE_C_COMPILER    armclang)
            SET(CMAKE_LINKER        armlink)
            SET(CMAKE_SYSTEM_PROCESSOR arm)

            SET(CMAKE_EXECUTABLE_SUFFIX ".elf")
            ADD_COMPILE_OPTIONS(--target=arm-arm-none-eabi -march=armv9-a)
            SET(CMAKE_EXE_LINKER_FLAGS "--target=arm-arm-none-eabi -march=armv9-a -Wl,--undefined=__udivti3")
            SET(OPENSSL_FLAGS -include base.h)
            SET(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
        endif()

        SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
        SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
        SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
        SET(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

    elseif(TOOLCHAIN STREQUAL "ARM_GNU")
        if(ARCH STREQUAL "aarch64")
            SET(CMAKE_C_COMPILER aarch64-none-linux-gnu-gcc)
            SET(CMAKE_AR aarch64-none-linux-gnu-gcc-ar)
            SET(CMAKE_LINKER aarch64-none-linux-gnu-gcc)
        elseif(ARCH STREQUAL "arm")
            SET(CMAKE_C_COMPILER arm-none-linux-gnueabihf-gcc)
            SET(CMAKE_AR arm-none-linux-gnueabihf-gcc-ar)
            SET(CMAKE_LINKER arm-none-linux-gnueabihf-gcc)
        endif()
        ADD_COMPILE_OPTIONS(-fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -Wno-address -fpie -fno-asynchronous-unwind-tables -flto -DUSING_LTO  -Wno-maybe-uninitialized -Wno-uninitialized  -Wno-builtin-declaration-mismatch -Wno-nonnull-compare -Werror-implicit-function-declaration)
        if(CMAKE_BUILD_TYPE STREQUAL "Debug")
           ADD_COMPILE_OPTIONS(-g)
        endif()
        if(GCOV STREQUAL "ON")
        ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage)
        endif()
        SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual)
        SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual)

        SET(CMAKE_EXE_LINKER_FLAGS "-flto -Wno-error -no-pie" )
        if(GCOV STREQUAL "ON")
        SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}  --coverage -lgcov -fprofile-arcs -ftest-coverage")
        endif()

        SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--start-group <LINK_LIBRARIES> -Wl,--end-group")


    elseif(TOOLCHAIN STREQUAL "ARM_GNU_BARE_METAL")
        if(ARCH STREQUAL "aarch64")
            SET(CMAKE_C_COMPILER aarch64-none-elf-gcc)
            SET(CMAKE_AR aarch64-none-elf-gcc-ar)
            SET(CMAKE_LINKER aarch64-none-elf-gcc)
        elseif(ARCH STREQUAL "arm")
            SET(CMAKE_C_COMPILER arm-none-eabi-gcc)
            SET(CMAKE_AR arm-none-eabi-gcc-ar)
            SET(CMAKE_LINKER arm-none-eabi-gcc)
        endif()
        if(NOT DEFINED MARCH)
            message(FATAL_ERROR "A target architecture must be set with the -DMARCH option")
        endif()
        if(DISABLE_LTO STREQUAL "1")
            SET(FLTO_COMPILE_OPTS "-fno-lto")
            SET(FLTO_LINK_OPTS "-fno-lto")
        else()
            if (DEFINED USING_LTO)
                SET(FLTO_COMPILE_OPTS "-flto" "-${USING_LTO}")
            else()
                SET(FLTO_COMPILE_OPTS "-flto")
            endif()
            SET(FLTO_LINK_OPTS "-flto")
        endif()
        SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
        ADD_COMPILE_OPTIONS(-march=${MARCH} -fshort-wchar --specs=nosys.specs -fno-strict-aliasing -Wall -Wno-error=format -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -Wno-address -fpie -fno-asynchronous-unwind-tables ${FLTO_COMPILE_OPTS}  -Wno-maybe-uninitialized -Wno-uninitialized  -Wno-builtin-declaration-mismatch -Wno-nonnull-compare -Werror-implicit-function-declaration)
        if(CMAKE_BUILD_TYPE STREQUAL "Debug")
            ADD_COMPILE_OPTIONS(-g)
        endif()

        SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual)
        SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wno-error=format -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual)
        SET(CMAKE_EXE_LINKER_FLAGS "--specs=nosys.specs -Wno-error -no-pie ${FLTO_LINK_OPTS}")

        SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--start-group <LINK_LIBRARIES> -Wl,--end-group")

    elseif(TOOLCHAIN STREQUAL "ARM_GCC")
        SET(CMAKE_C_COMPILER arm-linux-gnueabi-gcc)
        ADD_COMPILE_OPTIONS(-fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -Wno-address -fpie -fno-asynchronous-unwind-tables -flto -DUSING_LTO  -Wno-maybe-uninitialized -Wno-uninitialized  -Wno-builtin-declaration-mismatch -Wno-nonnull-compare -Werror-implicit-function-declaration)
        if(CMAKE_BUILD_TYPE STREQUAL "Debug")
            ADD_COMPILE_OPTIONS(-g)
        endif()
        if(GCOV STREQUAL "ON")
        ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage)
        endif()
        SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual)
        SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual)

        SET(CMAKE_AR arm-linux-gnueabi-gcc-ar)

        SET(CMAKE_LINKER arm-linux-gnueabi-gcc)
        SET(CMAKE_EXE_LINKER_FLAGS "-flto -Wno-error -no-pie" )
        if(GCOV STREQUAL "ON")
        SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}  --coverage -lgcov -fprofile-arcs -ftest-coverage")
        endif()
        SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--start-group <LINK_LIBRARIES> -Wl,--end-group")

    elseif(TOOLCHAIN STREQUAL "AARCH64_GCC")
        SET(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
        ADD_COMPILE_OPTIONS(-fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -Wno-address -fpie -fno-asynchronous-unwind-tables -flto -DUSING_LTO  -Wno-maybe-uninitialized -Wno-uninitialized  -Wno-builtin-declaration-mismatch -Wno-nonnull-compare -Werror-implicit-function-declaration)
        if(CMAKE_BUILD_TYPE STREQUAL "Debug")
           ADD_COMPILE_OPTIONS(-g)
        endif()
        if(GCOV STREQUAL "ON")
        ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage)
        endif()
        SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual)
        SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual)

        SET(CMAKE_AR aarch64-linux-gnu-gcc-ar)

        SET(CMAKE_LINKER aarch64-linux-gnu-gcc)
        SET(CMAKE_EXE_LINKER_FLAGS "-flto -Wno-error -no-pie" )
        if(GCOV STREQUAL "ON")
        SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}  --coverage -lgcov -fprofile-arcs -ftest-coverage")
        endif()

        SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--start-group <LINK_LIBRARIES> -Wl,--end-group")

    elseif(TOOLCHAIN STREQUAL "RISCV_GNU")
        if(ARCH STREQUAL "riscv32")
            SET(CMAKE_C_COMPILER riscv32-unknown-linux-gnu-gcc)
            SET(CMAKE_AR riscv32-unknown-linux-gnu-gcc-ar)
            SET(CMAKE_LINKER riscv32-unknown-linux-gnu-gcc)
        elseif(ARCH STREQUAL "riscv64")
            SET(CMAKE_C_COMPILER riscv64-unknown-linux-gnu-gcc)
            SET(CMAKE_AR riscv64-unknown-linux-gnu-gcc-ar)
            SET(CMAKE_LINKER riscv64-unknown-linux-gnu-gcc)
        endif()
        ADD_COMPILE_OPTIONS(-fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -Wno-address -fpie -fno-asynchronous-unwind-tables -flto -DUSING_LTO  -Wno-maybe-uninitialized -Wno-uninitialized  -Wno-builtin-declaration-mismatch -Wno-nonnull-compare -Werror-implicit-function-declaration)
        if(CMAKE_BUILD_TYPE STREQUAL "Debug")
           ADD_COMPILE_OPTIONS(-g)
        endif()
        if(GCOV STREQUAL "ON")
        ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage)
        endif()
        SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual)
        SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual)

        SET(CMAKE_EXE_LINKER_FLAGS "-flto -Wno-error -no-pie" )
        if(GCOV STREQUAL "ON")
        SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}  --coverage -lgcov -fprofile-arcs -ftest-coverage")
        endif()

        SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--start-group <LINK_LIBRARIES> -Wl,--end-group")

    elseif(TOOLCHAIN STREQUAL "RISCV64_GCC")
        SET(CMAKE_C_COMPILER riscv64-linux-gnu-gcc)
        ADD_COMPILE_OPTIONS(-fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -Wno-address -fpie -fno-asynchronous-unwind-tables -flto -DUSING_LTO  -Wno-maybe-uninitialized -Wno-uninitialized  -Wno-builtin-declaration-mismatch -Wno-nonnull-compare -Werror-implicit-function-declaration)
        if(CMAKE_BUILD_TYPE STREQUAL "Debug")
           ADD_COMPILE_OPTIONS(-g)
        endif()
        if(GCOV STREQUAL "ON")
        ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage)
        endif()
        SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual)
        SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual)

        SET(CMAKE_AR riscv64-linux-gnu-gcc-ar)

        SET(CMAKE_LINKER riscv64-linux-gnu-gcc)
        SET(CMAKE_EXE_LINKER_FLAGS "-flto -Wno-error -no-pie" )
        if(GCOV STREQUAL "ON")
        SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}  --coverage -lgcov -fprofile-arcs -ftest-coverage")
        endif()

        SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--start-group <LINK_LIBRARIES> -Wl,--end-group")

    elseif(TOOLCHAIN STREQUAL "RISCV_NONE")
        SET(CMAKE_C_COMPILER riscv64-elf-gcc)
        ADD_COMPILE_OPTIONS(-nostdlib -lgcc)
        if(CMAKE_BUILD_TYPE STREQUAL "Debug")
           ADD_COMPILE_OPTIONS(-g)
        endif()

        if(ARCH STREQUAL "riscv32")
            ADD_COMPILE_OPTIONS(-march=rv32imac_zicsr -mabi=ilp32)
        elseif(ARCH STREQUAL "riscv64")
            ADD_COMPILE_OPTIONS(-march=rv64imac_zicsr -mabi=lp64)
        else()
            ADD_COMPILE_OPTIONS(-march=error -mabi=error)
        endif()

        SET(CMAKE_AR riscv64-elf-ar)

        SET(CMAKE_LINKER riscv64-elf-gcc)
        SET(CMAKE_EXE_LINKER_FLAGS "-no-pie" )

        SET(MBEDTLS_FLAGS -nostdlib -lgcc)

        SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--start-group <LINK_LIBRARIES> -Wl,--end-group")

    elseif(TOOLCHAIN STREQUAL "RISCV_XPACK")
        SET(CMAKE_C_COMPILER riscv-none-elf-gcc)
        SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")

        if(ARCH STREQUAL "riscv32")
            ADD_COMPILE_OPTIONS(-march=rv32imafdc_zicsr -mabi=ilp32d)
        elseif(ARCH STREQUAL "riscv64")
            ADD_COMPILE_OPTIONS(-march=rv64imafdc_zicsr -mabi=lp64d)
        else()
            ADD_COMPILE_OPTIONS(-march=error -mabi=error)
        endif()

        ADD_COMPILE_OPTIONS(-fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds   -Wno-error=format -ffunction-sections -fdata-sections -fno-common -Wno-address -fpie -fno-asynchronous-unwind-tables -flto -DUSING_LTO  -Wno-maybe-uninitialized -Wno-uninitialized  -Wno-builtin-declaration-mismatch -Wno-nonnull-compare -Werror-implicit-function-declaration)
        if(CMAKE_BUILD_TYPE STREQUAL "Debug")
           ADD_COMPILE_OPTIONS(-g)
        endif()

        SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual)
        SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow  -Wno-error=format -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual)

        SET(CMAKE_AR riscv-none-elf-ar)

        SET(CMAKE_LINKER riscv-none-elf-gcc)

        if(ARCH STREQUAL "riscv32")
            SET(CMAKE_EXE_LINKER_FLAGS "-march=rv32imafdc_zicsr -mabi=ilp32d -flto -Wno-error -no-pie" )
        elseif(ARCH STREQUAL "riscv64")
            SET(CMAKE_EXE_LINKER_FLAGS "-march=rv64imafdc_zicsr -mabi=lp64d -flto -Wno-error -no-pie" )
        endif()

        SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--start-group <LINK_LIBRARIES> -Wl,--end-group")

    elseif(TOOLCHAIN STREQUAL "ARC_GCC")
        SET(CMAKE_C_COMPILER arc-linux-gcc)
        ADD_COMPILE_OPTIONS(-fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -Wno-address -fpie -fno-asynchronous-unwind-tables -flto -DUSING_LTO  -Wno-maybe-uninitialized -Wno-uninitialized  -Wno-builtin-declaration-mismatch -Wno-nonnull-compare -Werror-implicit-function-declaration)
        if(CMAKE_BUILD_TYPE STREQUAL "Debug")
           ADD_COMPILE_OPTIONS(-g)
        endif()
        if(GCOV STREQUAL "ON")
        ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage)
        endif()
        SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual)
        SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual)

        SET(CMAKE_AR arc-linux-gcc-ar)

        SET(CMAKE_LINKER arc-linux-gcc)
        SET(CMAKE_EXE_LINKER_FLAGS "-flto -Wno-error -no-pie" )
        if(GCOV STREQUAL "ON")
        SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}  --coverage -lgcov -fprofile-arcs -ftest-coverage")
        endif()

        SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--start-group <LINK_LIBRARIES> -Wl,--end-group")


    elseif(TOOLCHAIN STREQUAL "CLANG")
        SET(CMAKE_C_COMPILER clang)
        ADD_COMPILE_OPTIONS(-std=c99 -fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -Wno-address -fpie -fno-asynchronous-unwind-tables -flto -DUSING_LTO -Werror-implicit-function-declaration)
        if(CMAKE_BUILD_TYPE STREQUAL "Debug")
           ADD_COMPILE_OPTIONS(-g)
        endif()
        if (ARCH STREQUAL "x64")
            ADD_COMPILE_OPTIONS(-mno-red-zone)
        endif()
        SET(OPENSSL_FLAGS -std=c11 -include base.h -Wno-error=format -Wno-format -Wno-cast-qual)
        SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual)

        SET(CMAKE_AR llvm-ar)
        SET(CMAKE_RANLIB llvm-ranlib)

        SET(CMAKE_LINKER clang)
        SET(CMAKE_EXE_LINKER_FLAGS "-flto -Wno-error -no-pie" )

        SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--start-group <LINK_LIBRARIES> -Wl,--end-group")

    elseif(TOOLCHAIN STREQUAL "CBMC")
        SET(CMAKE_C_COMPILER goto-cc)
        ADD_COMPILE_OPTIONS(-fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -maccumulate-outgoing-args -mno-red-zone -Wno-address -fpie -fno-asynchronous-unwind-tables -flto -DUSING_LTO  -Wno-maybe-uninitialized -Wno-uninitialized  -Wno-builtin-declaration-mismatch -Wno-nonnull-compare -DCBMC -DDEBUG_ASSERT_CHOICE=0 -Werror-implicit-function-declaration)
        if(CMAKE_BUILD_TYPE STREQUAL "Debug")
           ADD_COMPILE_OPTIONS(-g)
        endif()
        SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual)
        SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual)

        SET(CMAKE_LINKER goto-cc)
        SET(CMAKE_EXE_LINKER_FLAGS "-flto -Wno-error")

        SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <OBJECTS> -o <TARGET>")

    elseif(TOOLCHAIN STREQUAL "AFL")
        SET(CMAKE_C_COMPILER afl-gcc)
        ADD_COMPILE_OPTIONS(-std=c99 -fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -maccumulate-outgoing-args -mno-red-zone -Wno-address -fpie -fno-asynchronous-unwind-tables -DUSING_LTO  -Wno-maybe-uninitialized -Wno-uninitialized  -Wno-builtin-declaration-mismatch -Wno-nonnull-compare -Werror-implicit-function-declaration)
        if(CMAKE_BUILD_TYPE STREQUAL "Debug")
           ADD_COMPILE_OPTIONS(-g)
        endif()
        if(GCOV STREQUAL "ON")
        ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage)
        endif()
        SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual)
        SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual)

        SET(CMAKE_AR gcc-ar)

        SET(CMAKE_LINKER gcc)
        SET(CMAKE_EXE_LINKER_FLAGS "-Wno-error -no-pie" )
        if(GCOV STREQUAL "ON")
        SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}  --coverage -lgcov -fprofile-arcs -ftest-coverage")
        endif()

        SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--start-group <LINK_LIBRARIES> -Wl,--end-group")

    elseif(TOOLCHAIN STREQUAL "KLEE")
        SET(CMAKE_C_COMPILER clang)
        ADD_COMPILE_OPTIONS(-fno-strict-aliasing -Wall  -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common  -mno-red-zone -Wno-address -fpie -fno-asynchronous-unwind-tables -flto -DUSING_LTO  -emit-llvm -DTEST_WITH_KLEE=TRUE -DDEBUG_ASSERT_CHOICE=0 -Werror-implicit-function-declaration)
        if(CMAKE_BUILD_TYPE STREQUAL "Debug")
           ADD_COMPILE_OPTIONS(-g)
        endif()
        SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual)
        SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual)

        SET(CMAKE_C_CREATE_STATIC_LIBRARY "")

        SET(CMAKE_LINKER llvm-link)

        SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <OBJECTS> -o <TARGET>")

    elseif(TOOLCHAIN STREQUAL "LIBFUZZER")
        SET(CMAKE_C_COMPILER clang)
        # -O1 may cause fuzzing test buffer overflow, use -O0 as workaround
        ADD_COMPILE_OPTIONS(-std=c99 -fshort-wchar -fno-strict-aliasing -Wall  -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common  -mno-red-zone -Wno-address -fpie -fno-asynchronous-unwind-tables -DUSING_LTO  -DTEST_WITH_LIBFUZZER=TRUE -O0 -fsanitize=fuzzer,address -Werror-implicit-function-declaration)
        if(CMAKE_BUILD_TYPE STREQUAL "Debug")
           ADD_COMPILE_OPTIONS(-g)
        endif()
        if(GCOV STREQUAL "ON")
        ADD_COMPILE_OPTIONS(-fprofile-instr-generate -fcoverage-mapping)
        endif()
        SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual)
        SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual)

        SET(CMAKE_AR llvm-ar)

        SET(CMAKE_LINKER clang)
        SET(CMAKE_EXE_LINKER_FLAGS "-Wno-error -no-pie -fsanitize=fuzzer,address" )
        if(GCOV STREQUAL "ON")
        SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-instr-generate")
        endif()

        SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--start-group <LINK_LIBRARIES> -Wl,--end-group")

    elseif(TOOLCHAIN STREQUAL "NIOS2_GCC")
        SET(CMAKE_C_COMPILER nios2-elf-gcc)
        ADD_COMPILE_OPTIONS(-xc -MP -MMD -pipe -O3  -Wall -Wno-maybe-uninitialized -Wno-unused-but-set-variable -Wno-nonnull-compare -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast  -Wno-builtin-declaration-mismatch  -mno-hw-div -mhw-mul -mno-hw-mulx -mgpopt=global -Werror-implicit-function-declaration)
        SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual)
        SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual)

        SET(CMAKE_AR nios2-elf-ar)

        SET(CMAKE_LINKER nios2-elf-gcc)
        SET(CMAKE_EXE_LINKER_FLAGS "")

        SET(CMAKE_C_LINK_EXECUTABLE "")
    endif()

    if(NOT TOOLCHAIN STREQUAL "NIOS2_GCC")
        SET(CMAKE_C_FLAGS_RELEASE     "-Os")
        SET(CMAKE_C_FLAGS_DEBUG       "-O0")
    endif()

    if(ARCH STREQUAL "x64")
        ADD_COMPILE_OPTIONS(-m64 -mcmodel=small)
    elseif(ARCH STREQUAL "ia32")
        ADD_COMPILE_OPTIONS(-m32)
        SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m32" )
    endif()

elseif(CMAKE_SYSTEM_NAME MATCHES "Windows")
    if(TOOLCHAIN STREQUAL "GCC")
        SET(CMAKE_C_COMPILER gcc)
        ADD_COMPILE_OPTIONS(-std=c99 -fshort-wchar -fno-strict-aliasing -Wall -Wno-error=incompatible-pointer-types -Wno-error=format-extra-args -Wno-error=format= -Wno-error=unknown-pragmas -Wno-error=attributes -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -Wno-address -fpie -fno-asynchronous-unwind-tables -Wno-maybe-uninitialized -Wno-uninitialized  -Wno-builtin-declaration-mismatch -Wno-nonnull-compare -Werror-implicit-function-declaration -Wcast-qual)
        if (ARCH STREQUAL "x64")
            ADD_COMPILE_OPTIONS(-mno-red-zone)
        endif()
        if (ARCH STREQUAL "x64" OR "ia32")
            ADD_COMPILE_OPTIONS(-maccumulate-outgoing-args)
        endif()
        if(CMAKE_BUILD_TYPE STREQUAL "Debug")
            ADD_COMPILE_OPTIONS(-g)
        endif()
        if(STACK_USAGE STREQUAL "ON")
            ADD_COMPILE_OPTIONS(-fstack-usage)
        else()
            ADD_COMPILE_OPTIONS(-fno-lto)
        endif()
        if(GCOV STREQUAL "ON")
        ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage)
        endif()
        SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual)
        if(STACK_USAGE STREQUAL "ON")
            SET(OPENSSL_FLAGS ${OPENSSL_FLAGS} -fstack-usage)
        endif()
        SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual)
        if(STACK_USAGE STREQUAL "ON")
            SET(CMOCKA_FLAGS ${CMOCKA_FLAGS} -fstack-usage)
        endif()

        SET(CMAKE_AR gcc-ar)

        if(NOT CMAKE_C_COMPILER_VERSION VERSION_GREATER 9.2)
                SET(CMAKE_C_ARCHIVE_FINISH true)
        endif()

        SET(CMAKE_LINKER gcc)
        SET(CMAKE_EXE_LINKER_FLAGS "-Wno-error -no-pie -fstack-protector" )
        if(GCOV STREQUAL "ON")
        SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}  --coverage -lgcov -fprofile-arcs -ftest-coverage")
        endif()
        SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--start-group /mingw64/lib/libbcrypt.a <LINK_LIBRARIES> -Wl,--end-group")
    elseif(TOOLCHAIN STREQUAL "CLANG")
        SET(CMAKE_C_COMPILER clang-cl.exe)
        ADD_COMPILE_OPTIONS(-fno-strict-aliasing -Wall  -Wno-array-bounds -Wno-address  -flto -DUSING_LTO  -D_CRT_SECURE_NO_WARNINGS /w)
        SET(OPENSSL_FLAGS /FIbase.h -Wno-cast-qual)
        SET(CMOCKA_FLAGS -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -Wformat -Wno-cast-qual)

        SET(CMAKE_STATIC_LINKER_FLAGS "")

        SET(CMAKE_LINKER lld-link.exe)
        SET(CMAKE_EXE_LINKER_FLAGS "/NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB:libcmt.lib /IGNORE:4086 /MLLVM:-exception-model=wineh /lldmap /OPT:REF")

        if(ARCH STREQUAL "x64")
            SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MACHINE:AMD64 /LIBPATH:'%VCToolsInstallDir%lib/x64' /LIBPATH:'%UniversalCRTSdkDir%lib/%UCRTVersion%/ucrt/x64' /LIBPATH:'%WindowsSdkDir%lib/%WindowsSDKLibVersion%/um/x64'")
        elseif(ARCH STREQUAL "ia32")
            SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MACHINE:I386 /LIBPATH:'%VCToolsInstallDir%lib/x86' /LIBPATH:'%UniversalCRTSdkDir%lib/%UCRTVersion%/ucrt/x86' /LIBPATH:'%WindowsSdkDir%lib/%WindowsSDKLibVersion%/um/x86'")
        endif()

        SET(CMAKE_C_FLAGS_RELEASE     "-Oz")
        SET(CMAKE_C_FLAGS_DEBUG       "-O0 -gcodeview")

        SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG:GHASH")

        if(ARCH STREQUAL "x64")
            ADD_COMPILE_OPTIONS(-m64)
        elseif(ARCH STREQUAL "ia32")
            ADD_COMPILE_OPTIONS(-m32 -march=i586)
        endif()

        SET(CMAKE_C_STANDARD_LIBRARIES "Kernel32.lib MSVCRTD.lib vcruntimed.lib ucrtd.lib Gdi32.lib User32.lib Winmm.lib Advapi32.lib ws2_32.lib")

    elseif(TOOLCHAIN STREQUAL "ARM_DS2022")
        SET(CMAKE_C_COMPILER    "armclang.exe")
        SET(CMAKE_AR            "armar.exe")
        SET(CMAKE_LINKER        "armlink.exe")
        SET(CMAKE_OBJCOPY       "fromelf.exe")
        SET(CMAKE_SYSTEM_ARCH   "armv8.2-a")
        SET(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT "GNU")
        SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
        SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
        SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
        SET(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
        SET(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN_PATH})
        SET(CMAKE_EXECUTABLE_SUFFIX ".elf")

        SET(OPENSSL_FLAGS  -include base.h)

        if (ARCH STREQUAL "arm")
        SET(CMAKE_SYSTEM_PROCESSOR ARM)
        ADD_COMPILE_OPTIONS(-marm)
        ADD_COMPILE_OPTIONS(--target=arm-arm-none-eabi)
        elseif (ARCH STREQUAL "aarch64")
        SET(CMAKE_SYSTEM_PROCESSOR aarch64v)
        ADD_COMPILE_OPTIONS(--target=aarch64-arm-none-eabi -Wl,--undefined=__udivti3)
        endif()

        SET(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
        SET(CMAKE_SYSTEM_NAME Linux )
        SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <LINK_FLAGS> -o <TARGET> <LINK_LIBRARIES> <OBJECTS>")

    elseif(TOOLCHAIN STREQUAL "LIBFUZZER")
        SET(CMAKE_C_COMPILER clang-cl.exe)
        ADD_COMPILE_OPTIONS(-fno-strict-aliasing -Wall  -Wno-array-bounds -Wno-address  -flto -DUSING_LTO  -D_CRT_SECURE_NO_WARNINGS /w -DTEST_WITH_LIBFUZZER=TRUE)
        SET(OPENSSL_FLAGS /FIbase.h -Wno-cast-qual)
        SET(CMOCKA_FLAGS -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -Wformat -Wno-cast-qual)

        SET(CMAKE_STATIC_LINKER_FLAGS "")

        SET(CMAKE_LINKER lld-link.exe)
        SET(CMAKE_EXE_LINKER_FLAGS "/NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB:libcmt.lib /IGNORE:4086 /MLLVM:-exception-model=wineh /lldmap /OPT:REF")

        if(ARCH STREQUAL "x64")
            SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MACHINE:AMD64 /LIBPATH:'%VCToolsInstallDir%lib/x64' /LIBPATH:'%UniversalCRTSdkDir%lib/%UCRTVersion%/ucrt/x64' /LIBPATH:'%WindowsSdkDir%lib/%WindowsSDKLibVersion%/um/x64'")
        elseif(ARCH STREQUAL "ia32")
            SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MACHINE:I386 /LIBPATH:'%VCToolsInstallDir%lib/x86' /LIBPATH:'%UniversalCRTSdkDir%lib/%UCRTVersion%/ucrt/x86' /LIBPATH:'%WindowsSdkDir%lib/%WindowsSDKLibVersion%/um/x86'")
        endif()

        SET(CMAKE_C_FLAGS_RELEASE     "-Oz")
        SET(CMAKE_C_FLAGS_DEBUG       "-O0 -gcodeview")

        SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG:GHASH")

        if(ARCH STREQUAL "x64")
            ADD_COMPILE_OPTIONS(-m64)
        elseif(ARCH STREQUAL "ia32")
            ADD_COMPILE_OPTIONS(-m32 -march=i586)
        endif()

        if(ARCH STREQUAL "x64")
            SET(CMAKE_C_STANDARD_LIBRARIES "Kernel32.lib MSVCRTD.lib vcruntimed.lib ucrtd.lib Gdi32.lib User32.lib Winmm.lib Advapi32.lib ws2_32.lib")
            SET(CMAKE_C_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES} C:/LLVM/lib/clang/13.0.0/lib/windows/clang_rt.asan_dynamic-x86_64.lib C:/LLVM/lib/clang/13.0.0/lib/windows/clang_rt.asan_dynamic_runtime_thunk-x86_64.lib C:/LLVM/lib/clang/13.0.0/lib/windows/clang_rt.fuzzer-x86_64.lib")
        elseif(ARCH STREQUAL "ia32")
            SET(CMAKE_C_STANDARD_LIBRARIES "Kernel32.lib MSVCRTD.lib vcruntimed.lib ucrtd.lib Gdi32.lib User32.lib Winmm.lib Advapi32.lib ws2_32.lib clang_rt.asan_dynamic-i386.lib clang_rt.asan_dynamic_runtime_thunk-i386.lib clang_rt.fuzzer-i386.lib")
        endif()

    elseif(TOOLCHAIN STREQUAL "CBMC")
        SET(CMAKE_C_COMPILER goto-cl.exe)
        # See https://gitlab.kitware.com/cmake/cmake/-/issues/18317 for following workaround
        STRING(REGEX REPLACE "/W3" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
        ADD_COMPILE_OPTIONS(/nologo /WX /W4 /Gs32768 /D UNICODE /Gy /EHs-c- /GR- /GF /Z7 /Oy- /D_CRT_SECURE_NO_WARNINGS /DCBMC_CC)
        SET(OPENSSL_FLAGS /FIbase.h /wd4090 /wd4132 /wd4244 /wd4245 /wd4267 /wd4306 /wd4310 /wd4700 /wd4389 /wd4702 /wd4706 /wd4819 /wd4013)
        SET(CMOCKA_FLAGS /wd4090 /wd4204 /wd4133 /wd4267 /wd4701 /wd4702 /wd4703 /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1 /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1 /D _CRT_NONSTDC_NO_WARNINGS=1)

        SET(CMAKE_C_CREATE_STATIC_LIBRARY "")

        SET(CMAKE_LINKER goto-cl.exe)

        SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <OBJECTS>")

        SET(CMAKE_C_FLAGS_RELEASE     "/GL /O1b2s")
        SET(CMAKE_C_FLAGS_DEBUG       "/Od")
    else()
        # See https://gitlab.kitware.com/cmake/cmake/-/issues/18317 for following workaround
        STRING(REGEX REPLACE "/W3" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
        ADD_COMPILE_OPTIONS(/nologo /WX /W4 /Gs32768 /D UNICODE /Gy /EHs-c- /GR- /GF /Z7 /Gw /Oy- /D_CRT_SECURE_NO_WARNINGS /wd4063 /wd4100 /wd4127 /wd4701 /wd4703 /wd4057)
        SET(OPENSSL_FLAGS /FIbase.h /wd4090 /wd4132 /wd4244 /wd4245 /wd4267 /wd4306 /wd4310 /wd4700 /wd4389 /wd4702 /wd4706 /wd4819 /wd4013)
        SET(CMOCKA_FLAGS /wd4090 /wd4204 /wd4133 /wd4267 /wd4701 /wd4702 /wd4703 /D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1 /D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1 /D_CRT_NONSTDC_NO_WARNINGS=1)

        SET(CMAKE_STATIC_LINKER_FLAGS "/NOLOGO /LTCG")

        SET(CMAKE_EXE_LINKER_FLAGS "/NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB:libcmt.lib /IGNORE:4086 /MAP /OPT:REF")

        SET(CMAKE_C_FLAGS_RELEASE     "/GL /O1b2s")
        SET(CMAKE_C_FLAGS_DEBUG       "/Od")
        SET(CMAKE_EXE_LINKER_FLAGS_RELEASE "/LTCG")
        SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG")

        if(ARCH STREQUAL "x64")
            SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MACHINE:AMD64")
        elseif(ARCH STREQUAL "ia32")
            SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MACHINE:I386")
        endif()
        SET(CMAKE_C_STANDARD_LIBRARIES "Kernel32.lib MSVCRTD.lib vcruntimed.lib ucrtd.lib Gdi32.lib User32.lib Winmm.lib Advapi32.lib ws2_32.lib")

    endif()
endif()

if(TOOLCHAIN STREQUAL "VS2015")
    if(ARCH STREQUAL "x64")
        SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LIBPATH:'%VCINSTALLDIR%Lib/AMD64' /LIBPATH:'%UniversalCRTSdkDir%lib/%UCRTVersion%/ucrt/x64' /LIBPATH:'%WindowsSdkDir%lib/%WindowsSDKLibVersion%/um/x64'")
    elseif(ARCH STREQUAL "ia32")
        SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LIBPATH:'%VCINSTALLDIR%Lib' /LIBPATH:'%UniversalCRTSdkDir%lib/%UCRTVersion%/ucrt/x86' /LIBPATH:'%WindowsSdkDir%lib/%WindowsSDKLibVersion%/um/x86'")
    endif()
elseif((TOOLCHAIN STREQUAL "VS2019") OR (TOOLCHAIN STREQUAL "VS2022"))
    if(ARCH STREQUAL "x64")
        SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LIBPATH:'%VCToolsInstallDir%lib/x64' /LIBPATH:'%UniversalCRTSdkDir%lib/%UCRTVersion%/ucrt/x64' /LIBPATH:'%WindowsSdkDir%lib/%WindowsSDKLibVersion%/um/x64'")
    elseif(ARCH STREQUAL "ia32")
        SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LIBPATH:'%VCToolsInstallDir%lib/x86' /LIBPATH:'%UniversalCRTSdkDir%lib/%UCRTVersion%/ucrt/x86' /LIBPATH:'%WindowsSdkDir%lib/%WindowsSDKLibVersion%/um/x86'")
    endif()
endif()

SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

ADD_CUSTOM_TARGET(copy_sample_key)

execute_process(COMMAND uname OUTPUT_VARIABLE uname)
if(CMAKE_SYSTEM_NAME MATCHES "Linux" OR uname MATCHES "^MINGW")
    ADD_CUSTOM_COMMAND(TARGET copy_sample_key
                    PRE_BUILD
                    COMMAND cp -r -f ${LIBSPDM_DIR}/unit_test/sample_key/* ${EXECUTABLE_OUTPUT_PATH})
elseif(CMAKE_SYSTEM_NAME MATCHES "Windows")
    STRING(REPLACE "/" "\\" SRC ${LIBSPDM_DIR}/unit_test/sample_key/*)
    if(CMAKE_GENERATOR MATCHES "^Visual Studio")
        if(CMAKE_BUILD_TYPE STREQUAL "Debug")
            STRING(REPLACE "/" "\\" DEST ${EXECUTABLE_OUTPUT_PATH}/Debug)
        else()
            STRING(REPLACE "/" "\\" DEST ${EXECUTABLE_OUTPUT_PATH}/Release)
        endif()
    else()
        STRING(REPLACE "/" "\\" DEST ${EXECUTABLE_OUTPUT_PATH})
    endif()
    ADD_CUSTOM_COMMAND(TARGET copy_sample_key
                    PRE_BUILD
                    COMMAND xcopy /y /s ${SRC} ${DEST})
endif()

ADD_CUSTOM_TARGET(copy_seed)

if(CMAKE_SYSTEM_NAME MATCHES "Linux" OR uname MATCHES "^MINGW")
    ADD_CUSTOM_COMMAND(TARGET copy_seed
                    PRE_BUILD
                    COMMAND cp -r -f ${LIBSPDM_DIR}/unit_test/fuzzing/seeds ${EXECUTABLE_OUTPUT_PATH}
                    COMMAND cp -r -f ${LIBSPDM_DIR}/unit_test/fuzzing/run_initial_seed.sh ${EXECUTABLE_OUTPUT_PATH})
elseif(CMAKE_SYSTEM_NAME MATCHES "Windows")
    STRING(REPLACE "/" "\\" SRC ${LIBSPDM_DIR}/unit_test/fuzzing/seeds)
    STRING(REPLACE "/" "\\" DEST ${EXECUTABLE_OUTPUT_PATH})

    ADD_CUSTOM_COMMAND(TARGET copy_seed
                       PRE_BUILD
                       COMMAND xcopy /y /s ${SRC} ${DEST})
endif()

if(CMAKE_BUILD_TYPE STREQUAL "Release")
    ADD_COMPILE_OPTIONS(-DLIBSPDM_DEBUG_ENABLE=0)
endif()

if(ENABLE_CODEQL STREQUAL "ON")
    ADD_SUBDIRECTORY(library/spdm_common_lib)
    ADD_SUBDIRECTORY(library/spdm_requester_lib)
    ADD_SUBDIRECTORY(library/spdm_responder_lib)
    ADD_SUBDIRECTORY(library/spdm_crypt_lib)
    ADD_SUBDIRECTORY(library/spdm_secured_message_lib)
    ADD_SUBDIRECTORY(library/spdm_transport_mctp_lib)
    ADD_SUBDIRECTORY(library/spdm_transport_pcidoe_lib)
    ADD_SUBDIRECTORY(os_stub/memlib)
    ADD_SUBDIRECTORY(os_stub/debuglib)
    ADD_SUBDIRECTORY(os_stub/debuglib_null)
    ADD_SUBDIRECTORY(os_stub/rnglib)
    ADD_SUBDIRECTORY(os_stub/platform_lib)
    ADD_SUBDIRECTORY(os_stub/platform_lib_null)
    ADD_SUBDIRECTORY(os_stub/malloclib)
    ADD_SUBDIRECTORY(os_stub/spdm_device_secret_lib_sample)
    ADD_SUBDIRECTORY(os_stub/spdm_device_secret_lib_null)
    ADD_SUBDIRECTORY(os_stub/spdm_cert_verify_callback_sample)
    ADD_SUBDIRECTORY(os_stub/cryptlib_null)
    ADD_SUBDIRECTORY(os_stub/cryptlib_mbedtls)
    ADD_SUBDIRECTORY(os_stub/cryptlib_openssl)
    ADD_SUBDIRECTORY(os_stub/spdm_crypt_ext_lib)
else()
    if(CRYPTO STREQUAL "mbedtls")
        ADD_SUBDIRECTORY(os_stub/cryptlib_mbedtls)
    elseif(CRYPTO STREQUAL "openssl")
        ADD_SUBDIRECTORY(os_stub/cryptlib_openssl)
    endif()

    if(NOT ENABLE_BINARY_BUILD STREQUAL "1")
        if(CRYPTO STREQUAL "mbedtls")
            ADD_SUBDIRECTORY(os_stub/mbedtlslib)
        elseif(CRYPTO STREQUAL "openssl")
            ADD_SUBDIRECTORY(os_stub/openssllib)
        endif()
    endif()

        ADD_SUBDIRECTORY(library/spdm_common_lib)
        ADD_SUBDIRECTORY(library/spdm_requester_lib)
        ADD_SUBDIRECTORY(library/spdm_responder_lib)
        ADD_SUBDIRECTORY(library/spdm_crypt_lib)
        ADD_SUBDIRECTORY(os_stub/spdm_crypt_ext_lib)
        ADD_SUBDIRECTORY(library/spdm_secured_message_lib)
        ADD_SUBDIRECTORY(library/spdm_transport_mctp_lib)
        ADD_SUBDIRECTORY(library/spdm_transport_pcidoe_lib)
        ADD_SUBDIRECTORY(os_stub/memlib)
        ADD_SUBDIRECTORY(os_stub/debuglib)
        ADD_SUBDIRECTORY(os_stub/debuglib_null)
        ADD_SUBDIRECTORY(os_stub/rnglib)
        ADD_SUBDIRECTORY(os_stub/platform_lib)
        ADD_SUBDIRECTORY(os_stub/platform_lib_null)
        ADD_SUBDIRECTORY(os_stub/malloclib)
        ADD_SUBDIRECTORY(os_stub/spdm_device_secret_lib_sample)
        ADD_SUBDIRECTORY(os_stub/spdm_device_secret_lib_null)
        ADD_SUBDIRECTORY(os_stub/spdm_cert_verify_callback_sample)

        if(NOT DISABLE_TESTS STREQUAL "1")
            ADD_SUBDIRECTORY(unit_test/spdm_transport_test_lib)
            ADD_SUBDIRECTORY(unit_test/cmockalib)

            if(TOOLCHAIN STREQUAL "ARM_DS2022" OR TOOLCHAIN STREQUAL "ARM_GNU" OR TOOLCHAIN STREQUAL "ARM_GNU_BARE_METAL")
            ADD_SUBDIRECTORY(os_stub/armbuild_lib)
            endif()

            if(NOT TOOLCHAIN STREQUAL "LIBFUZZER")
            ADD_SUBDIRECTORY(unit_test/test_spdm_requester)
            ADD_SUBDIRECTORY(unit_test/test_spdm_responder)
            ADD_SUBDIRECTORY(unit_test/test_crypt)
            ADD_SUBDIRECTORY(unit_test/test_spdm_crypt)
            ADD_SUBDIRECTORY(unit_test/test_spdm_fips)
            ADD_SUBDIRECTORY(unit_test/test_spdm_secured_message)
            ADD_SUBDIRECTORY(unit_test/test_spdm_sample)
            endif()

            if((NOT TOOLCHAIN STREQUAL "ARM_DS2022") AND (NOT TOOLCHAIN STREQUAL "RISCV_XPACK"))
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_get_version)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_version)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_get_capabilities)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_capabilities)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_negotiate_algorithms)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_algorithms)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_get_digests)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_digests)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_get_certificate)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_certificate)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_get_measurements)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_measurements)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_key_exchange)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_key_exchange)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_finish)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_finish_rsp)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_psk_exchange)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_psk_exchange_rsp)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_heartbeat)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_heartbeat_ack)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_key_update)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_key_update)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_end_session)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_end_session)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_psk_finish_rsp)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_psk_finish)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_challenge)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_challenge_auth)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_encap_challenge_auth)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_encap_challenge)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_encap_certificate)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_encap_get_certificate)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_encap_digests)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_encap_get_digests)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_encap_key_update)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_encap_key_update)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_encap_request)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_encap_response)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_if_ready)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_transport/test_spdm_transport_mctp_encode_message)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_transport/test_spdm_transport_mctp_decode_message)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_transport/test_spdm_transport_pci_doe_encode_message)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_transport/test_spdm_transport_pci_doe_decode_message)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_secured_message/test_spdm_decode_secured_message)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_secured_message/test_spdm_encode_secured_message)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_spdm_crypt/test_x509_certificate_check)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_set_certificate)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_set_certificate)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_csr)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_get_csr)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_chunk_get)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_chunk_get)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_spdm_common/test_process_opaque_data)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_chunk_send_ack)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_chunk_send)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_supported_event_types)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_get_event_types)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_requester/test_spdm_requester_vendor_cmds)
            ADD_SUBDIRECTORY(unit_test/fuzzing/test_responder/test_spdm_responder_vendor_cmds)
            endif()

            ADD_SUBDIRECTORY(os_stub/cryptlib_null)
            ADD_SUBDIRECTORY(unit_test/test_size/cryptstublib_dummy)
            ADD_SUBDIRECTORY(unit_test/test_size/intrinsiclib)
            ADD_SUBDIRECTORY(unit_test/test_size/malloclib_null)
            ADD_SUBDIRECTORY(unit_test/test_size/malloclib_simple)
            ADD_SUBDIRECTORY(unit_test/test_size/rnglib_null)

            if(NOT TOOLCHAIN STREQUAL "LIBFUZZER")
            ADD_SUBDIRECTORY(unit_test/test_spdm_common)
            endif()

        if(GCOV STREQUAL "OFF")
            if((CMAKE_SYSTEM_NAME MATCHES "Windows" AND ARCH STREQUAL "x64" AND TOOLCHAIN STREQUAL "VS2019") OR
            (CMAKE_SYSTEM_NAME MATCHES "Linux" AND ARCH STREQUAL "x64" AND (TOOLCHAIN STREQUAL "GCC" OR TOOLCHAIN STREQUAL "CLANG")) OR
            (CMAKE_SYSTEM_NAME MATCHES "Linux"  AND TOOLCHAIN STREQUAL "RISCV_XPACK") OR
            (CMAKE_SYSTEM_NAME MATCHES "Linux" AND ARCH STREQUAL "aarch64"))
                ADD_SUBDIRECTORY(unit_test/test_size/test_size_of_spdm_requester)
                ADD_SUBDIRECTORY(unit_test/test_size/test_size_of_spdm_responder)
            endif()
        endif()
    endif()

    if ((BUILD_LINUX_SHARED_LIB STREQUAL "ON") AND (CMAKE_SYSTEM_NAME MATCHES "Linux"))
        SET(LIB_NAME "spdm")
        SET(CMAKE_PROJECT_NAME "libspdm")
        SET(CMAKE_PROJECT_DESCRIPTION "libspdm shared library")

        if(NOT TOOLCHAIN STREQUAL "NONE")
            SET(CMAKE_SKIP_BUILD_RPATH FALSE)
            SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
            SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
            SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
        endif()

        add_library(${LIB_NAME} SHARED
            $<TARGET_OBJECTS:spdm_common_lib>
            $<TARGET_OBJECTS:spdm_crypt_lib>
            $<TARGET_OBJECTS:spdm_requester_lib>
            $<TARGET_OBJECTS:spdm_responder_lib>
            $<TARGET_OBJECTS:spdm_secured_message_lib>
            $<TARGET_OBJECTS:spdm_transport_mctp_lib>
            $<TARGET_OBJECTS:spdm_transport_pcidoe_lib>
        )

        add_library(${LIB_NAME}_platform SHARED
            $<TARGET_OBJECTS:debuglib>
            $<TARGET_OBJECTS:malloclib>
            $<TARGET_OBJECTS:platform_lib>
            $<TARGET_OBJECTS:rnglib>
            $<TARGET_OBJECTS:memlib>
        )

        add_library(${LIB_NAME}_crypto SHARED
            $<TARGET_OBJECTS:spdm_crypt_ext_lib>
            $<TARGET_OBJECTS:cryptlib_${CRYPTO}>
        )

        if(CRYPTO STREQUAL "mbedtls")
            SET(CRYPTO_DEPS "-lmbedtls -lmbedx509 -lmbedcrypto")
            TARGET_LINK_LIBRARIES(${LIB_NAME}_crypto
                PUBLIC mbedtls
                PUBLIC mbedx509
                PUBLIC mbedcrypto
            )
        elseif(CRYPTO STREQUAL "openssl")
            SET(CRYPTO_DEPS "-lssl -lcrypto")
            if(TOOLCHAIN STREQUAL "NONE")
                TARGET_LINK_LIBRARIES(${LIB_NAME}_crypto
                    PUBLIC openssllib
                    PUBLIC cryptlib_openssl
                )
            else()
                TARGET_LINK_LIBRARIES(${LIB_NAME}_crypto
                    PUBLIC ssl
                    PUBLIC crypto
                )
            endif()
        endif()

        TARGET_LINK_LIBRARIES(${LIB_NAME}
            PUBLIC ${LIB_NAME}_platform
            PUBLIC ${LIB_NAME}_crypto
        )

        install(DIRECTORY include DESTINATION include/libspdm)
        configure_file(libspdm.pc.in lib/pkgconfig/libspdm.pc @ONLY)
        install(FILES ${CMAKE_BINARY_DIR}/lib/pkgconfig/libspdm.pc DESTINATION lib/pkgconfig/)
        install(TARGETS ${LIB_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
        install(TARGETS ${LIB_NAME}_platform LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
        install(TARGETS ${LIB_NAME}_crypto LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
    endif()
endif()
