#===============================================================================
# Copyright 2021 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#===============================================================================

if(dpcpp_driver_check_cmake_included)
   return()
endif()
set(dpcpp_driver_check_cmake_included true)

include(CheckCXXCompilerFlag)
include(CheckCXXSourceCompiles)

# oneDNN can handle two kinds of compiler drivers for DPCPP runtime:
# 1. icx/icpx - when Intel oneAPI DPC++ Compiler is used.
# 2. clang/clang++ - when an open-source version of oneAPI DPC++ Compiler
#    is used.
#
# We need to make sure that the passed clang/clang++ drivers are not from
# Intel oneAPI DPC++ Compiler.
function(CHECK_COMPILER_DRIVER)
    # Check if the CXX compiler supports `-fsycl` flag.
    CHECK_CXX_COMPILER_FLAG(-fsycl SYCL_FLAG_SUPPORTED)
    if(NOT SYCL_FLAG_SUPPORTED)
        message(FATAL_ERROR "${CMAKE_CXX_COMPILER_ID} doesn't support -fsycl flag.")
    endif()

    if(CMAKE_BASE_NAME MATCHES "(icx|icpx|dpcpp)")
        return()
    endif()

    set(CHECK_COMPILER_DRIVER_SOURCE
    "
        int main() {
        #ifdef __INTEL_LLVM_COMPILER
          return 0;
        #else
          breaks_on_purpose
        #endif
        }
    ")
    # TODO: add c check?
    CHECK_CXX_SOURCE_COMPILES("${CHECK_COMPILER_DRIVER_SOURCE}" INTEL_LLVM_COMPILER_DETECTED)
    if(CMAKE_BASE_NAME MATCHES "(clang\\+\\+|clang-cl)" AND INTEL_LLVM_COMPILER_DETECTED)
        message(FATAL_ERROR "Please use icx/icpx compiler drivers instead of ${CMAKE_BASE_NAME}")
    endif()
endfunction()

CHECK_COMPILER_DRIVER()

# On Windows, CMake uses the standard system linker that cannot handle object
# files generated by oneAPI DPC++ Compiler, which results in runtime issues.
# Below is a workaround to force linking to happen via the oneAPI DPC++ Compiler
# driver in order to ensure that the object files are handled appropriately.
if(WIN32 AND CMAKE_BASE_NAME MATCHES "(icx|dpcpp)")
    # XXX: Some arguments that CMake adds to the link line can be unknown for
    # the icx driver but they are handled via the workaround hence ignore the
    # corresponding warnings.
    string(APPEND CMAKE_CXX_LINK_FLAGS " -fsycl -Wno-unknown-argument ")

    # Use lists to break too long line.
    set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> ${CMAKE_CL_NOLOGO} "
                                  "<OBJECTS> ${CMAKE_START_TEMP_FILE} /o "
                                  "<TARGET> <CMAKE_CXX_LINK_FLAGS> "
                                  "<LINK_FLAGS> <LINK_LIBRARIES> "
                                  "${CMAKE_END_TEMP_FILE}")

    set(CMAKE_CXX_CREATE_SHARED_LIBRARY "<CMAKE_CXX_COMPILER> "
                                        "${CMAKE_CL_NOLOGO} <OBJECTS> "
                                        "${CMAKE_START_TEMP_FILE} /o <TARGET> "
                                        "<CMAKE_CXX_LINK_FLAGS> /LD "
                                        "<LINK_FLAGS> <LINK_LIBRARIES> "
                                        "${CMAKE_END_TEMP_FILE}")

    set(CMAKE_CXX_CREATE_STATIC_LIBRARY "<CMAKE_CXX_COMPILER> "
                                        "${CMAKE_CL_NOLOGO} <OBJECTS> "
                                        "${CMAKE_START_TEMP_FILE} "
                                        "/fuse-ld=llvm-lib /link /OUT:<TARGET> "
                                        "<CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> "
                                        "<LINK_LIBRARIES> "
                                        "${CMAKE_END_TEMP_FILE}")
    # Convert lists to strings.
    string(REPLACE ";" "" CMAKE_CXX_LINK_EXECUTABLE
        "${CMAKE_CXX_LINK_EXECUTABLE}")
    string(REPLACE ";" "" CMAKE_CXX_CREATE_SHARED_LIBRARY
        "${CMAKE_CXX_CREATE_SHARED_LIBRARY}")
    string(REPLACE ";" "" CMAKE_CXX_CREATE_STATIC_LIBRARY
        "${CMAKE_CXX_CREATE_STATIC_LIBRARY}")
endif()
