-rwxr-xr-x 24573 lib25519-20220426/configure raw
#!/usr/bin/env python3
import os
import shutil
import sys
import platform
import subprocess
import tempfile
import re
prefix = '/usr/local'
clean = True
host = platform.machine()
host = ''.join(c for c in host if c in '_0123456789abcdefghijklmnopqrstuvwxyz')
def dirlinksym(dir,source,target):
  with tempfile.TemporaryDirectory(dir=dir) as t:
    os.symlink(target,'%s/symlink' % t)
    os.rename('%s/symlink' % t,'%s/%s' % (dir,source))
makefile = ''
librandombytes = 'randombytes_kernel'
libcpucycles = 'cpucycles'
linktype = 'so'
for arg in sys.argv[1:]:
  if arg.startswith('--prefix='):
    prefix = arg[9:]
    continue
  if arg.startswith('--host='):
    host = arg[8:]
    host = host.split('-')[0]
    continue
  if arg == '--clean':
    clean = True
    continue
  if arg == '--noclean':
    clean = False
    continue
  if arg == '--staticbinaries':
    linktype = 'a' # binaries usable by themselves
    continue
  if arg == '--nostaticbinaries':
    linktype = 'so' # save disk space
    continue
  raise ValueError('unrecognized argument %s' % arg)
if host == 'x86_64': host = 'amd64'
if host == 'i686': host = 'x86'
if host == 'armv7': host = 'arm'
echoargs = './configure'
echoargs += ' --prefix=%s' % prefix
echoargs += ' --host=%s' % host
if clean: echoargs += ' --clean'
if not clean: echoargs += ' --noclean'
if linktype == 'a': echoargs += ' --staticbinaries'
if linktype == 'so': echoargs += ' --nostaticbinaries'
print(echoargs)
if prefix[0] != '/':
  raise ValueError('prefix %s is not an absolute path' % prefix)
rpath = None
# XXX: rpath = '%s/lib' % prefix
if clean:
  shutil.rmtree('build/%s' % host,ignore_errors=True)
os.makedirs('build/%s' % host,exist_ok=True)
os.makedirs('build/%s/package/bin' % host,exist_ok=True)
os.makedirs('build/%s/package/lib' % host,exist_ok=True)
os.makedirs('build/%s/package/include' % host,exist_ok=True)
def copytree(src,dst):
  # starting with python 3.8 can use shutil.copytree
  # with dirs_exist_ok=True
  # but want to support older versions of python too
  os.makedirs(dst,exist_ok=True)
  for fn in sorted(os.listdir(src)):
    srcfn = '%s/%s' % (src,fn)
    dstfn = '%s/%s' % (dst,fn)
    if os.path.isdir(srcfn):
      copytree(srcfn,dstfn)
    else:
      shutil.copy2(srcfn,dstfn)
  shutil.copystat(src,dst)
shutil.copy2('api','build/%s/api' % host)
copytree('scripts-build','build/%s/scripts' % host)
copytree('cpuid','build/%s/cpuid' % host)
copytree('priority','build/%s/priority' % host)
os.makedirs('build/%s/include-build' % host,exist_ok=True)
shutil.copy2('randombytes/randombytes.h','build/%s/include-build/randombytes.h' % host)
shutil.copy2('cpucycles/cpucycles.h','build/%s/include-build/cpucycles.h' % host)
for bits in 8,16,32,64:
  with open('build/%s/include-build/crypto_int%d.h' % (host,bits),'w') as f:
    f.write('#include <inttypes.h>\n')
    f.write('#define crypto_int%d int%d_t' % (bits,bits))
  with open('build/%s/include-build/crypto_uint%d.h' % (host,bits),'w') as f:
    f.write('#include <inttypes.h>\n')
    f.write('#define crypto_uint%d uint%d_t' % (bits,bits))
