# This is a CMake file that sets up the add_python_module() macro.  This macro
# lets you easily make python modules that use dlib.  
#
# The macro takes the module name as its first argument and then a list of
# source files to compile into the module.  See ../tools/python/CMakeLists.txt
# for an example.
#
# It also sets up a macro called install_${module_name}_to() where
# ${module_name} is whatever you named your module.  This install_*_to() macro
# takes a folder name and creates an install target that will copy the compiled
# python module to that folder when you run "make install".  Note that the path
# given to install_*_to() is relative to your CMakeLists.txt file.
#


option(PYTHON3 "Build a Python3 compatible library rather than Python2." OFF)

# Avoid cmake warnings about changes in behavior of some Mac OS X path 
# variable we don't care about.
if (POLICY CMP0042)
    cmake_policy(SET CMP0042 NEW)
endif()


# Sometimes a computer will have multiple python verions installed.  So in this
# block of code we find the one in the user's path and add its home folder into
# cmake's search path.  That way it will use that version of python first. 
if (PYTHON3)
    find_program(PYTHON_EXECUTABLE python3)
endif()
if (NOT PYTHON_EXECUTABLE)
    find_program(PYTHON_EXECUTABLE python)
endif()
# Resolve symbolic links, hopefully this will give us a path in the proper
# python home directory.
get_filename_component(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE} REALPATH)
# Pick out the parent directories
get_filename_component(PYTHON_PATH ${PYTHON_EXECUTABLE} PATH)
get_filename_component(PYTHON_PATH ${PYTHON_PATH} PATH)
list(APPEND CMAKE_PREFIX_PATH "${PYTHON_PATH}")


# To avoid dll hell, always link everything statically when compiling in
# visual studio.  This way, the resulting library won't depend on a bunch
# of other dll files and can be safely copied to someone elese's computer
# and expected to run.
if (MSVC)
    include(${CMAKE_CURRENT_LIST_DIR}/tell_visual_studio_to_use_static_runtime.cmake)
    add_definitions(-DBOOST_PYTHON_STATIC_LIB)
    SET(Boost_USE_STATIC_LIBS ON)
    SET(Boost_USE_MULTITHREADED ON)
    SET(Boost_USE_STATIC_RUNTIME ON)
endif()

set(Boost_NO_BOOST_CMAKE ON)

if (NOT WIN32)
    set(BOOST_LIBRARYDIR ${BOOST_LIBRARYDIR} $ENV{BOOST_LIBRARYDIR}  
            /usr/lib/x86_64-linux-gnu/)
else()
    link_directories($ENV{BOOST_LIBRARYDIR})
endif()
if (PYTHON3)
    # On some systems the boost python3 module is called python-py34 so check
    # for that one first.  
    FIND_PACKAGE(Boost 1.41.0  COMPONENTS python-py34 )
    if (NOT Boost_FOUND)
        FIND_PACKAGE(Boost 1.41.0 COMPONENTS python-py35)
    endif()
    if (NOT Boost_FOUND)
        FIND_PACKAGE(Boost 1.41.0 COMPONENTS python3)
    endif()
    if (NOT Boost_FOUND)
        FIND_PACKAGE(Boost 1.41.0 COMPONENTS python)
    endif()
    set(Python_ADDITIONAL_VERSIONS 3.5 3.6)
    FIND_PACKAGE(PythonLibs 3.4)
else()
    FIND_PACKAGE(Boost 1.41.0 COMPONENTS python)
    FIND_PACKAGE(PythonLibs 2.6)
endif()

if (CMAKE_COMPILER_IS_GNUCXX)
    # Just setting CMAKE_POSITION_INDEPENDENT_CODE should be enough to set
    # -fPIC for GCC but sometimes it still doesn't get set, so make sure it
    # does.
    add_definitions("-fPIC")
    set(CMAKE_POSITION_INDEPENDENT_CODE True)
else()
    set(CMAKE_POSITION_INDEPENDENT_CODE True)
endif()

# include dlib so we can link against it
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/.. dlib_build)
if (USING_OLD_VISUAL_STUDIO_COMPILER)
   message(FATAL_ERROR "You have to use a version of Visual Studio that supports C++11.  As of December 2017, the only versions that have good enough C++11 support to compile the dlib Pyhton API is a fully updated Visual Studio 2015 or a fully updated Visual Studio 2017.  Older versions of either of these compilers have bad C++11 support and will fail to compile the Python extension. ***SO UPDATE YOUR VISUAL STUDIO TO MAKE THIS ERROR GO AWAY***")
endif()


