Skip to content

Commit b078588

Browse files
authored
feat: add cpp binary rule (#19)
1 parent 9234d5a commit b078588

File tree

11 files changed

+249
-56
lines changed

11 files changed

+249
-56
lines changed

cpp/private/actions/compile.bzl

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,48 @@
22
Compile input C++ files into object files
33
"""
44

5-
load("//cpp/private:common.bzl", "get_compile_command_args")
65
load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
6+
load("//cpp/private:common.bzl", "get_compile_command_args")
7+
load("//cpp/private:extra_actions.bzl", "EXTRA_ACTIONS")
78

8-
def _cpp_compile_impl(ctx, sources, headers, includes, features, toolchain):
9+
def _cpp_compile_impl(ctx, sources, headers, includes, modules, features, toolchain, module_srcs = []):
910
obj_files = []
1011

11-
compiler = cc_common.get_tool_for_action(
12-
feature_configuration = features,
13-
action_name = ACTION_NAMES.cpp_compile,
14-
)
12+
extra_vars = {
13+
"cpp_precompiled_modules": [],
14+
}
15+
16+
module_files = []
17+
module_vars = []
18+
19+
for m in modules:
20+
module_files.append(m["file"])
21+
module_vars.append("{name}={file}".format(name = m["name"], file = m["file"].path))
22+
23+
extra_vars["cpp_precompiled_modules"] = module_vars
1524

1625
for src in sources:
26+
action_name = ACTION_NAMES.cpp_compile
27+
if src.extension in ["pcm"]:
28+
action_name = EXTRA_ACTIONS.cpp_module_compile
29+
compiler = cc_common.get_tool_for_action(
30+
feature_configuration = features,
31+
action_name = action_name,
32+
)
33+
1734
outfile = ctx.actions.declare_file("_objs/" + src.basename + ".o")
1835
args = get_compile_command_args(
1936
toolchain,
2037
source = src.path,
2138
output = outfile.path,
2239
features = features,
2340
include_directories = includes,
41+
extra_vars = extra_vars,
2442
)
2543

2644
ctx.actions.run(
2745
outputs = [outfile],
28-
inputs = depset([src], transitive = [depset(headers), toolchain.all_files]),
46+
inputs = depset([src], transitive = [depset(headers), depset(module_files), toolchain.all_files, depset(module_srcs)]),
2947
executable = compiler,
3048
arguments = args,
3149
mnemonic = "CppCompile",

cpp/private/common.bzl

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,44 @@
11
load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
2+
load("//cpp:providers.bzl", "CppModuleInfo")
23

34
def collect_external_headers(deps):
45
headers = []
56

67
for dep in deps:
7-
headers.extend(dep[CcInfo].compilation_context.direct_public_headers)
8-
headers.extend(dep[CcInfo].compilation_context.direct_textual_headers)
8+
if CcInfo in dep:
9+
headers.extend(dep[CcInfo].compilation_context.direct_public_headers)
10+
headers.extend(dep[CcInfo].compilation_context.direct_textual_headers)
911

1012
return headers
1113

1214
def collect_external_includes(deps):
1315
includes = []
1416
for dep in deps:
15-
includes.extend(dep[CcInfo].compilation_context.includes.to_list())
17+
if CcInfo in dep:
18+
includes.extend(dep[CcInfo].compilation_context.includes.to_list())
1619
return depset(includes)
1720

21+
def collect_modules(deps):
22+
modules = []
23+
24+
for dep in deps:
25+
if CppModuleInfo in dep:
26+
modules.append({
27+
"name": dep[CppModuleInfo].module_name,
28+
"file": dep[CppModuleInfo].pcm,
29+
})
30+
31+
return modules
32+
33+
def collect_module_objects(deps):
34+
obj_files = []
35+
36+
for dep in deps:
37+
if CppModuleInfo in dep:
38+
obj_files.extend(dep[CppModuleInfo].objs)
39+
40+
return obj_files
41+
1842
def create_compilation_context(ctx, headers = [], is_aspect = False):
1943
"""
2044
Creates a compiler context structure to be used with C++ rules.
@@ -59,13 +83,18 @@ def create_compilation_context(ctx, headers = [], is_aspect = False):
5983
includes = includes,
6084
)
6185

