cmake_minimum_required(VERSION 3.11)

project(buildbox VERSION 1.3.53 LANGUAGES CXX)

set(TOOLS "ON" CACHE STRING "Build and test tools")
set_property(CACHE TOOLS PROPERTY STRINGS "ON" "OFF")

set(CASD "AUTO" CACHE STRING "Build and test buildbox-casd")
set_property(CACHE CASD PROPERTY STRINGS "AUTO" "ON" "OFF")

set(CASD_WRAP "AUTO" CACHE STRING "Build and test buildbox-casd-wrap")
set_property(CACHE CASD_WRAP PROPERTY STRINGS "AUTO" "ON" "OFF")

set(CASDOWNLOAD "AUTO" CACHE STRING "Build and test casdownload")
set_property(CACHE CASDOWNLOAD PROPERTY STRINGS "AUTO" "ON" "OFF")

set(CASUPLOAD "AUTO" CACHE STRING "Build and test casupload")
set_property(CACHE CASUPLOAD PROPERTY STRINGS "AUTO" "ON" "OFF")

set(CASUPLOAD_OCI "AUTO" CACHE STRING "Build and test casupload-oci")
set_property(CACHE CASUPLOAD_OCI PROPERTY STRINGS "AUTO" "ON" "OFF")

set(FUSE "AUTO" CACHE STRING "Build and test buildbox-fuse (only on Linux unless overridden)")
set_property(CACHE FUSE PROPERTY STRINGS "AUTO" "ON" "OFF")

set(LOGSTREAMRECEIVER "AUTO" CACHE STRING "Build and test logstreamreceiver")
set_property(CACHE LOGSTREAMRECEIVER PROPERTY STRINGS "AUTO" "ON" "OFF")

set(LOGSTREAMTAIL "AUTO" CACHE STRING "Build and test logstreamtail")
set_property(CACHE LOGSTREAMTAIL PROPERTY STRINGS "AUTO" "ON" "OFF")

option(OCI "Build and test OCI support (requires CURL and nlohmann-json)" ON)

set(OUTPUTSTREAMER "AUTO" CACHE STRING "Build and test outputstreamer")
set_property(CACHE OUTPUTSTREAMER PROPERTY STRINGS "AUTO" "ON" "OFF")

set(PLATFORM_COMPILER "AUTO" CACHE STRING "Default compiler of the platform")
set_property(CACHE PLATFORM_COMPILER PROPERTY STRINGS "AUTO" "gcc" "clang" "CC")

set(RECC "AUTO" CACHE STRING "Build and test recc")
set_property(CACHE RECC PROPERTY STRINGS "AUTO" "ON" "OFF")

set(REXPLORER "AUTO" CACHE STRING "Build and test rexplorer")
set_property(CACHE REXPLORER PROPERTY STRINGS "AUTO" "ON" "OFF")

set(RUMBAD "AUTO" CACHE STRING "Build and test rumbad")
set_property(CACHE RUMBAD PROPERTY STRINGS "AUTO" "ON" "OFF")

set(RUN_BUBBLEWRAP "AUTO" CACHE STRING "Build and test buildbox-run-bubblewrap (only on Linux unless overridden)")
set_property(CACHE RUN_BUBBLEWRAP PROPERTY STRINGS "AUTO" "ON" "OFF")

set(RUN_HOSTTOOLS "AUTO" CACHE STRING "Build and test buildbox-run-hosttools")
set_property(CACHE RUN_HOSTTOOLS PROPERTY STRINGS "AUTO" "ON" "OFF")

set(RUN_OCI "AUTO" CACHE STRING "Build and test buildbox-run-oci (only on Linux unless overridden)")
set_property(CACHE RUN_OCI PROPERTY STRINGS "AUTO" "ON" "OFF")

set(RUN_SYMLINK "AUTO" CACHE STRING "Target of buildbox-run symlink")
set_property(CACHE RUN_SYMLINK PROPERTY STRINGS "AUTO" "bubblewrap" "hosttools" "oci" "userchroot" "OFF")

set(RUN_USERCHROOT "AUTO" CACHE STRING "Build and test buildbox-run-userchroot")
set_property(CACHE RUN_USERCHROOT PROPERTY STRINGS "AUTO" "ON" "OFF")

set(TREXE "AUTO" CACHE STRING "Build and test trexe")
set_property(CACHE TREXE PROPERTY STRINGS "AUTO" "ON" "OFF")

set(WORKER "AUTO" CACHE STRING "Build and test buildbox-worker")
set_property(CACHE WORKER PROPERTY STRINGS "AUTO" "ON" "OFF")

option(BUILD_MOSTLY_STATIC "Build statically (as static as the platform allows)")
if(BUILD_MOSTLY_STATIC)
  set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
endif()

option(HARDEN "Enable hardening")
if(HARDEN)
  add_compile_options(-O1 -D_FORTIFY_SOURCE=2)
endif()

# Add ASAN option
option(ASAN "Enable AddressSanitizer")
if(ASAN)
  message(STATUS "Building with AddressSanitizer")
  add_compile_options(-fsanitize=address)
  add_link_options(-fsanitize=address)
endif()

