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
|
# Copyright (C) 2006 CSC-Scientific Computing Ltd.
# Please see the accompanying LICENSE file for further information.
import os
import sys
import re
import shlex
from sysconfig import get_platform
from subprocess import run
from pathlib import Path
from stat import ST_MTIME
def mtime(path, name, mtimes):
"""Return modification time.
The modification time of a source file is returned. If one of its
dependencies is newer, the mtime of that file is returned.
This function fails if two include files with the same name
are present in different directories."""
include = re.compile(r'^#\s*include "(\S+)"', re.MULTILINE)
if name in mtimes:
return mtimes[name]
t = os.stat(os.path.join(path, name))[ST_MTIME]
for name2 in include.findall(open(os.path.join(path, name)).read()):
path2, name22 = os.path.split(name2)
if name22 != name:
t = max(t, mtime(os.path.join(path, path2), name22, mtimes))
mtimes[name] = t
return t
def check_dependencies(sources):
# Distutils does not do deep dependencies correctly. We take care of
# that here so that "python setup.py build_ext" always does the right
# thing!
mtimes = {} # modification times
# Remove object files if any dependencies have changed:
plat = get_platform() + '-{maj}.{min}'.format(maj=sys.version_info[0],
min=sys.version_info[1])
remove = False
for source in sources:
path, name = os.path.split(source)
t = mtime(path + '/', name, mtimes)
o = 'build/temp.%s/%s.o' % (plat, source[:-2]) # object file
if os.path.exists(o) and t > os.stat(o)[ST_MTIME]:
print('removing', o)
os.remove(o)
remove = True
so = 'build/lib.{}/_gpaw.so'.format(plat)
if os.path.exists(so) and remove:
# Remove shared object C-extension:
# print 'removing', so
os.remove(so)
def write_configuration(define_macros, include_dirs, libraries, library_dirs,
extra_link_args, extra_compile_args,
runtime_library_dirs, extra_objects, compiler):
# Write the compilation configuration into a file
try:
out = open('configuration.log', 'w')
except IOError as x:
print(x)
return
print("Current configuration", file=out)
print("compiler", compiler, file=out)
print("libraries", libraries, file=out)
print("library_dirs", library_dirs, file=out)
print("include_dirs", include_dirs, file=out)
print("define_macros", define_macros, file=out)
print("extra_link_args", extra_link_args, file=out)
print("extra_compile_args", extra_compile_args, file=out)
print("runtime_library_dirs", runtime_library_dirs, file=out)
print("extra_objects", extra_objects, file=out)
out.close()
def build_interpreter(
compiler, extension, extension_objects, *,
link_extra_preargs, link_extra_postargs,
build_temp, build_bin, debug):
exename = compiler.executable_filename('gpaw-python')
print(f'building {repr(exename)} executable', flush=True)
macros = extension.define_macros.copy()
for undef in extension.undef_macros:
macros.append((undef,))
# Compile the sources that define GPAW_INTERPRETER
sources = ['c/main.c']
objects = compiler.compile(
sources,
output_dir=str(build_temp),
macros=macros,
include_dirs=extension.include_dirs,
debug=debug,
extra_postargs=extension.extra_compile_args)
objects += extension_objects
# Link the custom interpreter
compiler.link_executable(
objects, exename,
output_dir=str(build_bin),
extra_preargs=link_extra_preargs,
libraries=extension.libraries,
library_dirs=extension.library_dirs,
runtime_library_dirs=extension.runtime_library_dirs,
extra_postargs=link_extra_postargs + extension.extra_link_args,
debug=debug,
target_lang=extension.language)
return build_bin / exename
def build_gpu(gpu_compiler, gpu_compile_args, gpu_include_dirs,
define_macros, undef_macros, build_temp):
print('building gpu kernels', flush=True)
kernels_dpath = Path('c/gpu/kernels')
# Create temp build directory
build_temp_kernels_dpath = build_temp / kernels_dpath
if not build_temp_kernels_dpath.exists():
print(f'creating {build_temp_kernels_dpath}', flush=True)
build_temp_kernels_dpath.mkdir(parents=True)
# Glob all kernel files, but remove those included by other kernels
kernels = sorted(kernels_dpath.glob('*.cpp'))
for name in ['interpolate-stencil.cpp',
'lfc-reduce.cpp',
'lfc-reduce-kernel.cpp',
'reduce.cpp',
'reduce-kernel.cpp',
'restrict-stencil.cpp']:
kernels.remove(kernels_dpath / name)
# Compile GPU kernels
objects = []
for src in kernels:
obj = build_temp / src.with_suffix('.o')
objects.append(str(obj))
run_args = [gpu_compiler]
run_args += gpu_compile_args
for (name, value) in define_macros:
arg = f'-D{name}'
if value is not None:
arg += f'={value}'
run_args += [arg]
run_args += [f'-U{name}' for name in undef_macros]
run_args += [f'-I{dpath}' for dpath in gpu_include_dirs]
run_args += ['-c', str(src)]
run_args += ['-o', str(obj)]
print(shlex.join(run_args), flush=True)
p = run(run_args, check=False, shell=False)
if p.returncode != 0:
print(f'error: command {repr(gpu_compiler)} failed '
f'with exit code {p.returncode}',
file=sys.stderr, flush=True)
sys.exit(1)
return objects
|