# The CMakeLists.txt be used for PC (Windows, Mac, Linux) and Android

cmake_minimum_required(VERSION 3.4.1)
project(mnnpybridge)

# python_path / numpy_path / mnn_path
option(DEPEND_AAPL_FMWK "use dependency library .framework instead of traditional .a/.dylib" OFF)
option(MNN_BUILD_SHARED_LIBS "MNN build shared or static lib" ON)
option(MNN_WIN_RUNTIME_MT "MNN use /MT on Windows dll" OFF)
option(PYMNN_USE_ALINNPYTHON "based on AliNNPython" ON)
option(PYMNN_RUNTIME_CHECK_VM "AliNNPython version (new/old) can be check on runtime" ON)
option(PYMNN_NEW_PYTHON "AliNNPython new version (when PYMNN_RUNTIME_CHECK_VM=OFF)" ON)
option(PYMNN_EXPR_API "MNN expr API be exposed" ON)
option(PYMNN_NUMPY_USABLE "Build based on numpy" OFF)
option(PYMNN_TRAIN_API "MNN train API be exposed" OFF)
option(PYMNN_INTERNAL_SERVING "Internal use only." OFF)
option(PYMNN_OPENCV_API "MNN OpenCV API be exposed" ON)
option(PYMNN_IMGCODECS "MNN IMGCODECS API be exposed" OFF)
option(PYMNN_AUDIO_API "MNN Audio API be exposed" OFF)
option(PYMNN_LLM_API "MNN LLM API be exposed" OFF)
option(PYMNN_OHOS_INTERNAL "compile for harmony internal." OFF)
option(PYMNN_LLM_COLLECTION "offline llm data collection." OFF)

if (PYMNN_OHOS_INTERNAL)
  include($ENV{NODE_PATH}/@ali/tcpkg/tcpkg.cmake)
endif()

if(PYMNN_INTERNAL_SERVING)
    file(GLOB_RECURSE SRC   ${CMAKE_CURRENT_LIST_DIR}/src/MNN.cc
            ${CMAKE_CURRENT_LIST_DIR}/src/internal/monitor_service.cc
            ${CMAKE_CURRENT_LIST_DIR}/src/internal/verify_service.cc
            ${CMAKE_CURRENT_LIST_DIR}/src/internal/http_util.cc)
else()
    file(GLOB_RECURSE SRC   ${CMAKE_CURRENT_LIST_DIR}/src/MNN.cc)
endif()

if (MNN_BUILD_SHARED_LIBS)
    add_library(mnnpybridge SHARED ${SRC})
else()
    add_library(mnnpybridge STATIC ${SRC})
endif()

if(PYMNN_USE_ALINNPYTHON)
    target_compile_definitions(mnnpybridge PRIVATE PYMNN_USE_ALINNPYTHON)
endif()
if(PYMNN_RUNTIME_CHECK_VM)
    target_compile_definitions(mnnpybridge PRIVATE PYMNN_RUNTIME_CHECK_VM)
endif()
if(PYMNN_NEW_PYTHON)
    target_compile_definitions(mnnpybridge PRIVATE PYMNN_NEW_PYTHON)
endif()
if(PYMNN_EXPR_API)
    target_compile_definitions(mnnpybridge PRIVATE PYMNN_EXPR_API)
endif()
if(PYMNN_NUMPY_USABLE)
    target_compile_definitions(mnnpybridge PRIVATE PYMNN_NUMPY_USABLE)
endif()
if(PYMNN_TRAIN_API)
    target_compile_definitions(mnnpybridge PRIVATE PYMNN_TRAIN_API)
endif()

if(PYMNN_OPENCV_API)
    target_compile_definitions(mnnpybridge PRIVATE PYMNN_OPENCV_API)
endif()

if(PYMNN_IMGCODECS)
    target_compile_definitions(mnnpybridge PRIVATE PYMNN_IMGCODECS)
endif()
if(PYMNN_IMGPROC_DRAW)
    target_compile_definitions(mnnpybridge PRIVATE PYMNN_IMGPROC_DRAW)
