Dependency/archive ordering causes compilation failure
This commit is contained in:
@@ -42,10 +42,10 @@ 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)
|
||||
# self.logger.info(cmdstr)
|
||||
|
||||
result = Result(
|
||||
success = False,
|
||||
@@ -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)
|
||||
|
||||
@@ -186,7 +186,7 @@ class GnucDriver(CompilerDriver):
|
||||
for archive in options.archives: args.append(f"-l{archive}")
|
||||
for define in options.defines: args.append(f"-D{define}")
|
||||
cmdstr = ' '.join(args)
|
||||
self.logger.info(cmdstr)
|
||||
# self.logger.info(cmdstr)
|
||||
|
||||
result = Result(
|
||||
success = False,
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
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)
|
||||
|
||||
_incs_set: set[Accessor] = field(init=False, default_factory=set)
|
||||
_dirs_set: set[Accessor] = field(init=False, default_factory=set)
|
||||
_opts_set: set[Accessor] = field(init=False, default_factory=set)
|
||||
_defs_set: set[Accessor] = field(init=False, default_factory=set)
|
||||
_deps_set: set[Accessor] = field(init=False, default_factory=set)
|
||||
_libs_set: set[Accessor] = field(init=False, default_factory=set)
|
||||
_srcs_set: set[Accessor] = 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 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 inc in self._incs_set:
|
||||
return
|
||||
self._incs_set.add(inc)
|
||||
self._incs_list.insert(0, inc)
|
||||
|
||||
def append_dir(self, lib: Accessor) -> None:
|
||||
if lib.level == Access.PRIVATE or lib in self._dirs_set:
|
||||
return
|
||||
self._dirs_set.add(lib)
|
||||
self._dirs_list.insert(0, lib)
|
||||
|
||||
def append_opt(self, opt: Accessor) -> None:
|
||||
if opt.level == Access.PRIVATE or opt in self._opts_set:
|
||||
return
|
||||
self._opts_set.add(opt)
|
||||
self._opts_list.insert(0, opt)
|
||||
|
||||
def append_def(self, dfn: Accessor) -> None:
|
||||
if dfn.level == Access.PRIVATE or dfn in self._defs_set:
|
||||
return
|
||||
self._defs_set.add(dfn)
|
||||
self._defs_list.insert(0, dfn)
|
||||
|
||||
def append_dep(self, dep: Accessor) -> None:
|
||||
if dep.level == Access.PRIVATE or dep in self._deps_set:
|
||||
return
|
||||
self._deps_set.add(dep)
|
||||
self._deps_list.insert(0, dep)
|
||||
|
||||
def append_lib(self, lib: Accessor) -> None:
|
||||
if lib.level == Access.PRIVATE or lib in self._libs_set:
|
||||
return
|
||||
self._libs_set.add(lib)
|
||||
self._libs_list.insert(0, lib)
|
||||
|
||||
def append_src(self, src: Accessor) -> None:
|
||||
if src.level == Access.PRIVATE or src in self._srcs_set:
|
||||
return
|
||||
self._srcs_set.add(src)
|
||||
self._srcs_list.insert(0, src)
|
||||
|
||||
|
||||
def flatten_targets(project: Project) -> None:
|
||||
for target in project.targets:
|
||||
if target._flattend:
|
||||
continue
|
||||
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
|
||||
))
|
||||
_flatten_target(context, 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 _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)
|
||||
target.incs.includes.extend(context.incs)
|
||||
target.incs.libraries.extend(context.dirs)
|
||||
target.opts.extend(context.opts)
|
||||
target.defs.extend(context.defs)
|
||||
target.deps.extend(context.deps)
|
||||
target.libs.extend(context.libs)
|
||||
target.srcs.extend(context.srcs)
|
||||
target._flattend = True
|
||||
|
||||
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)
|
||||
target.incs.includes.extend(context.incs)
|
||||
target.incs.libraries.extend(context.dirs)
|
||||
target.opts.extend(context.opts)
|
||||
target.defs.extend(context.defs)
|
||||
target.deps.extend(context.deps)
|
||||
target.libs.extend(context.libs)
|
||||
target.srcs.extend(context.srcs)
|
||||
target._flattend = True
|
||||
|
||||
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!"
|
||||
|
||||
_flatten_target(context, 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
|
||||
))
|
||||
|
||||
@@ -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
|
||||
@@ -64,69 +63,6 @@ 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:
|
||||
|
||||
@@ -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
|
||||
|
||||
+26
-10
@@ -21,15 +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)
|
||||
|
||||
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:
|
||||
return {
|
||||
@@ -69,11 +85,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
|
||||
|
||||
@@ -43,9 +43,9 @@ 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)
|
||||
@@ -56,7 +56,7 @@ def prepare(
|
||||
outfile.parent.mkdir(parents=True, exist_ok=True)
|
||||
objects.append(dstfile)
|
||||
|
||||
defopts.objfiles.update(objects)
|
||||
defopts.objfiles.extend(objects)
|
||||
del objects
|
||||
|
||||
defopts.pic = False
|
||||
@@ -66,10 +66,10 @@ 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)
|
||||
defopts.libdirs.append(libprj.destination.libpath)
|
||||
defopts.archives.append(library.value)
|
||||
elif libtgt.type == Output.DLL:
|
||||
defopts.objfiles.add(libprj.destination.dll(library.value))
|
||||
defopts.objfiles.append(libprj.destination.dll(library.value))
|
||||
|
||||
if len(defopts.objfiles) == 0:
|
||||
return commands
|
||||
|
||||
@@ -29,6 +29,10 @@ def test(
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user