# ----- compilers
def compilerversion(c):
  try:
    p = subprocess.Popen(c.split()+['--version'],stdout=subprocess.PIPE,stderr=subprocess.STDOUT,universal_newlines=True)
    out,err = p.communicate()
    assert not err
    assert not p.returncode
    return out
  except:
    pass
compilerversionline = {}
compilers = {}
for arch in sorted(os.listdir('compilers')):
  if arch.endswith('.c'): continue
  if arch == 'default' or arch == host or arch.startswith('%s+' % host):
    with open('compilers/%s' % arch) as f:
      for c in f.readlines():
        c = c.strip()
        cv = compilerversion(c)
        if cv == None:
          print('skipping %s compiler %s' % (arch,c))
          continue
        if arch not in compilers: compilers[arch] = []
        compilers[arch] += [c]
        cv = (c+'\n'+cv).strip().replace('\n','; ')
        compilerversionline[arch,c] = cv
        print('using %s compiler %s' % (arch,cv))
firstcompiler = compilers['default'][0]
compilerabbrev = {}
i = 0
for arch in sorted(compilers):
  for compiler in compilers[arch]:
    compilerabbrev[arch,compiler] = 'C%d'%i
    i += 1
    print('abbreviating %s = %s %s' % (compilerabbrev[arch,compiler],arch,compiler))
os.makedirs('build/%s/compilerarch' % host,exist_ok=True)
for arch,compiler in compilerabbrev:
  with open('build/%s/compilerarch/%s' % (host,compilerabbrev[arch,compiler]),'w') as f:
    f.write('%s\n' % arch)
os.makedirs('build/%s/compilerversion' % host,exist_ok=True)
for arch,compiler in compilerabbrev:
  with open('build/%s/compilerversion/%s' % (host,compilerabbrev[arch,compiler]),'w') as f:
    f.write('%s\n' % compilerversionline[arch,compiler])
with open('build/%s/scripts/compiledefault' % host,'w') as f:
  f.write('#!/bin/sh\n')
  f.write('\n')
  f.write('dir="$1"; shift\n')
  f.write('base="$1"; shift\n')
  f.write('ext="$1"; shift\n')
  f.write('\n')
  f.write('cd "$dir" && \\\n')
  f.write('%s \\\n' % firstcompiler)
  f.write('  -fvisibility=hidden \\\n')
  f.write('  "$@" \\\n')
  f.write('  -c "$base.$ext"\n')
os.chmod('build/%s/scripts/compiledefault' % host,0o755)
# ----- run-time checks for whether host actually supports compiler
copytree('compilers','build/%s/compilers' % host)
for arch in sorted(compilers):
  if arch == 'default': continue
  assert os.path.exists('compilers/%s.c'%arch)
  arch_csymbol = ''.join(x if x in '0123456789abcdefghijklmnopqrstuvwxyz' else '_' for x in arch)
  M = '\n'
  M += 'compilers/%s.o: compilers/%s.c\n' % (arch,arch)
  M += '\tscripts/compiledefault compilers %s c -Dsupports=lib25519_supports_%s\n' % (arch,arch_csymbol)
  makefile = M + makefile
M = '\n'
M += 'compilers-all: %s\n' % ' '.join('compilers/%s.o'%arch for arch in sorted(compilers) if arch != 'default')
M += '\ttouch compilers-all\n'
makefile = M + makefile
# ----- crypto
operations = []
primitives = {}
sizes = {}
exports = {}
prototypes = {}
with open('api') as f:
  for line in f:
    line = line.strip()
    if line.startswith('crypto_'):
      line = line.split('/')
      assert len(line) == 2
      o = line[0].split('_')[1]
      if o not in operations: operations += [o]
      p = line[1]
      primitives[o] = p
      continue
    if line.startswith('#define '):
      x = line.split(' ')
      x = x[1].split('_')
      assert len(x) == 3
      assert x[0] == 'crypto'
      o = x[1]
      if o not in sizes: sizes[o] = ''
      sizes[o] += line+'\n'
      continue
    if line.endswith(');'):
      fun,args = line[:-2].split('(')
      rettype,fun = fun.split()
      fun = fun.split('_')
      o = fun[1]
      assert fun[0] == 'crypto'
      if o not in exports: exports[o] = []
      exports[o] += ['_'.join(fun[1:])]
      if o not in prototypes: prototypes[o] = []
      prototypes[o] += [(rettype,fun,args)]
