I am starting to use Bazel as my C++ project build system.
However I am stuck with the following problem:
I am in a scenario where I automatically generate the file.hpp file.cpp (literate programming).
To reproduce my problem one can simply use this minimal generator:
-- file.sh --
#!/bin/sh
echo "int foo();" >> file.hpp
echo "#include \"myLib/file.hpp\"\n\nint foo() { return 2017; }" >> file.cpp
My project repo is: (WORKSPACE is an empty file)
├── myLib
│ ├── BUILD
│ └── file.sh
└── WORKSPACE
The BUILD file is
genrule(
name = "tangle_file",
srcs = ["file.sh"],
outs = ["file.cpp","file.hpp"],
cmd = "./$(location file.sh);cp file.cpp $(@D);cp file.hpp $(@D);"
)
cc_library(
name = "file",
srcs = ["file.cpp"],
hdrs = ["file.hpp"],
# deps = [":tangle_file"],
visibility = ["//bin:__pkg__"],
)
I have two problems:
Question (A), dealing with the genrule() part:
The fact that I must use
cmd = "./$(location file.sh);cp file.cpp $(@D);cp file.hpp $(@D);"
is quite mysterious.
My first attempt was:
cmd = "./$(location file.sh)"
However in that case I get the following error:
declared output 'myLib/file.cpp' was not created by genrule. This is probably because the genrule actually didn't create this output, or because the output was a directory and the genrule was run remotely (note that only the contents of declared file outputs are copied from genrules run remotely)
Question (B), dealing with the cc_library() part
I do not know how to make Bazel aware of that the :file target depends on the :tangle_file target.
If I uncomment:
deps = [":tangle_file"],
I get the following error:
in deps attribute of cc_library rule //myLib:file: genrule rule '//myLib:tangle_file' is misplaced here (expected cc_inc_library, cc_library, objc_library, experimental_objc_library or cc_proto_library).
Bazel is a tool that automates software builds and tests. Supported build tasks include running compilers and linkers to produce executable programs and libraries, and assembling deployable packages for Android, iOS and other target environments.
Bazel supports multiple build files and multiple targets per BUILD file, allowing for builds that are more incremental than Maven's. Maven takes charge of steps for the deployment process. Bazel does not automate deployment. Bazel enables you to express dependencies between languages.
Bazel is fast and builds correctly - It can cache build results and only rebuild what it needs to, which make it fast. Its platform independent - It can run on Linux, macOS, Windows. Bazel scales - It can handle large source files easily. It works with various repositories and user bases in the tens of thousands.
In summary, the data and analysis indicates clearly that Gradle is a better choice than Bazel for most JVM projects. We will provide an equivalent comparison for Android projects in a follow up article.
The error that you are seeing is because the genrule cmd is not run inside of its output directory. If you hardcoded bazel-out/local-fastbuild/genfiles/myLib/file.cpp
instead of file.cpp
in your file.sh
script, it would work. However, the recommended approach would be for your script to takes its output directory as an argument.
For example,
genrule(
name = "tangle_file",
srcs = ["file.sh"],
outs = ["file.cpp","file.hpp"],
cmd = "./$(location file.sh) $(@D)"
)
and
#!/bin/sh
echo "int foo();" >> $1/file.hpp
echo "#include \"myLib/file.hpp\"\n\nint foo() { return 2017; }" >> $1/file.cpp
The fact that you have
srcs = ["file.cpp"],
hdrs = ["file.hpp"],
in your cc_library
is what tells Bazel that it depends on the genrule
, since the genrule
creates those files. If you want to make it more explicit, you could use the label syntax, which does the same thing:
srcs = ["//myLib:file.cpp"],
hdrs = ["//myLib:file.hpp"],
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With