Skip to content
Snippets Groups Projects
MakePythonWheel.cmake 6.18 KiB
# This function makes a Python distribution wheel for the given version of Python platform.

include("multipython/PyDirectories") # set_python_package_dirs

function(make_python_wheel)
    # parse function arguments for text like 'PYTAG xy',
    # and set local variable '__PYTAG' to 'xy'.
    cmake_parse_arguments("_" "" "Py3_EXECUTABLE;Py3_VERSION" "Py3_INCLUDE_DIRS;Py3_LIBRARY_DIRS" ${ARGN})

    set(header "Python wheel (${__Py3_VERSION}):")

    # make directories for the Python wheel
    set_python_package_dirs(${__Py3_VERSION})

    #-- define the main target to build a Python wheel
    # store the external libraries needed for making the Python wheel
    if(WIN32)
        set(_extra_libs "${BA_Dependencies_WIN32}")
    else()
        set(_extra_libs "${BA_Dependencies}")
    endif()

    # make the Python wheel
    if(APPLE)
        # On MacOS, building the Python packages needs further effort
        # which is performed in a dedicated shell script which
        # should be executed after build process is done (like CPack).
        set(BA_PY_MODE "ON")
        set(MACPKG_EXTRA_LIBS "${_extra_libs}")

        configure_file("${CMAKE_SOURCE_DIR}/devtools/deploy/mac/mac_package.py.in"
            ${BUILD_VAR_DIR}/mac_py_package.py @ONLY)

        add_custom_target(BAPyWheel ALL
            COMMENT "${header} Script to build the Python wheel: "
            "'${${BUILD_VAR_DIR}/mk_pypack_macos.zsh}'"
            )
    elseif(LINUX)
        # On Linux, building the Python packages needs further effort
        # which is performed in a dedicated shell script which
        # should be executed after build process is done (like CPack).
        configure_file("${CMAKE_SOURCE_DIR}/devtools/deploy/linux/mk_pypack_linux.sh.in"
            ${BUILD_VAR_DIR}/mk_pypack_linux.sh @ONLY)
        add_custom_target(BAPyWheel ALL
            COMMENT "${header} Script to build the Python wheel: "
            "'${${BUILD_VAR_DIR}/mk_pypack_linux.sh}'"
            )
    else()
        # MS-Windows
        add_custom_target(BAPyWheel ALL
            COMMAND ${__Py3_EXECUTABLE} -m pip wheel ${BA_PY_OUTPUT_DIR} --no-deps --wheel ${BA_PY_PACKAGE_WHEEL_DIR}
            COMMENT "${header} Making the Python wheel..."
            )
    endif()

    set_target_properties(BAPyWheel PROPERTIES
        _EXTRA_LIBRARIES "${_extra_libs}")

    #-- store the configuration files for the Python package
    # make the version-dependent setup config
    set(_setup_cfg ${BA_PY_OUTPUT_DIR}/setup.cfg)
    set(BA_PY_VERSION_MAJOR ${BornAgain_VERSION_MAJOR})
    set(BA_PY_VERSION_MINOR ${BornAgain_VERSION_MINOR})

    set(_setup_py ${BA_PY_OUTPUT_DIR}/setup.py)
    set(BA_PY_PACKAGE_C_EXT "src/bornagain_c_ext_dummy.c")
    set(BA_PY_PACKAGE_C_EXT_INC_DIRS "${__Py3_INCLUDE_DIRS}")
    set(BA_PY_PACKAGE_C_EXT_LIB_DIRS "${__Py3_LIBRARY_DIRS}")
    configure_file(${BA_PY_PACKAGE_ROOT_DIR}/setup.cfg.in
        ${_setup_cfg} @ONLY)
    configure_file(${BA_PY_PACKAGE_ROOT_DIR}/setup.py.in
        ${_setup_py} @ONLY)

    # copy config files
    set(_dst ${BA_PY_OUTPUT_DIR}/)
    file(GLOB _config_files
        ${BA_PY_PACKAGE_ROOT_DIR}/pyproject.toml
        ${BA_PY_PACKAGE_ROOT_DIR}/MANIFEST.in
        )
    add_custom_target(BAPyWheel_config_files
        COMMAND ${CMAKE_COMMAND} -E copy ${_config_files} ${_dst}
        COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/README.md ${_dst}/
        COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/COPYING ${_dst}/
        COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/CITATION ${_dst}/
        COMMENT "${header} Copying config files to '${_dst}'..."
        DEPENDS ${_setup_cfg} ${_setup_py}
        )
    # store dummy C extension for the Python package
    # NOTE: Dummy C extension is used merely to set the correct wheel tag
    # according to PEP 425
    set(_dst ${BA_PY_SOURCE_OUTPUT_DIR})
    file(GLOB _c_dummy_file ${BA_PY_PACKAGE_ROOT_DIR}/${BA_PY_PACKAGE_C_EXT})
    add_custom_target(BAPyWheel_c_dummy_file
        COMMAND ${CMAKE_COMMAND} -E copy ${_c_dummy_file} ${_dst}
        COMMENT "${header} Copying dummy C extension file to '${_dst}'..."
        )
    # store init files for the Python package
    set(_dst ${BA_PY_INIT_OUTPUT_DIR}/)
    set(_dst_lib ${BA_PY_LIBRARY_OUTPUT_DIR}/)
    file(GLOB _ba_py_files ${BA_PY_PACKAGE_ROOT_DIR}/src/bornagain/*.py)
    file(GLOB _init_files_lib ${BA_PY_PACKAGE_ROOT_DIR}/src/bornagain/lib/*.py)
    configure_file(${BA_PY_PACKAGE_ROOT_DIR}/src/bornagain/__init__.py.in
        ${_dst}/__init__.py @ONLY)

    add_custom_target(BAPyWheel_init_files
        COMMAND ${CMAKE_COMMAND} -E copy ${_ba_py_files} ${_dst}
        COMMAND ${CMAKE_COMMAND} -E copy ${_init_files_lib} ${_dst_lib}
        COMMENT "${header} Copying init files to '${_dst}'..."
        )
    # store the required extra libraries
    set(_dst ${BA_PY_EXTRA_LIBRARY_OUTPUT_DIR})
    add_custom_target(BAPyWheel_extra_libs
        COMMAND ${CMAKE_COMMAND} -E copy ${_extra_libs} ${_dst}
        COMMENT "${header} Copying extra libraries {${_extra_libs}} to '${_dst}'..."
        )
    # add dependencies
    add_dependencies(BAPyWheel
        BAPyWheel_config_files
        BAPyWheel_c_dummy_file
        BAPyWheel_init_files
        BAPyWheel_extra_libs
        )
endfunction()


function(add_library_to_wheel lib)
    # add_library_to_wheel: Add a BornAgain library to the Python wheel
    # NOTE: Target BAPyWheel must be already defined.

    add_dependencies(BAPyWheel ${lib})
    # eg., 'libBornAgain.so'
    get_target_property(libfilename ${lib} _BASEFILENAME)

    # copy the shared library and its Python interface to the Python wheel folder
    set(_dst ${BA_PY_LIBRARY_OUTPUT_DIR}/)

    add_custom_command(TARGET ${lib}
        POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE:${lib}>" ${_dst}/${libfilename}
        COMMENT "Add library ${lib} to the Python wheel..."
    )

    get_target_property(lib_LIBRARY_PY ${lib} _LIBRARY_PY)
    string(STRIP ${lib_LIBRARY_PY} lib_LIBRARY_PY)
    if(lib_LIBRARY_PY)
        add_custom_command(TARGET ${lib}
            POST_BUILD
            COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_PROPERTY:${lib},_LIBRARY_PY>" ${_dst}
            COMMENT "Add Python wrapper-script of library ${lib} to the Python wheel..."
        )
    endif()

endfunction()