diff --git a/clang_build/directories.py b/clang_build/directories.py index cd74c22..d43a9e5 100644 --- a/clang_build/directories.py +++ b/clang_build/directories.py @@ -1,7 +1,5 @@ class Directories: - def __init__(self, files, dependencies, public_dependencies): - self.dependencies = dependencies - + def __init__(self, files, public_dependencies): # Include directories self.include_private = files["include_directories"] self.include_public = files["public_include_directories"] diff --git a/clang_build/project.py b/clang_build/project.py index d04d3a6..8076a58 100644 --- a/clang_build/project.py +++ b/clang_build/project.py @@ -323,7 +323,6 @@ def add_targets(self, target_list: list): # Add nodes and edges for targets in self for target in target_list: self._project_tree.add_node(target, data=target) - self._project_tree.add_edges_from((self, target) for target in target_list) # Create a dotfile of the dependency graph create_dotfile = False @@ -342,12 +341,8 @@ def add_targets(self, target_list: list): # Add edges for dependencies in targets defined in project for target in target_list: target.config["dependencies"] = self._get_dependencies_2(target, target.config.get("dependencies", [])) - target.config["public_dependencies"] = self._get_dependencies_2(target, target.config.get("public_dependencies", [])) - for dependency in target.config["dependencies"]: self._project_tree.add_edge(target, dependency) - for dependency in target.config["public_dependencies"]: - self._project_tree.add_edge(target, dependency, public=True) # Create new dotfile with full dependency graph if create_dotfile: @@ -445,43 +440,47 @@ def build( targets_to_build = self._get_targets_to_build(build_all, target_list) # Sort targets in build order - target_build_description_list = [ + build_list = [ target for target in reversed(list(_nx.topological_sort(self._project_tree))) - if target in targets_to_build + if (target in targets_to_build or build_all) and not isinstance(self._project_tree.nodes[target]["data"], Project) ] # Get project sources, if any project_build_list = [] - for target_description in target_build_description_list: - for predecessor in self._project_tree.predecessors(target_description): - if isinstance(predecessor, Project): - project_build_list.append(predecessor) + for target_description in build_list: + project_build_list.append(target_description.parent_project) project_build_list = list(dict.fromkeys(project_build_list)) for project in project_build_list: project.get_sources() - for target in target_build_description_list: - parent_project = next(self._project_tree.predecessors(target)) - target.parent_directory = parent_project._directory - target.parent_build_directory = parent_project._build_directory - ### Note: the project_tree needs to be updated directly for dependencies ### to be used correctly in the `_target_from_description` function target_build_list = [] - for target in target_build_description_list: - if isinstance(target, _TargetDescription): - target_instance = self._target_from_description( - self._project_tree.nodes[target]["data"]#, self._project_tree + for list_entry in build_list: + if isinstance(list_entry, _TargetDescription): + target = self._target_from_description( + self._project_tree.nodes[list_entry]["data"] ) - target_build_list.append(target_instance) - self._project_tree.nodes[target]["data"] = target_instance + if target: + target_build_list.append(target) + self._project_tree.nodes[list_entry]["data"] = target + elif isinstance(list_entry, _Target): + target_build_list.append(list_entry) else: - target_build_list.append(target) + error_message = self.parent.log_message( + f"Found {target} in target list, which cannot be used because" + " it is not derived from Target or TargetDescription." + ) + + self._logger.exception(error_message) + raise RuntimeError(error_message) if not target_build_list: self._logger.info("No targets to be built") + else: + self._logger.info(f"Building {', '.join([str(target) for target in target_build_list])}") # Compile with _Pool(processes=number_of_threads) as process_pool: @@ -623,15 +622,9 @@ def _get_dependencies(self, target_description): for dependency in self._project_tree.successors(target_description) ] - public_dependencies = [] - successors = self._project_tree.successors(target_description) - for target, dependency, public in self._project_tree.subgraph([target_description] + [s for s in successors]).edges(data="public"): - if public == True: - public_dependencies.append(self._project_tree.nodes()[dependency]["data"]) - # Are there executables named as dependencies? executable_dependencies = [ - target for target in dependencies+public_dependencies if isinstance(target, _Executable) + target for target in dependencies if isinstance(target, _Executable) ] if executable_dependencies: exelist = ", ".join([f"[{dep.name}]" for dep in executable_dependencies]) @@ -641,7 +634,7 @@ def _get_dependencies(self, target_description): self._logger.error(error_message) raise RuntimeError(error_message) - return dependencies, public_dependencies + return dependencies def _get_dependencies_2(self, target, names): dependencies = [] @@ -686,7 +679,7 @@ def _target_from_description(self, target_description): Returns the correct target type based on input parameters """ - dependencies, public_dependencies = self._get_dependencies(target_description) + dependencies = self._get_dependencies(target_description) # Sources target_description.get_sources() @@ -703,7 +696,7 @@ def _target_from_description(self, target_description): if target_type is not None: target_type = str(target_type).lower() if target_type in _TARGET_MAP: - return _TARGET_MAP[target_type](target_description, files, dependencies, public_dependencies) + return _TARGET_MAP[target_type](target_description, files, dependencies) else: error_message = target_description.log_message( f'ERROR: Unsupported target type: "{target_description.config["target_type"].lower()}"' @@ -717,12 +710,12 @@ def _target_from_description(self, target_description): target_description.log_message( "no source files found. Creating header-only target." ) - return _HeaderOnly(target_description, files, dependencies, public_dependencies) + return _HeaderOnly(target_description, files, dependencies) target_description.log_message( f'{len(files["sourcefiles"])} source file(s) found. Creating executable target.' ) - return _Executable(target_description, files, dependencies, public_dependencies) + return _Executable(target_description, files, dependencies) def get_sources(self): """External sources, if present, will be downloaded to build_directory/external_sources. diff --git a/clang_build/target.py b/clang_build/target.py index fd7fa98..1691021 100644 --- a/clang_build/target.py +++ b/clang_build/target.py @@ -52,13 +52,6 @@ def dependencies(self): """ return self._dependencies - @property - def public_dependencies(self): - """Return a list of any:`clang_build.target.Target`, which this - target depends on. - """ - return self._public_dependencies - @property def root_directory(self): """Folders "include", "src", etc. are searched @@ -87,7 +80,7 @@ def directories(self): """ return self._directories - def __init__(self, target_description, files, dependencies=None, public_dependencies=None): + def __init__(self, target_description, files, dependencies=None): """Initialise a target. The procedure for initialisation is: @@ -107,9 +100,6 @@ def __init__(self, target_description, files, dependencies=None, public_dependen dependencies Optional. A list of any:`clang_build.target.Target` which this target depends on. - public_dependencies - Optional. A list of any:`clang_build.target.Target` which this target - depends on and which should also be available to dependent targets. """ _NamedLogger.__init__(self, _LOGGER) self._name = target_description.name @@ -118,23 +108,20 @@ def __init__(self, target_description, files, dependencies=None, public_dependen if dependencies is None: dependencies = [] - self._dependencies = dependencies - if public_dependencies is None: - public_dependencies = [] - - self._public_dependencies = public_dependencies + self._root_directory = _Path(target_description.root_directory) + self._build_directory = target_description.build_directory self._headers = list(dict.fromkeys(files["headers"])) - self._directories = Directories(files, self.dependencies, self.public_dependencies) + self._directories = Directories(files, self.dependencies) # Compile and link flags self._build_flags = self._get_default_flags() # Dependencies' flags - for target in self.dependencies + self.public_dependencies: + for target in self.dependencies: # Header only libraries will forward all non-private flags self._add_dependency_flags(target) @@ -182,7 +169,7 @@ def bundle(self): """ self.unsuccessful_bundle = False bundle_files = [] - for dependency in self.dependencies + self.public_dependencies: + for dependency in self.dependencies: bundle_files += dependency.bundle() return bundle_files @@ -213,7 +200,7 @@ class HeaderOnly(Target): TODO: need to check whether "public" makes sense for header-only, when we have implemented "private" dependencies """ - def __init__(self, target_description, files, dependencies=None, public_dependencies=None): + def __init__(self, target_description, files, dependencies=None): """Initialise a header-only target. Header-only targets' private flags and include-directories are public. @@ -221,8 +208,7 @@ def __init__(self, target_description, files, dependencies=None, public_dependen super().__init__( target_description=target_description, files=files, - dependencies=dependencies, - public_dependencies=public_dependencies + dependencies=dependencies ) if files["sourcefiles"]: @@ -274,8 +260,7 @@ def __init__( platform_flags, prefix, suffix, - dependencies=None, - public_dependencies=None + dependencies=None ): self.source_files = files["sourcefiles"] self.is_c_target = not any( @@ -285,8 +270,7 @@ def __init__( super().__init__( target_description=target_description, files=files, - dependencies=dependencies, - public_dependencies=public_dependencies + dependencies=dependencies ) if not self.source_files: @@ -342,12 +326,12 @@ def compile(self, process_pool, progress_disabled): """ # Object file only needs to be (re-)compiled if the source file or headers it depends on changed - if not self._environment.force_build: + if self._environment.force_build: + self.needed_buildables = self.buildables + else: self.needed_buildables = [ buildable for buildable in self.buildables if buildable.needs_rebuild ] - else: - self.needed_buildables = self.buildables # If the target was not modified, it may not need to compile if not self.needed_buildables: @@ -407,7 +391,7 @@ class Executable(Compilable): An executable cannot be the dependency of another target. """ - def __init__(self, target_description, files, dependencies=None, public_dependencies=None): + def __init__(self, target_description, files, dependencies=None): """Initialise an executable target. """ @@ -418,8 +402,7 @@ def __init__(self, target_description, files, dependencies=None, public_dependen platform_flags=target_description.environment.toolchain.platform_defaults['PLATFORM_EXTRA_FLAGS_EXECUTABLE'], prefix=target_description.environment.toolchain.platform_defaults['EXECUTABLE_PREFIX'], suffix=target_description.environment.toolchain.platform_defaults['EXECUTABLE_SUFFIX'], - dependencies=dependencies, - public_dependencies=public_dependencies + dependencies=dependencies ) ### Bundling requires extra flags @@ -431,7 +414,7 @@ def bundle(self): ### Gather bundle_files = [] - for dependency in self.dependencies + self.public_dependencies: + for dependency in self.dependencies: bundle_files += dependency.bundle() ### Copy @@ -529,8 +512,8 @@ def link(self): [buildable.object_file for buildable in self.buildables], self.outfile, self._build_flags._language_flags() + self._build_flags.final_link_flags_list(), - [target.output_folder.resolve() for target in self.dependencies+self.public_dependencies if target.__class__ is not HeaderOnly], - [target.outname for target in self.dependencies+self.public_dependencies if target.__class__ is not HeaderOnly], + [target.output_folder.resolve() for target in self.dependencies if target.__class__ is not HeaderOnly], + [target.outname for target in self.dependencies if target.__class__ is not HeaderOnly], False, self.is_c_target) @@ -542,7 +525,7 @@ def link(self): {self.identifier: self.link_report}) class SharedLibrary(Compilable): - def __init__(self, target_description, files, dependencies=None, public_dependencies=None): + def __init__(self, target_description, files, dependencies=None): super().__init__( target_description=target_description, @@ -551,8 +534,7 @@ def __init__(self, target_description, files, dependencies=None, public_dependen platform_flags=target_description.environment.toolchain.platform_defaults['PLATFORM_EXTRA_FLAGS_SHARED'], prefix=target_description.environment.toolchain.platform_defaults['SHARED_LIBRARY_PREFIX'], suffix=target_description.environment.toolchain.platform_defaults['SHARED_LIBRARY_SUFFIX'], - dependencies=dependencies, - public_dependencies=public_dependencies + dependencies=dependencies ) # TODO: This has to go to the flags department I guess @@ -576,7 +558,7 @@ def bundle(self): self_bundle_files.append(_Path(str(self.outfile)[:-3] + "lib")) bundle_files = [] - for dependency in self.dependencies + self.public_dependencies: + for dependency in self.dependencies: bundle_files += dependency.bundle() ### Copy @@ -611,8 +593,8 @@ def link(self): [buildable.object_file for buildable in self.buildables], self.outfile, self._build_flags._language_flags() + self._build_flags.final_link_flags_list(), - [target.output_folder.resolve() for target in self.dependencies+self.public_dependencies if target.__class__ is not HeaderOnly], - [target.outname for target in self.dependencies+self.public_dependencies if target.__class__ is not HeaderOnly], + [target.output_folder.resolve() for target in self.dependencies if target.__class__ is not HeaderOnly], + [target.outname for target in self.dependencies if target.__class__ is not HeaderOnly], True, self.is_c_target) @@ -634,8 +616,7 @@ def __init__(self, target_description, files, dependencies=None): platform_flags=target_description.environment.toolchain.platform_defaults['PLATFORM_EXTRA_FLAGS_STATIC'], prefix=target_description.environment.toolchain.platform_defaults['STATIC_LIBRARY_PREFIX'], suffix=target_description.environment.toolchain.platform_defaults['STATIC_LIBRARY_SUFFIX'], - dependencies=dependencies, - public_dependencies=public_dependencies + dependencies=dependencies ) def _add_dependency_flags(self, target): @@ -656,7 +637,7 @@ def link(self): objects = [buildable.object_file for buildable in self.buildables] # Dependencies' objects - for target in self.dependencies+self.public_dependencies: + for target in self.dependencies: if not target.__class__ is HeaderOnly: objects += [buildable.object_file for buildable in target.buildables] diff --git a/test/public_dependency/clang-build.toml b/test/public_dependency/clang-build.toml deleted file mode 100644 index c70862f..0000000 --- a/test/public_dependency/clang-build.toml +++ /dev/null @@ -1,8 +0,0 @@ -name = "mainproject" - -subprojects = ["libA"] - -[myexe] - output_name = "runLib" - directory = "myexe" - dependencies = ["libA.libA"] \ No newline at end of file diff --git a/test/public_dependency/libA/clang-build.toml b/test/public_dependency/libA/clang-build.toml deleted file mode 100644 index 4b39262..0000000 --- a/test/public_dependency/libA/clang-build.toml +++ /dev/null @@ -1,9 +0,0 @@ -name = "libA" - -subprojects = ["libB", "libC"] - -[libA] - version = "0.0.0" - target_type = "static library" - dependencies = ["libB.libB"] - public_dependencies = ["libC.libC"] \ No newline at end of file diff --git a/test/public_dependency/libA/libA.cpp b/test/public_dependency/libA/libA.cpp deleted file mode 100644 index 6c8978f..0000000 --- a/test/public_dependency/libA/libA.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include -#include - -namespace libA { - -float triple(float x) { return libB::triple(x); } - -} // namespace libA \ No newline at end of file diff --git a/test/public_dependency/libA/libA.hpp b/test/public_dependency/libA/libA.hpp deleted file mode 100644 index 88b3b26..0000000 --- a/test/public_dependency/libA/libA.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -namespace libA { - -float triple(float x); - -} \ No newline at end of file diff --git a/test/public_dependency/libA/libB/clang-build.toml b/test/public_dependency/libA/libB/clang-build.toml deleted file mode 100644 index aa4fec8..0000000 --- a/test/public_dependency/libA/libB/clang-build.toml +++ /dev/null @@ -1,5 +0,0 @@ -name = "libB" - -[libB] - version = "0.0.0" - target_type = "static library" \ No newline at end of file diff --git a/test/public_dependency/libA/libB/libB.cpp b/test/public_dependency/libA/libB/libB.cpp deleted file mode 100644 index b5a4d62..0000000 --- a/test/public_dependency/libA/libB/libB.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include - -namespace libB { - -float triple(float x) { return 3 * x; } - -} // namespace libB \ No newline at end of file diff --git a/test/public_dependency/libA/libB/libB.hpp b/test/public_dependency/libA/libB/libB.hpp deleted file mode 100644 index 4e77a6d..0000000 --- a/test/public_dependency/libA/libB/libB.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -namespace libB { - -float triple(float x); - -} \ No newline at end of file diff --git a/test/public_dependency/libA/libC/clang-build.toml b/test/public_dependency/libA/libC/clang-build.toml deleted file mode 100644 index 9204b06..0000000 --- a/test/public_dependency/libA/libC/clang-build.toml +++ /dev/null @@ -1,4 +0,0 @@ -name = "libC" - -[libC] - target_type = "header only" \ No newline at end of file diff --git a/test/public_dependency/libA/libC/libC.hpp b/test/public_dependency/libA/libC/libC.hpp deleted file mode 100644 index 506ed91..0000000 --- a/test/public_dependency/libA/libC/libC.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -namespace libC { - -float half(float x) { return 0.5f * x; }; - -} // namespace libC \ No newline at end of file diff --git a/test/public_dependency/myexe/main.cpp b/test/public_dependency/myexe/main.cpp deleted file mode 100644 index bc36cbe..0000000 --- a/test/public_dependency/myexe/main.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include - -#include -#include - -int main() { - std::cerr << "Hello! libC::half(libA::triple(4)) returned " - << libC::half(libA::triple(4)) << std::endl; - return 0; -} \ No newline at end of file diff --git a/test/test.py b/test/test.py index 94f8308..e9ce0a1 100644 --- a/test/test.py +++ b/test/test.py @@ -162,16 +162,6 @@ def test_subproject(self): self.assertEqual(output, 'Hello! mylib::triple(3) returned 9') - def test_public_dependency(self): - clang_build_try_except(['-d', 'test/public_dependency', '-V']) - - try: - output = subprocess.check_output(['./build/myexe/default/bin/runLib'], stderr=subprocess.STDOUT).decode('utf-8').strip() - except subprocess.CalledProcessError as e: - self.fail(f'Could not run compiled program. Message:\n{e.output}') - - self.assertEqual(output, 'Hello! libC::half(libA::triple(4)) returned 6') - def test_pyapi_subproject(self): clang_build_try_except(['-d', 'test/py-api/subproject', '-V'])