|
| 1 | +import json |
| 2 | +import re |
1 | 3 | from conan import ConanFile |
2 | 4 | from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout |
3 | | -from conan.tools.files import copy, get, rmdir |
| 5 | +from conan.tools.files import copy, get, rmdir, load, save, collect_libs |
4 | 6 | import os |
5 | 7 |
|
6 | 8 | required_conan_version = ">=2.2.2" |
@@ -48,12 +50,75 @@ def package(self): |
48 | 50 | copy(self, pattern="LICENSE", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses")) |
49 | 51 | cmake = CMake(self) |
50 | 52 | cmake.install() |
| 53 | + self._create_components_file() |
51 | 54 | rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig")) |
| 55 | + rmdir(self, os.path.join(self.package_folder, "lib", "cmake")) |
| 56 | + |
| 57 | + def _create_components_file(self): |
| 58 | + components = {} |
| 59 | + dbg = "_d" if self.settings.build_type == "Debug" else "" |
| 60 | + targets_file = os.path.join(self.package_folder, "lib", "cmake", "absl", "abslTargets.cmake") |
| 61 | + abs_target_content = load(self, targets_file).replace("\r\n", "\n") |
| 62 | + |
| 63 | + cmake_functions = re.findall(r"(?P<func>add_library|set_target_properties)[\n|\s]*\([\n|\s]*(?P<args>[^)]*)\)", abs_target_content) |
| 64 | + for cmake_function_name, cmake_function_args in cmake_functions: |
| 65 | + cmake_function_args = re.split(r"[\s|\n]+", cmake_function_args, maxsplit=2) |
| 66 | + cmake_imported_target_name = cmake_function_args[0] |
| 67 | + cmake_target_nonamespace = cmake_imported_target_name.replace("absl::", "") |
| 68 | + potential_lib_name = "absl_" + cmake_target_nonamespace |
| 69 | + components.setdefault(potential_lib_name, {"cmake_target": cmake_target_nonamespace}) |
| 70 | + |
| 71 | + if cmake_function_name == "add_library": |
| 72 | + cmake_imported_target_type = cmake_function_args[1] |
| 73 | + if cmake_imported_target_type in ["STATIC", "SHARED"]: |
| 74 | + components[potential_lib_name]["libs"] = [ |
| 75 | + f"{potential_lib_name}{dbg}" if cmake_target_nonamespace != "abseil_dll" else f"abseil_dll{dbg}" |
| 76 | + ] |
| 77 | + elif cmake_function_name == "set_target_properties": |
| 78 | + target_properties = re.findall( |
| 79 | + r"(?P<property>INTERFACE_COMPILE_DEFINITIONS|INTERFACE_INCLUDE_DIRECTORIES|INTERFACE_LINK_LIBRARIES)[\n|\s]+(?P<values>.+)", |
| 80 | + cmake_function_args[2], |
| 81 | + ) |
| 82 | + for target_property in target_properties: |
| 83 | + property_type = target_property[0] |
| 84 | + if property_type == "INTERFACE_LINK_LIBRARIES": |
| 85 | + values_list = target_property[1].replace('"', "").split(";") |
| 86 | + for dependency in values_list: |
| 87 | + if dependency.startswith("absl::"): # abseil targets |
| 88 | + components[potential_lib_name].setdefault("requires", []).append(dependency.replace("absl::", "absl_")) |
| 89 | + else: |
| 90 | + if self.settings.os == "Linux": |
| 91 | + if dependency == "Threads::Threads": |
| 92 | + components[potential_lib_name].setdefault("system_libs", []).append("pthread") |
| 93 | + elif "-lm" in dependency: |
| 94 | + components[potential_lib_name].setdefault("system_libs", []).append("m") |
| 95 | + elif "-lrt" in dependency: |
| 96 | + components[potential_lib_name].setdefault("system_libs", []).append("rt") |
| 97 | + elif self.settings.os == "Windows": |
| 98 | + for system_lib in ["bcrypt", "advapi32", "dbghelp"]: |
| 99 | + if system_lib in dependency: |
| 100 | + components[potential_lib_name].setdefault("system_libs", []).append(system_lib) |
| 101 | + elif property_type == "INTERFACE_COMPILE_DEFINITIONS": |
| 102 | + values_list = target_property[1].replace('"', "").split(";") |
| 103 | + for definition in values_list: |
| 104 | + if definition == r"\$<\$<PLATFORM_ID:AIX>:_LINUX_SOURCE_COMPAT>": |
| 105 | + continue |
| 106 | + components[potential_lib_name].setdefault("defines", []).append(definition) |
| 107 | + content = json.dumps(components, indent=4) |
| 108 | + save(self, os.path.join(self.package_folder, "lib", "abseil_components.json"), content) |
52 | 109 |
|
53 | 110 | def package_info(self): |
54 | | - self.cpp_info.builddirs.append(os.path.join("lib", "cmake")) |
55 | | - self.cpp_info.set_property("cmake_find_mode", "none") # do NOT generate cmake files, they are generated by abseil |
56 | | - self.cpp_info.set_property("cmake_file_name", "absl") # let CMake search for absl, not abseil (the package name) |
57 | | - self.cpp_info.set_property( |
58 | | - "cmake_target_name", "absl::base" |
59 | | - ) # let CMake link to absl::base, not abseil::abseil (derived from the package name) |
| 111 | + # self.cpp_info.set_property("cpe", "") # No CPE yet? |
| 112 | + self.cpp_info.set_property("base_purl", "github/abseil/abseil-cpp") |
| 113 | + self.cpp_info.set_property("cmake_file_name", "absl") |
| 114 | + |
| 115 | + collect_libs(self) |
| 116 | + abseil_components = json.loads(load(self, os.path.join(self.package_folder, "lib", "abseil_components.json"))) |
| 117 | + for pkgconfig_name, values in abseil_components.items(): |
| 118 | + cmake_target = values["cmake_target"] |
| 119 | + self.cpp_info.components[pkgconfig_name].set_property("cmake_target_name", f"absl::{cmake_target}") |
| 120 | + self.cpp_info.components[pkgconfig_name].set_property("pkg_config_name", pkgconfig_name) |
| 121 | + self.cpp_info.components[pkgconfig_name].defines = values.get("defines", []) |
| 122 | + self.cpp_info.components[pkgconfig_name].system_libs = values.get("system_libs", []) |
| 123 | + self.cpp_info.components[pkgconfig_name].requires = values.get("requires", []) |
| 124 | + self.cpp_info.components[pkgconfig_name].libs = values.get("libs", []) |
0 commit comments