Skip to content

Commit

Permalink
topological order of buildenv (#9491)
Browse files Browse the repository at this point in the history
* topological order of buildenv

* fix buildenv order in test

* adding preprend case
  • Loading branch information
memsharded committed Aug 30, 2021
1 parent 4f1de46 commit b1c79d5
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 7 deletions.
8 changes: 5 additions & 3 deletions conan/tools/env/virtualbuildenv.py
Expand Up @@ -22,8 +22,9 @@ def environment(self):
profile_env = self._conanfile.buildenv
build_env.compose_env(profile_env)

for require, build_require in self._conanfile.dependencies.build.items():
if require.direct:
build_requires = self._conanfile.dependencies.build.topological_sort
for require, build_require in reversed(build_requires.items()):
if require.direct: # Only buildenv_info from direct deps is propagated
# higher priority, explicit buildenv_info
if build_require.buildenv_info:
build_env.compose_env(build_require.buildenv_info)
Expand All @@ -34,7 +35,8 @@ def environment(self):
build_env.compose_env(runenv_from_cpp_info(self._conanfile, build_require.cpp_info))

# Requires in host context can also bring some direct buildenv_info
for require in self._conanfile.dependencies.host.values():
host_requires = self._conanfile.dependencies.host.topological_sort
for require in reversed(host_requires.values()):
if require.buildenv_info:
build_env.compose_env(require.buildenv_info)

Expand Down
3 changes: 3 additions & 0 deletions conans/model/conanfile_interface.py
Expand Up @@ -19,6 +19,9 @@ def __eq__(self, other):
"""
return self._conanfile == other._conanfile

def __hash__(self):
return hash(self._conanfile)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
30 changes: 28 additions & 2 deletions conans/model/dependencies.py
@@ -1,6 +1,5 @@
from collections import OrderedDict

from conans.client.graph.graph import CONTEXT_BUILD
from conans.model.conanfile_interface import ConanFileInterface
from conans.model.ref import ConanFileReference

Expand Down Expand Up @@ -122,7 +121,34 @@ def expand(nodes, is_build, is_test):
return ConanFileDependencies(d)

def filter(self, require_filter):
return super(ConanFileDependencies, self).filter(require_filter)
# FIXME: Copy of hte above, to return ConanFileDependencies class object
def filter_fn(require):
for k, v in require_filter.items():
if getattr(require, k) != v:
return False
return True

data = OrderedDict((k, v) for k, v in self._data.items() if filter_fn(k))
return ConanFileDependencies(data, require_filter)

@property
def topological_sort(self):
# Return first independent nodes, final ones are the more direct deps
result = OrderedDict()
opened = self._data.copy()

while opened:
opened_values = set(opened.values())
new_opened = OrderedDict()
for req, conanfile in opened.items():
deps_in_opened = any(d in opened_values for d in conanfile.dependencies.values())
if deps_in_opened:
new_opened[req] = conanfile # keep it for next iteration
else:
result[req] = conanfile # No dependencies in open set!

opened = new_opened
return ConanFileDependencies(result)

@property
def direct_host(self):
Expand Down
54 changes: 54 additions & 0 deletions conans/test/integration/build_requires/build_requires_test.py
Expand Up @@ -451,3 +451,57 @@ def build(self):
.with_build_requires("harfbuzz/1.0@test/test")})
client.run("install . --build=missing")
self.assertIn("ZLIBS LIBS: ['myzlib']", client.out)


def test_dependents_new_buildenv():
client = TestClient()
boost = textwrap.dedent("""
from conans import ConanFile
class Boost(ConanFile):
def package_info(self):
self.buildenv_info.define_path("PATH", "myboostpath")
""")
other = textwrap.dedent("""
from conans import ConanFile
class Other(ConanFile):
requires = "boost/1.0"
def package_info(self):
self.buildenv_info.append_path("PATH", "myotherpath")
self.buildenv_info.prepend_path("PATH", "myotherprepend")
""")
consumer = textwrap.dedent("""
from conans import ConanFile
from conan.tools.env import VirtualBuildEnv
import os
class Lib(ConanFile):
build_requires = {}
def generate(self):
build_env = VirtualBuildEnv(self).environment()
with build_env.apply():
self.output.info("LIB PATH %s" % os.getenv("PATH"))
""")
client.save({"boost/conanfile.py": boost,
"other/conanfile.py": other,
"consumer/conanfile.py": consumer.format('"boost/1.0", "other/1.0"'),
"profile_define": "[buildenv]\nPATH=(path)profilepath",
"profile_append": "[buildenv]\nPATH+=(path)profilepath",
"profile_prepend": "[buildenv]\nPATH=+(path)profilepath"})
client.run("create boost boost/1.0@")
client.run("create other other/1.0@")
client.run("install consumer")
result = os.pathsep.join(["myotherprepend", "myboostpath", "myotherpath"])
assert "LIB PATH {}".format(result) in client.out

# Now test if we declare in different order, still topological order should be respected
client.save({"consumer/conanfile.py": consumer.format('"other/1.0", "boost/1.0"')})
client.run("install consumer")
assert "LIB PATH {}".format(result) in client.out

client.run("install consumer -pr=profile_define")
assert "LIB PATH profilepath" in client.out
client.run("install consumer -pr=profile_append")
result = os.pathsep.join(["myotherprepend", "myboostpath", "myotherpath", "profilepath"])
assert "LIB PATH {}".format(result) in client.out
client.run("install consumer -pr=profile_prepend")
result = os.pathsep.join(["profilepath", "myotherprepend", "myboostpath", "myotherpath"])
assert "LIB PATH {}".format(result) in client.out
4 changes: 2 additions & 2 deletions conans/test/integration/environment/test_env.py
Expand Up @@ -267,13 +267,13 @@ def generate(self):
""")
client.save({"conanfile.py": consumer}, clean_first=True)
client.run("install . -s:b os=Windows -s:h os=Linux --build")
assert "BUILDENV: MyOpenSSLWindowsValue MyGCCValue "\
assert "BUILDENV: MyGCCValue MyOpenSSLWindowsValue "\
"MyCMakeRunValue MyCMakeBuildValue!!!" in client.out
assert "RUNENV: MyOpenSSLLinuxValue!!!" in client.out

# Even if the generator is duplicated in command line (it used to fail due to bugs)
client.run("install . -s:b os=Windows -s:h os=Linux --build -g VirtualRunEnv -g VirtualBuildEnv")
assert "BUILDENV: MyOpenSSLWindowsValue MyGCCValue "\
assert "BUILDENV: MyGCCValue MyOpenSSLWindowsValue "\
"MyCMakeRunValue MyCMakeBuildValue!!!" in client.out
assert "RUNENV: MyOpenSSLLinuxValue!!!" in client.out

Expand Down

0 comments on commit b1c79d5

Please sign in to comment.