Compare commits

...
12 Commits
17 changed files with 407 additions and 170 deletions
+6 -5
View File
@@ -42,8 +42,8 @@ class GnucDriver(CompilerDriver):
args.extend(options.flags)
if len(options.archives) > 0:
for directory in options.libdirs: args.append(f"-L{str(directory)}")
for archive in options.archives: args.append(f"-l{archive}")
args.extend([f"-L{str(directory)}" for directory in options.libdirs])
args.extend([f"-l{str(archive)}" for archive in options.archives])
cmdstr = ' '.join(args)
# self.logger.info(cmdstr)
@@ -126,8 +126,8 @@ class GnucDriver(CompilerDriver):
args.extend(options.flags)
if len(options.archives) > 0:
for directory in options.libdirs: args.append(f"-L{str(directory)}")
for archive in options.archives: args.append(f"-l{archive}")
args.extend([f"-L{str(directory)}" for directory in options.libdirs])
args.extend([f"-l{str(archive)}" for archive in options.archives])
cmdstr = ' '.join(args)
# self.logger.info(cmdstr)
@@ -174,7 +174,8 @@ class GnucDriver(CompilerDriver):
args = [
f"{compiler}",
f"-c {str(srcpath)}",
f"-o {str(dstpath)}"
f"-o {str(dstpath)}",
f"-MMD -MP -MF {str(dstpath.with_suffix('.d'))}"
]
if options.pic:
args.append("-fPIC")
+12 -12
View File
@@ -16,12 +16,12 @@ class CompilerOptions:
stdcpp: StdCpp = StdCpp.C14
optlevel: Optimization = Optimization.NONE
incdirs: set[Path] = field(default_factory=set)
libdirs: set[Path] = field(default_factory=set)
objfiles: set[Path] = field(default_factory=set)
archives: set[str] = field(default_factory=set)
defines: set[str] = field(default_factory=set)
flags: set[str] = field(default_factory=set)
incdirs: list[Path] = field(default_factory=list)
libdirs: list[Path] = field(default_factory=list)
objfiles: list[Path] = field(default_factory=list)
archives: list[str] = field(default_factory=list)
defines: list[str] = field(default_factory=list)
flags: list[str] = field(default_factory=list)
def __deepcopy__(self, memo) -> Self:
return CompilerOptions(
@@ -30,10 +30,10 @@ class CompilerOptions:
self.stdc,
self.stdcpp,
self.optlevel,
set(self.incdirs),
set(self.libdirs),
set(self.objfiles),
set(self.archives),
set(self.defines),
set(self.flags)
list(self.incdirs),
list(self.libdirs),
list(self.objfiles),
list(self.archives),
list(self.defines),
list(self.flags)
)
+2
View File
@@ -4,6 +4,8 @@ from ..models import Project
from ..models import Target
from ._except import NoProjectFoundError
from ._latest import latest
from ._latest import read_depfile
from ._latest import stale
from ._load import load
+212
View File
@@ -0,0 +1,212 @@
from dataclasses import dataclass
from dataclasses import field
from ..models import Access
from ..models import Accessor
from ..models import Output
from ..models import Project
from ..models import Target
from ._shared import targets_by_name_mapping
from ._shared import tests_by_name_mapping
from ._shared import project_by_targets_mapping
@dataclass
class _FlattenContext:
_incs_list: list[Accessor] = field(init=False, default_factory=list)
_dirs_list: list[Accessor] = field(init=False, default_factory=list)
_opts_list: list[Accessor] = field(init=False, default_factory=list)
_defs_list: list[Accessor] = field(init=False, default_factory=list)
_deps_list: list[Accessor] = field(init=False, default_factory=list)
_libs_list: list[Accessor] = field(init=False, default_factory=list)
_srcs_list: list[Accessor] = field(init=False, default_factory=list)
# Keyed by value so the same entry at different access levels isn't repeated.
_incs_set: set[str] = field(init=False, default_factory=set)
_dirs_set: set[str] = field(init=False, default_factory=set)
_opts_set: set[str] = field(init=False, default_factory=set)
_defs_set: set[str] = field(init=False, default_factory=set)
_deps_set: set[str] = field(init=False, default_factory=set)
_libs_set: set[str] = field(init=False, default_factory=set)
_srcs_set: set[str] = field(init=False, default_factory=set)
@property
def incs(self) -> list[Accessor]:
return self._incs_list
@property
def dirs(self) -> list[Accessor]:
return self._dirs_list
@property
def opts(self) -> list[Accessor]:
return self._opts_list
@property
def defs(self) -> list[Accessor]:
return self._defs_list
@property
def deps(self) -> list[Accessor]:
return self._deps_list
@property
def libs(self) -> list[Accessor]:
return self._libs_list
@property
def srcs(self) -> list[Accessor]:
return self._srcs_list
def inherit_target(self, target: Target) -> None:
for inc in target.incs.includes: self.append_inc(inc)
for drn in target.incs.libraries: self.append_dir(drn)
for opt in target.opts: self.append_opt(opt)
for dfn in target.defs: self.append_def(dfn)
for dep in target.deps: self.append_dep(dep)
for lib in target.libs: self.append_lib(lib)
if target.type == Output.INT:
for src in target.srcs: self.append_src(src)
def append_inc(self, inc: Accessor) -> None:
if inc.level == Access.PRIVATE or str(inc.value) in self._incs_set:
return
self._incs_set.add(str(inc.value))
self._incs_list.insert(0, inc)
def append_dir(self, lib: Accessor) -> None:
if lib.level == Access.PRIVATE or str(lib.value) in self._dirs_set:
return
self._dirs_set.add(str(lib.value))
self._dirs_list.insert(0, lib)
def append_opt(self, opt: Accessor) -> None:
if opt.level == Access.PRIVATE or str(opt.value) in self._opts_set:
return
self._opts_set.add(str(opt.value))
self._opts_list.insert(0, opt)
def append_def(self, dfn: Accessor) -> None:
if dfn.level == Access.PRIVATE or str(dfn.value) in self._defs_set:
return
self._defs_set.add(str(dfn.value))
self._defs_list.insert(0, dfn)
def append_dep(self, dep: Accessor) -> None:
if dep.level == Access.PRIVATE or str(dep.value) in self._deps_set:
return
self._deps_set.add(str(dep.value))
self._deps_list.insert(0, dep)
def append_lib(self, lib: Accessor) -> None:
if lib.level == Access.PRIVATE or str(lib.value) in self._libs_set:
return
self._libs_set.add(str(lib.value))
self._libs_list.insert(0, lib)
def append_src(self, src: Accessor) -> None:
if src.level == Access.PRIVATE or str(src.value) in self._srcs_set:
return
self._srcs_set.add(str(src.value))
self._srcs_list.insert(0, src)
def flatten_targets(project: Project) -> None:
for target in project.targets:
if target._flattend:
continue
_flatten_target(_target_context(project, target), target)
def flatten_tests(project: Project) -> None:
for target in project.tests:
if target._flattend:
continue
context = _FlattenContext()
context.append_inc(Accessor(
level = Access.PRIVATE,
value = project.origination.src("include")
))
context.append_dir(Accessor(
level = Access.PRIVATE,
value = project.destination.libpath
))
_flatten_test(context, target)
def _target_context(project: Project, target: Target) -> _FlattenContext:
context = _FlattenContext()
context.append_inc(Accessor(
level = Access.PUBLIC \
if target.name in project.exports \
else Access.PROTECTED,
value = project.origination.src("include")
))
context.append_dir(Accessor(
level = Access.PUBLIC,
value = project.destination.libpath
))
return context
def _flatten_target(context: _FlattenContext, target: Target) -> None:
if target._flattend:
return
for dependency in target.deps:
if (parent:=targets_by_name_mapping.get(dependency.value)) == None:
raise ValueError(f"No such dependable target: {dependency.value}")
_target_inherit_target(context, parent)
_extend_target(context, target)
def _flatten_test(context: _FlattenContext, target: Target) -> None:
if target._flattend:
return
for dependency in target.deps:
if (parent:=targets_by_name_mapping.get(dependency.value)) == None:
raise ValueError(f"No such dependable target: {dependency.value}")
_test_inherit_target(context, parent)
_extend_target(context, target)
def _extend_target(context: _FlattenContext, target: Target) -> None:
_extend_unique(target.incs.includes, context.incs)
_extend_unique(target.incs.libraries, context.dirs)
_extend_unique(target.opts, context.opts)
_extend_unique(target.defs, context.defs)
_extend_unique(target.deps, context.deps)
_extend_unique(target.libs, context.libs)
_extend_unique(target.srcs, context.srcs)
target._flattend = True
def _extend_unique(dst: list[Accessor], src: list[Accessor]) -> None:
values = {str(v.value) for v in dst}
for accessor in src:
if str(accessor.value) not in values:
values.add(str(accessor.value))
dst.append(accessor)
def _target_inherit_target(context: _FlattenContext, parent: Target) -> None:
if parent.name in tests_by_name_mapping:
raise ValueError("Cannot inherit tests")
_inherit_raw(context, parent)
def _test_inherit_target(context: _FlattenContext, parent: Target) -> None:
_inherit_raw(context, parent)
def _inherit_raw(context: _FlattenContext, parent: Target) -> None:
parent_project = project_by_targets_mapping.get(parent.name)
assert parent_project is not None, "Parent project not mapped!"
# Parents flatten in their own context so the child's entries don't leak into them.
_flatten_target(_target_context(parent_project, parent), parent)
context.inherit_target(parent)
context.append_inc(Accessor(
level = Access.PROTECTED,
value = parent_project.origination.src("include")
))
context.append_dir(Accessor(
level = Access.PROTECTED,
value = parent_project.destination.libpath
))
context.append_lib(Accessor(
level = Access.PROTECTED,
value = parent.name
))
+30 -3
View File
@@ -1,10 +1,37 @@
import re
from pathlib import Path
from typing import Iterable
def latest(src: Path, dst: Path) -> bool:
return not stale(dst, [src])
def stale(dst: Path, inputs: Iterable[Path]) -> bool:
if not Path.exists(dst):
return True
dstmtime = dst.stat().st_mtime
for src in inputs:
if not Path.exists(src) or src.stat().st_mtime >= dstmtime:
return True
return False
srcmtime = src.stat().st_mtime
dstmtime = dst.stat().st_mtime
return srcmtime < dstmtime
def read_depfile(path: Path) -> list[Path]:
if not Path.exists(path):
return []
with open(path, 'r') as file:
text = file.read().replace("\\\n", " ")
# Only the first rule matters, the rest are phony rules from -MP.
rule = text.split("\n", 1)[0]
_, _, prereqs = rule.partition(": ")
paths: list[Path] = []
for token in re.split(r"(?<!\\)\s+", prereqs.strip()):
if len(token) == 0:
continue
token = re.sub(r"\\([ #])", r"\1", token).replace("$$", "$")
paths.append(Path(token))
return paths
+15 -69
View File
@@ -1,18 +1,17 @@
import yaml
from copy import deepcopy
from pathlib import Path
from ..models import Access
from ..models import Accessor
from ..models import Dependency
from ..models import Destination
from ..models import Origination
from ..models import Output
from ..models import Project
from ..models import Target
from ..shell import execute
from .._config import Config
from ._except import NoProjectFoundError
from ._flatten import flatten_targets
from ._flatten import flatten_tests
from ._shared import projects_by_name_mapping
from ._shared import targets_by_name_mapping
from ._shared import tests_by_name_mapping
@@ -37,8 +36,8 @@ def load(path: Path) -> Project:
_collect_required(project)
_collect_targets(project)
_collect_tests(project)
_flatten_targets(project)
_flatten_tests(project)
flatten_targets(project)
flatten_tests(project)
return project
except Exception as rethrowme:
raise rethrowme
@@ -51,7 +50,7 @@ def _collect_profiles(project: Project) -> None:
def _collect_required(project: Project) -> None:
for required in project.requires:
_clone_then_load_required(required)
_load_required(required)
def _collect_targets(project: Project) -> None:
for target in project.targets:
@@ -64,68 +63,12 @@ def _collect_tests(project: Project) -> None:
if test.name not in tests_by_name_mapping:
tests_by_name_mapping[test.name] = test
def _flatten_targets(project: Project) -> None:
for target in project.targets:
_flatten_target(target)
target.incs.includes.add(Accessor(
level = Access.PUBLIC \
if target.name in project.exports \
else Access.PRIVATE,
value = project.origination.src("include")
))
target.incs.libraries.add(Accessor(
level = Access.PUBLIC,
value = project.destination.libpath
))
def _flatten_tests(project: Project) -> None:
for test in project.tests:
_flatten_target(test)
test.incs.includes.add(Accessor(
level = Access.PRIVATE,
value = project.origination.src("include")
))
test.incs.libraries.add(Accessor(
level = Access.PRIVATE,
value = project.destination.libpath
))
def _flatten_target(target: Target) -> None:
for dependency in target.deps:
if (parent:=targets_by_name_mapping.get(dependency.value)) == None:
raise ValueError(f"No such dependable target: {dependency.value}")
_inherit_target(target, parent)
def _inherit_target(target: Target, parent: Target) -> None:
if parent.name in tests_by_name_mapping:
raise ValueError("Cannot inherit tests")
_flatten_target(parent)
target.incs.includes.update([v for v in parent.incs.includes if v.level != Access.PRIVATE])
target.incs.libraries.update([v for v in parent.incs.libraries if v.level != Access.PRIVATE])
parent_project = project_by_targets_mapping.get(parent.name)
assert parent_project is not None, "Parent project not mapped!"
target.incs.includes.add(Accessor(
level = Access.PUBLIC,
value = parent_project.origination.src("include")
))
target.incs.libraries.add(Accessor(
level = Access.PUBLIC,
value = parent_project.destination.libpath
))
target.opts.update([v for v in parent.opts if v.level != Access.PRIVATE])
target.defs.update([v for v in parent.defs if v.level != Access.PRIVATE])
target.deps.update([v for v in parent.deps if v.level != Access.PRIVATE])
target.libs.update([v for v in parent.libs if v.level != Access.PRIVATE])
target.libs.add(Accessor(
level = Access.PUBLIC,
value = parent.name
))
if parent.type == Output.INT:
target.srcs.update([v for v in parent.srcs if v.level != Access.PRIVATE])
def _load_required(required: Dependency) -> None:
# Determine if local then load or clone then load.
if required.local:
load(Path(required.remote))
return
_clone_then_load_required(required)
def _clone_then_load_required(required: Dependency) -> None:
reqpath = Config.config_directory / required.cid
@@ -146,6 +89,9 @@ def _clone_required(
global errstr
errstr = stderr
from .._logger import logger
logger.info(f"Cloning {required.remote}...")
execute(
f"git clone -b {required.branch} --depth 1 {required.remote} {reqpath}",
handle_success,
+9 -2
View File
@@ -1,6 +1,7 @@
import yaml
from dataclasses import dataclass
from dataclasses import field
from typing import ClassVar
from typing import Self
@@ -15,7 +16,13 @@ class Dependency(yaml.YAMLError):
yaml_tag: ClassVar[str] = u"!dependency"
remote: str
branch: Branch
branch: Branch = field(default="main")
local: bool = field(default=False)
def __post_init__(self) -> None:
from urllib.parse import urlparse
url = urlparse(self.remote)
self.local = not self.remote.startswith("git@") and not url.scheme
@property
def cid(self) -> str:
@@ -27,7 +34,7 @@ class Dependency(yaml.YAMLError):
path = parsed.path.strip("/")
if path.endswith(".git"):
path = path[:-4]
return path + str(self.branch)
return path + "@" + str(self.branch)
@classmethod
def to_dict(cls, data: Self) -> dict:
+5 -8
View File
@@ -24,21 +24,15 @@ class Destination:
def objpath(self) -> Path:
return self._objpath
def __init__(self, outpath: Path, mkdirs=True) -> None:
def __init__(self, outpath: Path) -> None:
self._root = outpath / ".chinook"
self._binpath = self._root / "bin"
self._libpath = self._root / "lib"
self._objpath = self._root / "obj"
if mkdirs:
self._root.mkdir(parents=True, exist_ok=True)
self._binpath.mkdir(parents=True, exist_ok=True)
self._libpath.mkdir(parents=True, exist_ok=True)
self._objpath.mkdir(parents=True, exist_ok=True)
@staticmethod
def cwd() -> 'Destination':
return Destination(Path.cwd(), mkdirs=False)
return Destination(Path.cwd())
def bin(self, file: str) -> Path:
return self.binpath / file
@@ -51,3 +45,6 @@ class Destination:
def obj(self, file: Path) -> Path:
return self.objpath / f"{file}.o"
def dep(self, file: Path) -> Path:
return self.objpath / f"{file}.d"
+4 -4
View File
@@ -16,8 +16,8 @@ class Includes(yaml.YAMLObject):
yaml_loader: ClassVar[Any] = yaml.SafeLoader
yaml_tag: ClassVar[str] = u"!includes"
includes: set[Accessor] = field(default_factory=set)
libraries: set[Accessor] = field(default_factory=set)
includes: list[Accessor] = field(default_factory=list)
libraries: list[Accessor] = field(default_factory=list)
@classmethod
def to_dict(cls, data: Self) -> dict:
@@ -38,8 +38,8 @@ class Includes(yaml.YAMLObject):
@classmethod
def from_dict(cls, data: dict) -> Self:
return cls(**{
"includes": set(Accessor.from_list(data.get("includes", []))),
"libraries": set(Accessor.from_list(data.get("libraries", [])))
"includes": Accessor.from_list(data.get("includes", [])),
"libraries": Accessor.from_list(data.get("libraries", []))
})
@classmethod
+27 -10
View File
@@ -21,14 +21,31 @@ class Target(yaml.YAMLObject):
name: str
type: Output
incs: Includes
opts: set[Accessor] = field(default_factory=set)
defs: set[Accessor] = field(default_factory=set)
deps: set[Accessor] = field(default_factory=set)
libs: set[Accessor] = field(default_factory=set)
srcs: set[Accessor] = field(default_factory=set)
opts: list[Accessor] = field(default_factory=list)
defs: list[Accessor] = field(default_factory=list)
deps: list[Accessor] = field(default_factory=list)
libs: list[Accessor] = field(default_factory=list)
srcs: list[Accessor] = field(default_factory=list)
# Internal to the tool.
_flattend: bool = field(init=False,default=False)
_prepared: bool = field(init=False,default=False)
_rebuilt: bool = field(init=False,default=False)
def __deepcopy__(self, memo) -> Self:
return Target(
self.name,
self.type,
Includes(
list(self.incs.includes),
list(self.incs.libraries)
),
list(self.opts),
list(self.defs),
list(self.deps),
list(self.libs),
list(self.srcs)
)
@classmethod
def to_dict(cls, data: Self) -> dict:
@@ -69,11 +86,11 @@ class Target(yaml.YAMLObject):
"name": data.get("name") or bad_attr("name", data),
"type": data.get("type") or bad_attr("type", data),
"incs": Includes.from_dict(data.get("incs", {})),
"opts": set(Accessor.from_list(data.get("opts", []))),
"defs": set(Accessor.from_list(data.get("defs", []))),
"deps": set(Accessor.from_list(data.get("deps", []))),
"libs": set(Accessor.from_list(data.get("libs", []))),
"srcs": set(Accessor.from_list(data.get("srcs", [])))
"opts": Accessor.from_list(data.get("opts", [])),
"defs": Accessor.from_list(data.get("defs", [])),
"deps": Accessor.from_list(data.get("deps", [])),
"libs": Accessor.from_list(data.get("libs", [])),
"srcs": Accessor.from_list(data.get("srcs", []))
})
@classmethod
+2 -20
View File
@@ -3,12 +3,12 @@ from logging import Logger
from ..models import Project
from ..models import Result
from ..models import Target
from .._config import Config
from ._commands import Command
from ._except import NoTargetsFoundError
from ._execute import execute
from ._prepare import prepare
from ._prepare import prepare_dependencies
_logger = getLogger("chinook")
@@ -23,24 +23,6 @@ def build(
commands: list[Command] = []
for target in project.targets:
commands.extend(_prepare_dependencies(appcfg, target, logger))
commands.extend(prepare_dependencies(appcfg, project, target, logger))
commands.extend(prepare(appcfg, project, target, logger))
return execute(commands, "Building")
def _prepare_dependencies(
appcfg: Config,
target: Target,
logger: Logger = _logger
) -> list[Command]:
from ..management import find_target_by_name
from ..management import find_project_by_target
commands: list[Command] = []
for required in target.deps:
dependency = find_target_by_name(required.value)
if dependency._prepared:
continue
project = find_project_by_target(required.value)
commands.extend(prepare(appcfg, project, target, logger))
return commands
+53 -14
View File
@@ -4,9 +4,10 @@ from pathlib import Path
from ..compiler import Compiler
from ..compiler import CompilerOptions
from ..management import latest
from ..management import find_target_by_name
from ..management import find_project_by_target
from ..management import read_depfile
from ..management import stale
from ..models import Output
from ..models import Project
from ..models import Target
@@ -28,8 +29,10 @@ def prepare(
) -> list[Command]:
commands: list[Command] = []
if target.type == Output.IMP or \
target.type == Output.INT:
target.type == Output.INT or \
target._prepared:
return commands
target._prepared = True
match target.type:
case Output.EXE: outfile = project.destination.bin(target.name)
@@ -43,19 +46,21 @@ def prepare(
defopts = CompilerOptions()
defopts.pic = target.type == Output.DLL
defopts.incdirs.update([v.value for v in target.incs.includes])
defopts.defines.update([v.value for v in target.defs])
defopts.flags.update([v.value for v in target.opts])
defopts.incdirs.extend([v.value for v in target.incs.includes])
defopts.defines.extend([v.value for v in target.defs])
defopts.flags.extend([v.value for v in target.opts])
for file in target.srcs:
srcfile = project.origination.src(file.value)
dstfile = project.destination.obj(file.value)
if not latest(srcfile, dstfile):
depfile = project.destination.dep(file.value)
objects.append(dstfile)
if not Path.exists(depfile) or \
stale(dstfile, [srcfile, *read_depfile(depfile)]):
dstfile.parent.mkdir(parents=True, exist_ok=True)
commands.append(CompileObject(compiler, defopts, logger, srcfile, dstfile))
if not latest(srcfile, outfile):
objects.append(dstfile)
defopts.objfiles.update(objects)
relink = len(commands) > 0 or stale(outfile, objects)
defopts.objfiles.extend(objects)
del objects
defopts.pic = False
@@ -65,12 +70,22 @@ def prepare(
libtgt = find_target_by_name(library.value)
libprj = find_project_by_target(libtgt.name)
if libtgt.type == Output.LIB:
defopts.libdirs.add(libprj.destination.libpath)
defopts.archives.add(library.value)
libfile = libprj.destination.lib(library.value)
if libprj.destination.libpath not in defopts.libdirs:
defopts.libdirs.append(libprj.destination.libpath)
defopts.archives.append(library.value)
elif libtgt.type == Output.DLL:
defopts.objfiles.add(libprj.destination.dll(library.value))
libfile = libprj.destination.dll(library.value)
defopts.objfiles.append(libfile)
else:
continue
if len(defopts.objfiles) == 0:
# Archives don't embed their libraries, so only relink linked outputs.
if target.type != Output.LIB and \
(libtgt._rebuilt or stale(outfile, [libfile])):
relink = True
if not relink or len(defopts.objfiles) == 0:
return commands
command: Command
@@ -80,6 +95,30 @@ def prepare(
case Output.DLL: command = CompileDynlib(compiler, defopts, logger, outfile)
case Output.OBJ: assert False, "Not Implemented"
target._prepared = True
outfile.parent.mkdir(parents=True, exist_ok=True)
target._rebuilt = True
commands.append(command)
return commands
def prepare_dependencies(
appcfg: Config,
project: Project,
target: Target,
logger: Logger = _logger
) -> list[Command]:
commands: list[Command] = []
for required in target.deps:
dependency = find_target_by_name(required.value)
if dependency.type == Output.IMP or \
dependency.type == Output.INT or \
dependency._prepared:
continue
parent = find_project_by_target(required.value)
if project.cid != parent.cid:
if required.value not in parent.exports:
raise Exception(f"Cannot depend on non-exported target: {required.value}")
commands.extend(prepare_dependencies(appcfg, parent, dependency, logger))
commands.extend(prepare(appcfg, parent, dependency, logger))
return commands
+6 -20
View File
@@ -3,13 +3,13 @@ from logging import Logger
from ..models import Project
from ..models import Result
from ..models import Target
from .._config import Config
from ._commands import Command
from ._commands import ExecuteTest
from ._except import NoTestsFoundError
from ._execute import execute
from ._prepare import prepare
from ._prepare import prepare_dependencies
_logger = getLogger("chinook")
@@ -24,31 +24,17 @@ def test(
commands: list[Command] = []
for target in project.tests:
commands.extend(_prepare_dependencies(appcfg, target, logger))
commands.extend(prepare_dependencies(appcfg, project, target, logger))
commands.extend(prepare(appcfg, project, target, logger))
results = execute(commands, "Building")
for result in results:
if not result.success:
return results
commands.clear()
for target in project.tests:
testfile = project.destination.bin(target.name)
commands.append(ExecuteTest(None, None, logger, testfile))
results.extend(execute(commands, "Testing"))
return results
def _prepare_dependencies(
appcfg: Config,
target: Target,
logger: Logger = _logger
) -> list[Command]:
from ..management import find_target_by_name
from ..management import find_project_by_target
commands: list[Command] = []
for required in target.deps:
dependency = find_target_by_name(required.value)
if dependency._prepared:
continue
project = find_project_by_target(required.value)
commands.extend(prepare(appcfg, project, dependency, logger))
return commands
+3
View File
@@ -11,3 +11,6 @@ targets:
type: program
deps: [example]
srcs: [./entry.cpp]
exports:
- example
+13
View File
@@ -0,0 +1,13 @@
name: local
gpid: examples
semv: 1.0.0
requires:
- remote: examples/archive
targets:
- name: hello
type: program
deps: [example] # Comes from local required
srcs:
- ./entry.cpp
+5
View File
@@ -0,0 +1,5 @@
extern "C" void print(const char* str);
int main() {
print("Hello, World!");
}
+1 -1
View File
@@ -9,7 +9,7 @@ targets:
- ./fibonacci.cpp
tests:
- name: factorial_test
- name: testing
type: program
deps: [fibonacci]
srcs: