forked from conan-io/conan
/
bazeldeps.py
122 lines (94 loc) · 3.83 KB
/
bazeldeps.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import textwrap
from jinja2 import Template
from conans.util.files import save
class BazelDeps(object):
def __init__(self, conanfile):
self._conanfile = conanfile
def generate(self):
local_repositories = []
for dependency in self._conanfile.dependencies.transitive_host_requires:
content = self._get_dependency_buildfile_content(dependency)
filename = self._save_dependendy_buildfile(dependency, content)
local_repository = self._create_new_local_repository(dependency, filename)
local_repositories.append(local_repository)
content = self._get_main_buildfile_content(local_repositories)
self._save_main_buildfiles(content)
def _save_dependendy_buildfile(self, dependency, buildfile_content):
filename = 'conandeps/{}/BUILD'.format(dependency.ref.name)
save(filename, buildfile_content)
return filename
def _get_dependency_buildfile_content(self, dependency):
template = textwrap.dedent("""
load("@rules_cc//cc:defs.bzl", "cc_import", "cc_library")
{% for lib in libs %}
cc_import(
name = "{{ lib }}_precompiled",
static_library = "{{ libdir }}/lib{{ lib }}.a"
)
{% endfor %}
cc_library(
name = "{{ name }}",
{% if headers %}
hdrs = glob([{{ headers }}]),
{% endif %}
{% if includes %}
includes = [{{ includes }}],
{% endif %}
{% if defines %}
defines = [{{ defines }}],
{% endif %}
visibility = ["//visibility:public"]
)
""")
dependency.new_cpp_info.aggregate_components()
if not dependency.new_cpp_info.libs and not dependency.new_cpp_info.includedirs:
return None
headers = []
includes = []
for path in dependency.new_cpp_info.includedirs:
headers.append('"{}/**"'.format(path))
includes.append('"{}"'.format(path))
headers = ', '.join(headers)
includes = ', '.join(includes)
defines = ('"{}"'.format(define) for define in dependency.new_cpp_info.defines)
defines = ', '.join(defines)
context = {
"name": dependency.ref.name,
"libs": dependency.new_cpp_info.libs,
"libdir": dependency.new_cpp_info.libdirs[0],
"headers": headers,
"includes": includes,
"defines": defines
}
content = Template(template).render(**context)
return content
def _create_new_local_repository(self, dependency, dependency_buildfile_name):
snippet = textwrap.dedent("""
native.new_local_repository(
name="{}",
path="{}",
build_file="{}",
)
""").format(
dependency.ref.name,
dependency.package_folder,
dependency_buildfile_name
)
return snippet
def _get_main_buildfile_content(self, local_repositories):
template = textwrap.dedent("""
def load_conan_dependencies():
{}
""")
if local_repositories:
function_content = "\n".join(local_repositories)
function_content = ' '.join(line for line in function_content.splitlines(True))
else:
function_content = ' pass'
content = template.format(function_content)
return content
def _save_main_buildfiles(self, content):
# A BUILD file must exist, even if it's empty, in order for bazel
# to detect it as a bazel package and allow to load the .bzl files
save("conandeps/BUILD", "")
save("conandeps/dependencies.bzl", content)