Skip to content

Instantly share code, notes, and snippets.

@gubatron
Created November 24, 2014 19:11
Show Gist options
  • Save gubatron/fee44631a73cb57af275 to your computer and use it in GitHub Desktop.
Save gubatron/fee44631a73cb57af275 to your computer and use it in GitHub Desktop.
libtorrent python binding setup.py to build on MacOSX
#!/usr/bin/env python
from distutils import sysconfig
from distutils.core import setup, Extension
import os
import platform
import sys
import shutil
import multiprocessing
import subprocess
def parse_cmd(cmdline, prefix, keep_prefix = False):
ret = []
for token in cmdline.split():
if token[:len(prefix)] == prefix:
if keep_prefix:
ret.append(token)
else:
ret.append(token[len(prefix):])
return ret
def arch():
if platform.system() != 'Darwin': return []
a = os.uname()[4]
if a == 'Power Macintosh': a = 'ppc'
return ['-arch', a]
def target_specific():
if platform.system() != 'Darwin': return []
# on mavericks, clang will fail when unknown arguments are
# passed in. python distutils will pass in arguments it doesn't
# know about
return ['-Wno-error=unused-command-line-argument-hard-error-in-future']
def get_boost_root_path():
if 'BOOST_ROOT' in os.environ:
return os.environ['BOOST_ROOT']
raise 'Error: Please set your BOOST_ROOT environment variable.'
def get_boost_lib_path():
if 'BOOST_LIB_PATH' in os.environ:
return os.environ['BOOST_LIB_PATH']
return os.path.join(get_boost_root_path(), 'stage', 'lib')
def copy_libtorrent_shared_library_here():
'''on mac, the libtorrent.dylib is called libtorrent.dylib.x.y.z, we bring it to this folder
and rename it to libtorrent.dylib, and we'll add this scripts folder as part of the link path'''
libtorrent_source_path = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)),'..','..'))
p = os.popen('find %s | grep dylib' % (libtorrent_source_path))
dylib_list = p.readlines()
p.close()
if len(dylib_list) == 1:
print dylib_list[0].strip()
shutil.copyfile(dylib_list[0].strip(),'libtorrent.dylib')
def get_libtorrent_shared_library_path():
libtorrent_source_path = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)),'..','..'))
p = os.popen('find %s | grep dylib' % (libtorrent_source_path))
dylib_list = p.readlines()
p.close()
if len(dylib_list) == 1:
return os.path.dirname(dylib_list[0]).strip()
if len(dylib_list) == 0:
raise "Could not find libtorrent's libtorrent.dylib file. Please build libtorrent shared library first."
def get_boost_library_names_available():
'''returns a list of all the boost .dylib filenames stripped off their "lib" prefix and ".dylib" extension'''
boost_lib_folder = os.path.join(get_boost_root_path(),'stage','lib')
boost_lib_files = os.listdir(boost_lib_folder)
boost_library_names = [libname[3:-6] for libname in boost_lib_files if libname.endswith('dylib')]
return boost_library_names
def get_DMACRO_compile_parameters():
# -D<macro> parameters
D_FLAGS = ['TORRENT_USE_OPENSSL',
'WITH_SHIPPED_GEOIP_H',
'BOOST_ASIO_HASH_MAP_BUCKETS=1021',
'BOOST_EXCEPTION_DISABLE',
'BOOST_ASIO_ENABLE_CANCELIO',
'BOOST_ASIO_DYN_LINK',
'TORRENT_LINKING_SHARED']
D_FLAGS_PARAMETERS = '-D' + ' -D'.join(D_FLAGS)
return D_FLAGS_PARAMETERS
def get_library_name_parameters():
# -l<library_name> parameters
all_boost_dylibs = get_boost_library_names_available()
# we only care about boost_system and boost_python, but we don't know if they were
# built with the '-mt' suffix or not
boost_needed_libraries = [libname for libname in all_boost_dylibs
if libname.startswith('boost_system') or
libname.startswith('boost_python')]
LIBRARIES = ['ssl','crypto'] + boost_needed_libraries
LIBRARIES_FLAGS_PARAMETERS = '-l' + ' -l'.join(LIBRARIES)
return LIBRARIES_FLAGS_PARAMETERS
def get_include_path_parameters():
# -I<include_path> parameters
I_PATHS = ['/usr/local/include',
os.path.join(get_boost_root_path(),'boost'),
'../../include']
I_PATHS_PARAMETERS = '-I' + ' -I'.join(I_PATHS)
return I_PATHS_PARAMETERS
def get_link_path_parameters():
# -L<link_path> parameters
LINK_PATHS = ['/usr/local/lib',
get_boost_lib_path(),
'./']
#get_libtorrent_shared_library_path()]
LINK_PATHS_PARAMETERS = '-L' + ' -L'.join(LINK_PATHS)
return LINK_PATHS_PARAMETERS
def get_mac_extra_cmd():
compile_flags = [get_DMACRO_compile_parameters(),
get_include_path_parameters(),
get_mac_ld_flags(),
get_library_name_parameters()]
return ' ' + ' '.join(compile_flags)
def get_mac_ld_flags():
return ' ' + get_link_path_parameters()
try:
if platform.system() != 'Darwin':
with open('compile_flags') as _file:
extra_cmd = _file.read()
else:
extra_cmd = get_mac_extra_cmd()
except Exception, e:
print e
extra_cmd = None
try:
if platform.system() != 'Darwin':
with open('link_flags') as _file:
ldflags = _file.read()
else:
# we copy the shared library from the libtorrent
# build folder into here as libtorrent.dylib
# and will add the current folder as one of the
# build paths.
copy_libtorrent_shared_library_here()
ldflags = get_mac_ld_flags()
except:
ldflags = None
ext = None
packages = None
if '--bjam' in sys.argv or ldflags == None or extra_cmd == None:
if '--bjam' in sys.argv:
del sys.argv[sys.argv.index('--bjam')]
if not '--help' in sys.argv \
and not '--help-commands' in sys.argv:
toolset = ''
file_ext = '.so'
if platform.system() == 'Windows':
# msvc 9.0 (2008) is the official windows compiler for python 2.6
# http://docs.python.org/whatsnew/2.6.html#build-and-c-api-changes
toolset = ' msvc-9.0'
file_ext = '.pyd'
parallell_builds = ' -j%d' % multiprocessing.cpu_count()
# build libtorrent using bjam and build the installer with distutils
cmdline = 'bjam boost=source link=static geoip=static boost-link=static release optimization=space stage_module --abbreviate-paths' + toolset + parallell_builds
print(cmdline)
if os.system(cmdline) != 0:
print('build failed')
sys.exit(1)
try: os.mkdir('build')
except: pass
try: shutil.rmtree('build/lib')
except: pass
try: os.mkdir('build/lib')
except: pass
try: os.mkdir('libtorrent')
except: pass
shutil.copyfile('libtorrent' + file_ext, 'build/lib/libtorrent' + file_ext)
packages = ['libtorrent']
else:
source_list = os.listdir(os.path.join(os.path.dirname(__file__), "src"))
source_list = [os.path.join("src", s) for s in source_list if s.endswith(".cpp")]
ext = [Extension('libtorrent',
sources = source_list,
language='c++',
include_dirs = parse_cmd(extra_cmd, '-I'),
library_dirs = parse_cmd(extra_cmd, '-L'),
extra_link_args = ldflags.split() + arch(),
extra_compile_args = parse_cmd(extra_cmd, '-D', True) + arch() \
+ target_specific(),
libraries = ['torrent'] + parse_cmd(extra_cmd, '-l'))]
setup(name = 'python-libtorrent',
version = '1.0.2',
author = 'Arvid Norberg',
author_email = 'arvid@rasterbar.com',
description = 'Python bindings for libtorrent-rasterbar',
long_description = 'Python bindings for libtorrent-rasterbar',
url = 'http://libtorrent.org',
platforms = [platform.system() + '-' + platform.machine()],
license = 'BSD',
packages = packages,
ext_modules = ext
)
@gubatron
Copy link
Author

As of November 2014, the /bindings/python/setup.py on the libtorrent codebase is broken for MacOSX, I've updated the script to dinamically find the include paths, link paths and libraries required to build the python bindings on MacOSX.

Just replace the bindings/python/setup.py with this version and issue python setup.py bdist and you should be good to go. (This script assumes you have built boost from sources and that you've set up your BOOST_ROOTenvironment variable. Setting up the BOOST_LIB_PATH helps too but it's not necessary for the script to build the bindings)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment