I can't properly add external dependency with bazel - c++

I trying to test "Hello World" C++ project with Bazel.
I have the following project structure:
WORKSPACE
/dependencies
BUILD
BUILD.gtest
/test
BUILD
WORKSPACE has the following structure:
load("#bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# gtest
http_archive(
name = "gtest",
url = "https://github.com/google/googletest/archive/release-1.10.0.zip",
sha256 = "94c634d499558a76fa649edb13721dce6e98fb1e7018dfaeba3cd7a083945e91",
build_file = "#//dependencies:BUILD.gtest",
strip_prefix = "googletest-release-1.10.0",
)
BUILD.gtest has the following structure:
cc_library(
name = "main",
srcs = glob(
["src/*.cc"],
exclude = ["src/gtest-all.cc"]
),
hdrs = glob([
"include/**/*.h",
"src/*.h"
]),
copts = ["-Iexternal/gtest/include"],
linkopts = ["-pthread"],
visibility = ["//visibility:public"],
)
test BUILD has the following structure:
cc_test(
name = "unittests",
srcs = ["scanner_test.cc"],
copts = ["-Iexternal/gtest/include"],
deps = [
"//scanner:scanner",
"#gtest//:main"
]
)
when I execute
bazel build //test:unittests
I get
INFO: Analyzed target //test:unittests (26 packages loaded, 315 targets configured).
INFO: Found 1 target...
ERROR: ../test/BUILD:1:8: Compiling test/scanner_test.cc failed: (Exit 1): gcc failed: error executing command /usr/bin/gcc -U_FORTIFY_SOURCE -fstack-protector -Wall -Wunused-but-set-parameter -Wno-free-nonheap-object -fno-omit-frame-pointer '-std=c++0x' -MD -MF ... (remaining 25 argument(s) skipped)
Use --sandbox_debug to see verbose messages from the sandbox
test/scanner_test.cc:1:10: fatal error: gtest/gtest.h: No such file or directory
1 | #include "gtest/gtest.h"
| ^~~~~~~~~~~~~~~
compilation terminated.
Target //test:unittests failed to build
Use --verbose_failures to see the command lines of failed build steps.
INFO: Elapsed time: 2.314s, Critical Path: 0.08s
INFO: 2 processes: 2 internal.
FAILED: Build did NOT complete successfully

As the other answer mentions:
The file BUILD.gtest is not needed.
Because gtest repo / release archive already provides one.
The reason why your own didn't behave as you might have expected is you've tried to point to the headers by manipulating copts which is applied only to building that one specific cc_library target (from linked docs):
The flags take effect only for compiling this target, not its dependencies, so be careful about header files included elsewhere.
Whereas to expose these interfaces to other targets consuming it you need to use includes (docs again):
Unlike COPTS, these flags are added for this rule and every rule that depends on it.

The file BUILD.gtest is not needed.
WORKSPACE.bazel:
workspace(name = "GTestDemo")
load("#bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "gtest",
url = "https://github.com/google/googletest/archive/release-1.10.0.tar.gz",
sha256 = "9dc9157a9a1551ec7a7e43daea9a694a0bb5fb8bec81235d8a1e6ef64c716dcb",
strip_prefix = "googletest-release-1.10.0",
)
BUILD.bazel:
cc_test(
name = "tests",
srcs = ["test.cpp"],
deps = [
"#gtest//:gtest",
"#gtest//:gtest_main",
],
)
test.cpp:
#include <iostream>
#include <fstream>
#include "gtest/gtest.h"
using namespace std;
TEST(sample_test_case, sample_test) {
EXPECT_EQ(1, 1);
}
Tested with Bazel 4.1.0.

Related

Bazel include file not found

Edit (2022-05-28): for anyone who ends up here from searching for bazel + sfml, I gave up on trying to compile it from source with bazel.
Instead, I installed SFML with brew. Then in WORKSPACE.bazel:
new_local_repository(
name = "SFML",
path = "/opt/homebrew",
build_file = "third_party/SFML/BUILD.bazel"
)
and third_party/SFML/BUILD.bazel:
cc_library(
name = "sfml",
srcs = glob(["lib/libsfml-*.dylib"]),
hdrs = glob(["include/SFML/**/*.*"]),
include_prefix = "SFML",
strip_include_prefix = "include/SFML",
visibility = ["//visibility:public"],
)
finally, as a dependency in any BUILD.bazel:
cc_binary(
name = "main",
srcs = ["main.cc"],
deps = [
"#SFML//:sfml",
]
)
This allows me to #include <SFML/Graphics.hpp> for example in main.cc and so far it's working.
I'm trying to use bazel to build SFML from source and use it in a project. Right now I have a very simple setup:
foo/
src/
main.cc
BUILD
third_party/
SFML/
...
BUILD
BUILD
WORKSPACE
# third_party/SFML/BUILD
load("#rules_cc//cc:defs.bzl", "cc_library")
cc_library(
name = "sfml",
srcs = glob(["src/*.cpp"]),
hdrs = glob(["include/*.hpp"]),
copts = ["-Ithird_party/SFML/include"],
linkopts = [
"-lsfml‑system",
"-lsfml‑window",
"-lsfml‑graphics",
"-lsfml‑audio",
],
visibility = ["//visibility:public"]
)
# src/BUILD
load("#rules_cc//cc:defs.bzl", "cc_binary")
cc_binary(
name = "mygame",
srcs = ["main.cc"],
deps = [
"//third_party/SFML:sfml",
],
)
and main.cc:
#include "third_party/SFML/sfml/Graphics.hpp"
#include "third_party/SFML/sfml/System.hpp"
#include "third_party/SFML/sfml/Window.hpp"
int main() {
// ...
}
When I run bazel build //src:mygame I get an error:
fatal error: 'third_party/SFML/Graphics.hpp' file not found
I also tried using #include "third_party/SFML/Graphics.hpp" but that doesn't work either.
Not sure what the correct include path needs to be. Any suggestions?

How to use Bazel in case of only header files (template classes/function) in C++?

I have the following problem:
Let's say that my project structure is:
├── project
│ ├── include
| | ├── BUILD
| | └── library.hpp
│ ├── src
| | ├── BUILD
| | └── main.cpp
| ├── test
| | ├── BUILD
| | └── library_test.cpp
└── WORKSPACE
library.hpp is a file which contains implementation of template class and it is included in main.cpp and library_test.cpp.
How to prepare BUILD files so I would not get compilation errors while compiling library_test.cpp and main.cpp that say:
src/main.cpp:2:10: fatal error: shared_ptr.hpp: No such file or directory
2 | #include "library.hpp"
| ^~~~~~~~~~~~~~~~
compilation terminated.
What I tried was:
include/BUILD
load("#rules_cc//cc:defs.bzl", "cc_library")
cc_library(
name = "library",
srcs = ["library.hpp"],
includes = ["include"],
visibility = [
"//visibility:public",
]
)
Above I also tried having hdrs and textual_hdrs instead of srcs.
test/BUILD:
load("#rules_cc//cc:defs.bzl", "cc_test")
cc_test(
name = "library_test",
srcs = ["library_test.cpp"],
deps = [
"#gtest//:gtest",
"#gtest//:gtest_main",
],
includes = ["include"],
copts = ["-Iproject/include"],
)
and to be thorough my WORKSPACE:
load("#bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
git_repository(
name = "gtest",
remote = "https://github.com/google/googletest",
branch = "v1.10.x",
)
I have a problem to figure it out by myself based on offical bazel tutorials, some presentations or similar questions I saw on the internet. They show only use of cc_library in case where definitions of the functions written in library are in cpp file and it can be compiled into object file.
# BUILD
cc_library(
name = "library",
hdrs= ["include/library.hpp"],
includes = ["include"],
visibility = [
"//visibility:public",
]
)
cc_test(
name = "library_test",
srcs = ["test/library_test.cpp"],
deps = [
"#gtest//:gtest_main", # gtest_main already contains gtest
":library"
],
)
cc_binary(
name = "binary",
srcs = ["src/main.cpp"],
deps = [
":library"
],
)
Notice:
Use hdrs, because srcs are not visible by dependent targets.
Do not use separate BUILD files for src/include/test directories. In Bazel you should create packages oriented by functionality, not by layer.
In you code a library_test target will not see headers from a library target, you must pass it as dependency via deps attribute. Bazel use sandboxing TL;DR: actions do not see files, which are not explicitly defined as dependency
Do not use copts = ["-Iproject/include"]. Bazel will do it for you when everything is done correctly: in that case you have to add an includes attribute to a library target. Include path will be set in a library_test, because the test targets depends on the library

Bazel, Windows 10 toolchain configuration with mingw64 compiler

I need to build my own toolchain with Bazel, and I would like to force Bazel to use the g++ compiler of mingw64. I am following the instruction in https://docs.bazel.build/versions/master/tutorial/cc-toolchain-config.html trying to adapt them to my Windows 10 machine.
Bazel is able to compile my Hello-world.cc and create the hello-world.exe, and if I run
bazel-bin/main/hello-world
I get the right output.
Nevertheless, Bazel throws the following errors:
bazel build --config=mingw64_config -s //main:hello-world --verbose_failures
Starting local Bazel server and connecting to it...
INFO: Analyzed target //main:hello-world (15 packages loaded, 47 targets configured).
INFO: Found 1 target...
SUBCOMMAND: # //main:hello-world [action 'Compiling main/hello-world.cc', configuration: e711ec75bfc5b6e1d77ea144cef912e655797b748714c6396a6b8cd3625eebee, execution platform: #local_config_platform//:host]
cd C:/users/_bazel_user/bcge3shs/execroot/__main__
SET PATH=c:\tools\msys64\usr\bin;c:\tools\msys64\bin;C:\WINDOWS;C:\WINDOWS\System32;C:\WINDOWS\System32\WindowsPowerShell\v1.0;C:\Program Files\Haskell\bin;C:\Program Files\Haskell Platform\8.6.5\lib\extralibs\bin;C:\Program Files\Haskell Platform\8.6.5\bin;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\Haskell Platform\8.6.5\mingw\bin;C:\Program Files\dotnet\;C:\Program Files\Git\cmd;C:\Program Files\TortoiseSVN\bin;C:\Users\Documents\Bazel\bazel_binary;C:\mingw64\bin;C:\Users\AppData\Roaming\cabal\bin;C:\Users\AppData\Roaming\local\bin;C:\Users\AppData\Local\Microsoft\WindowsApps;C:\Program Files\LLVM\bin
SET PWD=/proc/self/cwd
SET RUNFILES_MANIFEST_ONLY=1
C:/mingw64/bin/g++ -MD -MF bazel-out/x64_windows-fastbuild/bin/main/_objs/hello-world/hello-world.d -frandom-seed=bazel-out/x64_windows-fastbuild/bin/main/_objs/hello-world/hello-world.o -iquote . -iquote bazel-out/x64_windows-fastbuild/bin -iquote external/bazel_tools -iquote bazel-out/x64_windows-fastbuild/bin/external/bazel_tools -c main/hello-world.cc -o bazel-out/x64_windows-fastbuild/bin/main/_objs/hello-world/hello-world.o
SUBCOMMAND: # //main:hello-world [action 'Linking main/hello-world', configuration: e711ec75bfc5b6e1d77ea144cef912e655797b748714c6396a6b8cd3625eebee, execution platform: #local_config_platform//:host]
cd C:/users/_bazel_user/bcge3shs/execroot/__main__
SET PATH=c:\tools\msys64\usr\bin;c:\tools\msys64\bin;C:\WINDOWS;C:\WINDOWS\System32;C:\WINDOWS\System32\WindowsPowerShell\v1.0;C:\Program Files\Haskell\bin;C:\Program Files\Haskell Platform\8.6.5\lib\extralibs\bin;C:\Program Files\Haskell Platform\8.6.5\bin;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\Haskell Platform\8.6.5\mingw\bin;C:\Program Files\dotnet\;C:\Program Files\Git\cmd;C:\Program Files\TortoiseSVN\bin;C:\Users\Documents\Bazel\bazel_binary;C:\mingw64\bin;C:\Users\AppData\Roaming\cabal\bin;C:\Users\AppData\Roaming\local\bin;C:\Users\AppData\Local\Microsoft\WindowsApps;C:\Program Files\LLVM\bin
SET PWD=/proc/self/cwd
SET RUNFILES_MANIFEST_ONLY=1
C:/mingw64/bin/g++ -o bazel-out/x64_windows-fastbuild/bin/main/hello-world bazel-out/x64_windows-fastbuild/bin/main/_objs/hello-world/hello-world.o -Wl,-S -lstdc++
ERROR: C:/users/documents/bazel/mingw64__compiler/main/BUILD:3:10: output 'main/hello-world' was not created
ERROR: C:/users/documents/bazel/mingw64__compiler/main/BUILD:3:10: not all outputs were created or valid
Target //main:hello-world failed to build
INFO: Elapsed time: 4.171s, Critical Path: 0.31s
INFO: 2 processes: 2 local.
FAILED: Build did NOT complete successfully
Below is my cc_toolchain_config.bzl:
# NEW
load("#bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
# NEW
load(
"#bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl",
"feature",
"flag_group",
"flag_set",
"tool_path",
)
all_link_actions = [ # NEW
ACTION_NAMES.cpp_link_executable,
ACTION_NAMES.cpp_link_dynamic_library,
ACTION_NAMES.cpp_link_nodeps_dynamic_library,
]
def _impl(ctx):
tool_paths = [
tool_path(
name = "gcc",
path = "C:/mingw64/bin/g++",
),
tool_path(
name = "ld",
path = "C:/mingw64/bin/ld",
),
tool_path(
name = "ar",
path = "C:/mingw64/bin/ar",
),
tool_path(
name = "cpp",
path = "C:/mingw64/bin/cpp",
),
tool_path(
name = "gcov",
path = "C:/mingw64/bin/gcov",
),
tool_path(
name = "nm",
path = "C:/mingw64/bin/nm",
),
tool_path(
name = "objdump",
path = "C:/mingw64/bin/objdump",
),
tool_path(
name = "strip",
path = "C:/mingw64/bin/strip",
),
]
features = [ # NEW
feature(
name = "default_linker_flags",
enabled = True,
flag_sets = [
flag_set(
actions = all_link_actions,
flag_groups = ([
flag_group(
flags = [
"-lstdc++",
],
),
]),
),
],
),
]
return cc_common.create_cc_toolchain_config_info(
ctx = ctx,
features = features, # NEW
cxx_builtin_include_directories = [
"C:/mingw64/include",
"C:/mingw64/x86_64-w64-mingw32/include",
"C:/mingw64/lib/gcc/x86_64-w64-mingw32/5.1.0/include-fixed",
"C:/mingw64/lib/gcc/x86_64-w64-mingw32/5.1.0/include",
"C:/mingw64/lib/gcc/x86_64-w64-mingw32/5.1.0",
],
toolchain_identifier = "local",
host_system_name = "local",
target_system_name = "local",
target_cpu = "x64_windows",
target_libc = "unknown",
compiler = "g++",
abi_version = "unknown",
abi_libc_version = "unknown",
tool_paths = tool_paths,
)
cc_toolchain_config = rule(
implementation = _impl,
attrs = {},
provides = [CcToolchainConfigInfo],
Any suggestions on what the problem could be?
The answer to this question can be found here:
Mingw-w64 toolchain for Bazel (Ubuntu 20.04.1 )
It is sufficient to load: artifact_name_pattern from #bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl and set artifact_name_patterns attribute of cc_common.create_cc_toolchain_config_info():
artifact_name_patterns = [
artifact_name_pattern(
category_name = "executable",
prefix = "",
extension = ".exe",
),]

How to specify -std=c++11 option in bazel BUILD file?

How to add this option into a target description section?
Thanks.
Add bazel build --cxxopt='-std=c++11' to .bazelrc file.
export BAZEL_CXXOPTS=-std=c++11
see source
Besides setting it globally in .bazelrc or using BAZEL_CXXOPTS , you can also set them individually for each target in their cc_binary or cc_test rules:
cc_binary(
name = "target1",
srcs = ["target1.cc"],
copts = ["--std=c++17"],
)
cc_binary(
name = "target2",
srcs = ["target2.cc"],
copts = ["--std=c++14"],
)

Include file downloaded by Bazel http_file

I'm using Bazel to build my project. I'd like to use the single-header test framework, Catch v2. I decided to use the http_file rule to make Bazel download the catch header. My WORKSPACE file looks like this:
load("#bazel_tools//tools/build_defs/repo:http.bzl", "http_file")
http_file(
name = "catch",
downloaded_file_path = "catch.hpp",
sha256 = "cc6cc272cf84d8e10fb28f66f52584dedbb80d1234aae69e6a1027af4f31ae6f",
urls = ["https://github.com/catchorg/Catch2/releases/download/v2.4.2/catch.hpp"],
)
According to the doc, the test depends on the generated package like this:
cc_test(
name = "my_test",
srcs = ["#catch//file", "my_test.cc"]
)
The test file my_test.cc can't get any simpler:
#include "catch.hpp"
However, I get the following error:
$ bazel test --config=opt -s //...
WARNING: [...]/BUILD:25:10: in srcs attribute of cc_test rule //test:my_test: please do not import '#catch//file:catch.hpp' directly. You should either move the file to this package or depend on an appropriate rule there
SUBCOMMAND: # //test:my_test [action 'Compiling test/my_test.cc']
(cd [...] && \
exec env - [...] \
/usr/bin/gcc
-U_FORTIFY_SOURCE -fstack-protector -Wall -B/usr/bin -B/usr/bin -Wunused-but-set-parameter -Wno-free-nonheap-object -fno-omit-frame-pointer '-std=c++0x' -MD -MF [...].d '-frandom-seed=[...].o' -fPIC
-iquote .
-iquote bazel-out/k8-fastbuild/genfiles
-iquote bazel-out/k8-fastbuild/bin
-iquote external/bazel_tools
-iquote bazel-out/k8-fastbuild/genfiles/external/bazel_tools
-iquote bazel-out/k8-fastbuild/bin/external/bazel_tools
-fno-canonical-system-headers -Wno-builtin-macro-redefined '-D__DATE__="redacted"' '-D__TIMESTAMP__="redacted"' '-D__TIME__="redacted"' -c test/my_test.cc
-o [...].o)
ERROR: [...]/BUILD:23:1: C++ compilation of rule '//test:my_test' failed (Exit 1)
test/my_test.cc:1:28: fatal error: catch.hpp: No such file or directory
compilation terminated.
[...]
FAILED: Build did NOT complete successfully
Creating a cc_library wrapper, or including catch/catch.hpp, catch/file/catch.hpp produces the same error.
By default, files downloaded by http_file can be included as:
#include "external/<name>/file/<file_name>"
In this specific case:
#include "external/catch/file/catch.hpp"
However, this include path is ugly, it should be wrapped by a cc_library.
Furthermore, compiling the full catch header file for each test will make the build slow. According to the catch docs, the implementation part of the catch header should be compiled separately. Like this:
test/BUILD:
cc_library(
name = "catch",
hdrs = ["#catch//file"],
srcs = ["catch.cpp"],
visibility = ["//visibility:public"],
strip_include_prefix = "/external/catch/file",
include_prefix = "catch",
linkstatic = True, # otherwise main() will could end up in a .so
)
cc_test(
name = "my_test",
deps = ["//test:catch"],
srcs = ["my_test.cc"],
)
test/catch.cpp:
#define CATCH_CONFIG_MAIN
#include "catch/catch.hpp"
test/my_test.cc:
#include "catch/catch.hpp"
TEST_CASE("my_test", "[main]") { /* ... */ }
This way catch.cpp will not be re-compiled if only my_test.cc changes, saving precious seconds.