lib25519h = """\
#ifndef lib25519_h
#define lib25519_h
#ifdef __cplusplus
extern "C" {
#endif
"""
with open('version') as f:
  version = f.readlines()[0].strip()
def cstring(x):
  return '"%s"' % x.replace('\\','\\\\').replace('"','\\"').replace('\n','\\n')
lib25519h += '\n'
lib25519h += '#define lib25519_version %s\n' % cstring(version)
lib25519h += '#define lib25519_arch %s\n' % cstring(host)
lib25519h += '\n'
lib25519h += 'extern void lib25519_cpuid(unsigned int *,long long);\n'
for o in operations:
  if len(sizes[o]) > 0:
    lib25519h += '\n'
    lib25519h += re.sub(' crypto_',' lib25519_',sizes[o])
  for rettype,fun,args in prototypes[o]:
    shortfun = '_'.join(fun[1:])
    lib25519h += '\n'
    lib25519h += 'extern %s lib25519_%s(%s);\n' % (rettype,shortfun,args)
    lib25519h += 'extern %s (*lib25519_dispatch_%s(long long))(%s);\n' % (rettype,shortfun,args)
  lib25519h += '\n'
  lib25519h += 'extern const char *lib25519_%s_implementation(void);\n' % o
  lib25519h += 'extern const char *lib25519_%s_compiler(void);\n' % o
  lib25519h += 'extern const char *lib25519_dispatch_%s_implementation(long long);\n' % o
  lib25519h += 'extern const char *lib25519_dispatch_%s_compiler(long long);\n' % o
  lib25519h += 'extern long long lib25519_numimpl_%s(void);\n' % o
lib25519h += """
#ifdef __cplusplus
}
#endif
#endif
"""
with open('build/%s/package/include/lib25519.h' % host,'w') as f:
  f.write(lib25519h)
os.chmod('build/%s/package/include/lib25519.h' % host,0o644)
for o in operations:
  cryptoh = ''
  cryptoh += '#ifndef crypto_%s_%s_h\n' % (o,primitives[o])
  cryptoh += '#define crypto_%s_%s_h\n' % (o,primitives[o])
  cryptoh += '\n'
  for rettype,fun,args in prototypes[o]:
    shortfun = '_'.join(fun[1:])
    cryptoh += '#define crypto_%s_%s lib25519_%s\n' % (shortfun,primitives[o],shortfun)
  cryptoh += '\n'
  cryptoh += re.sub('crypto_%s_'%o,'crypto_%s_%s_'%(o,primitives[o]),sizes[o])
  cryptoh += '\n'
  for rettype,fun,args in prototypes[o]:
    shortfun = '_'.join(fun[1:])
    cryptoh += 'extern %s crypto_%s_%s(%s);\n' % (rettype,shortfun,primitives[o],args)
  cryptoh += '\n'
  cryptoh += '#endif\n'
  with open('build/%s/include-build/crypto_%s_%s.h' % (host,o,primitives[o]),'w') as f:
    f.write(cryptoh)
