Skip to content

Commit fcd644e

Browse files
jjmaestroJames Sharpe
andauthored
feat: meson additional targets (#1385)
Co-authored-by: James Sharpe <[email protected]>
1 parent e74bd93 commit fcd644e

File tree

10 files changed

+269
-46
lines changed

10 files changed

+269
-46
lines changed

examples/meson_simple/BUILD.bazel

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
load("@rules_cc//cc:defs.bzl", "cc_test")
2+
load("@rules_foreign_cc//foreign_cc:defs.bzl", "meson")
3+
load("@rules_shell//shell:sh_test.bzl", "sh_test")
4+
5+
meson(
6+
name = "meson_lib",
7+
build_data = ["//meson_simple/code:clang_wrapper.sh"],
8+
env = select({
9+
"//:windows": {
10+
"CLANG_WRAPPER": "$(execpath //meson_simple/code:clang_wrapper.sh)",
11+
"CXX_FLAGS": "/MD",
12+
},
13+
"//conditions:default": {
14+
"CLANG_WRAPPER": "$(execpath //meson_simple/code:clang_wrapper.sh)",
15+
"CXX_FLAGS": "-fPIC",
16+
},
17+
}),
18+
lib_source = "//meson_simple/code:srcs",
19+
out_static_libs = ["liba.a"],
20+
)
21+
22+
cc_test(
23+
name = "test_lib",
24+
srcs = [
25+
"test_libb.cpp",
26+
],
27+
deps = [
28+
":meson_lib",
29+
],
30+
)
31+
32+
meson(
33+
name = "meson_lib-introspect",
34+
lib_source = "//meson_simple/code:srcs",
35+
out_data_files = ["introspect.json"],
36+
out_include_dir = "",
37+
targets = ["introspect"],
38+
)
39+
40+
sh_test(
41+
name = "test_introspect",
42+
srcs = ["test_introspect.sh"],
43+
args = ["$(location meson_lib-introspect)"],
44+
data = [":meson_lib-introspect"],
45+
deps = ["@bazel_tools//tools/bash/runfiles"],
46+
)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
exports_files(["clang_wrapper.sh"])
2+
3+
filegroup(
4+
name = "srcs",
5+
srcs = [
6+
"liba.cpp",
7+
"liba.h",
8+
"meson.build",
9+
],
10+
visibility = ["//meson_simple:__subpackages__"],
11+
)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/usr/bin/env bash
2+
3+
set -o errexit
4+
set -o nounset
5+
6+
if [[ $(uname) == *"NT"* ]]; then
7+
# If Windows
8+
exec clang-cl "$@"
9+
else
10+
exec clang "$@"
11+
fi
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#include "liba.h"
2+
3+
std::string hello_liba(void) { return "Hello from LIBA!"; }

examples/meson_simple/code/liba.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#ifndef LIBA_H_
2+
#define LIBA_H_ (1)
3+
4+
#include <stdio.h>
5+
6+
#include <string>
7+
8+
std::string hello_liba(void);
9+
10+
#endif
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
project('liba', 'cpp')
2+
3+
builddir = 'rules_foreign_cc_build'
4+
5+
cxx = meson.get_compiler('cpp')
6+
7+
liba = static_library(
8+
'a',
9+
'liba.cpp',
10+
cpp_args: cxx.get_supported_arguments(),
11+
include_directories: include_directories('.'),
12+
install: true,
13+
install_dir: join_paths(get_option('prefix'), 'lib'),
14+
)
15+
16+
install_headers('liba.h', subdir: 'include')
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env bash
2+
3+
# --- begin runfiles.bash initialization ---
4+
# The runfiles library itself defines rlocation which you would need to look
5+
# up the library's runtime location, thus we have a chicken-and-egg problem.
6+
#
7+
# Copy-pasted from Bazel's Bash runfiles library (tools/bash/runfiles/runfiles.bash).
8+
set -euo pipefail
9+
if [[ ! -d "${RUNFILES_DIR:-/dev/null}" && ! -f "${RUNFILES_MANIFEST_FILE:-/dev/null}" ]]; then
10+
if [[ -f "$0.runfiles_manifest" ]]; then
11+
export RUNFILES_MANIFEST_FILE="$0.runfiles_manifest"
12+
elif [[ -f "$0.runfiles/MANIFEST" ]]; then
13+
export RUNFILES_MANIFEST_FILE="$0.runfiles/MANIFEST"
14+
elif [[ -f "$0.runfiles/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then
15+
export RUNFILES_DIR="$0.runfiles"
16+
fi
17+
fi
18+
if [[ -f "${RUNFILES_DIR:-/dev/null}/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then
19+
source "${RUNFILES_DIR}/bazel_tools/tools/bash/runfiles/runfiles.bash"
20+
elif [[ -f "${RUNFILES_MANIFEST_FILE:-/dev/null}" ]]; then
21+
source "$(grep -m1 "^bazel_tools/tools/bash/runfiles/runfiles.bash " \
22+
"$RUNFILES_MANIFEST_FILE" | cut -d ' ' -f 2-)"
23+
else
24+
echo >&2 "ERROR: cannot find @bazel_tools//tools/bash/runfiles:runfiles.bash"
25+
exit 1
26+
fi
27+
# --- end runfiles.bash initialization ---
28+
29+
[[ -f $(rlocation $TEST_WORKSPACE/$1) ]] && exit 0
30+
exit 1
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <iostream>
2+
#include <stdexcept>
3+
#include <string>
4+
5+
#include "include/liba.h"
6+
7+
int main(int argc, char* argv[]) {
8+
std::string result = hello_liba();
9+
if (result != "Hello from LIBA!") {
10+
throw std::runtime_error("Wrong result: " + result);
11+
}
12+
std::cout << "Everything's fine!";
13+
}

foreign_cc/meson.bzl

Lines changed: 100 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -99,46 +99,98 @@ def _create_meson_script(configureParameters):
9999
root = detect_root(ctx.attr.lib_source)
100100
data = ctx.attr.data + ctx.attr.build_data
101101

102-
# Generate a list of arguments for meson
103-
options_str = " ".join([
104-
"-D{}=\"{}\"".format(key, ctx.attr.options[key])
105-
for key in ctx.attr.options
106-
])
102+
if attrs.tool_prefix:
103+
tool_prefix = "{} ".format(
104+
expand_locations_and_make_variables(ctx, attrs.tool_prefix, "tool_prefix", data),
105+
)
106+
else:
107+
tool_prefix = ""
108+
109+
meson_path = "{tool_prefix}{meson_path}".format(
110+
tool_prefix = tool_prefix,
111+
meson_path = attrs.meson_path,
112+
)
107113

108-
prefix = "{} ".format(expand_locations_and_make_variables(ctx, attrs.tool_prefix, "tool_prefix", data)) if attrs.tool_prefix else ""
114+
target_args = dict(ctx.attr.target_args)
109115

110-
setup_args_str = " ".join(expand_locations_and_make_variables(ctx, ctx.attr.setup_args, "setup_args", data))
116+
# --- TODO: DEPRECATED, delete on a future release ------------------------
117+
# Convert the deprecated arguments into the new target_args argument. Fail
118+
# if there's a deprecated argument being used together with its new
119+
# target_args (e.g. setup_args and a "setup" target_args).
111120

112-
script.append("{prefix}{meson} setup --prefix={install_dir} {setup_args} {options} {source_dir}".format(
113-
prefix = prefix,
114-
meson = attrs.meson_path,
115-
install_dir = "$$INSTALLDIR$$",
116-
setup_args = setup_args_str,
117-
options = options_str,
118-
source_dir = "$$EXT_BUILD_ROOT$$/" + root,
119-
))
121+
deprecated = [
122+
("setup", ctx.attr.setup_args),
123+
("compile", ctx.attr.build_args),
124+
("install", ctx.attr.install_args),
125+
]
126+
127+
for target_name, args_ in deprecated:
128+
if args_ and target_name in target_args:
129+
fail("Please migrate '{t}_args' to 'target_args[\"{t}\"]'".format(t = target_name))
130+
131+
target_args[target_name] = args_
132+
133+
# --- TODO: DEPRECATED, delete on a future release ------------------------
120134

121-
build_args = [] + ctx.attr.build_args
122-
build_args_str = " ".join([
123-
ctx.expand_location(arg, data)
124-
for arg in build_args
125-
])
135+
# Expand target args
136+
for target_name, args_ in target_args.items():
137+
if target_name == "setup":
138+
args = expand_locations_and_make_variables(ctx, args_, "setup_args", data)
139+
else:
140+
args = [ctx.expand_location(arg, data) for arg in args_]
126141

127-
script.append("{prefix}{meson} compile {args}".format(
128-
prefix = prefix,
129-
meson = attrs.meson_path,
130-
args = build_args_str,
142+
target_args[target_name] = args
143+
144+
script.append("{meson} setup --prefix={install_dir} {setup_args} {options} {source_dir}".format(
145+
meson = meson_path,
146+
install_dir = "$$INSTALLDIR$$",
147+
setup_args = " ".join(target_args.get("setup", [])),
148+
options = " ".join([
149+
"-D{}=\"{}\"".format(key, ctx.attr.options[key])
150+
for key in ctx.attr.options
151+
]),
152+
source_dir = "$$EXT_BUILD_ROOT$$/" + root,
131153
))
132154

133-
if ctx.attr.install:
134-
install_args = " ".join([
135-
ctx.expand_location(arg, data)
136-
for arg in ctx.attr.install_args
137-
])
138-
script.append("{prefix}{meson} install {args}".format(
139-
prefix = prefix,
140-
meson = attrs.meson_path,
141-
args = install_args,
155+
targets = ctx.attr.targets
156+
157+
# --- TODO: DEPRECATED, delete on a future release ------------------------
158+
targets = [
159+
t
160+
for t in targets
161+
if t != "install" or ctx.attr.install
162+
]
163+
# --- TODO: DEPRECATED, delete on a future release ------------------------
164+
165+
# NOTE:
166+
# introspect has an "old API" and doesn't work like other commands.
167+
# It requires a builddir argument and it doesn't have a flag to output to a
168+
# file, so it requires a redirect. And, most probably, it will remain like
169+
# this for the foreseable future (see
170+
# https://github.com/mesonbuild/meson/issues/8182#issuecomment-758183324).
171+
#
172+
# To keep things simple, we provide a basic API: users must supply the
173+
# introspection JSON file in `out_data_files`, and we offer a sensible
174+
# default for the introspect command that users can override if needed.
175+
if "introspect" in targets:
176+
if len(ctx.attr.out_data_files) != 1:
177+
msg = "Meson introspect expects a single JSON filename via "
178+
msg += "out_data_files; only one filename should be provided."
179+
fail(msg)
180+
181+
introspect_file = ctx.attr.out_data_files[0]
182+
183+
introspect_args = ["$$BUILD_TMPDIR$$"]
184+
introspect_args += target_args.get("introspect", ["--all", "--indent"])
185+
introspect_args += [">", "$$INSTALLDIR$$/{}".format(introspect_file)]
186+
187+
target_args["introspect"] = introspect_args
188+
189+
for target_name in targets:
190+
script.append("{meson} {target} {args}".format(
191+
meson = meson_path,
192+
target = target_name,
193+
args = " ".join(target_args.get(target_name, [])),
142194
))
143195

144196
return script
@@ -153,26 +205,34 @@ def _attrs():
153205

154206
attrs.update({
155207
"build_args": attr.string_list(
156-
doc = "Arguments for the Meson build command",
208+
doc = "__deprecated__: please use `target_args` with `'build'` target key.",
157209
mandatory = False,
158210
),
159211
"install": attr.bool(
160-
doc = "If True, the `meson install` comand will be performed after a build",
212+
doc = "__deprecated__: please use `targets` if you want to skip install.",
161213
default = True,
162214
),
163215
"install_args": attr.string_list(
164-
doc = "Arguments for the meson install command",
216+
doc = "__deprecated__: please use `target_args` with `'install'` target key.",
165217
mandatory = False,
166218
),
167219
"options": attr.string_dict(
168-
doc = (
169-
"Meson option entries to initialize (they will be passed with `-Dkey=value`)"
170-
),
220+
doc = "Meson `setup` options (converted to `-Dkey=value`)",
171221
mandatory = False,
172222
default = {},
173223
),
174224
"setup_args": attr.string_list(
175-
doc = "Arguments for the Meson setup command",
225+
doc = "__deprecated__: please use `target_args` with `'setup'` target key.",
226+
mandatory = False,
227+
),
228+
"target_args": attr.string_list_dict(
229+
doc = "Dict of arguments for each of the Meson targets. The " +
230+
"target name is the key and the list of args is the value.",
231+
mandatory = False,
232+
),
233+
"targets": attr.string_list(
234+
doc = "A list of targets to run. Defaults to ['compile', 'install']",
235+
default = ["compile", "install"],
176236
mandatory = False,
177237
),
178238
})

0 commit comments

Comments
 (0)