-
Notifications
You must be signed in to change notification settings - Fork 986
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* - use CMake File API Signed-off-by: SSE4 <tomskside@gmail.com> * Update conan/tools/cmake/file_api.py * Update conan/tools/cmake/file_api.py * Update conan/tools/cmake/file_api.py * Update conans/model/cpp_package.py * Update conans/model/cpp_package.py * Update conans/model/cpp_package.py * Update conans/model/cpp_package.py * Update conans/model/cpp_package.py * Update conans/model/cpp_package.py * Update conans/model/cpp_package.py * Update conans/model/cpp_package.py * Update conans/model/cpp_package.py * review * Update conans/test/functional/toolchains/cmake/test_file_api.py * Update conans/test/functional/toolchains/cmake/test_file_api.py * Update conans/test/functional/toolchains/cmake/test_file_api.py * Update conan/tools/files/cpp_package.py * - process only known target types Signed-off-by: SSE4 <tomskside@gmail.com> Co-authored-by: memsharded <james@conan.io>
- Loading branch information
1 parent
c3a2805
commit 07e59c4
Showing
7 changed files
with
410 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
from conan.tools.cmake.toolchain import CMakeToolchain | ||
from conan.tools.cmake.cmake import CMake | ||
from conan.tools.cmake.cmakedeps.cmakedeps import CMakeDeps | ||
from conan.tools.cmake.file_api import CMakeFileAPI |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
import json | ||
import fnmatch | ||
import os | ||
|
||
from conan.tools.files import CppPackage | ||
from conans.util.files import save, load | ||
|
||
|
||
class CMakeFileAPI(object): | ||
""" | ||
implements https://cmake.org/cmake/help/latest/manual/cmake-file-api.7.html | ||
""" | ||
CODEMODELV2 = "codemodel-v2" | ||
SKIP_TARGETS = ["ZERO_CHECK", "ALL_BUILD"] | ||
# https://cmake.org/cmake/help/v3.21/prop_tgt/TYPE.html | ||
SUPPORTED_TARGET_TYPES = ['STATIC_LIBRARY', 'SHARED_LIBRARY', 'MODULE_LIBRARY'] | ||
|
||
def __init__(self, conanfile): | ||
self._conanfile = conanfile | ||
|
||
@property | ||
def api_dir(self): | ||
""" | ||
:return: api directory <build>/.cmake/api/v1/ | ||
""" | ||
return os.path.join(self._conanfile.build_folder, ".cmake", "api", "v1") | ||
|
||
@property | ||
def query_dir(self): | ||
""" | ||
:return: api query sub-directory <build>/.cmake/api/v1/query | ||
""" | ||
return os.path.join(self.api_dir, "query") | ||
|
||
@property | ||
def reply_dir(self): | ||
""" | ||
:return: api reply sub-directory <build>/.cmake/api/v1/reply | ||
""" | ||
return os.path.join(self.api_dir, "reply") | ||
|
||
def query(self, query): | ||
""" | ||
prepare the CMake File API query (the actual query will be done during the configure step) | ||
:param query: type of the CMake File API query (e.g. CODEMODELV2) | ||
:return: new query object | ||
""" | ||
if query == self.CODEMODELV2: | ||
# implements codemodel-v2 query | ||
# https://cmake.org/cmake/help/latest/manual/cmake-file-api.7.html#codemodel-version-2 | ||
os.makedirs(self.query_dir) | ||
save(os.path.join(self.query_dir, "codemodel-v2"), "") | ||
return | ||
raise NotImplementedError() | ||
|
||
def reply(self, reply): | ||
""" | ||
obtain the CMake File API reply (which should have been made during the configure step) | ||
:param reply: type of the CMake File API reply (e.g. CODEMODELV2) | ||
:return: new reply object | ||
""" | ||
if reply == self.CODEMODELV2: | ||
return self.CodeModelReplyV2(self) | ||
raise NotImplementedError() | ||
|
||
@property | ||
def build_type(self): | ||
""" | ||
:return: active build type (configuration) | ||
""" | ||
return self._conanfile.settings.get_safe("build_type") | ||
|
||
class CodeModelReplyV2(object): | ||
""" | ||
implements codemodel-v2 reply | ||
https://cmake.org/cmake/help/latest/manual/cmake-file-api.7.html#codemodel-version-2 | ||
""" | ||
def __init__(self, api): | ||
|
||
def loadjs(filename): | ||
return json.loads(load(filename)) | ||
|
||
codemodels = os.listdir(api.reply_dir) | ||
codemodels = [c for c in codemodels if fnmatch.fnmatch(c, "codemodel-v2-*.json")] | ||
assert len(codemodels) == 1 | ||
self._codemodel = loadjs(os.path.join(api.reply_dir, codemodels[0])) | ||
|
||
self._configurations = dict() | ||
for configuration in self._codemodel['configurations']: | ||
if configuration["name"] != api.build_type: | ||
continue | ||
|
||
self._components = dict() | ||
for target in configuration["targets"]: | ||
if target['name'] in CMakeFileAPI.SKIP_TARGETS: | ||
continue | ||
self._components[target["name"]] = \ | ||
loadjs(os.path.join(api.reply_dir, target['jsonFile'])) | ||
|
||
@classmethod | ||
def _name_on_disk2lib(cls, name_on_disk): | ||
""" | ||
convert raw library file name into conan-friendly one | ||
:param name_on_disk: raw library file name read from target.json | ||
:return: conan-friendly library name, without suffix and prefix | ||
""" | ||
if name_on_disk.endswith('.lib'): | ||
return name_on_disk[:-4] | ||
elif name_on_disk.endswith('.dll'): | ||
return name_on_disk[:-4] | ||
elif name_on_disk.startswith('lib') and name_on_disk.endswith('.a'): | ||
return name_on_disk[3:-2] | ||
else: | ||
# FIXME: This fails to parse executables | ||
raise Exception("don't know how to convert %s" % name_on_disk) | ||
|
||
@classmethod | ||
def _parse_dep_name(cls, name): | ||
""" | ||
:param name: extract dependency name from the id like 'decoder::@5310dfab9e417c587352' | ||
:return: dependency name (part before ::@ token) | ||
""" | ||
return name.split("::@")[0] | ||
|
||
def to_conan_package(self): | ||
""" | ||
converts codemodel-v2 into conan_package.json object | ||
:return: ConanPackage instance | ||
""" | ||
|
||
conan_package = CppPackage() | ||
|
||
for name, target in self._components.items(): | ||
if target['type'] not in CMakeFileAPI.SUPPORTED_TARGET_TYPES: | ||
continue | ||
component = conan_package.add_component(name) | ||
# TODO: CMakeDeps has nothing to do here | ||
component.names["CMakeDeps"] = name | ||
component.libs = [self._name_on_disk2lib(target['nameOnDisk'])] | ||
deps = target["dependencies"] if 'dependencies' in target else [] | ||
deps = [self._parse_dep_name(d['id']) for d in deps] | ||
component.requires = [d for d in deps if d not in CMakeFileAPI.SKIP_TARGETS] | ||
|
||
return conan_package |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
from conan.tools.files.files import load, save, mkdir, ftp_download, download, get, rename, \ | ||
load_build_json, save_build_json | ||
from conan.tools.files.patches import patch, apply_conandata_patches | ||
from conan.tools.files.cpp_package import CppPackage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import json | ||
from conans.util.files import load, save | ||
|
||
|
||
class CppPackage(object): | ||
""" | ||
models conan_package.json, serializable object | ||
""" | ||
|
||
DEFAULT_FILENAME = "cpp_package.json" | ||
|
||
def __init__(self): | ||
self.components = dict() | ||
|
||
@classmethod | ||
def load(cls, filename=DEFAULT_FILENAME): | ||
""" | ||
loads package model into memory from the conan_package.json file | ||
:param filename: path to the cpp_package.json | ||
:return: a new instance of CppPackage | ||
""" | ||
def from_json(o): | ||
if "components" in o: | ||
return {n: CppPackage.Component(c) for n, c in o["components"].items()} | ||
else: | ||
return o | ||
conan_package = CppPackage() | ||
conan_package.components = json.loads(load(filename), object_hook=from_json) | ||
return conan_package | ||
|
||
def save(self, filename=DEFAULT_FILENAME): | ||
""" | ||
saves package model from memory into the cpp_package.json file | ||
:param filename: path to the cpp_package.json | ||
:return: None | ||
""" | ||
text = json.dumps(self, default=lambda o: o.__dict__, indent=4) | ||
save(filename, text) | ||
|
||
def package_info(self, conanfile): | ||
""" | ||
performs an automatically generated package_info method on conanfile, populating | ||
conanfile.package_info with the information available inside cpp_package.json | ||
:return: None | ||
""" | ||
for cname, component in self.components.items(): | ||
conanfile.cpp_info.components[cname].libs = component.libs | ||
conanfile.cpp_info.components[cname].requires = component.requires | ||
for generator, gname in component.names.items(): | ||
conanfile.cpp_info.components[cname].set_property("cmake_target_name", gname, generator) | ||
|
||
def add_component(self, name): | ||
""" | ||
appens a new CppPackage.Configuration into the internal dictionary | ||
:param name: name of the given configuration (e.g. Debug) | ||
:return: a new CppPackage.Configuration instance (empty) | ||
""" | ||
self.components[name] = CppPackage.Component() | ||
return self.components[name] | ||
|
||
class Component(object): | ||
""" | ||
represents a single component (aka target) within package configuration | ||
""" | ||
def __init__(self, values=None): | ||
if values: | ||
self.names = values["names"] | ||
self.requires = values["requires"] | ||
self.libs = values["libs"] | ||
else: | ||
self.names = dict() | ||
self.requires = [] | ||
self.libs = [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.