blob: beb86f271f15e55b8cbd3cf4a81ffdfede1b39df [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
################################################################################################
# Build a cython module
#
# Usage:
# mxnet_external_build_cython(<python major version>)
#
function(mxnet_build_cython_module python_version _cython_modules)
string(REGEX REPLACE "@" ";" PROP_MXNET_INCLUDE_DIRECTORIES "${MXNET_INCLUDE_DIRECTORIES}")
string(REGEX REPLACE "@" ";" PROP_MXNET_INTERFACE_LINK_LIBRARIES "${MXNET_INTERFACE_LINK_LIBRARIES}")
foreach(var ${PROP_MXNET_INCLUDE_DIRECTORIES})
include_directories(${var})
endforeach()
unset(PYTHONLIBS_FOUND)
unset(PYTHON_LIBRARIES)
unset(PYTHON_INCLUDE_PATH)
unset(PYTHON_INCLUDE_DIRS)
unset(PYTHON_DEBUG_LIBRARIES)
unset(PYTHONLIBS_VERSION_STRING)
unset(PYTHONINTERP_FOUND)
unset(PYTHON_EXECUTABLE)
unset(PYTHON_VERSION_STRING)
unset(PYTHON_VERSION_MAJOR)
unset(PYTHON_VERSION_MINOR)
unset(PYTHON_VERSION_PATCH)
if(python_version EQUAL 2)
set(Python_ADDITIONAL_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0)
elseif(python_version EQUAL 3)
set(Python_ADDITIONAL_VERSIONS 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
else()
message(FATAL_ERROR "Nov alid python_version set (must be 2 or 3)")
return()
endif()
set(python_libs_version ${python_version})
include(${MXNET_ROOT_DIR}/cmake/UseCython.cmake) # set from mxnet_external_build_cython
if(NOT CYTHON${python_version}_FOUND)
message(WARNING " Could not build cython target for Python ${python_version}")
return()
endif()
set(CYTHON_SUBDIR ".")
file(GLOB_RECURSE CYTHON_SOURCE "${MXNET_ROOT_DIR}/python/mxnet/*.pyx")
if(NOT MXNET_LIB_LOCATION)
set(MXNET_LIB_LOCATION mxnet)
endif()
set(CYTHON_CXX_SOURCE "")
foreach(cy_file ${CYTHON_SOURCE})
set_source_files_properties(${cy_file} PROPERTIES CYTHON_IS_CXX TRUE)
list(APPEND CYTHON_CXX_SOURCE ${cy_file_generated})
get_filename_component(cy_module ${cy_file} NAME_WE)
get_filename_component(cy_dir ${cy_file} DIRECTORY)
# message(STATUS "MXNET_ROOT_DIR: ${MXNET_ROOT_DIR}")
file(RELATIVE_PATH cy_directory "${MXNET_ROOT_DIR}" ${cy_dir})
# message(STATUS "cy_directory: ${cy_directory}")
# message(STATUS "MXNET_BINARY_DIR: ${MXNET_BINARY_DIR}")
set(bin_directory "${MXNET_BINARY_DIR}/${cy_directory}")
# message(STATUS "bin_directory: ${bin_directory}")
set(CYTHON_SUBDIR "${bin_directory}/cy${python_version}")
#message(STATUS "CYTHON_SUBDIR: ${CYTHON_SUBDIR}")
file(MAKE_DIRECTORY ${CYTHON_SUBDIR})
# We need cmake to have different target names for python 2 and 3
set(cy_module_name ${cy_module})
# cython_add_module expects cxx outyput dir to be relative to current binary dir
file(RELATIVE_PATH CYTHON_SUBDIR "${CMAKE_CURRENT_BINARY_DIR}" ${CYTHON_SUBDIR})
#${CMAKE_CURRENT_BINARY_DIR}/${c_cxx_output_subdir}
cython_add_module(${cy_module_name}
"${CYTHON_SUBDIR}"
"${MXNET_BINARY_DIR}/cython/cy${python_version}"
${cy_file})
set_target_properties(${cy_module_name}
PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${CYTHON_SUBDIR}/"
INTERFACE_LINK_LIBRARIES "${PROP_MXNET_INTERFACE_LINK_LIBRARIES}"
)
target_link_libraries(${cy_module_name} ${MXNET_LIB_LOCATION})
list(APPEND output_cython_modules ${cy_module_name})
endforeach()
set(${_cython_modules} ${output_cython_modules} PARENT_SCOPE)
#message(STATUS "output_cython_modules: ${output_cython_modules}")
endfunction()
################################################################################################
# Copy cython modules into source python dir
#function(_cython_install_into_source_dir python_version _cython_binary_dir _source_root_dir)
# file(GLOB_RECURSE cython_module_runtimes
# "${_cython_binary_dir}/*.so"
# "${_cython_binary_dir}/*.dll"
# "${_cython_binary_dir}/*.pyd")
# #message(STATUS "cython_module_runtimes: ${cython_module_runtimes}")
# set(_running_target_suffix "")
# foreach(_file ${cython_module_runtimes})
# set(_running_target_suffix "${_running_target_suffix}_")
# message(STATUS "_file: ${_file}")
# get_filename_component(_cy_module_name ${_file} NAME_WE)
# get_filename_component(_cy_module_directory ${_file} DIRECTORY)
# #message(STATUS "_cy_module_name: ${_cy_module_name}")
# #message(STATUS "_cy_module_directory: ${_cy_module_directory}")
# file(RELATIVE_PATH _relpath_source ${_cython_binary_dir} ${_file})
# #message(STATUS "_relpath_source: ${_relpath_source}")
# set(_dest_file "${_source_root_dir}/${_relpath_source}")
# #message(STATUS "_dest_file: ${_dest_file}")
# get_filename_component(_dest_file_dir ${_dest_file} DIRECTORY)
# file(MAKE_DIRECTORY ${_dest_file_dir})
# #message(STATUS "${_file} -> ${_dest_file}")
# set(_target_name cython_${_cy_module_name}_copy_shared_obj)
# #message(STATUS "target: ${_target_name}")
# add_custom_target(${_target_name} ALL
# DEPENDS ${_cy_module_name}
# COMMAND ${CMAKE_COMMAND} -E copy_if_different ${_file} ${_dest_file})
# add_custom_target(cython_${_cy_module_name}_copy_cython_debug ALL
# DEPENDS ${_cy_module_name}
# COMMAND ${CMAKE_COMMAND} -E copy_directory
# ${_cy_module_directory}/cython_debug
# ${_dest_file_dir}/cython_debug
# )
# endforeach()
#endfunction()
function(cython_install_into_source_dir
_cython_binary_dir
_source_root_dir
_dependencies
)
file(GLOB_RECURSE cython_module_runtimes
"${_cython_binary_dir}/*.so"
"${_cython_binary_dir}/*.dll"
"${_cython_binary_dir}/*.pyd")
#message(STATUS "cython_module_runtimes: ${cython_module_runtimes}")
set(_running_target_suffix "")
foreach(_file ${cython_module_runtimes})
#set(_running_target_suffix "${_running_target_suffix}_")
#message(STATUS "_file: ${_file}")
get_filename_component(_cy_module_name ${_file} NAME_WE)
get_filename_component(_cy_module_directory ${_file} DIRECTORY)
#message(STATUS "_cy_module_name: ${_cy_module_name}")
#message(STATUS "_cy_module_directory: ${_cy_module_directory}")
file(RELATIVE_PATH _relpath_source ${_cython_binary_dir} ${_file})
#message(STATUS "_relpath_source: ${_relpath_source}")
set(_dest_file "${_source_root_dir}/${_relpath_source}")
#message(STATUS "_dest_file: ${_dest_file}")
get_filename_component(_dest_file_dir ${_dest_file} DIRECTORY)
file(MAKE_DIRECTORY ${_dest_file_dir})
#message(STATUS "${_file} -> ${_dest_file}")
#message(STATUS "target: ${_target_name}")
#message(STATUS "_dependencies: ${${_dependencies}}")
file(RELATIVE_PATH _full_module_name ${CMAKE_CURRENT_SOURCE_DIR} ${_dest_file})
string(REGEX REPLACE "/" "." _full_module_name "${_full_module_name}")
string(REGEX REPLACE "\\\\" "." _full_module_name "${_full_module_name}")
#message(STATUS "_full_module_name: ${_full_module_name}")
#message(STATUS "**** LINK: ${_cy_module_directory}/* -> ${_dest_file_dir}/")
if(UNIX)
#message("add_custom_target(${_full_module_name} ALL)")
add_custom_target(
${_full_module_name} ALL
#DEPENDS ${${_dependencies}}
#COMMAND ln -sf ${_file} ${_dest_file}
#COMMAND echo "***************************************************"
COMMAND ln -sf ${_cy_module_directory}/* ${_dest_file_dir}/
)
else()
add_custom_target(
${_full_module_name} ALL
#DEPENDS ${${_dependencies}}
#COMMAND ${CMAKE_COMMAND} -E copy ${_file} ${_dest_file}
COMMAND ${CMAKE_COMMAND} -E copy ${_cy_module_directory}/* ${_dest_file_dir}
)
endif()
endforeach()
endfunction()
################################################################################################
# Spawn external CMakeLists.txt in order to build a particular cython/python version
#
# The spawn approach is because we need to detect and build with both python version 2 and 3
# This is not osmething that a single process of cmake can deal with, so we launch
# a cmake process for the cython build 2, then for 3, passing it our relevant config
#
# Usage:
# mxnet_external_build_cython(<python major version>)
#
function(mxnet_external_build_cython python_major_version target)
set(PMV ${python_major_version})
if(CYTHON_WITHOUT_MXNET_TARGET)
set(CYTHON_DEPS "")
set(CYTHON_MXNET_LIB_LOCATION "")
else()
set(CYTHON_DEPS mxnet)
set(CYTHON_MXNET_LIB_LOCATION $<TARGET_LINKER_FILE:mxnet>)
endif()
file(GLOB_RECURSE CYTHON_SOURCE "python/mxnet/cython/*.pyx")
get_cmake_property(CACHE_VARS CACHE_VARIABLES)
foreach(_cache_var ${CACHE_VARS})
#message(STATUS "${_cache_var}=${${_cache_var}}")
get_property(CACHE_VAR_HELPSTRING CACHE ${_cache_var} PROPERTY HELPSTRING)
if(NOT _cache_var MATCHES "CMAKE_EXTRA_GENERATOR_.+"
AND NOT _cache_var MATCHES "FIND_PACKAGE_MESSAGE_.+"
)
if(_cache_var MATCHES "USE_.+"
OR _cache_var MATCHES "CMAKE_MODULE_.+"
OR CACHE_VAR_HELPSTRING STREQUAL "No help, variable specified on the command line."
)
get_property(_cache_var_type CACHE ${_cache_var} PROPERTY TYPE)
if(_cache_var_type STREQUAL "UNINITIALIZED")
set(_cache_var_type)
else()
set(_cache_var_type :${_cache_var_type})
endif()
set(CMAKE_ARGS "${CMAKE_ARGS} -D${_cache_var}${_cache_var_type}=\"${${_cache_var}}\"")
endif()
endif()
endforeach()
get_property(PROP_MXNET_INCLUDE_DIRECTORIES TARGET mxnet PROPERTY INCLUDE_DIRECTORIES)
string(REGEX REPLACE "\;" "@" MXNET_INCLUDE_DIRECTORIES "${PROP_MXNET_INCLUDE_DIRECTORIES}")
get_property(PROP_MXNET_INTERFACE_LINK_LIBRARIES TARGET mxnet PROPERTY INTERFACE_LINK_LIBRARIES)
string(REGEX REPLACE "\;" "@" MXNET_INTERFACE_LINK_LIBRARIES "${PROP_MXNET_INTERFACE_LINK_LIBRARIES}")
set(CYTHON_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/cython/cy${PMV})
set(_config_cleanup_files "")
set(_config_cleanup_files_ex "")
foreach(_file ${CYTHON_SOURCE})
get_filename_component(_cy_module ${_file} NAME_WE)
list(APPEND _config_cleanup_files "${CYTHON_BINARY_DIR}/${_cy_module}.so")
list(APPEND _config_cleanup_files "${CYTHON_BINARY_DIR}/${_cy_module}.cxx")
list(APPEND _config_cleanup_files "${CYTHON_BINARY_DIR}/${_cy_module}.c")
endforeach()
# Clear some cmake-generated files
list(APPEND _config_cleanup_files_ex "${CYTHON_BINARY_DIR}/CMakeCache.txt")
list(APPEND _config_cleanup_files_ex "${CYTHON_BINARY_DIR}/Makefile")
# Get current cleanup files
get_directory_property(CLEANUP_FILES ADDITIONAL_MAKE_CLEAN_FILES)
list(APPEND CLEANUP_FILES ${_config_cleanup_files})
list(APPEND CLEANUP_FILES ${_config_cleanup_files_ex})
# Set new list of cleanup files
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${CLEANUP_FILES}")
file(MAKE_DIRECTORY ${CYTHON_BINARY_DIR})
add_custom_target(${PROJECT_NAME}_ConfigCython${PMV} ALL
${CMAKE_COMMAND}
${CMAKE_ARGS}
-G "${CMAKE_GENERATOR}"
-DCMAKE_MODULE_PATH="${CMAKE_MODULE_PATH}"
-DMXNET_INCLUDE_DIRECTORIES="${MXNET_INCLUDE_DIRECTORIES}"
-DMXNET_INTERFACE_LINK_LIBRARIES="${MXNET_INTERFACE_LINK_LIBRARIES}"
-DMXNET_LIB_LOCATION=${CYTHON_MXNET_LIB_LOCATION}
-DMXNET_ROOT_DIR=${CMAKE_CURRENT_SOURCE_DIR}
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
#-DINSTALL_CYTHON_INPLACE=${INSTALL_CYTHON_INPLACE}
-DMXNET_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/src/cython/cy${PMV}
WORKING_DIRECTORY ${CYTHON_BINARY_DIR}
DEPENDS ${CYTHON_DEPS}
)
add_custom_target(${PROJECT_NAME}_BuildCython${PMV} ALL
${CMAKE_COMMAND}
--build ${CYTHON_BINARY_DIR}
--config ${CMAKE_BUILD_TYPE}
WORKING_DIRECTORY ${CYTHON_BINARY_DIR}
DEPENDS ${PROJECT_NAME}_ConfigCython${PMV}
)
set(${target} ${PROJECT_NAME}_BuildCython${PMV} PARENT_SCOPE)
endfunction()