2017-09-20 8 views
0

Je crée un paquet Python qui a un module d'extension C++ et la bibliothèque partagée de quelqu'un d'autre dont il a besoin. Je veux tout installer via pip. Mon fichier actuel setup.py fonctionne quand j'utilise pip install -e . mais quand je n'utilise pas le mode de développement (par exemple le -e) j'obtiens "ne peut pas ouvrir le fichier objet partagé" lors de l'importation du module en Python. Je crois que la raison en est que setuptools ne considère pas la bibliothèque partagée comme faisant partie de mon paquet, donc le lien relatif à la bibliothèque est cassé lors de l'installation lorsque les fichiers sont copiés dans le répertoire d'installation.Comment inclure des bibliothèques (construites par script) avec l'installation du paquet?

Voici ce que mon fichier setup.py ressemble:

from setuptools import setup, Extension, Command 
import setuptools.command.develop 
import setuptools.command.build_ext 
import setuptools.command.install 
import distutils.command.build 
import subprocess 
import sys 
import os 

# This function downloads and builds the shared-library 
def run_clib_install_script(): 
    build_clib_cmd = ['bash', 'clib_install.sh'] 
    if subprocess.call(build_clib_cmd) != 0: 
     sys.exit("Failed to build C++ dependencies") 

# I make a new command that will build the shared-library 
class build_clib(Command): 
    user_options = [] 
    def initialize_options(self): 
     pass 
    def finalize_options(self): 
     pass 
    def run(self): 
     run_clib_install_script() 

# I subclass install so that it will call my new command 
class install(setuptools.command.install.install): 
    def run(self): 
     self.run_command('build_clib') 
     setuptools.command.install.install.run(self) 

# I do the same for build... 
class build(distutils.command.build.build): 
    sub_commands = [ 
     ('build_clib', lambda self: True), 
     ] + distutils.command.build.build.sub_commands 

# ...and the same for develop 
class develop(setuptools.command.develop.develop): 
    def run(self): 
     self.run_command('build_clib') 
     setuptools.command.develop.develop.run(self) 

# These are my includes... 
# note that /clib/include only exists after calling clib_install.sh 
cwd = os.path.dirname(os.path.abspath(__file__)) 
include_dirs = [ 
    cwd, 
    cwd + '/clib/include', 
    cwd + '/common', 
] 

# These are my arguments for the compiler to my shared-library 
lib_path = os.path.join(cwd, "clib", "lib") 
library_dirs = [lib_path] 
link_args = [os.path.join(lib_path, "libclib.so")] 

# My extension module gets these arguments so it can link to clib 
mygen_module = Extension('mygen', 
        language="c++14", 
        sources=["common/mygen.cpp"], 
        libraries=['clib'], 
        extra_compile_args=['-std=c++14'], 
        include_dirs=include_dirs, 
        library_dirs=library_dirs, 
        extra_link_args=link_args 
         + ['-Wl,-rpath,$ORIGIN/../clib/lib']) 

# I use cmdclass to override the default setuptool commands 
setup(name='mypack', 
     cmdclass = {'install': install, 
        'build_clib': build_clib, 'build': build, 
        'develop': develop}, 
     packages=['mypack'], 
     ext_package='mypack', 
     ext_modules=[mygen_module], 
     # package_dir={'mypack': '.'}, 
     # package_data={'mypack': ['docs/*md']}, 
     include_package_data=True) 

I sous-classe certaines des commandes de setuptools afin de construire la bibliothèque partagée avant qu'il compile l'extension. clib_install.sh est un script bash qui télécharge et crée localement la bibliothèque partagée dans /clib, créant les en-têtes (dans /clib/include) et le fichier .so (dans /clib/lib). Pour résoudre les problèmes liés à la dépendance aux dépendances de bibliothèques partagées, j'ai utilisé $ORIGIN/../clib/lib comme argument de lien afin que le chemin absolu de clib ne soit pas nécessaire.

Malheureusement, le répertoire /clib n'est pas copié dans l'emplacement d'installation. J'ai essayé de bricoler avec package_data mais il n'a pas copié mon répertoire. En fait, je ne sais même pas ce que fait pip/setuptools avec /clib après l'appel du script, je suppose qu'il est fait dans un répertoire de construction temporaire et qu'il est supprimé après. Je ne suis pas sûr comment obtenir /clib là où il doit être après qu'il est fait.

Répondre

0
package_data={ 
    'mypack': [ 
     'clib/include/*.h', 
     'clib/lib/*.so', 
     'docs/*md', 
    ] 
},