ofiles = []
oicdirs = []
for o in operations:
  for i in sorted(os.listdir('crypto_%s/%s' % (o,primitives[o]))):
    impldir = 'crypto_%s/%s/%s' % (o,primitives[o],i)
    if not os.path.isdir(impldir): continue
    if os.stat(impldir).st_mode & 0o1000 == 0o1000:
      print('skipping sticky %s' % impldir)
      continue
    implarch = None
    if os.path.exists('%s/architectures' % impldir):
      with open('%s/architectures' % impldir) as f:
        for line in f:
          line = line.strip().split()
          if len(line) == 0: continue
          if line[0] != host: continue
          implarch = line
    else:
      implarch = [host]
    if implarch == None: continue
    assert implarch[0] == host
    for arch in compilers:
      if any(implarchreq not in arch.split('+')[1:] for implarchreq in implarch[1:]):
        continue
      for compiler in compilers[arch]:
        compilerdir = compilerabbrev[arch,compiler]
        namespace = 'lib25519_%s_%s_%s' % (o,i.replace('-','_'),compilerabbrev[arch,compiler])
        oicdirs += ['%s/%s/%s' % (o,i,compilerdir)]
        builddir = 'build/%s/%s/%s/%s' % (host,o,i,compilerdir)
        os.makedirs(builddir,exist_ok=True)
        copytree(impldir,builddir)
        doth = ''
        doth += '#ifndef crypto_%s_h\n' % o
        doth += '#define crypto_%s_h\n' % o
        doth += '\n'
        for m in exports[o]:
          doth += '#define crypto_%s CRYPTO_NAMESPACE(%s)\n' % (m,m)
        doth += '\n'
        doth += sizes[o]
        doth += '\n'
        for rettype,fun,args in prototypes[o]:
          doth += 'extern %s %s(%s) __attribute__((visibility("default")));\n' % (rettype,'_'.join(fun),args)
        doth += '\n'
        doth += '#endif\n'
        with open('%s/crypto_%s.h' % (builddir,o),'w') as f:
          f.write(doth)
        with open('%s/compile' % builddir,'w') as f:
          f.write('#!/bin/sh\n')
          f.write('base="$1"; shift\n')
          f.write('ext="$1"; shift\n')
          f.write('if %s \\\n' % compiler)
          f.write('  -I ../../../include-build \\\n')
          f.write('  -fvisibility=hidden \\\n')
          f.write('  -D"CRYPTO_NAMESPACE(name)=%s_##name" \\\n' % namespace)
          f.write('  -D"_CRYPTO_NAMESPACE(name)=_%s_##name" \\\n' % namespace)
          f.write('  -c "$base.$ext"\n')
          f.write('then\n')
          f.write('  :\n')
          f.write('else\n')
          f.write('  case "$?" in\n')
          f.write('    111)\n')
          f.write('      # maybe someday compilers can be convinced\n')
          f.write('      # to use exit code 111 for temporary failures\n')
          f.write('      exit 111\n')
          f.write('      ;;\n')
          f.write('    *)\n')
          f.write('      : > "$base.o"\n')
          f.write('      touch "$base.o.compilefailed"\n')
          f.write('  esac\n')
          f.write('fi\n')
        os.chmod('%s/compile' % builddir,0o755)
        for fn in sorted(os.listdir(builddir)):
          if fn.endswith('.c') or fn.endswith('.S'):
            base = fn[:-2]
            ext = fn[-1:]
            makefile += '\n'
            ofiles += ['%s/%s/%s/%s.o' % (o,i,compilerdir,base)]
            makefile += '%s/%s/%s/%s.o: %s/%s/%s/%s\n' % (o,i,compilerdir,base,o,i,compilerdir,fn)
            makefile += '\tcd %s/%s/%s && ./compile %s %s\n' % (o,i,compilerdir,base,ext)
# ----- dispatch
M = 'compiledimplementations: scripts/compiledimplementations \\\n'
for ofile in ofiles:
  M += '%s \\\n' % ofile
M += '\n'
M += '\tscripts/compiledimplementations \\\n'
for oicdir in oicdirs:
  M += '\t%s \\\n' % oicdir
