diff options
Diffstat (limited to 'third_party/bazel/rules_haskell/haskell/private/version_macros.py')
-rwxr-xr-x | third_party/bazel/rules_haskell/haskell/private/version_macros.py | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/third_party/bazel/rules_haskell/haskell/private/version_macros.py b/third_party/bazel/rules_haskell/haskell/private/version_macros.py new file mode 100755 index 000000000000..4bc6052cb032 --- /dev/null +++ b/third_party/bazel/rules_haskell/haskell/private/version_macros.py @@ -0,0 +1,101 @@ +#!/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() |