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.