M += '\t> compiledimplementations\n'
makefile = M + makefile
for goal in 'auto','manual':
  os.makedirs('build/%s/dispatch-%s' % (host,goal),exist_ok=True)
  M = ''
  for o in operations:
    M += 'dispatch-%s/%s.c: scripts/dispatch compiledimplementations\n' % (goal,o)
    M += '\tscripts/dispatch %s %s %s < compiledimplementations > dispatch-%s/%s.c\n' % (goal,o,host,goal,o)
    M += '\n'
  makefile = M + makefile
  M = ''
  for o in operations:
    M += 'dispatch-%s/%s.o: dispatch-%s/%s.c\n' % (goal,o,goal,o)
    M += '\tscripts/compiledefault dispatch-%s %s c\n' % (goal,o)
    M += '\n'
  makefile = M + makefile
  M = 'dispatch-%s-all: \\\n' % goal
  for o in operations:
    M += 'dispatch-%s/%s.o \\\n' % (goal,o)
  M += '\n'
  M += '\ttouch dispatch-%s-all\n' % goal
  M += '\n'
  makefile = M + makefile
# ----- lib25519
M = 'odirs: compiledimplementations\n'
M += '\t( cat compiledimplementations; echo dispatch-auto; echo dispatch-manual; echo compilers; echo cpuid ) > odirs\n'
M += '\n'
makefile = M + makefile
M = 'ofiles: scripts/ofiles scripts/checknamespace odirs compiledimplementations dispatch-auto-all dispatch-manual-all compilers-all cpuid-all\n'
M += '\tscripts/ofiles < odirs\n'
M += '\tscripts/checknamespace lib25519 < odirs\n'
M += '\n'
makefile = M + makefile
with open('build/%s/scripts/staticlib' % host,'w') as f:
  f.write('#!/bin/sh\n')
  f.write('\n')
  f.write('rm -f package/lib/lib25519.a\n')
  f.write('ar cr package/lib/lib25519.a ofiles/*.o\n')
  f.write('ranlib package/lib/lib25519.a || :\n')
  f.write('chmod 644 package/lib/lib25519.a\n')
os.chmod('build/%s/scripts/staticlib' % host,0o755)
M = 'package/lib/lib25519.a: scripts/staticlib ofiles\n'
M += '\tscripts/staticlib\n'
M += '\n'
makefile = M + makefile
with open('build/%s/scripts/sharedlib' % host,'w') as f:
  f.write('#!/bin/sh\n')
  f.write('\n')
  f.write('%s -shared \\\n' % firstcompiler)
  if rpath:
    f.write('  -Wl,-rpath=%s \\\n' % rpath)
  f.write('  -Wl,-soname,lib25519.so.1 \\\n')
  f.write('  -o package/lib/lib25519.so.1 \\\n')
  f.write('  ofiles/*.o\n')
  f.write('chmod 644 package/lib/lib25519.so.1\n')
os.chmod('build/%s/scripts/sharedlib' % host,0o755)
M = 'package/lib/lib25519.so.1: scripts/sharedlib ofiles\n'
M += '\tscripts/sharedlib\n'
M += '\n'
makefile = M + makefile
M = 'package/lib/lib25519.so: package/lib/lib25519.so.1\n'
M += '\trm -f package/lib/lib25519.so\n'
M += '\tln -s lib25519.so.1 package/lib/lib25519.so\n'
M += '\n'
makefile = M + makefile
# ----- librandombytes
copytree('randombytes','build/%s/randombytes' % host)
for r in 'devurandom',:
  M = 'randombytes/%s.o: randombytes/%s.c\n' % (r,r)
  M += '\tscripts/compiledefault randombytes %s c -I ../include-build\n' % r
  M += '\n'
makefile = M + makefile
with open('build/%s/randombytes/staticlib' % host,'w') as f:
  f.write('#!/bin/sh\n')
  f.write('\n')
  f.write('rm -f package/lib/lib%s.a\n' % librandombytes)
  f.write('ar cr package/lib/lib%s.a randombytes/*.o\n' % librandombytes)
  f.write('ranlib package/lib/lib%s.a || :\n' % librandombytes)
  f.write('chmod 644 package/lib/lib%s.a\n' % librandombytes)
