mirror of
https://github.com/facebook/sapling.git
synced 2024-10-11 09:17:30 +03:00
05c70db64f
Summary: The portability/ subdirectory always needs to be listed in the compiler include paths in order to successfully build. This fixes setup.py to always add it to the list of include directories, rather than only adding it when INCLUDE_DIRS was not specified through the environment. Test Plan: Successfully built the fb-hgext repository when specifying alternate system header paths through the INCLUDE_DIRS environment variable. Reviewers: tja, wez, ikostia Reviewed By: ikostia Subscribers: net-systems-diffs@fb.com, yogeshwer, mjpieters Differential Revision: https://phabricator.intern.facebook.com/D4865296 Signature: t1:4865296:1491903269:fc07edf01a89117e25805e9ee936b2e2eee22410
359 lines
12 KiB
Python
359 lines
12 KiB
Python
from distutils.version import LooseVersion
|
|
from distutils.core import setup, Extension
|
|
import distutils
|
|
from glob import glob
|
|
|
|
import os, sys
|
|
|
|
iswindows = os.name == 'nt'
|
|
WERROR = "/WX" if iswindows else "-Werror"
|
|
WSTRICTPROTOTYPES = None if iswindows else "-Werror=strict-prototypes"
|
|
WALL = "/Wall" if iswindows else "-Wall"
|
|
STDC99 = "" if iswindows else "-std=c99"
|
|
STDCPP0X = "" if iswindows else "-std=c++0x"
|
|
WEXTRA = "" if iswindows else "-Wextra"
|
|
WCONVERSION = "" if iswindows else "-Wconversion"
|
|
PEDANTIC = "" if iswindows else "-pedantic"
|
|
NOOPTIMIZATION = "/Od" if iswindows else "-O0"
|
|
PRODUCEDEBUGSYMBOLS = "/DEBUG:FULL" if iswindows else "-g"
|
|
|
|
# --component allows the caller to specify what components they want. We can't
|
|
# use argparse like normal, because setup() at the bottom has it's own argument
|
|
# logic.
|
|
components = []
|
|
args = []
|
|
skip = False
|
|
for i, arg in enumerate(sys.argv):
|
|
if skip:
|
|
skip = False
|
|
continue
|
|
|
|
if arg == '--component' and len(sys.argv) > i + 1:
|
|
components.extend(sys.argv[i + 1].split(','))
|
|
skip = True
|
|
else:
|
|
args.append(arg)
|
|
|
|
sys.argv = args
|
|
|
|
cflags = []
|
|
|
|
# if this is set, compile all C extensions with -O0 -g for easy debugging. note
|
|
# that this is not manifested in any way in the Makefile dependencies.
|
|
# therefore, if you already have build products, they won't be rebuilt!
|
|
if os.getenv('FB_HGEXT_CDEBUG') is not None:
|
|
cflags.extend([NOOPTIMIZATION, PRODUCEDEBUGSYMBOLS])
|
|
else:
|
|
cflags.append(WERROR)
|
|
|
|
def get_env_path_list(var_name, default=None):
|
|
'''Get a path list from an environment variable. The variable is parsed as
|
|
a colon-separated list.'''
|
|
value = os.environ.get(var_name)
|
|
if not value:
|
|
return default
|
|
return value.split(os.path.pathsep)
|
|
|
|
include_dirs = get_env_path_list('INCLUDE_DIRS')
|
|
library_dirs = get_env_path_list('LIBRARY_DIRS')
|
|
|
|
# Historical default values.
|
|
# We should perhaps clean these up in the future after verifying that it
|
|
# doesn't break the build on any platforms.
|
|
#
|
|
# The /usr/local/* directories shouldn't actually be needed--the compiler
|
|
# should already use these directories when appropriate (e.g., if we are
|
|
# using the standard system compiler that has them in its default paths).
|
|
#
|
|
# The /opt/local paths may be necessary on Darwin builds.
|
|
if include_dirs is None:
|
|
if iswindows:
|
|
include_dirs = []
|
|
else:
|
|
include_dirs = [
|
|
'/usr/local/include',
|
|
'/opt/local/include',
|
|
'/opt/homebrew/include/',
|
|
]
|
|
include_dirs.append('portability')
|
|
|
|
def distutils_dir_name(dname):
|
|
"""Returns the name of a distutils build directory"""
|
|
f = "{dirname}.{platform}-{version}"
|
|
return f.format(dirname=dname,
|
|
platform=distutils.util.get_platform(),
|
|
version=sys.version[:3])
|
|
|
|
if library_dirs is None:
|
|
if iswindows:
|
|
library_dirs = []
|
|
else:
|
|
library_dirs = [
|
|
'/usr/local/lib',
|
|
'/opt/local/lib',
|
|
'/opt/homebrew/lib/',
|
|
]
|
|
library_dirs.append('build/' + distutils_dir_name('lib'))
|
|
|
|
# Override the default c static library building code in distutils since it
|
|
# doesn't pass enough args, like libraries and extra args.
|
|
import distutils.command.build_clib
|
|
from distutils.errors import DistutilsSetupError
|
|
def build_libraries(self, libraries):
|
|
for (lib_name, build_info) in libraries:
|
|
sources = build_info.get('sources')
|
|
if sources is None or not isinstance(sources, (list, tuple)):
|
|
raise DistutilsSetupError(
|
|
"in 'libraries' option (library '%s'), " +
|
|
"'sources' must be present and must be " +
|
|
"a list of source filenames") % lib_name
|
|
sources = list(sources)
|
|
|
|
# First, compile the source code to object files in the library
|
|
# directory. (This should probably change to putting object
|
|
# files in a temporary build directory.)
|
|
macros = build_info.get('macros')
|
|
include_dirs = build_info.get('include_dirs')
|
|
extra_args = build_info.get('extra_args')
|
|
objects = self.compiler.compile(sources,
|
|
output_dir=self.build_temp,
|
|
macros=macros,
|
|
include_dirs=include_dirs,
|
|
debug=self.debug,
|
|
extra_postargs=extra_args)
|
|
|
|
# Now "link" the object files together into a static library.
|
|
# (On Unix at least, this isn't really linking -- it just
|
|
# builds an archive. Whatever.)
|
|
libraries = build_info.get('libraries', [])
|
|
for lib in libraries:
|
|
self.compiler.add_library(lib)
|
|
self.compiler.create_static_lib(objects, lib_name,
|
|
output_dir=self.build_clib,
|
|
debug=self.debug)
|
|
distutils.command.build_clib.build_clib.build_libraries = build_libraries
|
|
|
|
# Static c libaries
|
|
if iswindows:
|
|
libraries = []
|
|
else:
|
|
libraries = [
|
|
("datapack", {
|
|
"sources" : ["cdatapack/cdatapack.c"],
|
|
"include_dirs" : ["clib"] + include_dirs,
|
|
"libraries" : ["lz4", "crypto"],
|
|
"extra_args" : filter(None,
|
|
[STDC99, WALL, WERROR, WSTRICTPROTOTYPES] + cflags),
|
|
}),
|
|
('mpatch', {
|
|
'sources': ['cstore/mpatch.c']
|
|
}),
|
|
]
|
|
|
|
# modules that are single files in hgext3rd
|
|
hgext3rd = [
|
|
p[:-3].replace('/', '.')
|
|
for p in glob('hgext3rd/*.py')
|
|
if p != 'hgext3rd/__init__.py'
|
|
]
|
|
|
|
# packages that are directories in hgext3rd
|
|
hgext3rdpkgs = [
|
|
p[:-12].replace('/', '.')
|
|
for p in glob('hgext3rd/*/__init__.py')
|
|
]
|
|
|
|
availablepymodules = hgext3rd + ['statprof']
|
|
|
|
availablepackages = hgext3rdpkgs + [
|
|
'infinitepush',
|
|
'phabricator',
|
|
'sqldirstate',
|
|
'remotefilelog',
|
|
]
|
|
|
|
if not iswindows:
|
|
availablepackages += [
|
|
'fastannotate',
|
|
'fastmanifest',
|
|
'treemanifest',
|
|
'linelog',
|
|
]
|
|
|
|
def distutils_dir_name(dname):
|
|
"""Returns the name of a distutils build directory"""
|
|
f = "{dirname}.{platform}-{version}"
|
|
return f.format(dirname=dname,
|
|
platform=distutils.util.get_platform(),
|
|
version=sys.version[:3])
|
|
|
|
if iswindows:
|
|
# The modules that successfully compile on Windows
|
|
availableextmodules = {}
|
|
else:
|
|
availableextmodules = {
|
|
'cstore' : [
|
|
Extension('cstore',
|
|
sources=[
|
|
'cstore/datapackstore.cpp',
|
|
'cstore/py-cstore.cpp',
|
|
'cstore/pythonutil.cpp',
|
|
'cstore/uniondatapackstore.cpp',
|
|
'ctreemanifest/manifest.cpp',
|
|
'ctreemanifest/manifest_entry.cpp',
|
|
'ctreemanifest/manifest_fetcher.cpp',
|
|
'ctreemanifest/treemanifest.cpp',
|
|
],
|
|
include_dirs=[
|
|
'cdatapack',
|
|
'clib'
|
|
'cstore',
|
|
'ctreemanifest',
|
|
] + include_dirs,
|
|
library_dirs=[
|
|
'build/' + distutils_dir_name('lib'),
|
|
] + library_dirs,
|
|
libraries=[
|
|
'crypto',
|
|
'datapack',
|
|
'lz4',
|
|
],
|
|
extra_compile_args=filter(None, [STDCPP0X, WALL] + cflags),
|
|
),
|
|
],
|
|
'cfastmanifest' : [
|
|
Extension('cfastmanifest',
|
|
sources=['cfastmanifest.c',
|
|
'cfastmanifest/bsearch.c',
|
|
'clib/buffer.c',
|
|
'cfastmanifest/checksum.c',
|
|
'cfastmanifest/node.c',
|
|
'cfastmanifest/tree.c',
|
|
'cfastmanifest/tree_arena.c',
|
|
'cfastmanifest/tree_convert.c',
|
|
'cfastmanifest/tree_copy.c',
|
|
'cfastmanifest/tree_diff.c',
|
|
'cfastmanifest/tree_disk.c',
|
|
'cfastmanifest/tree_iterator.c',
|
|
'cfastmanifest/tree_path.c',
|
|
],
|
|
include_dirs=[
|
|
'cfastmanifest',
|
|
'clib',
|
|
] + include_dirs,
|
|
library_dirs=library_dirs,
|
|
libraries=['crypto',
|
|
],
|
|
extra_compile_args=filter(None, [
|
|
STDC99,
|
|
WALL,
|
|
WSTRICTPROTOTYPES,
|
|
] + cflags),
|
|
),
|
|
],
|
|
'linelog' : [
|
|
Extension('linelog',
|
|
sources=['linelog/pyext/linelog.pyx'],
|
|
extra_compile_args=filter(None, [
|
|
STDC99, WALL, WEXTRA, WCONVERSION, PEDANTIC,
|
|
]),
|
|
),
|
|
],
|
|
'patchrmdir': [
|
|
Extension('hgext3rd.patchrmdir',
|
|
sources=['hgext3rd/patchrmdir.pyx'],
|
|
extra_compile_args=filter(None, [
|
|
STDC99, WALL, WEXTRA, WCONVERSION, PEDANTIC,
|
|
]),
|
|
),
|
|
],
|
|
}
|
|
|
|
allnames = availablepackages + availableextmodules.keys() + availablepymodules
|
|
COMPONENTS = sorted(name.split('.')[-1] for name in allnames)
|
|
|
|
if not components:
|
|
components = COMPONENTS
|
|
|
|
dependencies = {
|
|
'absorb' : ['linelog'],
|
|
'cstore' : ['ctreemanifest', 'cdatapack'],
|
|
'fastannotate' : ['linelog'],
|
|
'infinitepush' : ['extutil'],
|
|
'remotefilelog' : ['cstore', 'extutil'],
|
|
'treemanifest' : ['cstore'],
|
|
}
|
|
|
|
processdep = True
|
|
while processdep:
|
|
processdep = False
|
|
for name, deps in dependencies.iteritems():
|
|
if name in components:
|
|
for dep in deps:
|
|
if dep not in components:
|
|
components.append(dep)
|
|
processdep = True
|
|
|
|
if iswindows:
|
|
# The modules that successfully compile on Windows
|
|
cythonmodules = []
|
|
else:
|
|
cythonmodules = [
|
|
'linelog',
|
|
'patchrmdir',
|
|
]
|
|
for cythonmodule in cythonmodules:
|
|
if cythonmodule in components:
|
|
import Cython
|
|
if LooseVersion(Cython.__version__) < LooseVersion('0.22'):
|
|
raise RuntimeError('Cython >= 0.22 is required')
|
|
|
|
from Cython.Build import cythonize
|
|
module = availableextmodules[cythonmodule]
|
|
availableextmodules[cythonmodule] = cythonize(module)
|
|
|
|
packages = []
|
|
for package in availablepackages:
|
|
if package.split('.')[-1] in components:
|
|
packages.append(package)
|
|
|
|
ext_modules = []
|
|
for ext_module in availableextmodules:
|
|
if ext_module in components:
|
|
ext_modules.extend(availableextmodules[ext_module])
|
|
|
|
# Dependencies between our native libraries means we need to build in order
|
|
ext_order = {
|
|
'libdatapack' : 0,
|
|
'cstore' : 3,
|
|
}
|
|
ext_modules = sorted(ext_modules, key=lambda k: ext_order.get(k.name, 999))
|
|
|
|
requires = []
|
|
requireslz4 = ['remotefilelog', 'cdatapack']
|
|
if any(c for c in components if c in requireslz4):
|
|
requires.append('lz4')
|
|
|
|
py_modules = []
|
|
for module in availablepymodules:
|
|
if module.split('.')[-1] in components:
|
|
py_modules.append(module)
|
|
|
|
setup(
|
|
name='fbhgext',
|
|
version='1.0',
|
|
author='Facebook Source Control Team',
|
|
maintainer='Facebook Source Control Team',
|
|
maintainer_email='sourcecontrol-dev@fb.com',
|
|
url='https://bitbucket.org/facebook/hg-experimental/',
|
|
description='Facebook mercurial extensions',
|
|
long_description="",
|
|
keywords='facebook fb hg mercurial shallow remote filelog',
|
|
license='GPLv2+',
|
|
packages=packages,
|
|
install_requires=requires,
|
|
py_modules=py_modules,
|
|
ext_modules = ext_modules,
|
|
libraries=libraries,
|
|
)
|