Ejemplo n.º 1
0
    def __init__(self,
                 context,
                 lib_root,
                 extensions_dir,
                 main_source_dirs=set(),
                 main_programs=set(),
                 no_property_checks=False,
                 generate_ada_api=True,
                 generate_gdb_hook=True,
                 pretty_print=False,
                 post_process_ada=None,
                 post_process_cpp=None,
                 post_process_python=None,
                 coverage=False,
                 relative_project=False,
                 unparse_script=None):
        """
        Generate sources for the analysis library. Also emit a tiny program
        useful for testing purposes.

        :param str lib_root: Path of the directory in which the library should
            be generated.

        :param str|None extensions_dir: Directory to contain extensions for
            code generation. If None is provided, assume there is no extension.

        :param set[str] main_source_dirs: List of source directories to use in
            the project file for mains. Source directories must be relative to
            the mains project file directory (i.e. $BUILD/src-mains).

        :param set[str] main_programs: List of names for programs to build in
            addition to the generated library. To each X program, there must be
            a X.adb source file in the $BUILD/src directory.

        :param bool no_property_checks: If True, do not emit safety checks in
            the generated code for properties. Namely, this disables null
            checks on field access.

        :param bool generate_ada_api: If True, generate the public Ada API. If
            False and there is no main to generate, do not generate this Ada
            API.

        :param bool generate_gdb_hook: Whether to generate the
            ".debug_gdb_scripts" section. Good for debugging, but better to
            disable for releases.

        :param bool pretty_print: If true, pretty-print the generated sources.

        :param post_process_ada: Optional post-processing for generated Ada
            source code.
        :type post_process_ada: None|(str) -> str

        :param post_process_cpp: Optional post-processing for generated C++
            source code.
        :type post_process_cpp: None|(str) -> str

        :param post_process_python: Optional post-processing for generated
            Python source code.
        :type post_process_python: None|(str) -> str

        :param bool coverage: Instrument the generated library to compute its
            code coverage. This requires GNATcoverage.

        :param bool relative_project: See libmanage's --relative-project
            option.
        """
        self.context = context
        self.verbosity = context.verbosity

        self.lib_root = lib_root
        self.cache = Cache(os.path.join(self.lib_root, 'obj', 'langkit_cache'))

        self.extensions_dir = extensions_dir

        # TODO: contain the add_template_dir calls to this context (i.e. avoid
        # global mutation).

        if self.extensions_dir:
            add_template_dir(self.extensions_dir)

        for dirpath in keep(self.context.template_lookup_extra_dirs):
            add_template_dir(dirpath)

        self.no_property_checks = no_property_checks
        self.generate_ada_api = generate_ada_api or bool(main_programs)
        self.generate_gdb_hook = generate_gdb_hook
        self.generate_unparser = context.generate_unparser
        self.pretty_print = pretty_print
        self.post_process_ada = post_process_ada
        self.post_process_cpp = post_process_cpp
        self.post_process_python = post_process_python
        self.coverage = coverage
        self.gnatcov = context.gnatcov
        self.relative_project = relative_project

        # Automatically add all source files in the "extensions/src" directory
        # to the generated library project.
        self.extensions_src_dir = None
        if self.extensions_dir:
            src_dir = path.join(self.extensions_dir, 'src')
            if path.isdir(src_dir):
                self.extensions_src_dir = src_dir
                for filename in os.listdir(src_dir):
                    filepath = path.join(src_dir, filename)
                    if path.isfile(filepath) and not filename.startswith('.'):
                        self.context.additional_source_files.append(filepath)

        self.main_source_dirs = main_source_dirs
        self.main_programs = main_programs

        self.lib_name_low = context.ada_api_settings.lib_name.lower()
        """
        Lower-case name for the generated library.
        """

        self.lib_name_up = context.ada_api_settings.lib_name.upper()
        """
        Upper-case name for the generated library.
        """

        # Paths for the various directories in which code is generated
        self.src_dir = path.join(self.lib_root, "src")
        self.src_mains_dir = path.join(self.lib_root, "src-mains")
        self.scripts_dir = path.join(self.lib_root, "scripts")
        self.python_dir = path.join(self.lib_root, "python")
        self.python_pkg_dir = path.join(
            self.lib_root, "python", context.python_api_settings.module_name)
        self.ocaml_dir = path.join(self.lib_root, "ocaml")

        self.lib_project = path.join(self.lib_root, f"{self.lib_name_low}.gpr")
        self.mains_project = path.join(self.lib_root, "mains.gpr")

        self.dfa_code = None
        """
        Holder for the data structures used to generate code for the lexer
        state machine (DFA). As an optimization, it is left to None if we
        decide not to generate it (i.e. when the already generated sources are
        up-to-date).

        :type: langkit.lexer.regexp.DFACodeGenHolder
        """

        self._project_file_emitted = False
        """
        Whether we emitted a project file for the generated library.

        :type: bool
        """

        self.project_languages = {'Ada'}
        """
        List of GPR names for languages used in the generated library.

        :type: set[str]
        """

        self.library_interfaces = set()
        """
        Set of source file base names for all sources that must appear in the
        "Interfaces" attribute of the generated library project file.

        :type: set[str]
        """

        self.instr_md = InstrumentationMetadata()

        # Add all additional source files to the list of library interfaces and
        # declare them as such in instrumentation metadata.
        for f in context.additional_source_files:
            self.add_library_interface(f, generated=False)

        if self.coverage:
            # Add the buffer-list unit from GNATcoverage's instrumentation to
            # the list of library interfaces. TODO: hopefully, we should not
            # have to do this anymore after S916-064 is addressed.
            self.library_interfaces.add(self.gnatcov.buffer_list_file(self))

        self.main_project_file = os.path.join(self.lib_root,
                                              f'{self.lib_name_low}.gpr')

        self.unparse_script = unparse_script
        """
        RA22-015: If set to something else than None, then the "dsl unparse"
        pass will be run on the given script.

        :type: langkit.compile_context.UnparseScript|None
        """

        # Determine whether we have user external properties. If so,
        # automatically WITH $.Implementation.Extensions from the body of
        # $.Analysis and $.Implementation.
        if any(prop.user_external
               for prop in context.all_properties(include_inherited=True)):
            for unit in ('Analysis', 'Implementation', 'Implementation.C'):
                context.add_with_clause(unit,
                                        ADA_BODY,
                                        '{}.Implementation.Extensions'.format(
                                            context.ada_api_settings.lib_name),
                                        use_clause=True)