os.chmod('build/%s/randombytes/staticlib' % host,0o755)
M = 'package/lib/lib%s.a: randombytes/staticlib randombytes/devurandom.o\n' % librandombytes
M += '\trandombytes/staticlib\n'
M += '\n'
makefile = M + makefile
with open('build/%s/randombytes/sharedlib' % host,'w') as f:
  f.write('#!/bin/sh\n')
  f.write('\n')
  f.write('%s -shared \\\n' % firstcompiler)
  if rpath:
    f.write('  -Wl,-rpath=%s \\\n' % rpath)
  f.write('  -Wl,-soname,lib%s.so.1 \\\n' % librandombytes)
  f.write('  -o package/lib/lib%s.so.1 \\\n' % librandombytes)
  f.write('  randombytes/devurandom.o\n')
  f.write('chmod 644 package/lib/lib%s.so.1\n' % librandombytes)
os.chmod('build/%s/randombytes/sharedlib' % host,0o755)
M = 'package/lib/lib%s.so.1: randombytes/sharedlib randombytes/devurandom.o\n' % librandombytes
M += '\trandombytes/sharedlib\n'
M += '\n'
makefile = M + makefile
M = 'package/lib/lib%s.so: package/lib/lib%s.so.1\n' % (librandombytes,librandombytes)
M += '\trm -f package/lib/lib%s.so\n' % librandombytes
M += '\tln -s lib%s.so.1 package/lib/lib%s.so\n' % (librandombytes,librandombytes)
M += '\n'
makefile = M + makefile
# ----- cpuid
cpuid = host
if not os.path.exists('cpuid/%s.c' % host):
  cpuid = 'default'
M = 'cpuid-all: cpuid/%s.o\n' % cpuid
M += '\ttouch cpuid-all\n'
M += '\n'
M += 'cpuid/%s.o: cpuid/%s.c\n' % (cpuid,cpuid)
M += '\tscripts/compiledefault cpuid %s c\n' % cpuid
M += '\n'
makefile += M
# ----- libcpucycles
os.makedirs('build/%s/cpucycles' % host,exist_ok=True)
with open('build/%s/cpucycles/compile-ticks' % host,'w') as f:
  f.write('#!/bin/sh\n')
  f.write('arch="$1"; shift\n')
  f.write('x="$1"; shift\n')
  f.write('for source in try-"$arch"-"$x".c try-default-zero.c\n')
  f.write('do\n')
  f.write('  cp "$source" "$arch"-"$x".c\n')
  f.write('  %s \\\n' % firstcompiler)
  f.write('    -I ../include-build \\\n')
  f.write('    -fvisibility=hidden \\\n')
  f.write('    -Dticks=cpucycles_ticks_"$arch"_"$x" \\\n')
  f.write('    -Dticks_setup=cpucycles_ticks_"$arch"_"$x"_setup \\\n')
  f.write('    -c "$arch"-"$x".c\n')
  f.write('  case $? in\n')
  f.write('    0) break ;;\n')
  f.write('    111) exit 111 ;;\n')
  f.write('  esac\n')
  f.write('done\n')
os.chmod('build/%s/cpucycles/compile-ticks' % host,0o755)
cpucyclesoptions = []
cpucyclesofiles = []
with open('cpucycles/options') as f:
  for line in f:
    line = line.strip()
    if line == '': continue
    if line[0] == '#': continue
    base = line.split()[0]
    if not os.path.exists('cpucycles/%s.c' % base): continue
    cpucycles = base.split('-')
    if len(cpucycles) != 2: continue
    if cpucycles[0] not in (host,'default'): continue
    cpucyclesoptions += [cpucycles]