if (NOT Boost_FOUND)
    message(STATUS " *****************************************************************************************************")
    if (WIN32)
        if (NOT DEFINED ENV{BOOST_ROOT} OR NOT DEFINED ENV{BOOST_LIBRARYDIR})
            message(STATUS "The BOOST_ROOT and/or BOOST_LIBRARYDIR environment variables are not set.  You need to set these ")
            message(STATUS "variables so we know where boost is installed.  So set these variables to something like this:")
            message(STATUS "    BOOST_ROOT=C:\\local\\boost_1_57_0 " )
            message(STATUS "    BOOST_LIBRARYDIR=C:\\local\\boost_1_57_0\\stage\\lib")
            message(STATUS "The best way to set enviornment variables in Windows is to go to the start menu's search box,")
            message(STATUS "type environment, and open the Environment Variables dialog.  That lets you add more variables.")
            message(STATUS "Add these variables to either user or system variables, it doesn't matter.")
            message(STATUS "You might have to log out and log back in before the environment changes take effect.")
        else()
            message(STATUS "We couldn't find the right version of boost python.  If you installed boost and you are still "
                    "getting this error then you might have installed a version of boost that was compiled with a different "
                    "version of visual studio than the one you are using.  So you have to make sure that the version of "
                    "visual studio is the same version that was used to compile the copy of boost you are using.")
            message(STATUS "")
            message(STATUS " You will likely need to compile boost yourself rather than using one of the precompiled ")
            message(STATUS " windows binaries.  Do this by going to the folder tools\\build\\ within boost and running ")
            message(STATUS " bootstrap.bat.  Then run the command: ")
            message(STATUS "    b2 install")
            message(STATUS " And then add the output bin folder to your PATH.  Usually this is the C:\\boost-build-engine\\bin")
            message(STATUS " folder. Finally, go to the boost root and run a command like this:")
            message(STATUS "    b2 -a --with-python address-model=64 toolset=msvc runtime-link=static")
            message(STATUS " Note that you will need to set the address-model based on if you want a 32 or 64bit python library.")
            message(STATUS " When it completes, set the BOOST_LIBRARYDIR environment variable equal to wherever b2 put the ")
            message(STATUS " compiled libraries.  You will also need to set BOOST_ROOT to the root folder of the boost install.")
            message(STATUS " E.g.  Something like this: ")
            message(STATUS "    set BOOST_ROOT=C:\\local\\boost_1_57_0 " )
            message(STATUS "    set BOOST_LIBRARYDIR=C:\\local\\boost_1_57_0\\stage\\lib")
            message(STATUS "")
            message(STATUS " Next, if you aren't using python setup.py then you will be invoking cmake to compile dlib.  ")
            message(STATUS " In this case you may have to use cmake's -G option to set the 64 vs. 32bit mode of visual studio. ")
            message(STATUS " Also, if you want a Python3 library you will need to add -DPYTHON3=1.  You do this with a statement like: ")
            message(STATUS "    cmake -G \"Visual Studio 14 2015 Win64\" -DPYTHON3=1 ..\\..\\tools\\python")
            message(STATUS " Rather than:")
            message(STATUS "    cmake ..\\..\\tools\\python")
            message(STATUS " Which will build a 32bit Python2 module by default on most systems.")
            message(STATUS "")
        endif()
    else()
        message(STATUS " To compile Boost.Python yourself download boost from boost.org and then go into the boost root folder")
        message(STATUS " and run these commands: ")
        message(STATUS "    ./bootstrap.sh --with-libraries=python") 
        message(STATUS "    ./b2")
        message(STATUS "    sudo ./b2 install")
    endif()
    message(STATUS " *****************************************************************************************************")
    message(FATAL_ERROR " Boost python library not found. ")
endif()




message(STATUS "USING BOOST_LIBS: ${Boost_LIBRARIES}")
if (WIN32)
    message(STATUS "USING PYTHON_LIBS: ${PYTHON_LIBRARIES}")
endif()

# We put the extra _ on the end of the name just so it's possible to
# have a module name of dlib and not get a conflict with the target named
# dlib in ../dlib/cmake.  We use the target OUPUT_NAME property to ensure the
# output name is set to what the user asked for (i.e. no _).
macro(add_python_module module_name module_sources )
   ADD_LIBRARY(${module_name}_ SHARED ${module_sources} ${ARGN} )
   TARGET_LINK_LIBRARIES(${module_name}_ ${Boost_LIBRARIES} dlib::dlib)

    target_include_directories(${module_name}_ SYSTEM PUBLIC "${Boost_INCLUDE_DIRS}")
    if (PYTHON_INCLUDE_PATH)
        target_include_directories(${module_name}_ SYSTEM PUBLIC "${PYTHON_INCLUDE_PATH}" )
    else()
        target_include_directories(${module_name}_ SYSTEM PUBLIC "${PYTHON_INCLUDE_DIRS}" )
    endif()


   if(WIN32 AND NOT CYGWIN)
      TARGET_LINK_LIBRARIES(${module_name}_ ${PYTHON_LIBRARIES})
      SET_TARGET_PROPERTIES( ${module_name}_
         PROPERTIES
         PREFIX ""
         SUFFIX ".pyd"
         OUTPUT_NAME ${module_name}
         )
   elseif(CYGWIN)
      SET_TARGET_PROPERTIES( ${module_name}_
         PROPERTIES
         PREFIX ""
         SUFFIX ".dll"
         OUTPUT_NAME ${module_name}
         )
    elseif(APPLE)
      SET_TARGET_PROPERTIES( ${module_name}_
         PROPERTIES
         LINK_FLAGS "-undefined dynamic_lookup"
         PREFIX ""
         SUFFIX ".so"
         OUTPUT_NAME ${module_name}
         )
   else()
      SET_TARGET_PROPERTIES( ${module_name}_
         PROPERTIES
         LINK_FLAGS "-shared"
         PREFIX ""
         SUFFIX ".so"
         OUTPUT_NAME ${module_name}
         )
   endif()

   macro(install_${module_name}_to path)
       # Determine the path to our CMakeLists.txt file.
       string(REGEX REPLACE "CMakeLists.txt$" "" base_path ${CMAKE_CURRENT_LIST_FILE})
       INSTALL(TARGETS ${module_name}_ 
            RUNTIME DESTINATION  "${base_path}/${path}"
            LIBRARY DESTINATION  "${base_path}/${path}"
           )
   endmacro()

endmacro()



