Skip to content

Commit

Permalink
make CppInfo an importable tool (#14101)
Browse files Browse the repository at this point in the history
* make CppInfo an importable tool

* load/save
  • Loading branch information
memsharded authored Jun 19, 2023
1 parent 64e20c4 commit 5ad2216
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 4 deletions.
8 changes: 8 additions & 0 deletions conan/tools/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from conans.model.build_info import CppInfo as _CppInfo


def CppInfo(conanfile):
# Creation of a CppInfo object, to decouple the creation from the actual internal location
# that at the moment doesn't require a ``conanfile`` argument, but might require in the future
# and allow us to refactor the location of conans.model.build_info import CppInfo
return _CppInfo()
4 changes: 2 additions & 2 deletions conan/tools/gnu/autotoolsdeps.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from conan.internal import check_duplicated_generator
from conan.tools import CppInfo
from conan.tools.env import Environment
from conan.tools.gnu.gnudeps_flags import GnuDepsFlags
from conans.model.build_info import CppInfo


class AutotoolsDeps:
Expand All @@ -18,7 +18,7 @@ def ordered_deps(self):
return self._ordered_deps

def _get_cpp_info(self):
ret = CppInfo()
ret = CppInfo(self._conanfile)
for dep in self.ordered_deps:
dep_cppinfo = dep.cpp_info.aggregated_components()
# In case we have components, aggregate them, we do not support isolated
Expand Down
4 changes: 2 additions & 2 deletions conan/tools/microsoft/nmakedeps.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import os

from conan.internal import check_duplicated_generator
from conan.tools import CppInfo
from conan.tools.env import Environment
from conans.model.build_info import CppInfo


class NMakeDeps(object):
Expand All @@ -16,7 +16,7 @@ def __init__(self, conanfile):

# TODO: This is similar from AutotoolsDeps: Refactor and make common
def _get_cpp_info(self):
ret = CppInfo()
ret = CppInfo(self._conanfile)
deps = self._conanfile.dependencies.host.topological_sort
deps = [dep for dep in reversed(deps.values())]
for dep in deps:
Expand Down
44 changes: 44 additions & 0 deletions conans/model/build_info.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import copy
import json
import os
from collections import OrderedDict, defaultdict

from conan.api.output import ConanOutput
from conans.errors import ConanException
from conans.util.files import load, save

_DIRS_VAR_NAMES = ["_includedirs", "_srcdirs", "_libdirs", "_resdirs", "_bindirs", "_builddirs",
"_frameworkdirs", "_objects"]
Expand Down Expand Up @@ -112,6 +114,35 @@ def serialize(self):
"properties": self._properties
}

@staticmethod
def deserialize(contents):
result = _Component()
# TODO: Refactor to avoid this repetition
fields = [
"includedirs",
"srcdirs",
"libdirs",
"resdirs",
"bindirs",
"builddirs",
"frameworkdirs",
"system_libs",
"frameworks",
"libs",
"defines",
"cflags",
"cxxflags",
"sharedlinkflags",
"exelinkflags",
"objects",
"sysroot",
"requires",
"properties"
]
for f in fields:
setattr(result, f"_{f}", contents[f])
return result

@property
def includedirs(self):
if self._includedirs is None:
Expand Down Expand Up @@ -420,6 +451,19 @@ def serialize(self):
ret[component_name] = info.serialize()
return ret

def deserialize(self, content):
self._package = _Component.deserialize(content.pop("root"))
for component_name, info in content.items():
self.components[component_name] = _Component.deserialize(info)
return self

def save(self, path):
save(path, json.dumps(self.serialize()))

def load(self, path):
content = json.loads(load(path))
return self.deserialize(content)

@property
def has_components(self):
return len(self.components) > 0
Expand Down
40 changes: 40 additions & 0 deletions conans/test/integration/conanfile/test_cpp_info_serialize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import json
import textwrap

from conans.test.utils.tools import TestClient


def test_cpp_info_serialize_round_trip():
""" test that serialize and deserialize CppInfo works
"""
# TODO: Define standard name for file
c = TestClient()
conanfile = textwrap.dedent("""\
import os
from conan import ConanFile
from conan.tools import CppInfo
class Pkg(ConanFile):
name = "pkg"
version = "0.1"
def package(self):
cpp_info = CppInfo(self)
cpp_info.includedirs = ["myinc"]
cpp_info.libs = ["mylib", "myother"]
cpp_info.libdirs = ["mylibs"]
p = os.path.join(self.package_folder, "cpp_info.json")
cpp_info.save(p)
def package_info(self):
cpp_info = CppInfo(self).load("cpp_info.json")
self.cpp_info = cpp_info
""")

c.save({"conanfile.py": conanfile})
c.run("create . --format=json")
graph = json.loads(c.stdout)
cpp_info = graph["graph"]["nodes"]["1"]["cpp_info"]["root"]
assert cpp_info["includedirs"][0].endswith("myinc")
assert cpp_info["libdirs"][0].endswith("mylibs")
assert cpp_info["libs"] == ["mylib", "myother"]

0 comments on commit 5ad2216

Please sign in to comment.