62-
def get_compile_command_args(toolchain, source = None, output = None, features = None, include_directories = None, pic = True, action_name = "", extra_vars = {}):
86+
def get_compile_command_args(toolchain, source = None, output = None, features = None, include_directories = None, pic = True, action_name = "", extra_vars = None):
6387
action = action_name
6488
if action == "":
6589
action = ACTION_NAMES.c_compile
6690
if source.endswith(".cpp") or source.endswith(".hpp"):
6791
action = ACTION_NAMES.cpp_compile
6892

93+
if extra_vars == None:
94+
extra_vars = {
95+
"cpp_precompiled_modules": [],
96+
}
97+
6998
variables = cc_common.create_compile_variables(
7099
cc_toolchain = toolchain,
71100
feature_configuration = features,
@@ -97,15 +126,16 @@ def resolve_dependency_libraries(ctx, prefer_static):
97126
always_link_libs = []
98127

99128
for dep in ctx.attr.deps:
100-
dep_libs = dep[CcInfo].linking_context.linker_inputs.to_list()
101-
for input in dep_libs:
102-
for item in input.libraries:
103-
if not item.resolved_symlink_dynamic_library == None and (not prefer_static or item.pic_static_library == None):
104-
libs.append(item.resolved_symlink_dynamic_library)
105-
elif not item.pic_static_library == None:
106-
libs.append(item.pic_static_library)
107-
else:
108-
libs.append(item.static_library)
129+
if CcInfo in dep:
130+
dep_libs = dep[CcInfo].linking_context.linker_inputs.to_list()
131+
for input in dep_libs:
132+
for item in input.libraries:
133+
if not item.resolved_symlink_dynamic_library == None and (not prefer_static or item.pic_static_library == None):
134+
libs.append(item.resolved_symlink_dynamic_library)
135+
elif not item.pic_static_library == None:
136+
libs.append(item.pic_static_library)
137+
else:
138+
libs.append(item.static_library)
109139

110140
return depset(libs), depset(always_link_libs)
111141

@@ -138,9 +168,14 @@ def resolve_linker_arguments(ctx, toolchain, features, output_file, is_linking_d
138168
library_search_directories = depset(link_dirs),
139169
)
140170

171+
action_name = ACTION_NAMES.cpp_link_executable
172+
173+
if is_linking_dynamic_library:
174+
action_name = ACTION_NAMES.cpp_link_dynamic_library
175+
141176
link_flags_frozen = cc_common.get_memory_inefficient_command_line(
142177
feature_configuration = features,
143-
action_name = ACTION_NAMES.cpp_link_dynamic_library,
178+
action_name = action_name,
144179
variables = link_variables,
145180
)
146181

cpp/private/extra_actions.bzl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
22

3-
CPP_MODULE_INTEFACE = "cpp-module-interface"
3+
CPP_MODULE_INTEFACE = "cpp20-module-interface"
4+
CPP_MODULE_COMPILE = "cpp20-module-compile"
45

56
EXTRA_ACTIONS = struct(
67
cpp_module_precompile_interface = CPP_MODULE_INTEFACE,
8+
cpp_module_compile = CPP_MODULE_COMPILE,
79
)
810

911
all_c_compile_actions = [
@@ -18,6 +20,7 @@ all_cpp_compile_actions = [
1820
ACTION_NAMES.cpp_header_parsing,
1921
ACTION_NAMES.cpp_module_compile,
2022
ACTION_NAMES.cpp_module_codegen,
23+
EXTRA_ACTIONS.cpp_module_compile,
2124
]
2225

2326
all_compile_actions = all_c_compile_actions + all_cpp_compile_actions

cpp/private/target_rules.bzl

Lines changed: 77 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Contains rules implementations for building C++ targets
44

55
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
66
load("//cpp:providers.bzl", "CppModuleInfo")
7-
load("//cpp/private:common.bzl", "collect_external_headers", "collect_external_includes", "get_compile_command_args", "resolve_linker_arguments")
7+
load("//cpp/private:common.bzl", "collect_external_headers", "collect_external_includes", "collect_module_objects", "collect_modules", "get_compile_command_args", "resolve_linker_arguments")
88
load("//cpp/private:extra_actions.bzl", "EXTRA_ACTIONS")
99
load("//cpp/private/actions:compile.bzl", "cpp_compile")
1010
load("//cpp/private/actions:strip.bzl", "cpp_strip_binary", "cpp_strip_objects")
@@ -49,9 +49,10 @@ def shlib_impl(ctx):
4949

5050
all_headers = headers + collect_external_headers(ctx.attr.deps)
5151
includes = depset([ctx.bin_dir.path + "/_virtual_includes/" + ctx.attr.name] + ctx.attr.includes, transitive = [collect_external_includes(ctx.attr.deps)])
52+
modules = collect_modules(ctx.attr.deps)
5253

53-
obj_files = cpp_compile(ctx.files.srcs, all_headers, includes, features, toolchain)
54-
obj_files = cpp_strip_objects(obj_files, features, toolchain)
54+
obj_files = cpp_compile(ctx.files.srcs, all_headers, includes, modules, features, toolchain)
55+
obj_files = cpp_strip_objects(obj_files, features, toolchain) + collect_module_objects(ctx.attr.deps)
5556

5657
shlib = ctx.actions.declare_file(ctx.attr.lib_prefix + ctx.attr.name + ctx.attr.lib_suffix)
5758
compile_output = shlib
@@ -73,7 +74,7 @@ def shlib_impl(ctx):
7374
inputs = depset(obj_files, transitive = [lib_inputs, toolchain.all_files]),
7475
executable = linker,
7576
arguments = link_flags,
76-
mnemonic = "CppLink",
77+
mnemonic = "CppLinkSharedLibrary",
7778
progress_message = "Compiling %{output}",
7879
)
7980

@@ -116,23 +117,26 @@ def module_impl(ctx):
116117
Returns:
117118
A tuple of providers
118119
"""
119-
toolchain = ctx.attr._cc_toolchain[cc_common.CcToolchainInfo]
120+
toolchain = find_cpp_toolchain(ctx)
120121

121122
features = cc_common.configure_features(ctx = ctx, cc_toolchain = toolchain, requested_features = ctx.features + ["no_agressive_strip"], unsupported_features = ctx.disabled_features)
122123

123124
headers = collect_external_headers(ctx.attr.deps)
124125
includes = depset(ctx.attr.includes, transitive = [collect_external_includes(ctx.attr.deps)])
126+
modules = collect_modules(ctx.attr.deps)
127+
128+
extra_vars = {
129+
"cpp_precompiled_modules": [],
130+
}
125131

126-
extra_modules = []
127132
module_files = []
128-
for dep in ctx.attr.deps:
129-
if CppModuleInfo in dep:
130-
module = dep[CppModuleInfo]
131-
extra_modules.append({
132-
"name": module.module_name,
133-
"file": module.pcm.path,
134-
})
135-
module_files.append(module.pcm)
133+
module_vars = []
134+
135+
for m in modules:
136+
module_files.append(m["file"])
137+
module_vars.append("{name}={file}".format(name = m["name"], file = m["file"].path))
138+
139+
extra_vars["cpp_precompiled_modules"] = module_vars
136140

137141
pcm = ctx.actions.declare_file("_pcm/" + ctx.attr.module_name + "-" + ctx.files.interface[0].basename[:-(len(ctx.files.interface[0].extension) + 1)] + ".pcm")
138142

@@ -143,8 +147,7 @@ def module_impl(ctx):
143147
features = features,
144148
include_directories = includes,
145149
action_name = EXTRA_ACTIONS.cpp_module_precompile_interface,
146-
extra_vars = {
147-
},
150+
extra_vars = extra_vars,
148151
)
149152

150153
compiler = cc_common.get_tool_for_action(
@@ -155,17 +158,72 @@ def module_impl(ctx):
155158
ctx.actions.run(
156159
outputs = [pcm],
157160
mnemonic = "CppModulePrecompile",
158-
inputs = depset(ctx.files.interface, transitive = [depset(headers), toolchain.all_files]),
161+
inputs = depset(ctx.files.interface, transitive = [depset(headers), depset(module_files), toolchain.all_files]),
159162
arguments = precompile_args,
160163
executable = compiler,
161164
progress_message = "Precompiling %{output}",
162165
)
163166

164-
obj_files = cpp_compile(ctx.files.srcs + [pcm], headers, includes, features, toolchain)
165-
obj_files = cpp_strip_objects(obj_files, features, toolchain)
167+
obj_files = cpp_compile(ctx.files.srcs + [pcm], headers, includes, modules, features, toolchain, module_srcs = ctx.files.interface)
168+
obj_files = cpp_strip_objects(obj_files, features, toolchain) + collect_module_objects(ctx.attr.deps)
166169

167170
return CppModuleInfo(
168171
module_name = ctx.attr.module_name,
169172
pcm = pcm,
170173
objs = obj_files,
171174
)
175+
176+
def binary_impl(ctx):
177+
"""
178+
Implements C++ rules for building C++ 20 modules
179+
180+
Return a tuple of providers
181+
182+
Args:
183+
ctx: rule context
184+
185+
Returns:
186+
A tuple of providers
187+
"""
188+
toolchain = find_cpp_toolchain(ctx)
189+
190+
features = cc_common.configure_features(ctx = ctx, cc_toolchain = toolchain, requested_features = ctx.features + ["no_agressive_strip"], unsupported_features = ctx.disabled_features)
191+
192+
all_headers = collect_external_headers(ctx.attr.deps)
193+
includes = collect_external_includes(ctx.attr.deps)
194+
195+
modules = collect_modules(ctx.attr.deps)
196+
197+
obj_files = cpp_compile(ctx.files.srcs, all_headers, includes, modules, features, toolchain)
198+
obj_files = cpp_strip_objects(obj_files, features, toolchain) + collect_module_objects(ctx.attr.deps)
199+
200+
bin = ctx.actions.declare_file(ctx.attr.name + ctx.attr.bin_suffix)
201+
compile_output = bin
202+
if _has_agressive_strip(features, toolchain):
203+
compile_output = ctx.actions.declare_file(ctx.attr.name + ".nonstripped" + ctx.attr.bin_suffix)
204+
205+
link_flags, lib_inputs = resolve_linker_arguments(ctx, toolchain, features, compile_output.path, False)
206+
207+
for obj in obj_files:
208+
link_flags.append(obj.path)
209+
210+
linker = cc_common.get_tool_for_action(
211+
feature_configuration = features,
212+
action_name = ACTION_NAMES.cpp_link_executable,
213+
)
214+
215+
ctx.actions.run(
216+
outputs = [compile_output],
217+
inputs = depset(obj_files, transitive = [lib_inputs, toolchain.all_files]),
218+
executable = linker,
219+
arguments = link_flags,
220+
mnemonic = "CppLinkExecutable",
221+
progress_message = "Linking %{output}",
222+
)
223+
224+
if _has_agressive_strip(features, toolchain):
225+
cpp_strip_binary(compile_output, compile_output, bin, toolchain)
226+
227+
default_provider = DefaultInfo(executable = bin)
228+
229+
return default_provider

cpp/private/toolchain.bzl

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,31 @@ def _get_clang_features(ctx):
166166
actions = [EXTRA_ACTIONS.cpp_module_precompile_interface],
167167
flag_groups = [
168168
flag_group(
169-
flags = ["-x", "c++-module", "%{cpp_module_interface_file}"],
170-
expand_if_available = "cpp_module_interface_file",
169+
flags = ["-x", "c++-module"],
170+
),
171+
],
172+
),
173+
],
174+
)
175+
176+
use_modules = feature(
177+
name = "c++20_modules",
178+
flag_sets = [
179+
flag_set(
180+
actions = all_cpp_compile_actions + [EXTRA_ACTIONS.cpp_module_precompile_interface],
181+
flag_groups = [
182+
flag_group(
183+
iterate_over = "cpp_precompiled_modules",
184+
expand_if_available = "cpp_precompiled_modules",
185+
flags = ["-fmodule-file=%{cpp_precompiled_modules}"],
186+
),
187+
],
188+
),
189+
flag_set(
190+
actions = [EXTRA_ACTIONS.cpp_module_precompile_interface],
191+
flag_groups = [
192+
flag_group(
193+
flags = ["--precompile"],
171194
),
172195
],
173196
),
@@ -195,12 +218,13 @@ def _get_clang_features(ctx):
195218
stdlib_feature,
196219
module_interface_precompile_feature,
197220
lld_feature,
221+
use_modules,
198222
]
199223

200224
def _get_action_configs(compiler, strip, archiver):
201225
return [
202226
action_config(action_name = name, enabled = True, tools = [struct(type_name = "tool", tool = compiler)])
203-
for name in all_c_compile_actions + all_cpp_compile_actions + all_link_actions
227+
for name in all_c_compile_actions + all_cpp_compile_actions + all_link_actions + [EXTRA_ACTIONS.cpp_module_precompile_interface]
204228
] + [
205229
action_config(action_name = name, enabled = True, tools = [struct(type_name = "tool", tool = archiver)])
206230
for name in [ACTION_NAMES.cpp_link_static_library]

0 commit comments

Comments
 (0)