2023-02-15 14:50:35 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
2023-12-20 11:00:49 +00:00
|
|
|
import dataclasses
|
2016-02-10 13:19:29 +01:00
|
|
|
import os
|
2020-01-02 14:46:11 +01:00
|
|
|
import os.path as P
|
2024-10-14 09:47:37 +00:00
|
|
|
import shlex
|
2016-02-10 13:19:29 +01:00
|
|
|
import shutil
|
2016-04-12 13:08:38 +02:00
|
|
|
import subprocess
|
2017-04-11 12:28:57 +02:00
|
|
|
import sys
|
2024-07-24 08:52:55 +00:00
|
|
|
import traceback
|
2022-07-04 14:32:53 +00:00
|
|
|
from typing import List, Optional, Set
|
2016-02-10 13:19:29 +01:00
|
|
|
|
2018-09-13 14:54:29 +02:00
|
|
|
import langkit
|
2018-02-27 11:17:30 +01:00
|
|
|
import langkit.compile_context
|
2024-01-10 15:21:03 +01:00
|
|
|
from langkit.compile_context import (
|
2024-10-14 09:47:37 +00:00
|
|
|
CacheCollectionConf, CompileCtx, LibraryEntity, UnparseScript
|
2024-01-10 15:21:03 +01:00
|
|
|
)
|
2020-01-02 14:46:11 +01:00
|
|
|
from langkit.diagnostics import DiagnosticError, Diagnostics, WarningSet
|
2016-04-12 13:08:38 +02:00
|
|
|
from langkit.libmanage import ManageScript
|
2016-02-10 13:19:29 +01:00
|
|
|
|
2020-05-29 12:12:57 +02:00
|
|
|
from drivers.valgrind import valgrind_cmd
|
2018-07-30 10:33:33 +02:00
|
|
|
|
2016-02-10 13:19:29 +01:00
|
|
|
|
2022-04-14 12:10:48 +02:00
|
|
|
python_support_dir = P.dirname(P.abspath(__file__))
|
2022-11-09 14:08:06 +00:00
|
|
|
c_support_dir = P.join(python_support_dir, "..", "c_support")
|
2022-04-14 12:10:48 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
Diagnostics.blacklisted_paths.append(python_support_dir)
|
2020-01-02 14:46:11 +01:00
|
|
|
|
|
|
|
|
|
2017-09-20 15:27:08 +02:00
|
|
|
default_warning_set = WarningSet()
|
|
|
|
|
|
2019-01-29 15:13:15 +01:00
|
|
|
# We don't want to be forced to provide dummy docs for nodes and public
|
|
|
|
|
# properties in testcases.
|
|
|
|
|
default_warning_set.disable(WarningSet.undocumented_nodes)
|
2017-09-20 15:29:11 +02:00
|
|
|
default_warning_set.disable(WarningSet.undocumented_public_properties)
|
|
|
|
|
|
2017-11-22 14:44:26 +01:00
|
|
|
pretty_print = bool(int(os.environ.get('LANGKIT_PRETTY_PRINT', '0')))
|
|
|
|
|
|
2017-11-15 09:50:25 +01:00
|
|
|
project_template = """
|
|
|
|
|
with "libfoolang";
|
|
|
|
|
|
|
|
|
|
project Gen is
|
2022-10-20 11:55:22 +00:00
|
|
|
for Languages use ({languages});
|
2022-11-09 14:08:06 +00:00
|
|
|
for Source_Dirs use ({source_dirs});
|
2017-11-15 09:50:25 +01:00
|
|
|
for Object_Dir use "obj";
|
2018-02-13 11:18:20 +01:00
|
|
|
for Main use ({main_sources});
|
2017-11-15 09:50:25 +01:00
|
|
|
|
|
|
|
|
package Compiler is
|
|
|
|
|
for Default_Switches ("Ada") use
|
|
|
|
|
("-g", "-O0", "-gnata", "-gnatwae", "-gnatyg");
|
2023-05-17 16:15:48 +02:00
|
|
|
for Default_Switches ("C") use
|
|
|
|
|
("-g", "-O0", "-Wall", "-W", "-Werror", "-pedantic");
|
2017-11-15 09:50:25 +01:00
|
|
|
end Compiler;
|
2024-05-21 15:10:56 +00:00
|
|
|
|
|
|
|
|
package Binder is
|
|
|
|
|
for Switches ("Ada") use ("-Es");
|
|
|
|
|
end Binder;
|
2017-11-15 09:50:25 +01:00
|
|
|
end Gen;
|
|
|
|
|
"""
|
|
|
|
|
|
2017-09-20 15:27:08 +02:00
|
|
|
|
2023-12-20 11:00:49 +00:00
|
|
|
@dataclasses.dataclass
|
2024-10-14 09:47:37 +00:00
|
|
|
class Main:
|
2023-12-20 11:00:49 +00:00
|
|
|
source_file: str
|
|
|
|
|
"""
|
|
|
|
|
Basename of the main source file.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
args: list[str] = dataclasses.field(default_factory=list)
|
|
|
|
|
"""
|
|
|
|
|
Arguments to pass to this main when running it.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def label(self) -> str:
|
|
|
|
|
"""
|
|
|
|
|
Return a representation of this main that is suitable to include in
|
|
|
|
|
test baselines.
|
|
|
|
|
"""
|
|
|
|
|
return " ".join([self.source_file] + self.args)
|
|
|
|
|
|
2024-10-14 09:47:37 +00:00
|
|
|
@property
|
|
|
|
|
def unit_name(self) -> str:
|
|
|
|
|
"""
|
|
|
|
|
Return the name of the main source file without extension.
|
|
|
|
|
"""
|
|
|
|
|
return os.path.splitext(self.source_file)[0]
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def parse(cls, value: str) -> Main:
|
|
|
|
|
"""
|
|
|
|
|
Create a Main instance from a shell-encoded list of arguments.
|
|
|
|
|
"""
|
|
|
|
|
argv = shlex.split(value)
|
|
|
|
|
return cls(argv[0], argv[1:])
|
|
|
|
|
|
2023-12-20 11:00:49 +00:00
|
|
|
|
2019-10-11 16:09:03 +02:00
|
|
|
valgrind_enabled = bool(os.environ.get('VALGRIND_ENABLED'))
|
2022-03-14 15:03:48 +01:00
|
|
|
jobs = int(os.environ.get('LANGKIT_JOBS', '1'))
|
2019-10-11 16:09:03 +02:00
|
|
|
|
|
|
|
|
|
2019-03-28 14:22:50 +01:00
|
|
|
# Determine where to find the root directory for Langkit sources
|
|
|
|
|
langkit_root = os.environ.get('LANGKIT_ROOT_DIR')
|
|
|
|
|
if not langkit_root:
|
2020-01-02 14:46:11 +01:00
|
|
|
test_dir = P.dirname(P.abspath(__file__))
|
|
|
|
|
testsuite_dir = P.dirname(test_dir)
|
|
|
|
|
langkit_root = P.dirname(testsuite_dir)
|
2019-03-28 14:22:50 +01:00
|
|
|
|
|
|
|
|
|
2020-01-21 15:11:13 +01:00
|
|
|
# When unparsing the concrete syntax, name of the file to write
|
|
|
|
|
unparse_destination = 'concrete_syntax.lkt'
|
2020-03-06 04:23:24 -05:00
|
|
|
unparse_script = ('to:{},import:lexer_example,grammar,nodes'
|
|
|
|
|
.format(unparse_destination))
|
|
|
|
|
unparse_all_script = 'to:{},lexer,grammar,nodes'.format(unparse_destination)
|
2020-01-21 15:11:13 +01:00
|
|
|
|
|
|
|
|
|
2020-02-24 17:04:44 +01:00
|
|
|
def prepare_context(grammar=None, lexer=None, lkt_file=None,
|
|
|
|
|
warning_set=default_warning_set,
|
2023-07-28 12:52:10 +00:00
|
|
|
default_unit_provider=None, symbol_canonicalizer=None,
|
|
|
|
|
show_property_logging=False, types_from_lkt=False,
|
|
|
|
|
lkt_semantic_checks=False,
|
2021-01-27 16:24:37 +01:00
|
|
|
case_insensitive: bool = False,
|
|
|
|
|
version: Optional[str] = None,
|
2022-04-01 17:13:54 +02:00
|
|
|
build_date: Optional[str] = None,
|
2022-07-04 14:32:53 +00:00
|
|
|
standalone: bool = False,
|
2023-12-05 08:26:46 +00:00
|
|
|
property_exceptions: Set[str] = set(),
|
2024-01-10 15:21:03 +01:00
|
|
|
generate_unparser: bool = False,
|
2024-05-23 12:00:07 +00:00
|
|
|
default_unparsing_config: str | None = None,
|
2024-01-10 15:21:03 +01:00
|
|
|
cache_coll_conf: Optional[CacheCollectionConf] = None):
|
2016-04-04 18:25:59 +02:00
|
|
|
"""
|
2016-04-12 13:08:38 +02:00
|
|
|
Create a compile context and prepare the build directory for code
|
|
|
|
|
generation.
|
2016-04-04 18:25:59 +02:00
|
|
|
|
2016-04-12 13:08:38 +02:00
|
|
|
:param langkit.parsers.Grammar grammar: The language grammar to use for
|
|
|
|
|
this context.
|
|
|
|
|
|
|
|
|
|
:param langkit.lexer.Lexer lexer: The language lexer to use for this
|
|
|
|
|
context.
|
2017-09-20 15:27:08 +02:00
|
|
|
|
2020-02-24 17:04:44 +01:00
|
|
|
:param str|None lkt_file: If provided, file from which to read the Lkt
|
|
|
|
|
language spec.
|
|
|
|
|
|
2017-09-20 15:27:08 +02:00
|
|
|
:param WarningSet warning_set: Set of warnings to emit.
|
2018-08-13 12:35:12 +02:00
|
|
|
|
2023-07-28 12:52:10 +00:00
|
|
|
:param langkit.compile_context.LibraryEntity|None default_unit_provider:
|
|
|
|
|
Default unit provider to use for this context, if any.
|
|
|
|
|
|
2018-08-13 12:35:12 +02:00
|
|
|
:param langkit.compile_context.LibraryEntity|None symbol_canonicalizer:
|
2020-01-07 15:05:23 +01:00
|
|
|
Symbol canonicalizer to use for this context, if any.
|
2020-01-07 15:03:39 +01:00
|
|
|
|
|
|
|
|
:param bool show_property_logging: See CompileCtx.show_property_logging.
|
2020-06-08 15:19:25 +02:00
|
|
|
|
|
|
|
|
:param bool types_from_lkt: See CompileCtx.types_from_lkt.
|
2021-01-20 10:28:04 +01:00
|
|
|
|
|
|
|
|
:param case_insensitive: See CompileCtx's constructor.
|
2021-01-27 16:24:37 +01:00
|
|
|
|
|
|
|
|
:param version: See CompileCtx's constructor.
|
|
|
|
|
|
|
|
|
|
:param build_date: See CompileCtx's constructor.
|
2022-04-01 17:13:54 +02:00
|
|
|
|
|
|
|
|
:param standalone: See CompileCtx's constructor.
|
2023-12-05 08:26:46 +00:00
|
|
|
|
|
|
|
|
:param generate_unparser: See CompileCtx's constructor.
|
2024-01-10 15:21:03 +01:00
|
|
|
|
2024-05-23 12:00:07 +00:00
|
|
|
:param default_unparsing_config: See the homonym CompileCtx constructor
|
|
|
|
|
argument.
|
|
|
|
|
|
2024-01-10 15:21:03 +01:00
|
|
|
:param cache_coll_conf: See CompileCtx's ``cache_collection_conf``
|
|
|
|
|
constructor argument.
|
2016-04-04 18:25:59 +02:00
|
|
|
"""
|
2016-04-12 13:08:38 +02:00
|
|
|
|
2016-02-10 13:19:29 +01:00
|
|
|
# Have a clean build directory
|
2020-01-02 14:46:11 +01:00
|
|
|
if P.exists('build'):
|
2016-02-10 13:19:29 +01:00
|
|
|
shutil.rmtree('build')
|
|
|
|
|
os.mkdir('build')
|
|
|
|
|
|
|
|
|
|
# Try to emit code
|
2024-05-23 12:00:07 +00:00
|
|
|
ctx = CompileCtx(
|
|
|
|
|
lang_name='Foo', short_name='foo', lexer=lexer, grammar=grammar,
|
|
|
|
|
default_unit_provider=default_unit_provider,
|
|
|
|
|
symbol_canonicalizer=symbol_canonicalizer,
|
|
|
|
|
show_property_logging=show_property_logging,
|
|
|
|
|
lkt_file=lkt_file,
|
|
|
|
|
types_from_lkt=types_from_lkt,
|
|
|
|
|
lkt_semantic_checks=lkt_semantic_checks,
|
|
|
|
|
case_insensitive=case_insensitive,
|
|
|
|
|
version=version,
|
|
|
|
|
build_date=build_date,
|
|
|
|
|
standalone=standalone,
|
|
|
|
|
property_exceptions=property_exceptions,
|
|
|
|
|
generate_unparser=generate_unparser,
|
|
|
|
|
default_unparsing_config=default_unparsing_config,
|
|
|
|
|
cache_collection_conf=cache_coll_conf,
|
|
|
|
|
)
|
2017-09-20 15:27:08 +02:00
|
|
|
ctx.warnings = warning_set
|
2017-11-22 14:44:26 +01:00
|
|
|
ctx.pretty_print = pretty_print
|
2016-04-12 13:08:38 +02:00
|
|
|
|
|
|
|
|
return ctx
|
|
|
|
|
|
|
|
|
|
|
2020-02-24 17:04:44 +01:00
|
|
|
def emit_and_print_errors(grammar=None, lexer=None, lkt_file=None,
|
2018-04-06 11:14:48 +02:00
|
|
|
warning_set=default_warning_set,
|
2020-01-21 15:11:13 +01:00
|
|
|
generate_unparser=False, symbol_canonicalizer=None,
|
2020-11-24 14:53:24 +01:00
|
|
|
unparse_script=None,
|
2023-11-29 15:57:48 +00:00
|
|
|
version=None,
|
|
|
|
|
build_date=None,
|
2021-11-29 18:10:16 +00:00
|
|
|
explicit_passes_triggers={},
|
2022-02-24 14:36:11 +00:00
|
|
|
lkt_semantic_checks=False,
|
|
|
|
|
types_from_lkt: bool = False):
|
2016-04-12 13:08:38 +02:00
|
|
|
"""
|
2020-11-24 14:53:24 +01:00
|
|
|
Compile and emit code the given set of arguments. Return the compile
|
|
|
|
|
context if this was successful, None otherwise.
|
2016-04-12 13:08:38 +02:00
|
|
|
|
2017-08-10 15:45:13 +02:00
|
|
|
:param langkit.parsers.Grammar grammar_fn: The language grammar to use.
|
2016-05-02 12:52:56 +02:00
|
|
|
|
|
|
|
|
:param langkit.lexer.Lexer lexer: The lexer to use along with the grammar.
|
2017-11-15 09:30:43 +01:00
|
|
|
Use `lexer_example.foo_lexer` if left to None.
|
2016-05-02 12:52:56 +02:00
|
|
|
|
2020-02-24 17:04:44 +01:00
|
|
|
:param str|None lkt_file: If provided, file from which to read the Lkt
|
|
|
|
|
language spec.
|
|
|
|
|
|
2017-09-20 15:27:08 +02:00
|
|
|
:param WarningSet warning_set: Set of warnings to emit.
|
|
|
|
|
|
2018-04-06 11:14:48 +02:00
|
|
|
:param bool generate_unparser: Whether to generate unparser.
|
|
|
|
|
|
2018-08-13 12:35:12 +02:00
|
|
|
:param langkit.compile_context.LibraryEntity|None symbol_canonicalizer:
|
|
|
|
|
Symbol canoncalizes to use for this context, if any.
|
|
|
|
|
|
2019-09-18 14:47:49 +02:00
|
|
|
:rtype: None|langkit.compile_context.CompileCtx
|
2020-01-21 15:11:13 +01:00
|
|
|
|
2020-03-05 09:28:43 -05:00
|
|
|
:param None|str unparse_script: Script to unparse the language spec.
|
2022-02-24 14:36:11 +00:00
|
|
|
|
2023-11-29 15:57:48 +00:00
|
|
|
:param version: See CompileCtx's constructor.
|
|
|
|
|
|
|
|
|
|
:param build_date: See CompileCtx's constructor.
|
|
|
|
|
|
2022-02-24 14:36:11 +00:00
|
|
|
:param types_from_lkt: See CompileCtx.types_from_lkt.
|
2022-07-04 14:32:53 +00:00
|
|
|
|
|
|
|
|
:param property_exceptions: See CompileCtx's constructor.
|
2016-04-12 13:08:38 +02:00
|
|
|
"""
|
2017-01-15 19:00:02 +01:00
|
|
|
|
2016-02-10 13:19:29 +01:00
|
|
|
try:
|
2023-11-29 15:57:48 +00:00
|
|
|
ctx = prepare_context(
|
|
|
|
|
grammar,
|
|
|
|
|
lexer,
|
|
|
|
|
lkt_file,
|
|
|
|
|
warning_set,
|
|
|
|
|
symbol_canonicalizer=symbol_canonicalizer,
|
|
|
|
|
types_from_lkt=types_from_lkt,
|
|
|
|
|
lkt_semantic_checks=lkt_semantic_checks,
|
|
|
|
|
version=version,
|
|
|
|
|
build_date=build_date,
|
2023-12-05 08:26:46 +00:00
|
|
|
generate_unparser=generate_unparser,
|
2023-11-29 15:57:48 +00:00
|
|
|
)
|
2020-11-24 14:53:24 +01:00
|
|
|
ctx.create_all_passes(
|
2023-12-05 08:26:46 +00:00
|
|
|
'build',
|
2020-11-24 14:53:24 +01:00
|
|
|
unparse_script=(UnparseScript(unparse_script)
|
|
|
|
|
if unparse_script else None),
|
|
|
|
|
explicit_passes_triggers=explicit_passes_triggers
|
|
|
|
|
)
|
|
|
|
|
ctx.emit()
|
2016-02-10 13:19:29 +01:00
|
|
|
# ... and tell about how it went
|
2016-03-25 12:02:04 +01:00
|
|
|
except DiagnosticError:
|
|
|
|
|
# If there is a diagnostic error, don't say anything, the diagnostics
|
|
|
|
|
# are enough.
|
2019-09-18 14:47:49 +02:00
|
|
|
return None
|
2016-02-10 13:19:29 +01:00
|
|
|
else:
|
2017-02-24 10:26:56 +01:00
|
|
|
print('Code generation was successful')
|
2019-09-18 14:47:49 +02:00
|
|
|
return ctx
|
2016-05-02 12:52:56 +02:00
|
|
|
finally:
|
2020-03-05 04:17:15 -05:00
|
|
|
if lexer is not None:
|
|
|
|
|
lexer._dfa_code = None
|
2018-09-13 14:54:29 +02:00
|
|
|
langkit.reset()
|
2016-03-16 18:06:40 +01:00
|
|
|
|
|
|
|
|
|
2024-10-14 09:47:37 +00:00
|
|
|
def build_and_run(
|
|
|
|
|
lkt_file: str,
|
|
|
|
|
generate_unparser: bool = False,
|
|
|
|
|
default_unparsing_config: str | None = None,
|
|
|
|
|
default_unit_provider: LibraryEntity | None = None,
|
|
|
|
|
symbol_canonicalizer: LibraryEntity | None = None,
|
|
|
|
|
show_property_logging: bool = False,
|
|
|
|
|
case_insensitive: bool = False,
|
|
|
|
|
version: str | None = None,
|
|
|
|
|
build_date: str | None = None,
|
|
|
|
|
property_exceptions: Set[str] = set(),
|
|
|
|
|
cache_collection_conf: Optional[CacheCollectionConf] = None,
|
|
|
|
|
py_script: str | None = None,
|
|
|
|
|
py_args: list[str] | None = None,
|
|
|
|
|
gpr_mains: list[Main] | None = None,
|
|
|
|
|
ocaml_main: Main | None = None,
|
|
|
|
|
java_main: Main | None = None,
|
|
|
|
|
ni_main: Main | None = None,
|
|
|
|
|
) -> None:
|
2016-04-12 13:08:38 +02:00
|
|
|
"""
|
2018-02-13 11:18:20 +01:00
|
|
|
Compile and emit code for `ctx` and build the generated library. Then,
|
|
|
|
|
execute the provided scripts/programs, if any.
|
2016-04-12 13:08:38 +02:00
|
|
|
|
|
|
|
|
An exception is raised if any step fails (the script must return code 0).
|
2017-09-20 15:27:08 +02:00
|
|
|
|
2024-10-14 09:47:37 +00:00
|
|
|
:param lkt_file: If provided, file from which to read the Lkt language
|
|
|
|
|
spec.
|
|
|
|
|
:param generate_unparser: Whether to generate unparser.
|
2024-05-23 12:00:07 +00:00
|
|
|
:param default_unparsing_config: See the homonym CompileCtx constructor
|
|
|
|
|
argument.
|
2024-10-14 09:47:37 +00:00
|
|
|
:param default_unit_provider: Default unit provider to use for this
|
|
|
|
|
context, if any.
|
|
|
|
|
:param symbol_canonicalizer: Symbol canonicalizer to use for this context,
|
|
|
|
|
if any.
|
|
|
|
|
:param show_property_logging: If true, any property that has been marked
|
|
|
|
|
with tracing activated will be traced on stdout by default, without
|
|
|
|
|
need for any config file.
|
2021-01-20 10:28:04 +01:00
|
|
|
:param case_insensitive: See CompileCtx's constructor.
|
2021-01-27 16:24:37 +01:00
|
|
|
:param version: See CompileCtx's constructor.
|
|
|
|
|
:param build_date: See CompileCtx's constructor.
|
2024-10-14 09:47:37 +00:00
|
|
|
:param property_exceptions: See CompileCtx's constructor.
|
|
|
|
|
:param cache_collection_conf: See CompileCtx's constructor.
|
|
|
|
|
:param py_script: If not None, name of the Python script to run with the
|
|
|
|
|
built library available.
|
2021-03-26 09:14:52 -04:00
|
|
|
:param python_args: Arguments to pass to the Python interpreter when
|
|
|
|
|
running a Python script.
|
2024-10-14 09:47:37 +00:00
|
|
|
:param gpr_mains: If not None, list of name of mains (Ada and/or C) for the
|
|
|
|
|
generated GPR file, to build and run with the generated library. Each
|
|
|
|
|
main can be either a Main instance or a string (for the main source
|
|
|
|
|
file basename, the main is run without arguments).
|
|
|
|
|
:param ocaml_main: If not None, name of the OCaml source file to build and
|
|
|
|
|
run with the built library available.
|
|
|
|
|
:param java_main: If not None, name of the Java main sourec file to build
|
|
|
|
|
and run with the Langkit Java lib through JNI.
|
|
|
|
|
:param ni_main: If not None, name of the Java main sourec file to build
|
|
|
|
|
and run with the Langkit Java lib through Native Image.
|
2016-04-12 13:08:38 +02:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
class Manage(ManageScript):
|
2020-06-08 15:19:25 +02:00
|
|
|
def __init__(self, ctx):
|
|
|
|
|
self._cached_context = ctx
|
2020-10-22 10:50:51 +02:00
|
|
|
super().__init__(root_dir=os.getcwd())
|
2020-06-08 15:19:25 +02:00
|
|
|
|
2016-04-12 13:08:38 +02:00
|
|
|
def create_context(self, args):
|
2020-06-08 15:19:25 +02:00
|
|
|
return self._cached_context
|
2019-08-27 16:39:38 -04:00
|
|
|
|
2024-07-24 08:52:55 +00:00
|
|
|
# The call to build_and_run in test.py scripts should never be considered
|
|
|
|
|
# as being part of the DSL to create diagnostics.
|
|
|
|
|
for frame in traceback.extract_stack():
|
|
|
|
|
Diagnostics.blacklist_frame(frame)
|
|
|
|
|
|
2019-10-30 07:24:02 -04:00
|
|
|
build_mode = 'dev'
|
2019-08-27 16:39:38 -04:00
|
|
|
|
2022-03-17 10:22:16 +01:00
|
|
|
maven_exec = os.environ.get('MAVEN_EXECUTABLE')
|
|
|
|
|
maven_repo = os.environ.get('MAVEN_LOCAL_REPO')
|
|
|
|
|
|
2024-10-14 09:47:37 +00:00
|
|
|
ctx = prepare_context(
|
|
|
|
|
grammar=None,
|
|
|
|
|
lexer=None,
|
|
|
|
|
lkt_file=lkt_file,
|
|
|
|
|
types_from_lkt=True,
|
|
|
|
|
generate_unparser=generate_unparser,
|
|
|
|
|
default_unparsing_config=default_unparsing_config,
|
|
|
|
|
default_unit_provider=default_unit_provider,
|
|
|
|
|
symbol_canonicalizer=symbol_canonicalizer,
|
|
|
|
|
show_property_logging=show_property_logging,
|
|
|
|
|
case_insensitive=case_insensitive,
|
|
|
|
|
version=version,
|
|
|
|
|
build_date=build_date,
|
|
|
|
|
property_exceptions=property_exceptions,
|
|
|
|
|
cache_coll_conf=cache_collection_conf,
|
|
|
|
|
)
|
|
|
|
|
m = Manage(ctx)
|
|
|
|
|
|
|
|
|
|
extensions_dir = P.abspath('extensions')
|
|
|
|
|
if P.isdir(extensions_dir):
|
|
|
|
|
ctx.extensions_dir = extensions_dir
|
|
|
|
|
|
|
|
|
|
# First build the library. Forward all test.py's arguments to the libmanage
|
|
|
|
|
# call so that manual testcase runs can pass "-g", for instance.
|
|
|
|
|
argv = (
|
|
|
|
|
['make']
|
|
|
|
|
+ sys.argv[1:]
|
|
|
|
|
+ ['-vnone', f'-j{jobs}', "--full-error-traces"]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# If there is a Java main, enable the Java bindings building
|
|
|
|
|
if java_main is not None or ni_main is not None:
|
|
|
|
|
argv.append('--enable-java')
|
|
|
|
|
if maven_exec:
|
|
|
|
|
argv.append('--maven-executable')
|
|
|
|
|
argv.append(maven_exec)
|
|
|
|
|
if maven_repo:
|
|
|
|
|
argv.append('--maven-local-repo')
|
|
|
|
|
argv.append(maven_repo)
|
|
|
|
|
if ni_main is not None and os.name == 'nt':
|
|
|
|
|
argv.append('--generate-msvc-lib')
|
|
|
|
|
|
|
|
|
|
argv.append('--build-mode={}'.format(build_mode))
|
|
|
|
|
for w in WarningSet.available_warnings:
|
|
|
|
|
argv.append(
|
|
|
|
|
'-{}{}'.format('W' if w in ctx.warnings else 'w', w.name)
|
2024-05-23 12:00:07 +00:00
|
|
|
)
|
2024-10-14 09:47:37 +00:00
|
|
|
if not pretty_print:
|
|
|
|
|
argv.append('--no-pretty-print')
|
2019-08-27 16:39:38 -04:00
|
|
|
|
2024-10-14 09:47:37 +00:00
|
|
|
# No testcase uses the generated mains, so save time: never build them
|
|
|
|
|
argv.append('--disable-all-mains')
|
2020-01-09 12:55:00 +01:00
|
|
|
|
2024-10-14 09:47:37 +00:00
|
|
|
return_code = m.run_no_exit(argv)
|
2016-04-12 13:08:38 +02:00
|
|
|
|
2024-10-14 09:47:37 +00:00
|
|
|
# Flush stdout and stderr, so that diagnostics appear deterministically
|
|
|
|
|
# before the script/program output.
|
|
|
|
|
sys.stdout.flush()
|
|
|
|
|
sys.stderr.flush()
|
2020-06-08 15:19:25 +02:00
|
|
|
|
2024-10-14 09:47:37 +00:00
|
|
|
if return_code != 0:
|
|
|
|
|
raise DiagnosticError()
|
2017-11-22 12:51:32 +01:00
|
|
|
|
2017-02-16 15:22:12 +01:00
|
|
|
# Write a "setenv" script to make developper investigation convenient
|
|
|
|
|
with open('setenv.sh', 'w') as f:
|
2020-11-25 16:54:56 +01:00
|
|
|
m.write_setenv(f)
|
2017-02-16 15:22:12 +01:00
|
|
|
|
2020-11-25 16:54:56 +01:00
|
|
|
env = m.derived_env()
|
2017-11-15 09:50:25 +01:00
|
|
|
|
2019-10-11 16:09:03 +02:00
|
|
|
def run(*argv, **kwargs):
|
2023-05-19 10:19:54 +02:00
|
|
|
subp_env = kwargs.pop("env", env)
|
2019-10-11 16:09:03 +02:00
|
|
|
valgrind = kwargs.pop('valgrind', False)
|
|
|
|
|
suppressions = kwargs.pop('valgrind_suppressions', [])
|
|
|
|
|
assert not kwargs
|
|
|
|
|
|
|
|
|
|
if valgrind_enabled and valgrind:
|
|
|
|
|
argv = valgrind_cmd(list(argv), suppressions)
|
|
|
|
|
|
2023-05-19 10:19:54 +02:00
|
|
|
subprocess.check_call(argv, env=subp_env)
|
2017-11-15 09:50:25 +01:00
|
|
|
|
|
|
|
|
if py_script is not None:
|
2022-04-14 12:10:48 +02:00
|
|
|
# Run the Python script.
|
|
|
|
|
#
|
|
|
|
|
# Note that in order to use the generated library, we have to use the
|
|
|
|
|
# special Python interpreter the testsuite provides us. See the
|
|
|
|
|
# corresponding code in testsuite/drivers/python_driver.py.
|
2021-03-26 09:14:52 -04:00
|
|
|
args = [os.environ['PYTHON_INTERPRETER']]
|
2024-10-14 09:47:37 +00:00
|
|
|
if py_args:
|
|
|
|
|
args.extend(py_args)
|
2022-04-14 12:10:48 +02:00
|
|
|
|
|
|
|
|
# Also note that since Python 3.8, we need special PATH processing for
|
|
|
|
|
# DLLs: see the path_wrapper.py script.
|
|
|
|
|
args.append(P.join(python_support_dir, "path_wrapper.py"))
|
|
|
|
|
|
2021-03-26 09:14:52 -04:00
|
|
|
args.append(py_script)
|
|
|
|
|
run(*args)
|
2017-11-15 09:50:25 +01:00
|
|
|
|
2023-05-15 16:43:55 +02:00
|
|
|
if gpr_mains:
|
2024-10-14 09:47:37 +00:00
|
|
|
# Canonicalize mains to Main instances
|
2023-12-20 11:00:49 +00:00
|
|
|
gpr_mains = [
|
2024-10-14 09:47:37 +00:00
|
|
|
(Main(m) if isinstance(m, str) else m) for m in gpr_mains
|
2023-12-20 11:00:49 +00:00
|
|
|
]
|
|
|
|
|
|
2023-05-15 16:43:55 +02:00
|
|
|
source_dirs = [".", c_support_dir]
|
2023-12-20 11:00:49 +00:00
|
|
|
main_source_files = sorted(m.source_file for m in gpr_mains)
|
2018-02-13 11:18:20 +01:00
|
|
|
|
2023-05-15 16:43:55 +02:00
|
|
|
# Detect languages based on the source files present in the test
|
|
|
|
|
# directory.
|
|
|
|
|
langs = set()
|
|
|
|
|
for f in os.listdir("."):
|
|
|
|
|
if any(f.endswith(ext) for ext in [".c", ".h"]):
|
|
|
|
|
langs.add("C")
|
|
|
|
|
if any(f.endswith(ext) for ext in [".adb", ".ads"]):
|
|
|
|
|
langs.add("Ada")
|
2022-10-20 11:55:22 +00:00
|
|
|
|
2023-05-15 16:43:55 +02:00
|
|
|
# Generate a project file to build the given mains. Do a static build
|
|
|
|
|
# (the default) to improve the debugging experience.
|
|
|
|
|
with open("gen.gpr", "w") as f:
|
2022-11-09 14:08:06 +00:00
|
|
|
|
|
|
|
|
def fmt_str_list(strings: List[str]) -> str:
|
|
|
|
|
return ", ".join(f'"{s}"' for s in strings)
|
|
|
|
|
|
2018-02-13 11:18:20 +01:00
|
|
|
f.write(project_template.format(
|
2022-11-09 14:08:06 +00:00
|
|
|
languages=fmt_str_list(langs),
|
|
|
|
|
source_dirs=fmt_str_list(source_dirs),
|
2023-12-20 11:00:49 +00:00
|
|
|
main_sources=fmt_str_list(main_source_files),
|
2018-02-13 11:18:20 +01:00
|
|
|
))
|
2023-05-15 16:43:55 +02:00
|
|
|
run("gprbuild", "-Pgen", "-q", "-p")
|
2018-02-13 11:18:20 +01:00
|
|
|
|
2023-05-15 16:43:55 +02:00
|
|
|
# Now run all mains. If there are more than one main to run, print a
|
|
|
|
|
# heading before each one.
|
|
|
|
|
for i, main in enumerate(gpr_mains):
|
2018-02-13 11:18:20 +01:00
|
|
|
if i > 0:
|
2023-05-15 16:43:55 +02:00
|
|
|
print("")
|
|
|
|
|
if len(gpr_mains) > 1:
|
2023-12-20 11:00:49 +00:00
|
|
|
print(f"== {main.label} ==")
|
2018-02-13 11:18:20 +01:00
|
|
|
sys.stdout.flush()
|
2023-05-15 16:43:55 +02:00
|
|
|
run(
|
2024-10-14 09:47:37 +00:00
|
|
|
P.join("obj", main.unit_name),
|
2023-12-20 11:00:49 +00:00
|
|
|
*main.args,
|
2022-02-23 20:09:39 +00:00
|
|
|
valgrind=True,
|
2023-05-15 16:43:55 +02:00
|
|
|
valgrind_suppressions=["gnat"],
|
|
|
|
|
)
|
2019-02-07 11:53:52 +01:00
|
|
|
|
2019-06-12 16:11:56 +02:00
|
|
|
if ocaml_main is not None:
|
2019-06-21 15:39:22 +02:00
|
|
|
# Set up a Dune project
|
|
|
|
|
with open('dune', 'w') as f:
|
|
|
|
|
f.write("""
|
|
|
|
|
(executable
|
|
|
|
|
(name {})
|
|
|
|
|
(flags (-w -9))
|
|
|
|
|
(libraries {}))
|
2024-10-14 09:47:37 +00:00
|
|
|
""".format(ocaml_main.unit_name, ctx.c_api_settings.lib_name))
|
2019-06-21 15:39:22 +02:00
|
|
|
with open('dune-project', 'w') as f:
|
|
|
|
|
f.write('(lang dune 1.6)')
|
|
|
|
|
|
2019-10-08 14:31:43 +02:00
|
|
|
# Build the ocaml executable
|
|
|
|
|
run('dune', 'build', '--display', 'quiet', '--root', '.',
|
2024-10-14 09:47:37 +00:00
|
|
|
'./{}.exe'.format(ocaml_main.unit_name))
|
2019-06-12 16:11:56 +02:00
|
|
|
|
2019-10-08 14:31:43 +02:00
|
|
|
# Run the ocaml executable
|
2024-10-14 09:47:37 +00:00
|
|
|
run('./_build/default/{}.exe'.format(ocaml_main.unit_name),
|
|
|
|
|
*ocaml_main.args,
|
2019-10-11 16:09:03 +02:00
|
|
|
valgrind=True,
|
|
|
|
|
valgrind_suppressions=['ocaml'])
|
2022-03-02 11:12:52 +00:00
|
|
|
|
2022-03-17 10:22:16 +01:00
|
|
|
if java_main is not None:
|
2023-04-06 10:44:35 +02:00
|
|
|
java_exec = P.realpath(P.join(
|
|
|
|
|
env['JAVA_HOME'],
|
|
|
|
|
'bin',
|
|
|
|
|
'java'
|
|
|
|
|
))
|
2023-03-20 17:58:39 +01:00
|
|
|
cmd = [
|
2023-04-06 10:44:35 +02:00
|
|
|
java_exec,
|
2022-03-17 10:22:16 +01:00
|
|
|
'-Dfile.encoding=UTF-8',
|
2023-03-14 10:47:32 +01:00
|
|
|
f"-Djava.library.path={env['LD_LIBRARY_PATH']}",
|
2023-03-20 17:58:39 +01:00
|
|
|
]
|
2023-04-06 10:44:35 +02:00
|
|
|
if 'graalvm' in env['JAVA_HOME']:
|
2023-03-20 17:58:39 +01:00
|
|
|
cmd.append((
|
|
|
|
|
'--add-opens=org.graalvm.truffle/com.oracle.truffle.api.'
|
|
|
|
|
'strings=ALL-UNNAMED'
|
|
|
|
|
))
|
2024-10-14 09:47:37 +00:00
|
|
|
cmd += [java_main.source_file] + java_main.args
|
2023-03-20 17:58:39 +01:00
|
|
|
run(*cmd)
|
2022-03-17 10:22:16 +01:00
|
|
|
|
2023-03-14 10:47:32 +01:00
|
|
|
if ni_main is not None:
|
|
|
|
|
# Compile the Java tests
|
2023-04-06 10:44:35 +02:00
|
|
|
javac_exec = P.realpath(P.join(
|
|
|
|
|
env['JAVA_HOME'],
|
|
|
|
|
'bin',
|
|
|
|
|
'javac'
|
|
|
|
|
))
|
2024-10-14 09:47:37 +00:00
|
|
|
run(javac_exec, '-encoding', 'utf8', ni_main.source_file)
|
2023-03-14 10:47:32 +01:00
|
|
|
|
2023-05-19 10:19:54 +02:00
|
|
|
# Run native-image to compile the tests. Building Java bindings does
|
|
|
|
|
# not go through GPRbuild, so we must explicitly give access to the
|
|
|
|
|
# generated C header.
|
|
|
|
|
java_env = m.derived_env(direct_c_header=True)
|
2023-03-14 10:47:32 +01:00
|
|
|
ni_exec = P.realpath(P.join(
|
2023-04-06 10:44:35 +02:00
|
|
|
os.environ['GRAAL_HOME'],
|
2023-03-14 10:47:32 +01:00
|
|
|
'bin',
|
2023-05-23 12:22:13 +02:00
|
|
|
('native-image.cmd' if os.name == 'nt' else 'native-image')
|
2023-03-14 10:47:32 +01:00
|
|
|
))
|
|
|
|
|
class_path = os.path.pathsep.join([
|
|
|
|
|
P.realpath('.'),
|
2023-04-06 10:44:35 +02:00
|
|
|
env['CLASSPATH'],
|
2023-03-14 10:47:32 +01:00
|
|
|
])
|
|
|
|
|
run(
|
|
|
|
|
ni_exec,
|
|
|
|
|
'-cp', class_path,
|
2023-03-17 11:42:05 +01:00
|
|
|
'--no-fallback',
|
|
|
|
|
'--macro:truffle',
|
2024-09-27 16:35:31 +02:00
|
|
|
'-H:NumberOfThreads=1',
|
2023-03-14 10:47:32 +01:00
|
|
|
'-H:+BuildOutputSilent',
|
2023-03-17 11:42:05 +01:00
|
|
|
'-H:+ReportExceptionStackTraces',
|
2024-10-14 09:47:37 +00:00
|
|
|
os.path.splitext(ni_main.source_file)[0],
|
2023-03-14 10:47:32 +01:00
|
|
|
'main',
|
2023-05-19 10:19:54 +02:00
|
|
|
env=java_env,
|
2023-03-14 10:47:32 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Run the newly created main
|
2024-10-14 09:47:37 +00:00
|
|
|
run(P.realpath('main'), *ni_main.args)
|
2023-03-14 10:47:32 +01:00
|
|
|
|
2022-03-02 11:12:52 +00:00
|
|
|
|
|
|
|
|
def indent(text: str, prefix: str = " ") -> str:
|
|
|
|
|
"""
|
|
|
|
|
Indent all lines in `text` with the given prefix.
|
|
|
|
|
|
|
|
|
|
:param text: Text to indent.
|
|
|
|
|
:param prefix: Indentation string.
|
|
|
|
|
"""
|
|
|
|
|
return "\n".join(prefix + line for line in text.splitlines())
|