Ejemplo n.º 2
0
    def __init__(self,
                 context,
                 lib_root,
                 extensions_dir,
                 main_source_dirs=set(),
                 main_programs=set(),
                 no_property_checks=False,
                 generate_astdoc=True,
                 generate_gdb_hook=True,
                 pretty_print=False,
                 post_process_ada=None,
                 post_process_cpp=None,
                 post_process_python=None):
        """
        Generate sources for the analysis library. Also emit a tiny program
        useful for testing purposes.

        :param str lib_root: Path of the directory in which the library should
            be generated.

        :param str|None extensions_dir: Directory to contain extensions for
            code generation. If None is provided, assume there is no extension.

        :param set[str] main_source_dirs: List of source directories to use in
            the project file for mains. Source directories must be relative to
            the mains project file directory (i.e. $BUILD/src).

        :param set[str] main_programs: List of names for programs to build in
            addition to the generated library. To each X program, there must be
            a X.adb source file in the $BUILD/src directory.

        :param bool no_property_checks: If True, do not emit safety checks in
            the generated code for properties. Namely, this disables null
            checks on field access.

        :param bool generate_astdoc: Whether to generate the HTML documentation
            for AST nodes, their fields and their properties.

        :param bool generate_gdb_hook: Whether to generate the
            ".debug_gdb_scripts" section. Good for debugging, but better to
            disable for releases.

        :param bool pretty_print: If true, pretty-print the generated sources.

        :param post_process_ada: Optional post-processing for generated Ada
            source code.
        :type post_process_ada: None|(str) -> str

        :param post_process_cpp: Optional post-processing for generated C++
            source code.
        :type post_process_cpp: None|(str) -> str

        :param post_process_python: Optional post-processing for generated
            Python source code.
        :type post_process_python: None|(str) -> str
        """
        self.context = context
        self.verbosity = context.verbosity

        self.lib_root = lib_root
        self.cache = Cache(os.path.join(self.lib_root, 'obj', 'langkit_cache'))

        self.extensions_dir = extensions_dir

        # TODO: contain the add_template_dir calls to this context (i.e. avoid
        # global mutation).

        if self.extensions_dir:
            add_template_dir(self.extensions_dir)

        for dirpath in keep(self.context.template_lookup_extra_dirs):
            add_template_dir(dirpath)

        self.no_property_checks = no_property_checks
        self.generate_astdoc = generate_astdoc
        self.generate_gdb_hook = generate_gdb_hook
        self.pretty_print = pretty_print
        self.post_process_ada = post_process_ada
        self.post_process_cpp = post_process_cpp
        self.post_process_python = post_process_python

        # Automatically add all source files in the "extensions/src" directory
        # to the generated library project.
        self.extensions_src_dir = None
        if self.extensions_dir:
            src_dir = path.join(self.extensions_dir, 'src')
            if path.isdir(src_dir):
                self.extensions_src_dir = src_dir
                for filename in os.listdir(src_dir):
                    filepath = path.join(src_dir, filename)
                    if path.isfile(filepath) and not filename.startswith('.'):
                        self.context.additional_source_files.append(filepath)

        self.main_source_dirs = main_source_dirs
        self.main_programs = main_programs

        self.lib_name_low = context.ada_api_settings.lib_name.lower()
        """
        Lower-case name for the generated library.
        """

        # Paths for the various directories in which code is generated
        self.include_path = path.join(self.lib_root, 'include')
        self.src_path = path.join(self.lib_root, 'include', self.lib_name_low)
        self.lib_path = path.join(self.lib_root, 'lib')
        self.share_path = path.join(self.lib_root, 'share', self.lib_name_low)
        self.python_path = path.join(self.lib_root, 'python')

        self.dfa_code = None
        """