endif()
if(PYMNN_IMGPROC_STRUCTURAL)
    target_compile_definitions(mnnpybridge PRIVATE PYMNN_IMGPROC_STRUCTURAL)
endif()
if(PYMNN_IMGPROC_MISCELLANEOUS)
    target_compile_definitions(mnnpybridge PRIVATE PYMNN_IMGPROC_MISCELLANEOUS)
endif()
if(PYMNN_IMGPROC_COLOR)
    target_compile_definitions(mnnpybridge PRIVATE PYMNN_IMGPROC_COLOR)
endif()
if(PYMNN_IMGPROC_GEOMETRIC)
    target_compile_definitions(mnnpybridge PRIVATE PYMNN_IMGPROC_GEOMETRIC)
endif()
if(PYMNN_IMGPROC_FILTER)
    target_compile_definitions(mnnpybridge PRIVATE PYMNN_IMGPROC_FILTER)
endif()
if(PYMNN_IMGPROC_HISTOGRAMS)
    target_compile_definitions(mnnpybridge PRIVATE PYMNN_IMGPROC_HISTOGRAMS)
endif()
if(PYMNN_CALIB3D)
    target_compile_definitions(mnnpybridge PRIVATE PYMNN_CALIB3D)
endif()
if(PYMNN_CVCORE)
    target_compile_definitions(mnnpybridge PRIVATE PYMNN_CVCORE)
endif()

if(PYMNN_AUDIO_API)
    target_compile_definitions(mnnpybridge PRIVATE PYMNN_AUDIO_API)
endif()

if(PYMNN_LLM_API)
    target_compile_definitions(mnnpybridge PRIVATE PYMNN_LLM_API)
endif()

if(PYMNN_INTERNAL_SERVING)
    message(STATUS "mnnpybridge define PYMNN_INTERNAL_SERVING")
    target_compile_definitions(mnnpybridge PRIVATE PYMNN_INTERNAL_SERVING)
endif()

if(CMAKE_SYSTEM_NAME MATCHES "^Android")
    add_definitions(-DMNN_USE_LOGCAT)
endif()

