1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
|
#!/usr/bin/python3
# Helper Script for INTEL-MKL Packaging
# Copyright (C) 2018 Mo Zhou <cdluminate@gmail.com>
# MIT License
import os, re, sys, subprocess, glob, copy
from typing import *
def dhVerbose() -> bool:
'''
Literally get the value of DH_VERBOSE
'''
return os.getenv('DH_VERBOSE') or True
def getDpkgArchitecture(query: str) -> str:
'''
dpkg-architecture -qQUERY
'''
result = subprocess.Popen(['dpkg-architecture', f'-q{query}'],
stdout=subprocess.PIPE).communicate()[0].decode().strip()
return result
def parsePackages() -> List[str]:
'''
Parse debian/control and return a list of Package names
'''
with open('debian/control', 'r') as f:
control = f.read()
packages = re.findall('Package:\s*(.*)', control)
return packages
def eGrep(ls: List[str], regex: str) -> List[str]:
'''
Just like grep -e.
'''
regex, match, unmatch = re.compile(regex), [], []
for l in ls:
if regex.match(l):
match.append(l)
else:
unmatch.append(l)
return match, unmatch
def installFile(fpath: str, package: str, dest: str = '') -> None:
'''
Write an entry in specified package's install file, for installing
the file to dest.
'''
if package not in parsePackages():
raise Exception(f'Package [{package}] is not found in debian/control!' +
f' cannot install {fpath}')
print(f'Installing {fpath} ➜ {package}')
with open(os.path.join('debian', f'{package}.install'), 'a') as f:
f.write(f'{fpath}\t{dest}\n' if dest else f'{fpath}')
def installSharedObjects(filelist: List[str],
*, verbose: bool = dhVerbose()) -> List[str]:
'''
Glob all the shared object from the file list, and write install entries
for them. The filtered list that does not contain .so file will be returned.
When verbose is toggled, it prints .so files ignored.
'''
print('# Shared Objects')
# lookup arch info
deb_host_arch = getDpkgArchitecture('DEB_HOST_ARCH')
deb_host_multiarch = getDpkgArchitecture('DEB_HOST_MULTIARCH')
# Glob libs
solibs, rest = eGrep(filelist, '.*\.so(\.?\d*)$')
libs = copy.copy(solibs)
# filter the lib list by architecture
if deb_host_arch == 'amd64':
_, libs = eGrep(libs, '.*ia32.*')
else:
_, libs = eGrep(libs, '.*intel64.*')
# report dropped files
for lib in solibs:
if lib not in libs and verbose:
print('Ignored', lib)
# now let's install them !
for so in libs:
path, fname = os.path.dirname(so), os.path.basename(so)
package = re.sub('\.so$', '', fname).replace('_', '-')
installFile(os.path.join(path, fname), package,
f'usr/lib/{deb_host_multiarch}/')
return rest
def installStaticLibs(filelist: List[str],
*, verbose: bool = dhVerbose()) -> List[str]:
'''
Glob all the static libraries from filelist, and add them into corresponding
.install files. A list contains no .a file will be returned.
When verbose is toggled, it prints ignored static libs.
'''
print('# Static Libraries')
# lookup arch info
deb_host_arch = getDpkgArchitecture('DEB_HOST_ARCH')
deb_host_multiarch = getDpkgArchitecture('DEB_HOST_MULTIARCH')
# Glob libs
alibs, rest = eGrep(filelist, '.*/linux/mkl/lib/.*\.a$')
libs = copy.copy(alibs)
# filter the lib list by architecture
if deb_host_arch == 'amd64':
libs = [x for x in libs if 'ia32' not in x]
else:
libs = [x for x in libs if 'intel64' not in x]
# report static libs being dropped
for lib in alibs:
if lib not in libs and verbose:
print('Ignored', lib)
# now let's install them !
for so in libs:
path, fname = os.path.dirname(so), os.path.basename(so)
if any(x in fname for x in ('thread', 'sequential')):
package = 'libmkl-threading-dev'
elif any(x in fname for x in ('blacs', 'scalapack', 'cdft')):
package = 'libmkl-cluster-dev'
elif any(x in fname for x in ('intel_', 'gf_', 'intel.a', 'blas95',
'lapack95', 'gf.a')):
package = 'libmkl-interface-dev'
elif any(x in fname for x in ('core', 'lapack', 'blas')):
package = 'libmkl-computational-dev'
else:
package = 'no-such-package'
installFile(os.path.join(path, fname), package,
f'usr/lib/{deb_host_multiarch}/')
return rest
def installIncludes(filelist: List[str],
*, verbose: bool = dhVerbose()) -> List[str]:
'''
Install docs and return the filtered list.
Print ignored files when verbose is set.
'''
print('# Headers')
_, rest = eGrep(filelist, '.*/linux/mkl/include/.*')
incs = 'opt/intel/compilers_and_libraries_*/linux/mkl/include/*'
installFile(incs, 'libmkl-dev', 'usr/include/mkl/')
return rest
def installTools(filelist: List[str],
*, verbose: bool = dhVerbose()) -> List[str]:
'''
Install tools. Argument is similary to previous functions.
'''
print('# Tools')
_, rest = eGrep(filelist, '.*/linux/mkl/tools/.*')
installFile(
'opt/intel/compilers_and_libraries_*/linux/mkl/bin/mkl_link_tool',
'intel-mkl-linktool', 'usr/bin/')
installFile(
'opt/intel/compilers_and_libraries_*/linux/mkl/tools/builder',
'libmkl-full-dev', 'usr/share/intel-mkl/')
return rest
def installDocs(filelist: List[str],
*, verbose: bool = dhVerbose()) -> List[str]:
'''
similar to previous functions.
'''
print('# Documentation')
_, rest = eGrep(filelist, '^opt/intel/documentation.*')
_, rest = eGrep(rest, '^opt/intel/samples.*')
installFile('opt/intel/documentation_*',
'intel-mkl-doc', 'usr/share/doc/intel-mkl/')
#installFile('opt/intel/samples_*',
# 'intel-mkl-doc', 'usr/share/doc/intel-mkl/')
return rest
def installCatalog(filelist: List[str],
*, verbose: bool = False) -> List[str]:
'''
similar to previous functions
'''
print('# Message Catalog')
deb_host_arch = getDpkgArchitecture('DEB_HOST_ARCH')
_, rest = eGrep(filelist, '.*\.cat$')
# find opt -type f -name '*.cat' -exec md5sum '{}' \;
# amd64 and i386 message catalog files are the same.
if 'amd64' == deb_host_arch:
installFile('opt/intel/compilers_and_libraries_*/linux/mkl/lib/intel64_lin/locale/en_US/mkl_msg.cat',
'libmkl-locale', 'usr/share/locale/en_US/')
else: # i386
installFile('opt/intel/compilers_and_libraries_*/linux/mkl/lib/ia32_lin/locale/en_US/mkl_msg.cat',
'libmkl-locale', 'usr/share/locale/en_US/')
return rest
def installExamples(filelist: List[str]) -> List[str]:
'''
similar to previous
'''
print('# Examples')
exs, rest = eGrep(filelist, '.*/linux/mkl/examples/.*')
for ex in exs:
installFile(ex, 'intel-mkl-doc', 'usr/share/intel-mkl/')
return rest
def installBenchmarks(filelist: List[str]) -> List[str]:
'''
similar to previous
'''
print('# Benchmarks')
_, rest = eGrep(filelist, '.*/linux/mkl/benchmarks/.*')
# hpcg is ignored.
# - because I didn't find the way to build them without Intel C++ compiler.
# linpack and ml_linpack are ignored. we have suggested hpcc package.
# - linpack directory contains a pile of binaries. they works.
# - mp_linpack same as above
return rest
def installDebianSpecific(deb_host_arch: str, deb_host_multiarch: str) -> None:
'''
install debian specific files that come from debian/
'''
print('# Debian Specific')
dest = f'/usr/lib/{deb_host_multiarch}/pkgconfig/'
installFile('debian/pkgconfig/*.pc', 'libmkl-dev', dest)
def _override(package: str, overrides: List[str]) -> None:
'''
Write a lintian override file for specified package
'''
overrides = [f'# Automatically overridden by debian/control.py'] + overrides
print(f'lintian overrides for {package} ...')
with open(f'debian/{package}.lintian-overrides', 'a') as f:
f.writelines(x + '\n' for x in overrides)
def overrideLintian() -> None:
'''
Write lintian-overrides files
'''
packages = parsePackages()
# shared lib packages
for p in [p for p in packages if 'libmkl-' in p
and 'meta' not in p and '-dev' not in p]:
overrides = ['hardening-no-bindnow', # upstream issue
'hardening-no-fortify-functions', # upstream issue
'library-not-linked-against-libc', # upstream issue
'shared-library-lacks-prerequisites', # upstream issue
'sharedobject-in-library-directory-missing-soname', # upstream issue
'shared-library-lacks-version', # upstream issue
'spelling-error-in-binary', # upstream issue
'specific-address-in-shared-library', # upstream issue
'unstripped-binary-or-object', # stripping not allowed
'exit-in-shared-library', # upstream issue
'lacks-ldconfig-trigger', # follows from sharedobject-in-library-directory-missing-soname
'[i386]: binary-file-built-without-LFS-support', # upstream issue
'no-symbols-control-file', # libraries without proper soname
]
_override(p, overrides)
# static lib packages
for p in [p for p in packages if 'libmkl-' in p
and 'meta' not in p and '-dev' in p]:
overrides = ['static-library-has-unneeded-sections', # upstream issue
'unstripped-static-library', # upstream issue
]
_override(p, overrides)
# overrides for libmkl-locale:any
p = 'libmkl-locale'
overrides = [ # we have to make it arch-dependent, because it's used
# by a number of Arch:any packages. Making it Arch:all
# triggers lintian Errors.
'package-contains-no-arch-dependent-files',
]
_override(p, overrides)
# overrides for intel-mkl-linktool:i386
p = 'intel-mkl-linktool'
overrides = ['no-manual-page', # upstream issue
'unstripped-binary-or-object', # upstream issue
'[i386]: binary-file-built-without-LFS-support', # upstream issue
]
_override(p, overrides)
if __name__ == '__main__':
# The two variables can be overriden in d/rules or by environment
# variables, for debugging i386 build under amd64 without any
# cross build tooling.
host_arch = getDpkgArchitecture('DEB_HOST_ARCH')
host_multiarch = getDpkgArchitecture('DEB_HOST_MULTIARCH')
allfiles = sorted(glob.glob('opt/**', recursive=True))
num_allfiles = len(allfiles)
# Remove directories from file list, and don't follow symlink
allfiles = [x for x in allfiles if not os.path.isdir(x)]
for dirname in set(map(os.path.dirname, allfiles)):
if os.path.islink(dirname):
print(dirname, 'is a symlink, we do not follow it')
_, allfiles = eGrep(allfiles, f'{dirname}/.*')
# [ Filter files that we never wanted ]
# -- upstream installer stuff. we don't need
_, allfiles = eGrep(allfiles, '^opt/intel/parallel_studio_xe.*')
# -- there is already libtbb-dev package.
_, allfiles = eGrep(allfiles, '.*/libtbb.*')
# -- libiomp5 is already prodided by other package.
_, allfiles = eGrep(allfiles, '.*/libiomp.*')
# -- these wrapper (interfaces/*) files relys on MKLROOT. We already broke
# upstream directory structure, rendering the these files hard to use.
_, allfiles = eGrep(allfiles, '.*/linux/mkl/interfaces/.*')
# install specific files and filter the list
allfiles = installSharedObjects(allfiles)
allfiles = installStaticLibs(allfiles)
allfiles = installIncludes(allfiles)
allfiles = installTools(allfiles)
allfiles = installDocs(allfiles)
allfiles = installCatalog(allfiles)
allfiles = installExamples(allfiles)
allfiles = installBenchmarks(allfiles)
installDebianSpecific(host_arch, host_multiarch)
# just like what dh-missing --list-missing does.
num_remaining = len(allfiles)
print('{num_remaining} / {num_allfiles} Files left uninstalled.'.format(**locals()))
if dhVerbose():
for f in allfiles: print('missing', '<><><>', f)
# notes about missing files:
# - /licensing/* not installed. They are in copyright.
# - the shell scripts for compiler variables are ignored. They are
# somewhat useless if we don't retain upstream directory structure.
# do the lintian overriding
overrideLintian()
|