如何自动为Cython编写setup.py文件并使用子进程运行它.波本



这个想法是,每次我想编译cython模块或包时,我不必自己编写setup.py文件,而是让一个函数来创建它。该函数还应该自己运行创建的setup.py。

因此,问题还在于"如何编写编写代码?"。

我找到了一个有效的解决方案。使用以下代码创建一个compile_cython.py文件:

import os
from subprocess import Popen
temp_dir = os.environ['TEMP']

def package(directory, packages, logfile=False, byproducts=None, annotate=False, language='C'):
    """Compile cython .pyx files to a .pyd file inplace
    :param directory: the directory where the main package lies.
    :param packages: List of packages to compile. A package is described in a
        :type tuple that consists of package name, relative path from main package, list of include files,
        list of include directories and the language (default is C).
    :param logfile: Path or :type bool. If true, a log will be created in :param directory:.
    :param byproducts: The directory in which the by-products will be stored.
        If None, by-products will be saved in "%TEMP%cython_byproducts".
    :param annotate: The Cython annotate option.
    :param language: Default language
    Example:
    package('C:\projects', [('graphics', 'game\graphics', ['OpenGL32'], [r'C:Program FilesMicrosoft SDKsWindowsv7.1Libx64']])
    """
    if not byproducts: byproducts = os.path.join(temp_dir, "cython_byproducts")
    if logfile is True: logfile = os.path.join(directory, "log.txt")
    elif not logfile: logfile = os.path.join(byproducts, "log.txt")
    if isinstance(packages, str):
        dir, package = os.path.split(packages)
        packages = [(package, package)]

    setup_file = os.path.join(byproducts, "setup.py")
    #Write a setup file
    with open(setup_file, 'w') as file:
        file.write("""
from distutils.core import setup, Extension
from Cython.Build import cythonize
import numpy as np
import sys
print(sys.argv) #print for logging
packages = {packages}
extensions = []
for package in packages:
    default = ['name', 'path', [], [], '{default_language}']
    default[:len(package)]=package
    extensions.append(Extension("%s.*" %default[0], ["%s\\*.pyx" %default[1]], libraries=default[2],
    library_dirs=default[3], language=default[4].lower()))
setup(include_dirs = np.get_include(),ext_modules = cythonize(extensions, annotate={annotate})) # accepts a glob pattern
""".format(packages=packages, annotate=annotate, default_language=language)
                        )
    p = Popen(r'python "{setup}" build_ext --inplace --build-temp "{byproducts}"'.format(setup=setup_file,
                                                                                         byproducts=byproducts,)                                                                                         ,
                                                                                        cwd=directory)
    with open(logfile, 'w') as log:
        stdout, stderr = p.communicate()
        log.write(stdout or 'NO OUTPUTn')
        log.write(stderr or 'NO ERRORSn')
def module(directory, modules, logfile=False, byproducts=None, annotate=False, language='C'):
    """Compile cython .pyx files to a .pyd file inplace
    :param directory: the directory where the module lies
    :param modules: The Path relative from :param directory or a List of modules to compile. A module is described in a
        :type tuple that consists of module name, relative path from :param directory, list of include files,
        list of include directories and the language (default is C).
    :param logfile: Path or :type bool. If true, a log will be created in :param directory:.
    :param byproducts: The directory in which the by-products will be stored.
        If None, by-products will be saved in "%TEMP%cython_byproducts".
    :param annotate: The Cython annotate option.
    :param language: Default language
    Example:
    module('C:\projects', [('effects', 'game\graphics\effects.pyx'])
    """
    if not byproducts: byproducts = os.path.join(temp_dir, "cython_byproducts")
    if logfile is True: logfile = os.path.join(directory, "log.txt")
    elif not logfile: logfile = os.path.join(byproducts, "log.txt")
    if isinstance(modules, str):
        dir, name_ext = os.path.split(modules)
        name, ext = os.path.splitext(name_ext)
        modules = [(name, name_ext)]
    setup_file = os.path.join(byproducts, "setup.py")
    #Write a setup file
    with open(setup_file, 'w') as file:
        file.write("""
from distutils.core import setup, Extension
from Cython.Build import cythonize
import numpy as np
import sys
print(sys.argv) #print for logging
modules = {modules}
extensions = []
for module in modules:
    default = ['name', 'path', [], [], '{default_language}']
    default[:len(module)]=module
    extensions.append(Extension("%s" %default[0], ["%s" %default[1]], libraries=default[2],
    library_dirs=default[3], language=default[4].lower()))
setup(include_dirs = np.get_include(),ext_modules = cythonize(extensions, annotate={annotate})) # accepts a glob pattern
""".format(modules=modules, annotate=annotate, default_language=language)
                        )
    p = Popen(r'python "{setup}" build_ext --inplace --build-temp "{byproducts}"'.format(setup=setup_file,
                                                                                         byproducts=byproducts,)                                                                                         ,
                                                                                         cwd=directory)
    with open(logfile, 'w') as log:
        stdout, stderr = p.communicate()
        log.write(stdout or 'NO OUTPUTn')
        log.write(stderr or 'NO ERRORSn')

它仍然需要一些修改才能编译纯C或C++文件,但它适用于Cython文件。

在此设置中,Numpy会自动包含在内。但我想这没问题,因为除非你使用numpy函数,否则它实际上不包括任何东西,或者是这样吗?

最新更新