# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

import argparse
import os
from io import StringIO

import buildconfig

from mozbuild.preprocessor import Preprocessor
from mozbuild.util import DefinesAction


def generate_symbols_file(output, *args):
    """ """
    parser = argparse.ArgumentParser()
    parser.add_argument("input")
    parser.add_argument("-D", action=DefinesAction)
    parser.add_argument("-U", action="append", default=[])
    args = parser.parse_args(args)
    input = os.path.abspath(args.input)

    pp = Preprocessor()
    pp.context.update(buildconfig.defines["ALLDEFINES"])
    if args.D:
        pp.context.update(args.D)
    for undefine in args.U:
        if undefine in pp.context:
            del pp.context[undefine]
    # Hack until MOZ_DEBUG_FLAGS are simply part of buildconfig.defines
    if buildconfig.substs.get("MOZ_DEBUG"):
        pp.context["DEBUG"] = "1"
    # Ensure @DATA@ works as expected (see the Windows section further below)
    if buildconfig.substs["OS_TARGET"] == "WINNT":
        pp.context["DATA"] = "DATA"
    else:
        pp.context["DATA"] = ""
    pp.out = StringIO()
    pp.do_filter("substitution")
    pp.do_include(input)

    symbols = [s.strip() for s in pp.out.getvalue().splitlines() if s.strip()]

    libname, ext = os.path.splitext(os.path.basename(output.name))

    if buildconfig.substs["OS_TARGET"] == "WINNT":
        # A def file is generated for MSVC link.exe that looks like the
        # following:
        # LIBRARY library.dll
        # EXPORTS
        #   symbol1
        #   symbol2
        #   ...
        #
        # link.exe however requires special markers for data symbols, so in
        # that case the symbols look like:
        #   data_symbol1 DATA
        #   data_symbol2 DATA
        #   ...
        #
        # In the input file, this is just annotated with the following syntax:
        #   data_symbol1 @DATA@
        #   data_symbol2 @DATA@
        #   ...
        # The DATA variable is "simply" expanded by the preprocessor, to
        # nothing on non-Windows, such that we only get the symbol name on
        # those platforms, and to DATA on Windows, so that the "DATA" part
        # is, in fact, part of the symbol name as far as the symbols variable
        # is concerned.
        assert ext == ".def"
        output.write("LIBRARY %s\nEXPORTS\n  %s\n" % (libname, "\n  ".join(symbols)))
    elif (
        buildconfig.substs.get("GCC_USE_GNU_LD")
        or buildconfig.substs["OS_TARGET"] == "SunOS"
    ):
        # A linker version script is generated for GNU LD that looks like the
        # following:
        # liblibrary.so {
        # global:
        #   symbol1;
        #   symbol2;
        #   ...
        # local:
        #   *;
        # };
        output.write(
            "%s {\nglobal:\n  %s;\nlocal:\n  *;\n};" % (libname, ";\n  ".join(symbols))
        )
    elif buildconfig.substs["OS_TARGET"] == "Darwin":
        # A list of symbols is generated for Apple ld that simply lists all
        # symbols, with an underscore prefix.
        output.write("".join("_%s\n" % s for s in symbols))

    return set(pp.includes)
