File: control.py

package info (click to toggle)
intel-mkl 2020.4.304-4
  • links: PTS, VCS
  • area: non-free
  • in suites: bookworm
  • size: 566,260 kB
  • sloc: xml: 3,919; sh: 798; python: 253; cpp: 211; ansic: 169; lisp: 145; awk: 117; makefile: 47
file content (345 lines) | stat: -rw-r--r-- 13,028 bytes parent folder | download | duplicates (2)
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()