1#!/usr/bin/env python 2# 3# Copyright (c) 2017-2020 Intel Corporation 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17# Provides unified tool for preparing TBB for packaging 18 19from __future__ import print_function 20import os 21import re 22import sys 23import shutil 24import platform 25import argparse 26from glob import glob 27from collections import OrderedDict 28 29jp = os.path.join 30is_win = (platform.system() == 'Windows') 31is_lin = (platform.system() == 'Linux') 32is_mac = (platform.system() == 'Darwin') 33 34default_prefix = os.getenv('PREFIX', 'install_prefix') 35if is_win: 36 default_prefix = jp(default_prefix, 'Library') # conda-specific by default on Windows 37 38parser = argparse.ArgumentParser() 39parser.add_argument('--tbbroot', default='.', help='Take Intel TBB from here') 40parser.add_argument('--prefix', default=default_prefix, help='Prefix') 41parser.add_argument('--prebuilt', default=[], action='append', help='Directories to find prebuilt files') 42parser.add_argument('--no-rebuild', default=False, action='store_true', help='do not rebuild') 43parser.add_argument('--install', default=False, action='store_true', help='install all') 44parser.add_argument('--install-libs', default=False, action='store_true', help='install libs') 45parser.add_argument('--install-devel', default=False, action='store_true', help='install devel') 46parser.add_argument('--install-docs', default=False, action='store_true', help='install docs') 47parser.add_argument('--install-python', default=False, action='store_true', help='install python module') 48parser.add_argument('--make-tool', default='make', help='Use different make command instead') 49parser.add_argument('--copy-tool', default=None, help='Use this command for copying ($ tool file dest-dir)') 50parser.add_argument('--build-args', default="", help='specify extra build args') 51parser.add_argument('--build-prefix', default='local', help='build dir prefix') 52parser.add_argument('--cmake-dir', help='directory to install CMake configuration files. Default: <prefix>/lib/cmake/tbb') 53if is_win: 54 parser.add_argument('--msbuild', default=False, action='store_true', help='Use msbuild') 55 parser.add_argument('--vs', default="2012", help='select VS version for build') 56 parser.add_argument('--vs-platform', default="x64", help='select VS platform for build') 57parser.add_argument('ignore', nargs='?', help="workaround conda-build issue #2512") 58 59args = parser.parse_args() 60 61if args.install: 62 args.install_libs = True 63 args.install_devel = True 64 args.install_docs = True 65 args.install_python= True 66 67def custom_cp(src, dst): 68 assert os.system(' '.join([args.copy_tool, src, dst])) == 0 69 70if args.copy_tool: 71 install_cp = custom_cp # e.g. to use install -p -D -m 755 on Linux 72else: 73 install_cp = shutil.copy 74 75bin_dir = jp(args.prefix, "bin") 76lib_dir = jp(args.prefix, "lib") 77inc_dir = jp(args.prefix, 'include') 78doc_dir = jp(args.prefix, 'share', 'doc', 'tbb') 79cmake_dir = jp(args.prefix, "lib", "cmake", "tbb") if args.cmake_dir is None else args.cmake_dir 80 81if is_win: 82 os.environ["OS"] = "Windows_NT" # make sure TBB will interpret it correctly 83 libext = '.dll' 84 libpref = '' 85 dll_dir = bin_dir 86else: 87 libext = '.dylib' if is_mac else '.so.2' 88 libpref = 'lib' 89 dll_dir = lib_dir 90 91tbb_names = ["tbb", "tbbmalloc", "tbbmalloc_proxy"] 92 93############################################################## 94 95def system(arg): 96 print('$ ', arg) 97 return os.system(arg) 98 99def run_make(arg): 100 if system('%s -j %s'% (args.make_tool, arg)) != 0: 101 print("\nBummer. Running serial build in order to recover the log and have a chance to fix the build") 102 assert system('%s %s'% (args.make_tool, arg)) == 0 103 104os.chdir(args.tbbroot) 105if args.prebuilt: 106 release_dirs = sum([glob(d) for d in args.prebuilt], []) 107 print("Using pre-built files from ", release_dirs) 108else: 109 if is_win and args.msbuild: 110 preview_release_dir = release_dir = jp(args.tbbroot, 'build', 'vs'+args.vs, args.vs_platform, 'Release') 111 if not args.no_rebuild or not os.path.isdir(release_dir): 112 assert os.system('msbuild /m /p:Platform=%s /p:Configuration=Release %s build/vs%s/makefile.sln'% \ 113 (args.vs_platform, args.build_args, args.vs)) == 0 114 preview_debug_dir = debug_dir = jp(args.tbbroot, 'build', 'vs'+args.vs, args.vs_platform, 'Debug') 115 if not args.no_rebuild or not os.path.isdir(debug_dir): 116 assert os.system('msbuild /m /p:Platform=%s /p:Configuration=Debug %s build/vs%s/makefile.sln'% \ 117 (args.vs_platform, args.build_args, args.vs)) == 0 118 else: 119 release_dir = jp(args.tbbroot, 'build', args.build_prefix+'_release') 120 debug_dir = jp(args.tbbroot, 'build', args.build_prefix+'_debug') 121 if not args.no_rebuild or not (os.path.isdir(release_dir) and os.path.isdir(debug_dir)): 122 run_make('tbb_build_prefix=%s %s'% (args.build_prefix, args.build_args)) 123 preview_release_dir = jp(args.tbbroot, 'build', args.build_prefix+'_preview_release') 124 preview_debug_dir = jp(args.tbbroot, 'build', args.build_prefix+'_preview_debug') 125 if not args.no_rebuild or not (os.path.isdir(preview_release_dir) and os.path.isdir(preview_debug_dir)): 126 run_make('tbb_build_prefix=%s_preview %s tbb_cpf=1 tbb'% (args.build_prefix, args.build_args)) 127 release_dirs = [release_dir, debug_dir, preview_release_dir, preview_debug_dir] 128 129filemap = OrderedDict() 130def append_files(names, dst, paths=release_dirs): 131 global filemap 132 files = sum([glob(jp(d, f)) for d in paths for f in names], []) 133 filemap.update(dict(zip(files, [dst]*len(files)))) 134 135 136if args.install_libs: 137 append_files([libpref+f+libext for f in tbb_names], dll_dir) 138 139if args.install_devel: 140 dll_files = [libpref+f+'_debug'+libext for f in tbb_names] # adding debug libraries 141 if not is_win or not args.msbuild: 142 dll_files += [libpref+"tbb_preview"+libext, libpref+"tbb_preview_debug"+libext] 143 if is_win: 144 dll_files += ['tbb*.pdb'] # copying debug info 145 if is_lin: 146 dll_files += ['libtbb*.so'] # copying linker scripts 147 # symlinks .so -> .so.2 should not be created instead 148 # since linking with -ltbb when using links can result in 149 # incorrect dependence upon unversioned .so files 150 append_files(dll_files, dll_dir) 151 if is_win: 152 append_files(['*.lib', '*.def'], lib_dir) # copying linker libs and defs 153 for rootdir, dirnames, filenames in os.walk(jp(args.tbbroot,'include')): 154 files = [f for f in filenames if not '.html' in f] 155 append_files(files, jp(inc_dir, rootdir.split('include')[1][1:]), paths=(rootdir,)) 156 157 # Preparing CMake configuration files 158 cmake_build_dir = jp(args.tbbroot, 'build', args.build_prefix+'_release', 'cmake_configs') 159 assert system('cmake -DINSTALL_DIR=%s -DSYSTEM_NAME=%s -DTBB_VERSION_FILE=%s -DINC_REL_PATH=%s -DLIB_REL_PATH=%s -DBIN_REL_PATH=%s -P %s' % \ 160 (cmake_build_dir, 161 platform.system(), 162 jp(args.tbbroot, 'include', 'tbb', 'tbb_stddef.h'), 163 os.path.relpath(inc_dir, cmake_dir), 164 os.path.relpath(lib_dir, cmake_dir), 165 os.path.relpath(bin_dir, cmake_dir), 166 jp(args.tbbroot, 'cmake', 'tbb_config_installer.cmake'))) == 0 167 append_files(['TBBConfig.cmake', 'TBBConfigVersion.cmake'], cmake_dir, paths=[cmake_build_dir]) 168 169if args.install_python: # RML part 170 irml_dir = jp(args.tbbroot, 'build', args.build_prefix+'_release') 171 run_make('-C src tbb_build_prefix=%s %s python_rml'% (args.build_prefix, args.build_args)) 172 if is_lin: 173 append_files(['libirml.so.1'], dll_dir, paths=[irml_dir]) 174 175if args.install_docs: 176 files = [ 177 'CHANGES', 178 'LICENSE', 179 'README', 180 'README.md', 181 'Release_Notes.txt', 182 ] 183 append_files(files, doc_dir, paths=release_dirs+[jp(args.tbbroot, d) for d in ('.', 'doc')]) 184 185for f in filemap.keys(): 186 assert os.path.exists(f) 187 assert os.path.isfile(f) 188 189if filemap: 190 print("Copying to prefix =", args.prefix) 191for f, dest in filemap.items(): 192 if not os.path.isdir(dest): 193 os.makedirs(dest) 194 print("+ %s to $prefix%s"%(f,dest.replace(args.prefix, ''))) 195 install_cp(f, dest) 196 197if args.install_python: # Python part 198 paths = [os.path.abspath(d) for d in [args.prefix, inc_dir, irml_dir, lib_dir]+release_dirs] 199 os.environ["TBBROOT"] = paths[0] 200 # all the paths must be relative to python/ directory or be absolute 201 assert system('python python/setup.py build -b%s build_ext -I%s -L%s install -f'% \ 202 (paths[2], paths[1], ':'.join(paths[2:]))) == 0 203 204print("done") 205