cpucyclesoptions += [['default','zero']] # must be last
for cpucycles in cpucyclesoptions:
  base = '-'.join(cpucycles)
  cpucyclesofiles += ['cpucycles/%s.o' % base]
  shutil.copy2('cpucycles/%s.c' % base,'build/%s/cpucycles/try-%s.c' % (host,base))
  M = 'cpucycles/%s.o: cpucycles/try-%s.c cpucycles/try-default-zero.c\n' % (base,base)
  M += '\tcd cpucycles && ./compile-ticks %s %s\n' % (cpucycles[0],cpucycles[1])
  M += '\n'
  makefile = M + makefile
for fn in sorted(os.listdir('cpucycles')):
  if not fn.endswith('.c'): continue
  if '-' in fn: continue
  base = fn[:-2]
  cpucyclesofiles += ['cpucycles/%s.o' % base]
  shutil.copy2('cpucycles/%s' % fn,'build/%s/cpucycles/%s' % (host,fn))
  M = 'cpucycles/%s.o: cpucycles/%s.c\n' % (base,base)
  M += '\tscripts/compiledefault cpucycles %s c -I ../include-build\n' % base
  M += '\n'
  makefile = M + makefile
with open('build/%s/cpucycles/options.inc' % host,'w') as f:
  f.write('#define NUMOPTIONS %d\n' % len(cpucyclesoptions))
  f.write('#define DEFAULTOPTION (NUMOPTIONS-1)\n')
  f.write('\n')
  for cpucycles in cpucyclesoptions:
    f.write('extern long long cpucycles_ticks_%s_%s_setup(void);\n' % (cpucycles[0],cpucycles[1]))
    f.write('extern long long cpucycles_ticks_%s_%s(void);\n' % (cpucycles[0],cpucycles[1]))
  f.write('\n')
  f.write('struct {\n')
  f.write('  const char *implementation;\n')
  f.write('  long long (*ticks_setup)(void);\n')
  f.write('  long long (*ticks)(void);\n')
  f.write('} options[NUMOPTIONS] = {\n')
  for cpucycles in cpucyclesoptions:
    f.write('{ "%s-%s", cpucycles_ticks_%s_%s_setup, cpucycles_ticks_%s_%s },\n' % (cpucycles[0],cpucycles[1],cpucycles[0],cpucycles[1],cpucycles[0],cpucycles[1]))
  f.write('} ;\n')
with open('build/%s/cpucycles/staticlib' % host,'w') as f:
  f.write('#!/bin/sh\n')
  f.write('\n')
  f.write('rm -f package/lib/lib%s.a\n' % libcpucycles)
  f.write('ar cr package/lib/lib%s.a "$@"\n' % libcpucycles)
  f.write('ranlib package/lib/lib%s.a || :\n' % libcpucycles)
  f.write('chmod 644 package/lib/lib%s.a\n' % libcpucycles)
os.chmod('build/%s/cpucycles/staticlib' % host,0o755)
M = 'package/lib/lib%s.a: cpucycles/staticlib %s\n' % (libcpucycles,' '.join(cpucyclesofiles))
M += '\tcpucycles/staticlib %s\n' % ' '.join(cpucyclesofiles)
M += '\n'
makefile = M + makefile
with open('build/%s/cpucycles/sharedlib' % host,'w') as f:
  f.write('#!/bin/sh\n')
  f.write('\n')
  f.write('%s -shared \\\n' % firstcompiler)
  if rpath:
    f.write('  -Wl,-rpath=%s \\\n' % rpath)
  f.write('  -Wl,-soname,lib%s.so.1 \\\n' % libcpucycles)
  f.write('  -o package/lib/lib%s.so.1 \\\n' % libcpucycles)
  f.write('  "$@"\n')
  f.write('chmod 644 package/lib/lib%s.so.1\n' % libcpucycles)