if(MSVC)
    foreach(flag_var
        CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
        CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
        CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
        CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
        if (MNN_WIN_RUNTIME_MT)
            if(${flag_var} MATCHES "/MD")
                string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
            endif()
        else ()
            if(${flag_var} MATCHES "/MT")
                string(REGEX REPLACE "/MT" "/MD" ${flag_var} "${${flag_var}}")
            endif()
        endif ()
    endforeach()
    set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4005 /wd4267 /experimental:preprocessor")
    set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4005 /wd4267 /experimental:preprocessor")
    SET(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF")
    SET(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF")
    SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zi")
    SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi")
else()
    set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-stack-protector -std=gnu99 -O2 -flax-vector-conversions -fvisibility=hidden")
    set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-stack-protector -std=c++11 -O2 -fvisibility=hidden -fvisibility-inlines-hidden")
endif()

if(PYMNN_TRAIN_API)
    set(MNN_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
    target_include_directories(mnnpybridge PRIVATE
        ${MNN_DIR}/tools/train/source/grad ${MNN_DIR}/tools/train/source/optimizer ${MNN_DIR}/tools/train/source/transformer ${MNN_DIR}/tools/train/source/nn
        ${MNN_DIR}/tools/train/source/data ${MNN_DIR}/schema/current ${MNN_DIR}/3rd_party/flatbuffers/include ${MNN_DIR}/tools/cv/include
        ${MNN_DIR}/express ${MNN_DIR}/express/module ${MNN_DIR}/tools)
endif()

if(WIN32 OR APPLE OR CMAKE_SYSTEM_NAME MATCHES "^Linux")
    set(DEPEND_PATH "${CMAKE_CURRENT_LIST_DIR}/3rd_party")
    set(LIB_SUBPATH "")
    if(WIN32)
        if (MNN_BUILD_SHARED_LIBS)
            set(LIB_SUBPATH "Dynamic")
        else()
            set(LIB_SUBPATH "Static")
        endif()
        if (MNN_WIN_RUNTIME_MT)
            set(LIB_SUBPATH "${LIB_SUBPATH}/MT")
        else()
            set(LIB_SUBPATH "${LIB_SUBPATH}/MD")
        endif()
    elseif(APPLE)
        if(MNN_BUILD_SHARED_LIBS)
            set(LIB_SUBPATH "Dynamic")
        else()
            set(LIB_SUBPATH "Static")
        endif()
    endif()
    if(CMAKE_BUILD_TYPE MATCHES Debug)
        set(LIB_SUBPATH "Debug/${LIB_SUBPATH}")
    else()
        set(LIB_SUBPATH "Release/${LIB_SUBPATH}")
    endif()
    if(WIN32)
        if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4")
            set(LIB_SUBPATH "x86/${LIB_SUBPATH}")
        else()
            set(LIB_SUBPATH "x64/${LIB_SUBPATH}")
        endif()
    endif()

    find_library(MNN NAMES MNN REQUIRED PATHS ${mnn_path}/lib/${LIB_SUBPATH})
    if(NOT DEPEND_AAPL_FMWK)
        target_include_directories(mnnpybridge PUBLIC ${mnn_path}/include)
    endif()
    target_link_libraries(mnnpybridge PUBLIC ${MNN})

    find_library(python NAMES python REQUIRED PATHS ${python_path}/lib/${LIB_SUBPATH})
    if(NOT DEPEND_AAPL_FMWK)
            target_include_directories(mnnpybridge PUBLIC ${python_path}/include)
    endif()
    target_link_libraries(mnnpybridge PUBLIC ${python})
    if(PYMNN_NUMPY_USABLE)
        find_library(numpy NAMES numpy_python REQUIRED PATHS ${numpy_path}/lib/${LIB_SUBPATH})
        if(NOT DEPEND_AAPL_FMWK)
            target_include_directories(mnnpybridge PUBLIC ${numpy_path}/include)
        endif()
        target_link_libraries(mnnpybridge PUBLIC ${numpy})
    endif()
else()
    target_include_directories(mnnpybridge PRIVATE ${MNN_DIR}/pymnn/src ${MNN_DIR}/pymnn/android/src/main/c/include)
    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${MNN_DIR}/pymnn/android/src/main/jniLibs/${ANDROID_ABI})
    if (PYMNN_OHOS_INTERNAL)
        target_link_libraries(mnnpybridge PRIVATE tcpkg::mnn)
        if(PYMNN_USE_ALINNPYTHON)
            target_link_libraries(mnnpybridge PRIVATE tcpkg::alinnpython)
        endif()
        export_headers(DIR ${CMAKE_SOURCE_DIR}/pip_package/MNN)
    else()
        if (PYMNN_AUDIO_API)
            target_link_libraries(mnnpybridge PRIVATE log MNN MNN_Express MNNOpenCV MNNAudio)
        else()
            target_link_libraries(mnnpybridge PRIVATE log MNN MNN_Express MNNOpenCV)
        endif()
        if(PYMNN_USE_ALINNPYTHON)
            target_link_libraries(mnnpybridge PRIVATE AliNNPython)
        endif()
        if(PYMNN_NUMPY_USABLE)
            target_link_libraries(mnnpybridge PRIVATE numpy_python)
        endif()
        if(PYMNN_LLM_API)
            target_link_libraries(mnnpybridge PRIVATE MNN_LLM)
        endif()
    endif()
endif()

if(CMAKE_SYSTEM_NAME MATCHES "^Android")
add_custom_command(
        TARGET mnnpybridge
        POST_BUILD
        COMMAND mkdir -p ${NATIVE_INCLUDE_OUTPUT}/../libs
        COMMAND cp -r ${CMAKE_CURRENT_SOURCE_DIR}/android/build/intermediates/cmake/release/obj/  ${NATIVE_INCLUDE_OUTPUT}/../libs
)
endif()
