Coverage for apio / scons / apio_env.py: 98%
68 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-24 01:53 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-24 01:53 +0000
1# -*- coding: utf-8 -*-
2# -- This file is part of the Apio project
3# -- (C) 2016-2018 FPGAwars
4# -- Author Jesús Arroyo
5# -- License GPLv2
6# -- Derived from:
7# ---- Platformio project
8# ---- (C) 2014-2016 Ivan Kravets <me@ikravets.com>
9# ---- License Apache v2
10"""A class with common services for the apio scons handlers."""
13import os
14from typing import List, Optional
15from SCons.Script.SConscript import SConsEnvironment
16from SCons.Environment import BuilderWrapper
17import SCons.Defaults
18from apio.common.apio_console import cout
19from apio.common.apio_styles import EMPH3
20from apio.common.common_util import env_build_path
21from apio.common.proto.apio_pb2 import SconsParams
24class ApioEnv:
25 """Provides abstracted scons env and other user services."""
27 def __init__(
28 self,
29 command_line_targets: List[str],
30 scons_params: SconsParams,
31 ):
32 # -- Save the arguments.
33 self.command_line_targets = command_line_targets
34 self.params = scons_params
36 # -- Create the base target.
37 self.target = str(self.env_build_path / "hardware")
39 # -- Create the target for the graph files (.dot, .svg, etc)
40 self.graph_target = str(self.env_build_path / "graph")
42 # -- Create the underlying scons env.
43 self.scons_env = SConsEnvironment(ENV=os.environ, tools=[])
45 # -- Set the location of the scons incremental build database.
46 # -- By default it would be stored in project root dir.
47 self.scons_env.SConsignFile(
48 self.env_build_path.absolute() / "sconsign.dblite"
49 )
51 # -- Since we ae not using the default environment, make sure it was
52 # -- not used unintentionally, e.g. in tests that run create multiple
53 # -- scons env in the same session.
54 # --
55 assert (
56 SCons.Defaults._default_env is None
57 ), "DefaultEnvironment already exists"
59 # Extra info for debugging.
60 if self.is_debug(2):
61 cout(f"command_line_targets: {command_line_targets}")
62 self.dump_env_vars()
64 @property
65 def env_name(self):
66 """Return the action apio env name for this invocation."""
67 return self.params.apio_env_params.env_name
69 @property
70 def env_build_path(self):
71 """Returns a relative path from the project dir to the env build
72 dir."""
73 return env_build_path(self.env_name)
75 @property
76 def is_windows(self):
77 """Returns True if we run on windows."""
78 return self.params.environment.is_windows
80 def is_debug(self, level: int):
81 """Returns true if we run in debug mode."""
82 return self.params.environment.debug_level >= level
84 @property
85 def platform_id(self):
86 """Returns the platform id."""
87 return self.params.environment.platform_id
89 @property
90 def scons_shell_id(self):
91 """Returns the shell id that scons is expected to use.."""
92 return self.params.environment.scons_shell_id
94 def targeting(self, *target_names) -> bool:
95 """Returns true if the any of the named target was specified in the
96 scons command line."""
97 for target_name in target_names:
98 if target_name in self.command_line_targets:
99 return True
100 return False
102 def builder(self, builder_id: str, builder):
103 """Append to the scons env a builder with given id. The env
104 adds it to the BUILDERS dict and also adds to itself an attribute with
105 that name that contains a wrapper to that builder."""
106 self.scons_env.Append(BUILDERS={builder_id: builder})
108 def builder_target(
109 self,
110 *,
111 builder_id: str,
112 target,
113 sources: List,
114 extra_dependencies: Optional[List] = None,
115 always_build: bool = False,
116 ):
117 """Creates an return a target that uses the builder with given id."""
119 # pylint: disable=too-many-arguments
121 # -- Scons wraps the builder with a wrapper. We use it to create the
122 # -- new target.
123 builder_wrapper: BuilderWrapper = getattr(self.scons_env, builder_id)
124 target = builder_wrapper(target, sources)
125 # -- Mark as 'always build' if requested.
126 if always_build:
127 self.scons_env.AlwaysBuild(target)
128 # -- Add extra dependencies, if any.
129 if extra_dependencies:
130 for dependency in extra_dependencies:
131 self.scons_env.Depends(target, dependency)
132 return target
134 def alias(self, name, *, source, action=None, always_build: bool = False):
135 """Creates a target with given dependencies"""
136 target = self.scons_env.Alias(name, source, action)
137 if always_build:
138 self.scons_env.AlwaysBuild(target)
139 return target
141 def dump_env_vars(self) -> None:
142 """Prints a list of the environment variables. For debugging."""
143 dictionary = self.scons_env.Dictionary()
144 keys = list(dictionary.keys())
145 keys.sort()
146 cout("")
147 cout(">>> Env vars BEGIN", style=EMPH3)
148 for key in keys:
149 cout(f"{key} = {self.scons_env[key]}")
150 cout("<<< Env vars END\n", style=EMPH3)