summaryrefslogtreecommitdiffstats
path: root/cmake/modules/Distutils.cmake
blob: daaae4ba63fdbc53f935387a34b4ade63971b3ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
include(CMakeParseArguments)

# ensure that we are using the exact python version specified by
# 'WITH_PYTHON3', in case some included 3rd party libraries call
# 'find_package(Python3 ...) without specifying the exact version number. if
# the building host happens to have a higher version of python3, that version
# would be picked up instead by find_package(Python3). and that is not want we
# expect.
find_package(Python3 ${WITH_PYTHON3} EXACT
  QUIET
  REQUIRED
  COMPONENTS Interpreter)

function(distutils_install_module name)
  set(py_srcs setup.py README.rst requirements.txt test-requirements.txt bin ${name})
  foreach(src ${py_srcs})
    if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${src})
      list(APPEND py_clone ${CMAKE_CURRENT_BINARY_DIR}/${src})
      add_custom_command(
        OUTPUT ${src}
        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${src}
        COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/${src} ${src})
    endif()
  endforeach()
  if(NOT TARGET ${name}-clone)
    add_custom_target(${name}-clone ALL
      DEPENDS ${py_clone})
  endif()
  cmake_parse_arguments(DU "" "INSTALL_SCRIPT" "" ${ARGN})
  install(CODE "
    set(options --prefix=${CMAKE_INSTALL_PREFIX})
    if(DEFINED ENV{DESTDIR})
      if(EXISTS /etc/debian_version)
        list(APPEND options --install-layout=deb)
      endif()
      list(APPEND options
        --root=\$ENV{DESTDIR}
        --single-version-externally-managed)
    endif()
    if(NOT \"${DU_INSTALL_SCRIPT}\" STREQUAL \"\")
      list(APPEND options --install-script=${DU_INSTALL_SCRIPT})
    endif()
    execute_process(
    COMMAND ${Python3_EXECUTABLE}
        setup.py install \${options}
    WORKING_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}\")")
endfunction(distutils_install_module)

function(distutils_add_cython_module target name src)
  get_property(compiler_launcher GLOBAL PROPERTY RULE_LAUNCH_COMPILE)
  get_property(link_launcher GLOBAL PROPERTY RULE_LAUNCH_LINK)
  # When using ccache, CMAKE_C_COMPILER is ccache executable absolute path
  # and the actual C compiler is CMAKE_C_COMPILER_ARG1.
  # However with a naive
  # set(PY_CC ${compiler_launcher} ${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1})
  # distutils tries to execve something like "/usr/bin/cmake gcc" and fails.
  # Removing the leading whitespace from CMAKE_C_COMPILER_ARG1 helps to avoid
  # the failure.
  string(STRIP "${CMAKE_C_COMPILER_ARG1}" c_compiler_arg1)
  string(STRIP "${CMAKE_CXX_COMPILER_ARG1}" cxx_compiler_arg1)
  # Note: no quotes, otherwise distutils will execute "/usr/bin/ccache gcc"
  # CMake's implicit conversion between strings and lists is wonderful, isn't it?
  set(PY_CFLAGS ${COMPILE_OPTIONS})
  cmake_parse_arguments(DU "DISABLE_VTA" "" "" ${ARGN})
  if(DU_DISABLE_VTA AND HAS_VTA)
    list(APPEND PY_CFLAGS -fno-var-tracking-assignments)
  endif()
  list(APPEND PY_CPPFLAGS -iquote${CMAKE_SOURCE_DIR}/src/include -w)
  # This little bit of magic wipes out __Pyx_check_single_interpreter()
  # Note: this is reproduced in distutils_install_cython_module
  list(APPEND PY_CPPFLAGS -D'void0=dead_function\(void\)')
  list(APPEND PY_CPPFLAGS -D'__Pyx_check_single_interpreter\(ARG\)=ARG\#\#0')
  set(PY_CC ${compiler_launcher} ${CMAKE_C_COMPILER} ${c_compiler_arg1})
  set(PY_CXX ${compiler_launcher} ${CMAKE_CXX_COMPILER} ${cxx_compiler_arg1})
  set(PY_LDSHARED ${link_launcher} ${CMAKE_C_COMPILER} ${c_compiler_arg1} "-shared")

  execute_process(COMMAND "${Python3_EXECUTABLE}" -c
    "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))"
    RESULT_VARIABLE result
    OUTPUT_VARIABLE ext_suffix
    ERROR_VARIABLE error
    OUTPUT_STRIP_TRAILING_WHITESPACE)
  if(NOT result EQUAL 0)
    message(FATAL_ERROR "Unable to tell python extension's suffix: ${error}")
  endif()
  set(output_dir "${CYTHON_MODULE_DIR}/lib.3")
  set(setup_py ${CMAKE_CURRENT_SOURCE_DIR}/setup.py)
  if(DEFINED ENV{VERBOSE})
    set(maybe_verbose --verbose)
  endif()
  add_custom_command(
    OUTPUT ${output_dir}/${name}${ext_suffix}
    COMMAND
    env
    CC="${PY_CC}"
    CFLAGS="${PY_CFLAGS}"
    CPPFLAGS="${PY_CPPFLAGS}"
    CXX="${PY_CXX}"
    LDSHARED="${PY_LDSHARED}"
    OPT=\"-DNDEBUG -g -fwrapv -O2 -w\"
    LDFLAGS=-L${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
    CYTHON_BUILD_DIR=${CMAKE_CURRENT_BINARY_DIR}
    CEPH_LIBDIR=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
    ${Python3_EXECUTABLE} ${setup_py}
    build ${maybe_verbose} --build-base ${CYTHON_MODULE_DIR}
    --build-platlib ${output_dir}
    MAIN_DEPENDENCY ${src}
    DEPENDS ${setup_py}
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
  add_custom_target(${target} ALL
    DEPENDS ${output_dir}/${name}${ext_suffix})
endfunction(distutils_add_cython_module)

function(distutils_install_cython_module name)
  get_property(compiler_launcher GLOBAL PROPERTY RULE_LAUNCH_COMPILE)
  get_property(link_launcher GLOBAL PROPERTY RULE_LAUNCH_LINK)
  set(PY_CC "${compiler_launcher} ${CMAKE_C_COMPILER}")
  set(PY_LDSHARED "${link_launcher} ${CMAKE_C_COMPILER} -shared")
  cmake_parse_arguments(DU "DISABLE_VTA" "" "" ${ARGN})
  if(DU_DISABLE_VTA AND HAS_VTA)
    set(CFLAG_DISABLE_VTA -fno-var-tracking-assignments)
  endif()
  if(DEFINED ENV{VERBOSE})
    set(maybe_verbose --verbose)
  endif()
  install(CODE "
    set(ENV{CC} \"${PY_CC}\")
    set(ENV{LDSHARED} \"${PY_LDSHARED}\")
    set(ENV{CPPFLAGS} \"-iquote${CMAKE_SOURCE_DIR}/src/include
                        -D'void0=dead_function\(void\)' \
                        -D'__Pyx_check_single_interpreter\(ARG\)=ARG\#\#0' \
                        ${CFLAG_DISABLE_VTA}\")
    set(ENV{LDFLAGS} \"-L${CMAKE_LIBRARY_OUTPUT_DIRECTORY}\")
    set(ENV{CYTHON_BUILD_DIR} \"${CMAKE_CURRENT_BINARY_DIR}\")
    set(ENV{CEPH_LIBDIR} \"${CMAKE_LIBRARY_OUTPUT_DIRECTORY}\")

    set(options --prefix=${CMAKE_INSTALL_PREFIX})
    if(DEFINED ENV{DESTDIR})
      if(EXISTS /etc/debian_version)
        list(APPEND options --install-layout=deb)
      endif()
      list(APPEND options --root=\$ENV{DESTDIR})
    else()
      list(APPEND options --root=/)
    endif()
    execute_process(
       COMMAND
           ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/setup.py
           build ${maybe_verbose} --build-base ${CYTHON_MODULE_DIR}
           --build-platlib ${CYTHON_MODULE_DIR}/lib.3
           build_ext --cython-c-in-temp --build-temp ${CMAKE_CURRENT_BINARY_DIR} --cython-include-dirs ${PROJECT_SOURCE_DIR}/src/pybind/rados
           install \${options} --single-version-externally-managed --record /dev/null
           egg_info --egg-base ${CMAKE_CURRENT_BINARY_DIR}
           ${maybe_verbose}
       WORKING_DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}\"
       RESULT_VARIABLE install_res)
    if(NOT \"\${install_res}\" STREQUAL 0)
      message(FATAL_ERROR \"Failed to build and install ${name} python module\")
    endif()
  ")
endfunction(distutils_install_cython_module)