In my bazel BUILD file, I have a line:
srcs = glob([<pattern1>, <pattern2>, ...])
I tried to have one of my patterns be "../dir/*.cc" but I get an error that I'm not allowed to use the .. sequence here.
Checking the documentation, I have found that it's not permitted, but I'm not sure what the expected substitute is.
Similarly, up-level references (..) and current-directory references (./) are forbidden.
How can I include these other source files in my srcs list given my current file structure? If I can't reference the up-level directory, is there a way to use the package name of the other directory instead?
Going "up" from your BUILD file would violate the package boundaries. If you really need that structure and cannot or don't want to change it, you have to make files from one package available to the other package by declaring the corresponding target(s) or at least export the files and making those visible. For instance assuming the following structure:
.
├── BUILD
├── WORKSPACE
├── hello.c
└── tgt
└── BUILD
It the // (top-level) package BUILD I could say:
filegroup(
name = "hello",
srcs = ["hello.c"],
visibility = ["//tgt:__pkg__"],
)
(Could also be: exports_files(["hello.c"], ["//tgt:__pkg__"]) instead in which case I would refer to the file by its name //:hello.c from tgt.)
And inside //tgt (tgt/BUILD) it can then read:
cc_binary(
name="tgt",
srcs=["//:hello"],
)
Which would give me:
$ bazel run //tgt
WARNING: /tmp/bzl1/tgt/BUILD:3:10: in srcs attribute of cc_binary rule //tgt:tgt: please do not import '//:hello.c' directly. You should either move the file to this package or depend on an appropriate rule there
INFO: Analyzed target //tgt:tgt (11 packages loaded, 68 targets configured).
INFO: Found 1 target...
Target //tgt:tgt up-to-date:
bazel-bin/tgt/tgt
INFO: Elapsed time: 0.247s, Critical Path: 0.09s
INFO: 2 processes: 2 linux-sandbox.
INFO: Build completed successfully, 6 total actions
INFO: Build completed successfully, 6 total actions
Hello World!
Note: bazel still flags this as something weird and noteworthy going on. I have to say I do not disagree with it. The tree structure does not seem to correspond to the content very well.
Perhaps in this example the tgt package boundary is artificial and not actually useful? Or hello.c is in the wrong place.
Related
I'm studying Bazel building system at present. I always see the # symbol in Bazel script, but I cannot find any documentation about it. I searched it on the website of Bazel but the result seems useless.
# in Bazel.
For example:
filegroup(
name = "toolchain_fg",
srcs = [
":cc-compiler-amd64",
"#x86_64_unknown_linux_gnu_gcc_730//:compiler_components",
],
)
Could anybody explain the # symbol here for me?
This is to reference a remote repository.
From the doc, depending on other Bazel projects
local_repository(
name = "coworkers_project",
path = "/path/to/coworkers-project",
)
If your coworker has a target //foo:bar, your project can refer to it
as #coworkers_project//foo:bar.
See also the design doc of remote repository and bind example in workspace rules.
In Bazel, targets are referred by labels.
Bazel labels have the following format:
#repoName//packageName:target
For example, in the following packages found in myRepo:
myRepo
├── WORKSPACE
├── package1
│ └── BUILD
│ └── src
└── package2
├── BUILD
└── src
a target called myTarget in package1/BUILD can be labeled as as #myRepo//package1:myTarget globally.
If referenced from the same repo, for example from package2/BUILD, then the #myRepo prefix can be omitted and you can use //package1:myTarget.
If referenced from the same package, for example in another target from package1/BUILD, then the package name can be omitted and you can use :myTarget. The colon can also be omitted if it does not create confusion with a name. Such short form labels should not be confused with the names. Labels start with '//' or ':'. But names never do. For example, the name of the first package is package1 but its label is //package1.
Reference: https://docs.bazel.build/versions/master/build-ref.html
This question is specific to avro-c, but the solution may be generalized to other packages in the OpenEmbedded BitBake system.
How do I create a do_populate_sdk task for avro-c?
I want to generate a Yocto SDK which includes avro-c. The avro-c layer in meta-openembedded is very small:
avro
├── avro-c
│ └── 0001-avro-c-Fix-build-with-clang-compiler.patch
└── avro-c_1.8.1.bb
The avro-c_1.8.1.bb recipe is only 20 lines:
SUMMARY = "Apache Avro data serialization system."
HOMEPAGE = "http://apr.apache.org/"
SECTION = "libs"
LICENSE = "Apache-2.0"
LIC_FILES_CHKSUM = "file://LICENSE;md5=73bdf70f268f0b3b9c5a83dd7a6f3324"
DEPENDS = "jansson zlib xz"
PV .= "+git${SRCPV}"
SRCREV = "4b3677c32b879e0e7f717eb95f9135ac654da760"
SRC_URI = "git://github.com/apache/avro \
file://0001-avro-c-Fix-build-with-clang-compiler.patch;patchdir=../../ \
"
S = "${WORKDIR}/git/lang/c"
LDFLAGS_append_libc-uclibc = " -lm"
inherit cmake
A target image which includes avro-c builds successfully, and ls /usr/bin/avro* lists the Avro functions.
However, avro-c is not included in the host SDK build. One way to troubleshoot this is to try the two commands:
$ bitbake avro-c
$ bitbake avro-c -c populate_sdk
The first command completes successfully. The second command fails with the following error messages:
ERROR: Task do_populate_sdk does not exist for target avro-c (/home/rdepew/workspace/clean1/build/../layers/meta-sporian/recipes-support/avro/avro-c_1.8.1.bb:do_populate_sdk). Close matches:
do_populate_lic
do_populate_sysroot
ERROR: Command execution failed: 1
I looked for clues in the other layers in my build system. It appeared that creating the file avro-c_%.bbappend, containing the single line
inherit nativesdk
might do the trick, but that generated two more BitBake error messages:
ERROR: Nothing PROVIDES 'virtual/x86_64-pokysdk-linux-compilerlibs' (but /home/rdepew/workspace/clean1/build/../layers/meta-sporian/recipes-support/avro/avro-c_1.8.1.bb DEPENDS on or otherwise requires it). Close matches:
virtual/nativesdk-x86_64-pokysdk-linux-compilerlibs
virtual/x86_64-pokysdk-linux-go-crosssdk
virtual/x86_64-pokysdk-linux-gcc-crosssdk
ERROR: Required build target 'avro-c' has no buildable providers.
Missing or unbuildable dependency chain was: ['avro-c', 'virtual/x86_64-pokysdk-linux-compilerlibs']
... and that's where I'm stuck. I'm not sure where to go from here.
Online places that I have researched:
I don't know if it's appropriate to list the URLS of places where I have looked for the answer. They include the GitHub repository for Avro, the Yocto Project ADT manual, and four related questions on StackOverflow. If it's appropriate, I will edit this question to include the URLs.
The right way to add something to SDK (or eSDK - Extended SDK) is via the image of your choice. So, the steps are:
Add a package to the image:
IMAGE_INSTALL_append = " avro-c"
Create Yocto SDK for an image of your choice:
bitbake core-image-full-cmdline -c populate_sdk
Create Yocto eSDK for an image of your choice:
bitbake core-image-full-cmdline -c populate_sdk_ext
Have fun! :-)
You need the following line in your recipe
BBCLASSEXTEND = "nativesdk"
This extends the same recipe to build for sdk as well. See here for more details.
EDIT:
do_populate_sdk: This task applies only for the image recipe. This handles two operations.
Target part: Compiles and installs the header and libraries for the target platform.
Host part: Installs the host part of the library and header based on SDKMACHINE
During these operations, it finds the list of packages needed for the SDK by examining the BBCLASSEXTEND variable and builds the nativesdk-<recipe_name> for combines them together in SDK.
So you have do_populate_sdk for image recipe which bundles the packages together.
See yocto manual here for more details.
I'm trying to use ArduinoJson in a C++ bazel project. It's a header only library with headers in subdirectories under src. But I get an undeclared inclusion(s) error.
This is how the //Third-Party/ArduinoJson cc_library def looks like:
cc_library(
name = "ArduinoJson",
hdrs = glob(["5.12.0/src/**"]),
includes = [
"5.12.0/src",
"5.12.0/src/ArduinoJson",
],
visibility = ["//visibility:public"],
)
The target that uses it (Serialization) does have //Third-Party/ArduinoJson in it's deps
Here is the error:
ERROR: /[...]/Serialization/BUILD:1:1: undeclared inclusion(s) in rule '//[...]/Serialization:Serialization':
this rule is missing dependency declarations for the following files included by '[...]/Serialization/JsonDeserializer.cpp':
'[...]/Third-Party/ArduinoJson/5.12.0/src/ArduinoJson/Data/Encoding.hpp'
'[...]/Third-Party/ArduinoJson/5.12.0/src/ArduinoJson/Serialization/FloatParts.hpp'
'[...]/Third-Party/ArduinoJson/5.12.0/src/ArduinoJson/Polyfills/math.hpp'
'[...]/Third-Party/ArduinoJson/5.12.0/src/ArduinoJson/TypeTraits/FloatTraits.hpp'
Target //[...]/Serialization:Serialization failed to build
Since it is only complaining about files in subdirectories of src, e.g. src/Data/Encoding.hpp, I'm guessing that might have something to do with it?
This is not a duplicate of "How to resolve bazel “undeclared inclusion(s)” error?" since that one is solved by doing what I'm already doing with deps.
Make sure there are no BUILD files in the subdirectories of Third-Party/ArduinoJson, otherwise Bazel regards those as packages and the glob won't pick up files from them.
If you do have BUILD files in those subdirectories, you need to create cc_library rules in them, exporting the headers that you wanted in //Third-Party/ArduinoJson:ArduinoJson, and depending on these cc_libraries from ArduinoJson.
I have a very simple directory structure:
.
├── libs
│ └── foo
│ ├── BUILD
│ ├── include
│ │ └── foo
│ │ └── func.h
│ └── src
│ └── func.cxx
└── WORKSPACE
With func.h:
#pragma once
int square(int );
And func.cxx:
#include <foo/func.h>
int square(int i) { return i * i; }
And BUILD:
cc_library(
name = "foo",
srcs = ["src/func.cxx"],
hdrs = ["include/foo/func.h"],
visibility = ["//visibility:public"],
)
This fails to build:
$ bazel build //libs/foo
INFO: Analysed target //libs/foo:foo (0 packages loaded).
INFO: Found 1 target...
ERROR: /home/brevzin/sandbox/bazel/libs/foo/BUILD:1:1: C++ compilation of rule '//libs/foo:foo' failed (Exit 1)
libs/foo/src/func.cxx:1:22: fatal error: foo/func.h: No such file or directory
#include <foo/func.h>
^
compilation terminated.
Target //libs/foo:foo failed to build
Use --verbose_failures to see the command lines of failed build steps.
INFO: Elapsed time: 0.299s, Critical Path: 0.02s
FAILED: Build did NOT complete successfully
How do I set the include path properly? I tried using include_prefix (whether include or include/foo) but that didn't change the behavior.
Hmm, the tricky part about including headers from another places is that you have to specify the header file from its relative location according to the workspace (where the WORKSPACE file resides).
Moreover, you should not use the angle-bracket including style #include <a/b.h> unless you are including the system header files.
The related specifications for #include can be found here: https://docs.bazel.build/versions/master/bazel-and-cpp.html#include-paths
TL;DR The only change you need to make to your func.cxx file is that, change the first line to #include "libs/foo/include/foo/func.h".
And then, when you run bazel build //... (build all targets in this workspace, similar to make makes all) from the root of the workspace, you will encounter no error.
However, this is not the only way that can solve your problem.
Another way to resolve this issue that does not involve changing the source code include statement would be specifying the include path in the attribute of the rule cc_library.
Which means, you can make changes to your BUILD in path libs/foo to make it look like this:
cc_library(
name = "foo",
srcs = ["src/func.cxx"],
hdrs = ["include/foo/func.h"],
copts = ["-Ilibs/foo/include"], # This is the key part
visibility = ["//visibility:public"],
)
After this change, the compiler will be able to figure out where to find the header file(s), and you don't have to change your source code, yay.
Related information can be found here: https://docs.bazel.build/versions/master/cpp-use-cases.html#adding-include-paths
Nevertheless, there is another hacky way to solve your problem, however, it involves in more changes to your code.
It makes uses of the rule cc_inc_library.
The rule cc_inc_library will strips prefix attribute passed to this rule from the relative path of the header files specified in the hdrs attribute.
The example on the website is a little confusing, your code and directory structure will yield a much better demonstration purpose.
In your case, you have to modify your BUILD file under libs/foo to something that looks like this:
cc_library(
name = "foo",
srcs = ["src/func.cxx"],
deps = [":lib"],
copts = ["-Ilibs/foo/include"],
visibility = ["//visibility:public"],
)
cc_inc_library(
name = "lib",
hdrs = ["include/foo/func.h"],
prefix = "include/foo",
)
In your case, the header file func.h which has a relative path from the package libs/foo as include/foo/func.h, which is specified in the hdrs attribute.
Since it has a relative path to the root of the workspace as libs/foo/include/foo/func.h, and the prefix attribute in the cc_inc_library is specified as include/foo: the value include/foo will be stripped form lib/foo/include/foo/func.h, making it libs/foo/func.h.
So, now you can include this header file in your func.cxx as #include "libs/foo/func.h".
And now, bazel will not report error saying that it was not able to find the header file.
You can find the information about this rule at: https://docs.bazel.build/versions/master/be/c-cpp.html#cc_inc_library.
However, as stated above, the explanation is confusing at best, possibly because the documentation for it is out of date.
I was puzzled by the office explanation on bazel.build for quite some time until I read the source code for this rule at: https://github.com/bazelbuild/bazel/blob/f20ae6b20816df6a393c6e8352befba9b158fdf4/src/main/java/com/google/devtools/build/lib/rules/cpp/CcIncLibrary.java#L36-L50
The comment for the actual code that implements the function does a much, much better job at explaining what this rule actually does.
cc_inc_library rule has been deprecated since Bazel release 0.12.
Use cc_library approach instead.
See: https://blog.bazel.build/2018/04/11/bazel-0.12.html
What you really want here is strip_include_prefix:
cc_library(
name = "foo",
srcs = ["src/func.cxx"],
hdrs = ["include/foo/func.h"],
# Here!
strip_include_prefix = "include",
visibility = ["//visibility:public"],
)
This will make the headers accessible via:
#include "foo/func.h"
This attribute has been available since at least Bazel 0.17.
Part of my build process is to create a tar file of an input directory, located at src/bundle/bundle. In src/bundle/SConscript:
Import('*')
bundleDir = Dir("bundle")
jsontar = Command("bundle.tar", bundleDir,
"/home/dbender/bin/mkvgconf $SOURCE $TARGET")
in my SConstruct:
SConscript(Split('src/bundle/SConscript'),
exports='bin_env lib_env', build_dir='tmp/bundle')
When attempting to build:
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
/home/dbender/bin/mkvgconf tmp/bundle/bundle tmp/bundle/bundle.tar
Input directory tmp/bundle/bundle not found!
scons: *** [tmp/bundle/bundle.tar] Error 1
scons: building terminated because of errors.
Clearly scons is not copying the src/bundle/bundle to tmp/bundle/bundle, but I am stumped as to why.
Footnotes:
Using absolute pathname for mkvgconf is bad practice but just intermediate until I have this problem solved.
SCons doesn't know anything about the contents of your input src/bundle/bundle - only the program mkvgconf knows what it does with that directory.
One solution is to add an explicit dependency in the SConscript:
import os
Depends('bundle.tar', Glob(str(bundleDir) + os.path.sep + '*'))
That also means that when you update the contents of the bundle directory, the mkvgconf script will be rerun.
PS. you might want to change the build_dir argument name to variant_dir, as the former is deprecated in favor of the latter in recent SCons releases.