#!/bin/bash
# SPDX-License-Identifier: LicenseRef-CSSL-1.0

# file build_oai
# brief OAI automated build tool that can be used to install, compile, run OAI.

# Include helper functions
THIS_SCRIPT_PATH=$(dirname $(readlink -f "$0"))
source "$THIS_SCRIPT_PATH"/tools/build_helper

# Set environment variables (OPENAIR_HOME, ...)
set_openair_env

# Variables for UE data generation
conf_nvram_path=$OPENAIR_DIR/openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf

HWs=""
BUILD_DIR=ran_build
CMAKE_BUILD_TYPE="RelWithDebInfo"
CMAKE_CMD="$CMAKE"
OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope ldpc_aal websrv oai_iqplayer imscope imscope_record"
TARGET_LIST=""
BUILD_TOOL_OPT="-j$(nproc)"

function print_help() {
  echo_info "
This script compiles OpenAirInterface Software, and can install dependencies
for a number of distributions (Ubuntu 22-24, Fedora, RHEL9).
Options:
--arch-native
   Passes -march=native to the compiler.
--build-tool-opt
   Pass options to build tool (ninja/make), e.g. -k (\"keep going\")
-c | --clean
   Erase all files to make a rebuild from start
-C | --clean-all
   Erase all files made by previous compilations, installations
--clean-kernel
   Erase previously installed features in kernel: iptables, drivers, ...
--cmake-opt
   Pass the supplied option verbatim to cmake.
-d | --build-dir
   Sets build directory (will be <oai-root>/cmake_targets/<build-dir>/build)
--build-e2
   Enable the the E2 Agent
-I | --install-external-packages
   Installs required packages such as LibXML, asn1.1 compiler, ...
   This option will require root password
--install-optional-packages
   Install useful but not mandatory packages such as valgrind
-g | --run-with-gdb <Release | RelWithDebInfo | MinSizeRel | Debug
  specify the build mode used by cmake. defaults to Debug mode if -g is used alone, with no mode parameter
  if -g is not specifies, Release mode is used.
-G | --cmaketrace
   enable cmake debugging messages
--eNB
  Makes the LTE softmodem
--gNB
  Makes the NR softmodem
--RU
  Makes the OAI RRU
--nrRU
  Makes the NR RRU
--UE
   Makes the UE specific parts (usim, nvram) from the given configuration file
--nrUE
  Makes the NR UE softmodem
--UE-conf-nvram [configuration file]
   Specify conf_nvram_path (default \"$conf_nvram_path\")
-w | --hardware
   USRP, BLADERF, LMSSDR, IRIS, SIMU, AW2SORI, AERIAL, ZMQ, None (Default)
   Adds this RF board support (in external packages installation and in compilation)
-t | --transport
   Selects the transport protocol type, options: None, Ethernet, oran_fhlib_5g, oran_fhlib_5g_mplane, WLS
-P | --phy_simulators
   Makes the unitary tests Layer 1 simulators
-V | --vcd
   Adds a debgging facility to the binary files: GUI with major internal synchronization events
--build-doxygen
   Builds doxygen based documentation.
--trace-asn1c-enc-dec
   Output asn1c logging traces via OAI logging system.
--enable-LTTNG
   Enable LTTNG log. While lttng is enabled, T-Tracer will be disabled
--disable-T-Tracer
   Disables the T tracer.
--disable-hardware-dependency
   Disable HW dependency during installation
--ue-trace
   Enable traces for UE debugging
--ue-timing
   Enable traces for timing
--uhd-images-dir
   Download UHD images in the indicated location
--build-eclipse
   Build eclipse project files.
--build-lib <libraries>
   Build optional shared library, <libraries> can be one or several of $OPTIONAL_LIBRARIES or \"all\"
--noavx512
   Disable AVX512 intrinsics whatever processor capability is
--noavx2
   Disable AVX2 intrinsics whatever processor capability is
--ninja
  Tell cmake to use the Ninja build system. Without, will generate make files
--sanitize
  Shortcut for usage of --sanitize-address --sanitize-undefined
--sanitize-address | -fsanitize=address
  Enable the address sanitizer on all targets
--sanitize-undefined | -fsanitize=undefined
  Enable the undefined behavior sanitizer on all targets
--sanitize-memory | -fsanitize=memory
  Enable the memory sanitizer on all targets. Requires clang, and is
  incompatible with ASan/UBSan. To build, issue:
  CC=/usr/bin/clang CXX=/usr/bin/clang++ ./build_oai ... --sanitize-memory
--sanitize-thread | -fsanitize=thread
  Enable the thread sanitizer on all targets
-h | --help
   Print this help"
}


function main() {

  until [ -z "$1" ]
  do
    case "$1" in
       --arch-native)
            echo_fatal "Error: specify --arch-native on the command line to cmake directly: ./build_oai --cmake-opt \"-DCMAKE_C_FLAGS=-march=native -DCMAKE_CXX_FLAGS=-march=native\""
            shift;;
       --build-tool-opt)
            BUILD_TOOL_OPT+=" $2"
            shift 2;;
       -c | --clean | -C | --clean-all)
            CLEAN=1
            shift;;
       --cmake-opt)
            CMAKE_CMD="$CMAKE_CMD $2"
            shift 2;;
       -d | --build-dir)
            BUILD_DIR=$2
            shift 2;;
       --build-e2 )
             CMAKE_CMD="$CMAKE_CMD -DE2_AGENT=ON"
             shift
             ;;
       -I | --install-external-packages)
            INSTALL_EXTERNAL=1
            echo_info "Will install external packages"
            shift;;
       --install-optional-packages)
            INSTALL_OPTIONAL=1
            echo_info "Will install optional packages"
            shift;;
       -g | --run-with-gdb)
            case "$2" in
                "Release")
                    CMAKE_BUILD_TYPE="Release"
                    echo_info "Will Compile without gdb symbols and with compiler optimization"
                    CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=Release"
                    shift
                    ;;
                "RelWithDebInfo")
                    CMAKE_BUILD_TYPE="RelWithDebInfo"
                    echo_info "Will Compile with gdb symbols"
                    CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_EXPORT_COMPILE_COMMANDS=1"
                    shift
                    ;;
                "MinSizeRel")
                    CMAKE_BUILD_TYPE="MinSizeRel"
                    echo_info "Will Compile for minimal exec size"
                    CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=MinSizeRel"
                    shift
                    ;;
                "Debug" | *)
                    CMAKE_BUILD_TYPE="Debug"
                    echo_info "Will Compile with gdb symbols and disable compiler optimization"
                    CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=Debug"
                    if [ "$2" == "Debug" ] ; then
                        shift
                    fi
                    ;;
            esac
            shift;;
       -G | --cmaketrace)
            CMAKE_CMD="$CMAKE_CMD --trace-expand"
            shift;;
       --eNB)
            eNB=1
            TARGET_LIST="$TARGET_LIST lte-softmodem"
            echo_info "Will compile eNB"
            shift;;
      --gNB)
            gNB=1
            TARGET_LIST="$TARGET_LIST nr-softmodem nr-cuup"
            echo_info "Will compile gNB"
            shift;;
       --RU)
            RU=1
            TARGET_LIST="$TARGET_LIST oairu"
            echo_info "Will compile RRU"
            shift;;
       --nrRU)
            NRRU=1
            CMAKE_CMD="$CMAKE_CMD -DOAI_RU_FRONTHAUL=ON"
            TARGET_LIST="$TARGET_LIST nr-oru"
            echo_info "Will compile NR O-RU"
            shift;;
       --UE)
            UE=1
            TARGET_LIST="$TARGET_LIST lte-uesoftmodem conf2uedata usim nvram"
            echo_info "Will compile UE"
            shift;;
       --nrUE)
            nrUE=1
            TARGET_LIST="$TARGET_LIST nr-uesoftmodem"
            echo_info "Will compile NR UE"
            shift;;
       --mu)
            CMAKE_CMD="$CMAKE_CMD -DUE_EXPANSION=True -DPRE_SCD_THREAD=True"
            echo_info "Will compile with UE_EXPANSION"
            shift;;
       --UE-conf-nvram)
            conf_nvram_path=$(readlink -f "$2")
            shift 2;;
       -w | --hardware)
            case "$2" in
                "USRP" | "BLADERF" | "LMSSDR" | "IRIS" | "ZMQ")
                    HWs+=" OAI_"$2
                    TARGET_LIST="$TARGET_LIST oai_${2,,}devif" # ,, makes lowercase
                    CMAKE_CMD="$CMAKE_CMD -DOAI_$2=ON"
                    ;;
                "SIMU")
                    HWs+=" OAI_"$2
                    TARGET_LIST="$TARGET_LIST rfsimulator"
                    CMAKE_CMD="$CMAKE_CMD -DOAI_$2=ON"
                    ;;
                "AW2SORI")
                    HWs=" OAI_"$2
                    TARGET_LIST="$TARGET_LIST aw2sori_transpro"
                    CMAKE_CMD="$CMAKE_CMD -DOAI_$2=ON"
                    ;;
                "AERIAL"|"Aerial"|"aerial")
                    HWs+=" OAI_AERIAL"
                    CMAKE_CMD="$CMAKE_CMD -DOAI_AERIAL=ON"
                    ;;
                "None")
                    ;;
                *)
                    echo_fatal "Unknown hardware type $2: exit..."
                    ;;
            esac
            shift 2;;
       -t | --transport)
            case "$2" in
              "Ethernet")
                TARGET_LIST="$TARGET_LIST oai_eth_transpro"
                CMAKE_CMD="$CMAKE_CMD -DOAI_${2^^}=ON" # ^^ makes uppercase
                ;;
              "oran_fhlib_5g")
                TARGET_LIST="$TARGET_LIST $2"
                CMAKE_CMD="$CMAKE_CMD -DOAI_FHI72=ON"
                ;;
              "oran_fhlib_5g_mplane")
                TARGET_LIST="$TARGET_LIST $2"
                CMAKE_CMD="$CMAKE_CMD -DOAI_FHI72=ON -DOAI_FHI72_MPLANE=ON"
                ;;
              "WLS"|"Wls"|"wls")
                  CMAKE_CMD="$CMAKE_CMD -DOAI_WLS=ON"
                  ;;
              "None")
                ;;
              *)
                echo_fatal "Unknown transport type $2; exit..."
                ;;
            esac
            shift 2;;
       -P | --phy_simulators)
            SIMUS_PHY=1
            CMAKE_CMD="$CMAKE_CMD -DENABLE_PHYSIM_TESTS=ON"
            # TODO: fix: dlsim_tm4 pucchsim prachsim pdcchsim pbchsim mbmssim
            TARGET_LIST="$TARGET_LIST dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim nr_psbchsim nr_srssim"
            echo_info "Will compile dlsim, ulsim, ..."
            shift;;
       -V | --vcd)
            echo_info "Setting gtk-wave output"
            CMAKE_CMD="$CMAKE_CMD -DENABLE_VCD_FIFO=True"
            shift;;
       --build-doxygen)
           CMAKE_CMD="$CMAKE_CMD -DGENERATE_DOXYGEN=ON"
           TARGET_LIST="$TARGET_LIST doc"
           echo_info "Will build Doxygen documentation: $DIR/$BUILD_DIR/build/doc/html/index.html"
           shift;;     
       --enable-LTTNG)
            CMAKE_CMD="$CMAKE_CMD -DENABLE_LTTNG=ON -DT_TRACER=OFF"
            echo_info "Enable LTTNG tracer"
            USE_LTTNG=1
            shift 1;;
       --disable-T-Tracer)
            CMAKE_CMD="$CMAKE_CMD -DT_TRACER=False"
            echo_info "Disabling the T tracer"
            shift 1;;
       --ue-trace)
            CMAKE_CMD="$CMAKE_CMD -DUE_DEBUG_TRACE=False"
            echo_info "Enabling UE trace for debug"
            shift 1;;
       --ue-timing)
            CMAKE_CMD="$CMAKE_CMD -DUE_TIMING_TRACE=True"
            echo_info "Enabling UE timing trace"
            shift 1;;
       --uhd-images-dir)
            UHD_IMAGES_DIR=$2
            echo_info "Downloading UHD images in the indicated location"
            shift 2;;
       --build-eclipse)
            CMAKE_CMD="$CMAKE_CMD"' -DCMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT=TRUE -G"Eclipse CDT4 - Unix Makefiles"'
            echo_info "Enabling build eclipse project support"
            shift 1;;
       --build-lib) 
            if [  "$2" == "all" ] ; then
              TARGET_LIST="$TARGET_LIST $OPTIONAL_LIBRARIES"
              for lib in $OPTIONAL_LIBRARIES; do CMAKE_CMD="$CMAKE_CMD -DENABLE_${lib^^}=ON"; done
              echo_info "Enabling build of all optional shared libraries ($OPTIONAL_LIBRARIES)" 
            else
              for reqlib in $2; do
                lib=$(echo $OPTIONAL_LIBRARIES | tr ' ' '\n' | grep -w -- $reqlib) # search given parameter in list
                [[ $? -ne 0 ]] && echo_fatal "Unknown optional library \"$reqlib\", valid libraries are: $OPTIONAL_LIBRARIES"
                TARGET_LIST="$TARGET_LIST $lib" # will append the found library
                CMAKE_CMD="$CMAKE_CMD -DENABLE_${lib^^}=ON"
                echo_info "Enabling build of optional shared library $lib"
              done
            fi
            shift 2;;
        --noavx512)
            CMAKE_CMD="$CMAKE_CMD -DAVX512=OFF"
            echo_info "Disabling AVX512 instructions"
            shift 1;;
        --noavx2)
            CMAKE_CMD="$CMAKE_CMD -DAVX2=OFF"
            echo_info "Disabling AVX2 instructions"
            shift 1;;
        --ninja)
            CMAKE_CMD="$CMAKE_CMD -GNinja"
            shift;;
        --sanitize)
            CMAKE_CMD="$CMAKE_CMD -DSANITIZE_ADDRESS=True -DSANITIZE_UNDEFINED=True"
            shift;;
        --sanitize-address | -fsanitize=address)
            CMAKE_CMD="$CMAKE_CMD -DSANITIZE_ADDRESS=True"
            shift;;
        --sanitize-undefined | -fsanitize=undefined)
            CMAKE_CMD="$CMAKE_CMD -DSANITIZE_UNDEFINED=True"
            shift;;
        --sanitize-memory | -fsanitize=memory)
            CMAKE_CMD="$CMAKE_CMD -DSANITIZE_MEMORY=ON -DSANITIZE_ADDRESS=OFF -DSANITIZE_UNDEFINED=OFF"
            shift;;
        --sanitize-thread | -fsanitize=thread)
            CMAKE_CMD="$CMAKE_CMD -DSANITIZE_THREAD=True"
            shift;;
       --trace-asn1c-enc-dec)
            CMAKE_CMD="$CMAKE_CMD -DTRACE_ASN1C_ENC_DEC=ON"
            echo_info "Enabling asn1c internal traces via OAI logging system"
            shift 1;;
        -h | --help)
            print_help
            exit 1;;
        *)
            print_help
            echo_fatal "Unknown option $1"
            break;;
   esac
  done

  #######################################################
  # Setting and printing OAI envs, we should check here #
  #######################################################

  echo "OPENAIR_DIR    = $OPENAIR_DIR"

  DIR=$OPENAIR_DIR/cmake_targets
  [ "$CLEAN" = "1" ] && rm -rf "$DIR/$BUILD_DIR"

  if [ "$INSTALL_EXTERNAL" = "1" ] ; then
    echo_info "Installing packages"
    check_install_oai_software
    if [ "$USE_LTTNG" = "1" ] ; then
      echo_info "installing LTTng"
      install_lttng $1
    fi
    for HW in $HWs; do
      if [ "$HW" == "OAI_USRP" ] ; then
        echo_info "installing packages for USRP support"
        check_install_usrp_uhd_driver
        if [ ! -v BUILD_UHD_FROM_SOURCE ]; then
          install_usrp_uhd_driver $UHD_IMAGES_DIR
        fi
      elif [ "$HW" == "OAI_BLADERF" ] ; then
        echo_info "installing packages for BLADERF support"
        check_install_bladerf_driver
      elif [ "$HW" == "OAI_IRIS" ] ; then
        echo_info "installing packages for IRIS support"
        check_install_soapy
      else
        echo_warning "no installation scripts for hardware $HW"
      fi
    done
  fi

  if [ "$INSTALL_OPTIONAL" = "1" ] ; then
    echo_info "Installing optional packages"
    check_install_additional_tools
  fi

  if [[ $TARGET_LIST != "" ]] && [[ -f $OPENAIR_DIR/CMakeLists.txt ]]; then
    # add some default libraries that should always be built
    # for eNB, gNB, UEs, simulators
    if [[ $gNB == 1 || $eNB == 1 || $UE == 1 || $nrUE == 1 || $SIMUS_PHY == 1 || $RU == 1 || $NRRU == 1 ]]; then
      TARGET_LIST="$TARGET_LIST params_libconfig coding rfsimulator dfts params_yaml vrtsim rf_emulator"
    fi

    mkdir -p $DIR/$BUILD_DIR/build
    cd $DIR/$BUILD_DIR/build

    # for historical reasons we build in a subdirectory cmake_targets/XYZ/build,
    # e.g., cmake_targets/ran_build/build, hence the ../../..
    CMAKE_CMD="$CMAKE_CMD ../../.."
    echo_info "Running \"$CMAKE_CMD\""
    eval $CMAKE_CMD || echo_fatal "cmake configuration failed"
    cmd="$CMAKE --build . --target ${TARGET_LIST} -- ${BUILD_TOOL_OPT}"
    echo_info "Running \"${cmd}\"" $green
    eval $cmd || echo_fatal "build failed"

    if [ "$UE" = 1 ] ; then
      echo_info "Generate LTE USIM default sim content UE specific part"
      # generate USIM data
      if [ -f conf2uedata ]; then
        install_nas_tools $conf_nvram_path $DIR/$BUILD_DIR/build "$DIR/$BUILD_DIR/build/conf2uedata.txt"
      else
        echo_warning "not generated UE NAS files: binaries not found"
      fi
    fi
  fi

  echo_success "BUILD SHOULD BE SUCCESSFUL"
}

main "$@"
