forked from ycm-core/ycmd
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Build script is now Python instead of shell
Letting a shell file become that long has always been a liability. With recent bugs regarding portability across various shells and systems, it's time to replace the shell file with something more maintainable.
Showing
4 changed files
with
177 additions
and
183 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
#!/usr/bin/env python | ||
|
||
import os | ||
import os.path as p | ||
import sys | ||
|
||
major, minor = sys.version_info[ 0 : 2 ] | ||
if major != 2 or minor < 6: | ||
sys.exit( 'The build script requires Python version > 2.6 and < 3.0.' ) | ||
|
||
DIR_OF_THIS_SCRIPT = p.dirname( p.abspath( __file__ ) ) | ||
|
||
for folder in os.listdir( p.join( DIR_OF_THIS_SCRIPT, 'third_party' ) ): | ||
if p.isdir( folder ) and not os.listdir( folder ): | ||
sys.exit( 'Some folders in ./third_party are empty; ' | ||
'you probably forgot to run:' | ||
'\n\tgit submodule update --init --recursive\n\n' ) | ||
|
||
sys.path.insert( 0, p.abspath( 'third_party/sh' ) ) | ||
sys.path.insert( 0, p.abspath( 'third_party/argparse' ) ) | ||
|
||
import sh | ||
import platform | ||
import argparse | ||
import multiprocessing | ||
from distutils.spawn import find_executable | ||
|
||
|
||
def OnMac(): | ||
return platform.system() == 'Darwin' | ||
|
||
|
||
def PathToFirstExistingExecutable( executable_name_list ): | ||
for executable_name in executable_name_list: | ||
path = find_executable( executable_name ) | ||
if path: | ||
return path | ||
return None | ||
|
||
|
||
def NumCores(): | ||
ycm_cores = os.environ.get( 'YCM_CORES' ) | ||
if ycm_cores: | ||
return int( ycm_cores ) | ||
try: | ||
return multiprocessing.cpu_count() | ||
except NotImplementedError: | ||
return 1 | ||
|
||
|
||
def CheckDeps(): | ||
if not PathToFirstExistingExecutable( [ 'cmake' ] ): | ||
sys.exit( 'Please install CMake and retry.') | ||
|
||
|
||
def CustomPythonCmakeArgs(): | ||
# The CMake 'FindPythonLibs' Module does not work properly. | ||
# So we are forced to do its job for it. | ||
|
||
python_prefix = sh.python_config( '--prefix' ).strip() | ||
if p.isfile( p.join( python_prefix, '/Python' ) ): | ||
python_library = p.join( python_prefix, '/Python' ) | ||
python_include = p.join( python_prefix, '/Headers' ) | ||
else: | ||
which_python = sh.python( | ||
'-c', | ||
'import sys;i=sys.version_info;print "python%d.%d" % (i.major, i.minor)' | ||
).strip() | ||
lib_python = '{0}/lib/lib{1}'.format( python_prefix, which_python ).strip() | ||
|
||
if p.isfile( '{0}.a'.format( lib_python ) ): | ||
python_library = '{0}.a'.format( lib_python ) | ||
# This check is for for CYGWIN | ||
elif p.isfile( '{0}.dll.a'.format( lib_python ) ): | ||
python_library = '{0}.dll.a'.format( lib_python ) | ||
else: | ||
python_library = '{0}.dylib'.format( lib_python ) | ||
python_include = '{0}/include/{1}'.format( python_prefix, which_python ) | ||
|
||
return [ | ||
'-DPYTHON_LIBRARY={0}'.format( python_library ), | ||
'-DPYTHON_INCLUDE_DIR={0}'.format( python_include ) | ||
] | ||
|
||
|
||
def ParseArguments(): | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument( '--clang-completer', action = 'store_true', | ||
help = 'Build C-family semantic completion engine.') | ||
parser.add_argument( '--system-libclang', action = 'store_true', | ||
help = 'Use system libclang instead of downloading one ' | ||
'from llvm.org. NOT RECOMMENDED OR SUPPORTED!' ) | ||
parser.add_argument( '--omnisharp-completer', action = 'store_true', | ||
help = 'Build C# semantic completion engine.' ) | ||
parser.add_argument( '--system-boost', action = 'store_true', | ||
help = 'Use the system boost instead of bundled one. ' | ||
'NOT RECOMMENDED OR SUPPORTED!') | ||
args = parser.parse_args() | ||
|
||
if args.system_libclang and not args.clang_completer: | ||
sys.exit( "You can't pass --system-libclang without also passing " | ||
"--clang-completer as well." ) | ||
return args | ||
|
||
|
||
def GetCmakeArgs( parsed_args ): | ||
cmake_args = [] | ||
if parsed_args.clang_completer: | ||
cmake_args.append( '-DUSE_CLANG_COMPLETER=ON' ) | ||
|
||
if parsed_args.system_libclang: | ||
cmake_args.append( '-DUSE_SYSTEM_LIBCLANG=ON' ) | ||
|
||
if parsed_args.system_boost: | ||
cmake_args.append( '-DUSE_SYSTEM_BOOST=ON' ) | ||
|
||
extra_cmake_args = os.environ.get( 'EXTRA_CMAKE_ARGS', '' ) | ||
cmake_args.extend( extra_cmake_args.split() ) | ||
return cmake_args | ||
|
||
|
||
def RunYcmdTests( build_dir ): | ||
tests_dir = p.join( build_dir, 'ycm/tests' ) | ||
sh.cd( tests_dir ) | ||
new_env = os.environ.copy() | ||
new_env[ 'LD_LIBRARY_PATH' ] = DIR_OF_THIS_SCRIPT | ||
sh.Command( p.join( tests_dir, 'ycm_core_tests' ) )( | ||
_env = new_env, _out = sys.stdout ) | ||
|
||
|
||
def BuildYcmdLibs( cmake_args ): | ||
build_dir = unicode( sh.mktemp( '-d', '-t', 'ycm_build.XXXXXX' ) ).strip() | ||
|
||
try: | ||
full_cmake_args = [ '-G', 'Unix Makefiles' ] | ||
if OnMac(): | ||
full_cmake_args.extend( CustomPythonCmakeArgs() ) | ||
full_cmake_args.extend( cmake_args ) | ||
full_cmake_args.append( p.join( DIR_OF_THIS_SCRIPT, 'cpp' ) ) | ||
|
||
sh.cd( build_dir ) | ||
sh.cmake( *full_cmake_args, _out = sys.stdout ) | ||
|
||
build_target = ( 'ycm_support_libs' if 'YCM_TESTRUN' not in os.environ else | ||
'ycm_core_tests' ) | ||
sh.make( '-j', NumCores(), build_target, _out = sys.stdout ) | ||
|
||
if 'YCM_TESTRUN' in os.environ: | ||
RunYcmdTests( build_dir ) | ||
finally: | ||
sh.cd( DIR_OF_THIS_SCRIPT ) | ||
sh.rm( '-rf', build_dir ) | ||
|
||
|
||
def BuildOmniSharp(): | ||
build_comamnd = PathToFirstExistingExecutable( | ||
[ 'msbuild', 'msbuild.exe', 'xbuild' ] ) | ||
if not build_comamnd: | ||
sys.exit( 'msbuild or xbuild is required to build Omnisharp' ) | ||
|
||
sh.cd( p.join( DIR_OF_THIS_SCRIPT, 'third_party/OmniSharpServer' ) ) | ||
sh.Command( build_comamnd )( _out = sys.stdout ) | ||
|
||
|
||
def Main(): | ||
CheckDeps() | ||
args = ParseArguments() | ||
BuildYcmdLibs( GetCmakeArgs( args ) ) | ||
if args.omnisharp_completer: | ||
BuildOmniSharp() | ||
|
||
if __name__ == "__main__": | ||
Main() |