101 lines
2.7 KiB
Python
Executable file
101 lines
2.7 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
"""Generate Cabal version macros.
|
|
|
|
Generates the content of a C header file for the given library name and version
|
|
and prints it to standard output.
|
|
"""
|
|
|
|
import argparse
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("name", help="The package name.")
|
|
parser.add_argument("version", help="The package version.")
|
|
args = parser.parse_args()
|
|
|
|
print(version_macros(args.name, args.version))
|
|
|
|
|
|
def version_macros(name, version):
|
|
"""Generate Cabal version macros.
|
|
|
|
Based on Cabal's version macro generation, see [1].
|
|
|
|
[1]: http://hackage.haskell.org/package/Cabal-2.4.1.0/docs/src/Distribution.Simple.Build.Macros.html#generatePackageVersionMacros
|
|
"""
|
|
(major1, major2, minor) = version_components(version)
|
|
escaped_name = cpp_escape_name(name)
|
|
return "\n".join([
|
|
# #define VERSION_pkg "1.2.3"
|
|
cpp_ifndef_define(
|
|
"VERSION_" + escaped_name,
|
|
[],
|
|
'"{}"'.format(version),
|
|
),
|
|
# #define MIN_VERSION_pkg(major1, major2, minor) ...
|
|
cpp_ifndef_define(
|
|
"MIN_VERSION_" + escaped_name,
|
|
["major1", "major2", "minor"],
|
|
" \\\n".join([
|
|
"(",
|
|
" (major1) < {} ||".format(major1),
|
|
" (major1) == {} && (major2) < {} ||".format(major1, major2),
|
|
" (major1) == {} && (major2) == {} && (minor) <= {} )".format(
|
|
major1, major2, minor),
|
|
])),
|
|
])
|
|
|
|
|
|
def version_components(version):
|
|
"""Split version string into major1.major2.minor components."""
|
|
components = version.split(".")
|
|
num = len(components)
|
|
|
|
if num < 1:
|
|
raise ValueError("version should have at least one component.")
|
|
|
|
major1 = components[0]
|
|
|
|
if num >= 2:
|
|
major2 = components[1]
|
|
else:
|
|
major2 = "0"
|
|
|
|
if num >= 3:
|
|
minor = components[2]
|
|
else:
|
|
minor = "0"
|
|
|
|
return (major1, major2, minor)
|
|
|
|
|
|
def cpp_escape_name(name):
|
|
"""Escape package name to be CPP macro safe."""
|
|
return name.replace("-", "_")
|
|
|
|
|
|
def cpp_define(macro, params, val):
|
|
"""CPP macro definition, optionally with parameters."""
|
|
return "#define {macro}{params} {val}".format(
|
|
macro = macro,
|
|
params = "({})".format(",".join(params)) if params else "",
|
|
val = val,
|
|
)
|
|
|
|
|
|
def cpp_ifndef(macro, body):
|
|
"""CPP ifndef block."""
|
|
return "#ifndef {macro}\n{body}\n#endif /* {macro} */".format(
|
|
macro = macro,
|
|
body = body,
|
|
)
|
|
|
|
|
|
def cpp_ifndef_define(macro, params, val):
|
|
"""CPP macro definition, if not previously defined."""
|
|
return cpp_ifndef(macro, cpp_define(macro, params, val))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|