os.chmod('build/%s/cpucycles/sharedlib' % host,0o755)
M = 'package/lib/lib%s.so.1: cpucycles/sharedlib %s\n' % (libcpucycles,' '.join(cpucyclesofiles))
M += '\tcpucycles/sharedlib %s\n' % ' '.join(cpucyclesofiles)
M += '\n'
makefile = M + makefile
M = 'package/lib/lib%s.so: package/lib/lib%s.so.1\n' % (libcpucycles,libcpucycles)
M += '\trm -f package/lib/lib%s.so\n' % libcpucycles
M += '\tln -s lib%s.so.1 package/lib/lib%s.so\n' % (libcpucycles,libcpucycles)
M += '\n'
makefile = M + makefile
# ----- command
copytree('command','build/%s/command'%host)
dirlinksym('build/%s/command'%host,'bin','../package/bin')
dirlinksym('build/%s/command'%host,'lib','../package/lib')
dirlinksym('build/%s/command'%host,'include-build','../include-build')
dirlinksym('build/%s/command'%host,'include','../package/include')
with open('build/%s/command/link' % host,'w') as f:
  f.write('#!/bin/sh\n')
  f.write('target="$1"; shift\n')
  f.write('%s \\\n' % firstcompiler)
  f.write('  -fvisibility=hidden \\\n')
  f.write('  -o "$target" "$@"\n')
os.chmod('build/%s/command/link' % host,0o755)
commands = []
for fn in sorted(os.listdir('command')):
  if not fn.endswith('.c'): continue
  libs = set()
  with open('command/%s' % fn) as f:
    for line in f:
      line = line.strip().split()
      if len(line) < 1: continue
      if line[0] != '#include': continue
      if '-lcpucycles' in line: libs.add('libcpucycles')
      if '-l25519' in line: libs.add('lib25519')
      if '-lrandombytes_kernel' in line: libs.add('librandombytes_kernel')
  libs = sorted(libs)
  # XXX: with more libs, might need non-default sort order for linking
  base = fn[:-2]
  M = 'command/%s.o: command/%s.c\n' % (base,base)
  M += '\tscripts/compiledefault command %s c -I include -I include-build\n' % base
  M += '\n'
  makefile = M + makefile
  M = 'package/bin/%s: command/%s.o%s\n' % (base,base,''.join(' package/lib/%s.%s' % (x,linktype) for x in libs))
  M += '\tcd command && ./link bin/%s %s.o%s\n' % (base,base,''.join(' lib/%s.%s' % (x,linktype) for x in libs))
  M += '\n'
  makefile = M + makefile
  commands += ['package/bin/%s' % base]
M = 'commands: %s\n' % ' '.join(commands)
M += '\n'
makefile = M + makefile
# ----- make install
M = 'install: scripts/install default\n'
M += '\tscripts/install %s\n' % prefix
M += '\n'
makefile = M + makefile
# ----- make default
M = 'default: package/lib/lib25519.a package/lib/lib25519.so package/lib/lib25519.so.1 \\\n'
M += 'package/lib/lib%s.a package/lib/lib%s.so package/lib/lib%s.so.1 \\\n' % (librandombytes,librandombytes,librandombytes)
M += 'package/lib/lib%s.a package/lib/lib%s.so package/lib/lib%s.so.1 \\\n' % (libcpucycles,libcpucycles,libcpucycles)
M += 'commands\n'
M += '\n'
makefile = M + makefile
with open('build/%s/Makefile' % host,'w') as f:
  f.write(makefile)
# ----- build/0, build/Makefile
dirlinksym('build','0',host)
with tempfile.TemporaryDirectory(dir='build') as t:
  os.symlink(host,'%s/0' % t)
  os.rename('%s/0' % t,'build/0')
with open('build/Makefile','w') as f:
  f.write('default:\n')
  f.write('\tcd %s && $(MAKE)\n' % host)
  f.write('\n')
  f.write('install:\n')
  f.write('\tcd %s && $(MAKE) install\n' % host)
  f.write('\n')
  f.write('clean:\n')
  f.write('\trm -r %s\n' % host)