if(NOT BUILDBOX_VERSION)
  find_program(GIT git)

  if(GIT STREQUAL "GIT-NOTFOUND")
    set(BUILDBOX_VERSION ${CMAKE_PROJECT_VERSION})
    message("Could not find git, setting version to 'CMAKE_PROJECT_VERSION'")
  elseif(NOT EXISTS "${CMAKE_SOURCE_DIR}/.git")
    set(BUILDBOX_VERSION ${CMAKE_PROJECT_VERSION})
    message("Not in a git repository, setting version to 'CMAKE_PROJECT_VERSION'")
  else()
    execute_process(
            COMMAND "git" "describe" "--tags"
            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
            OUTPUT_VARIABLE BUILDBOX_VERSION
            OUTPUT_STRIP_TRAILING_WHITESPACE)
    message(STATUS "Using git tag as version: ${BUILDBOX_VERSION}")
  endif()
endif()

include(CMakeFindDependencyMacro)
include(GNUInstallDirs)
include(CheckCXXCompilerFlag)

set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
find_package(Threads REQUIRED)

find_package(OpenSSL REQUIRED)
set(OPENSSL_TARGET OpenSSL::Crypto)

include("${CMAKE_SOURCE_DIR}/cmake/BuildboxCommonConfig.cmake")

add_subdirectory(protos)

include_directories("common")
include_directories("commonmetrics")
include_directories(${PROTO_GEN_DIR})

# Define 64-bit interface as default, required on 32-bit platforms,
# no effect on 64-bit platforms.
add_compile_options(-D_FILE_OFFSET_BITS=64)

if(${PLATFORM_COMPILER} STREQUAL "AUTO")
  if(CMAKE_SYSTEM_NAME MATCHES "SunOS")
    set(PLATFORM_COMPILER "CC")
  elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
    set(PLATFORM_COMPILER "gcc")
  elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin")
    set(PLATFORM_COMPILER "clang")
  else()
    set(PLATFORM_COMPILER "unknown")
  endif()
endif()

if(${CMAKE_SYSTEM_NAME} MATCHES "SunOS" AND CMAKE_CXX_COMPILER_ID STREQUAL GNU)
  if(BUILD_MOSTLY_STATIC AND NOT ${PLATFORM_COMPILER} STREQUAL "gcc")
    # Statically link to gcc libraries when building BuildBox with gcc
    # while gcc is not configured as default compiler on the platform.
    add_compile_options(-static-libgcc -static-libstdc++)
    add_link_options(-static-libgcc -static-libstdc++)
  endif()
endif()

include("${CMAKE_SOURCE_DIR}/cmake/check_protobuf_print_options.cmake")

include(CTest)
if(BUILD_TESTING)
  include_directories(third_party/grpc/include)
endif()
include_directories(third_party/ThreadPool)

add_subdirectory(common)
add_subdirectory(commonmetrics)

function(enable_tool TOOL_DIR TOOL_VAR)
  if((${TOOLS} STREQUAL "ON" AND ${TOOL_VAR} STREQUAL "AUTO") OR ${TOOL_VAR} STREQUAL "ON")
    add_subdirectory(${TOOL_DIR})
  endif()
endfunction()

function(enable_linux_tool TOOL_DIR TOOL_VAR)
  if((${TOOLS} STREQUAL "ON" AND ${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND ${TOOL_VAR} STREQUAL "AUTO")
            OR ${TOOL_VAR} STREQUAL "ON")
    add_subdirectory(${TOOL_DIR})
  endif()
endfunction()

if(NOT OCI)
  if(${CASUPLOAD_OCI} STREQUAL "AUTO")
    set(CASUPLOAD_OCI "OFF")
  elseif(${CASUPLOAD_OCI} STREQUAL "ON")
    message(FATAL_ERROR "CASUPLOAD_OCI cannot be enabled if OCI is disabled")
  endif()
endif()

enable_tool(casd ${CASD})
enable_tool(casd-wrap ${CASD_WRAP})
enable_tool(casdownload ${CASDOWNLOAD})
enable_tool(casupload ${CASUPLOAD})
enable_tool(casupload-oci ${CASUPLOAD_OCI})
enable_linux_tool(fuse ${FUSE})
enable_tool(logstreamreceiver ${LOGSTREAMRECEIVER})
enable_tool(logstreamtail ${LOGSTREAMTAIL})
enable_tool(outputstreamer ${OUTPUTSTREAMER})
enable_tool(recc ${RECC})
enable_tool(rexplorer ${REXPLORER})
enable_tool(rumbad ${RUMBAD})
enable_linux_tool(run-bubblewrap ${RUN_BUBBLEWRAP})
enable_tool(run-hosttools ${RUN_HOSTTOOLS})
enable_linux_tool(run-oci ${RUN_OCI})
enable_tool(run-userchroot ${RUN_USERCHROOT})
enable_tool(trexe ${TREXE})
enable_tool(worker ${WORKER})

if(${RUN_SYMLINK} STREQUAL "AUTO")
  if(${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND TARGET buildbox-run-bubblewrap)
    set(RUN_SYMLINK "bubblewrap")
  else()
    set(RUN_SYMLINK "OFF")
  endif()
endif()

if(NOT ${RUN_SYMLINK} STREQUAL "OFF")
  if(NOT TARGET buildbox-run-${RUN_SYMLINK})
    message(FATAL_ERROR "RUN_SYMLINK is set to an unknown or disabled runner: ${RUN_SYMLINK}")
  endif()
  add_custom_target(buildbox-run ALL COMMAND ${CMAKE_COMMAND} -E create_symlink buildbox-run-${RUN_SYMLINK} buildbox-run)
  install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/buildbox-run DESTINATION bin)
endif()
