Skip to content

Instantly share code, notes, and snippets.

@Profpatsch
Created August 15, 2019 20:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Profpatsch/122a08726e0db971c720573124c65be1 to your computer and use it in GitHub Desktop.
Save Profpatsch/122a08726e0db971c720573124c65be1 to your computer and use it in GitHub Desktop.
Code to generate a sysdeps.h header file from a structured sysdeps file
{ lib }:
let
example =
{
target = "aarch64-linux-gnu";
endianness = "little";
has = {
clockrt = true;
clockmon = true;
posixspawn = true;
timer = true;
nullispointer = true;
accept4 = true;
cmsgcloexec = true;
devurandom = true;
dirfd = true;
eventfd = true;
flock = true;
getpeereid = false;
sopeercred = true;
getpeerucred = false;
ipv6 = true;
malloc0 = true;
msgdontwait = true;
odirectory = true;
openat = true;
linkat = true;
memmem = true;
pipe2 = true;
ppoll = true;
revoke = true;
sendfile = true;
setgroups = true;
settimeofday = true;
signalfd = true;
splice = true;
strcasestr = true;
strnlen = true;
uint64t = true;
futimens = true;
futimes = true;
arc4random = false;
arc4random_addrandom = false;
getrandom = true;
itimer = true;
namespaces = true;
nsgetparent = true;
explicit_bzero = true;
emptyregex = true;
};
sizeof = {
sizeofushort = 2;
sizeofuint = 4;
sizeofulong = 8;
sizeofsize = 8;
sizeofuid = 4;
sizeofgid = 4;
sizeofpid = 4;
sizeoftime = 8;
sizeofdev = 8;
sizeofino = 8;
};
signed = {
signedsize = false;
signeduid = false;
signedgid = false;
signedpid = true;
signedtime = true;
signeddev = false;
signedino = false;
};
};
# sizeTy = with types; enum int [ 2 4 8 ];
# sysdepsTy = with types; product {
# target = string;
# endianness = enum string [ "little" "big" ];
# has = attrs bool;
# sizeof = attrs sizeTy;
# signed = attrs bool;
# };
# headerFieldsTy = with types;
# attrs (union [
# boolean
# string
# sizeTy
# (product { eitherDefined = string; })
# ]);
# Convert sysdeps struct to header fields struct
sysdepsToHeaderFields = sysdeps:
let
# A macro for bool value, conditionally defined if true
has = lib.mapAttrs' (n: v: {
name = "SKALIBS_HAS${lib.toUpper n}";
value = v;
});
# A macro for the sizes, defined with uint
sizeof = lib.mapAttrs' (n: v: {
name = "SKALIBS_${lib.toUpper n}";
value = v;
});
# These are slightly different, there’s two possible macro names,
# conditionally defined based on the value.
signed = lib.mapAttrs' (n: v: {
name = if v
then "SKALIBS_HAS${lib.toUpper n}"
else "SKALIBS_HASUN${lib.toUpper n}";
value = true;
});
in {
SKALIBS_TARGET = sysdeps.target;
SKALIBS_BSD_SUCKS = {
eitherDefined = [
"__FreeBSD__"
"__OpenBSD__"
"__NetBSD__"
"__bsdi__"
"__DragonFly__"
];
};
endianness = sysdeps.endianness;
}
// (has sysdeps.has)
// (sizeof sysdeps.sizeof)
// (signed sysdeps.signed);
headerFieldsToHeaderFile = headerFields:
let
print = v:
if builtins.isString v
then ''"${lib.escape [''"''] v}"''
else lib.generators.mkValueStringDefault {} v;
define = n: v:
"#define ${n}${if v == null then "" else " ${print v}"}";
maybeDefine = n: v:
if builtins.isBool v then
if v then define n null else ""
else if builtins.isString v then
define n v
else if builtins.isInt v then
define n v
else if builtins.isAttrs v then
if v ? eitherDefined
then ''
#if defined ${lib.concatMapStringsSep " || " (s: "defined(${s})") v.eitherDefined}
# define SKALIBS_BSD_SUCKS
#endif''
else throw "unreachable (programming error)"
else throw "unreachable (programming error)";
allFlags = lib.concatStringsSep "\n" (lib.concatLists
(lib.mapAttrsToList
(n: v:
[
""
"#undef ${n}"
] ++
(let m = maybeDefine n v;
in if m == "" then [] else [m]))
headerFields));
in ''
#ifndef SYSDEPS_H
#define SYSDEPS_H
${allFlags}
#endif
'';
in headerFieldsToHeaderFile (sysdepsToHeaderFields example)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment