mirror of
https://github.com/hermitcore/libhermit.git
synced 2025-03-30 00:00:15 +01:00
137 lines
4.3 KiB
Python
Executable file
137 lines
4.3 KiB
Python
Executable file
#!/usr/bin/env python
|
|
# Copyright 2015-2017 Obsidian Research Corp.
|
|
# Licensed under BSD (MIT variant) or GPLv2. See COPYING.
|
|
import argparse
|
|
import subprocess
|
|
import os
|
|
import collections
|
|
|
|
headers = {
|
|
"endian.h",
|
|
"netinet/in.h",
|
|
"pthread.h",
|
|
"sys/socket.h",
|
|
"stdatomic.h",
|
|
};
|
|
|
|
def norm_header(fn):
|
|
for I in headers:
|
|
flat = I.replace("/","-");
|
|
if fn.endswith(flat):
|
|
return I;
|
|
if fn.endswith(flat + ".diff"):
|
|
return I;
|
|
return None;
|
|
|
|
def get_buildlib_patches(dfn):
|
|
"""Within the buildlib directory we store patches for the glibc headers. Each
|
|
patch is in a numbered sub directory that indicates the order to try, the
|
|
number should match the glibc version used to make the diff."""
|
|
res = [];
|
|
for d,_,files in os.walk(dfn):
|
|
for I in files:
|
|
if d != dfn:
|
|
bn = int(os.path.basename(d));
|
|
else:
|
|
bn = 0;
|
|
|
|
res.append((bn,os.path.join(d,I)));
|
|
res.sort(reverse=True);
|
|
|
|
ret = collections.defaultdict(list);
|
|
for _,I in res:
|
|
ret[norm_header(I)].append(I);
|
|
return ret;
|
|
|
|
def is_patch(fn):
|
|
with open(fn) as F:
|
|
return F.read(10).startswith("-- /");
|
|
|
|
def apply_patch(src,patch,dest):
|
|
"""Patch a single system header. The output goes into our include search path
|
|
and takes precedence over the system version."""
|
|
dfn = os.path.dirname(dest);
|
|
if not os.path.isdir(dfn):
|
|
os.makedirs(dfn);
|
|
|
|
if not patch.endswith(".diff"):
|
|
if not os.path.exists(dest):
|
|
os.symlink(patch,dest);
|
|
return True;
|
|
|
|
try:
|
|
if os.path.exists(dest + ".rej"):
|
|
os.unlink(dest + ".rej");
|
|
|
|
subprocess.check_output(["patch","-f","--follow-symlinks","-V","never","-i",patch,"-o",dest,src]);
|
|
|
|
if os.path.exists(dest + ".rej"):
|
|
print "Patch from %r failed"%(patch);
|
|
return False;
|
|
except subprocess.CalledProcessError:
|
|
print "Patch from %r failed"%(patch);
|
|
return False;
|
|
return True;
|
|
|
|
def replace_header(fn):
|
|
tries = 0;
|
|
for pfn in patches[fn]:
|
|
if apply_patch(os.path.join(args.REF,fn),
|
|
pfn,os.path.join(args.INCLUDE,fn)):
|
|
return;
|
|
tries = tries + 1;
|
|
|
|
print "Unable to apply any patch to %r, tries %u"%(fn,tries);
|
|
global failed;
|
|
failed = True;
|
|
|
|
def save(fn,outdir):
|
|
"""Diff the header file in our include directory against the system header and
|
|
store the diff into buildlib. This makes it fairly easy to maintain the
|
|
replacement headers."""
|
|
if os.path.islink(os.path.join(args.INCLUDE,fn)):
|
|
return;
|
|
|
|
flatfn = fn.replace("/","-") + ".diff";
|
|
flatfn = os.path.join(outdir,flatfn);
|
|
|
|
with open(flatfn,"wt") as F:
|
|
try:
|
|
subprocess.check_call(["diff","-u",
|
|
os.path.join(args.REF,fn),
|
|
os.path.join(args.INCLUDE,fn)],
|
|
stdout=F);
|
|
except subprocess.CalledProcessError as ex:
|
|
if ex.returncode == 1:
|
|
return;
|
|
raise;
|
|
|
|
parser = argparse.ArgumentParser(description='Produce sparse shim header files')
|
|
parser.add_argument("--out",dest="INCLUDE",required=True,
|
|
help="Directory to write header files to");
|
|
parser.add_argument("--src",dest="SRC",required=True,
|
|
help="Top of the source tree");
|
|
parser.add_argument("--ref",dest="REF",default="/usr/include/",
|
|
help="System headers to manipulate");
|
|
parser.add_argument("--save",action="store_true",default=False,
|
|
help="Save mode will write the current content of the headers to buildlib as a diff.");
|
|
args = parser.parse_args();
|
|
|
|
if args.save:
|
|
# Get the glibc version string
|
|
ver = subprocess.check_output(["ldd","--version"]).splitlines()[0].split(' ')[-1];
|
|
ver = ver.partition(".")[-1];
|
|
outdir = os.path.join(args.SRC,"buildlib","sparse-include",ver);
|
|
if not os.path.isdir(outdir):
|
|
os.makedirs(outdir);
|
|
|
|
for I in headers:
|
|
save(I,outdir);
|
|
else:
|
|
failed = False;
|
|
patches = get_buildlib_patches(os.path.join(args.SRC,"buildlib","sparse-include"));
|
|
for I in headers:
|
|
replace_header(I);
|
|
|
|
if failed:
|
|
raise ValueError("Patch applications failed");
|