Where does bazel project store its ".so" files? - c++

I've got a very simple bazel project which builds out a library and a binary like below:
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
deps = [":hello-greet"],
)
cc_library(
name = "hello-greet",
srcs = ["hello-greet.cc"],
hdrs = ["hello-greet.h"],
)
Yes it works in my ubuntu box:
# cat hello-greet.cc
#include<stdio.h>
void f(){
printf("f function\n");
}
# cat hello-world.cc
#include<stdio.h>
#include"hello-greet.h"
int main(){
f();
printf("%s \n", "abc");
return 0;
}
"bazel build hello-world && bazel run hello-world" will print:
f function
abc
Ok, fine. But I cannot find where is my libhello-greet.so is, where is it stored? I cannot find it under my current directory.
Thanks a lot.

Bazel treats the source tree as read-only and puts its outputs in a separate output directory. The official way to find the this directory is to run bazel info output_base. However, as a convenience, Bazel also makes a symlink to this directory called bazel-out in the workspace root.
In your specific case, there may or may not be a shared library for hello-greet actually created—it's perfectly possible to build a binary without creating the intermediate shared objects. bazel build //:hello-greet should build and display the path to a shared object for hello-greet.

It says where in the output of bazel build. Typically in bazel-bin/..., following the same directory structure as the source file.

Related

Why does bazel not see includes defined in bazelrc?

I am migrating large legacy makefiles project to Bazel. Project used to copy all sources and headers into single "build dir" before build, and because of this all source and header files use single level includes, without any prefix (#include "1.hpp").
Bazel requires that modules (libraries) use relative path to header starting at WORKSPACE file, however my goal is to introduce Bazel build files, which require 0 modifications of a source code.
I use bazelrc to globally set paths to includes as if structure was flat:
.bazelrc:
build --copt=-Ia/b/c
/a/b/BUILD
cc_library(
name = "lib",
srcs = ["c/1.cpp"],
hdrs = ["c/1.hpp"],
visibility = ["//visibility:public"]
)
When I build this target, I see my -I flag in compiler invocation, but compilation fails because bazel can not find header 1.hpp:
$ bazel build -s //a/b:lib
...
a/b/c/1.cpp:13:10: fatal error: 1.hpp: No such file or directory
13 | #include "1.hpp"
|
Interestingly enough, it prints me gcc command that it invokes during build and if I run this command, compiler is able to find 1.hpp and 1.cpp compiles.
How to make bazel "see" this includes? Do I really need to additionally specify copts for every target in addition to global -I flags?
Bazel use sandboxing: for each action (compile a C++ file, link a library) the specific build directory is prepared. That directory contains only files (using symlinks and other Linux sorcery), which are explicitly defined as dependency/source/header for given target.
That trick with --copt=-Ia/b/c is a bad idea, because that option will work only for targets, which depend on //a/b:lib.
Use includes or strip_include_prefix attribute instead:
cc_library(
name = "lib",
srcs = ["c/1.cpp"],
hdrs = ["c/1.hpp"],
strip_include_prefix = "c",
visibility = ["//visibility:public"]
)
and add the lib as a dependency of every target, which need to access these headers:
cc_binary(
name = "some bin",
srcs = ["foo.cpp"],
deps = ["//a/b:lib"],
)

bazel run immediately Segmentation faults

I am trying to use a locally built package (this one) within an existing bazel project. It bazel builds without any errors, but when I try to bazel run it, it immediately segfaults. I tried building it in debug mode, but when I run it in debug mode it still immediately segfaults without any useful error message.
I built the external package following the instructions in the README and the examples run fine (outside of bazel), so I know that the external libraries are not the issue.
I made a repository to access this package in my WORKSPACE file
new_local_repository(
name = "ApproxMVBB",
path = "/absolute/path/to/ApproxMVBB",
build_file = "approxmvbb.BUILD", )
The approxmvbb.BUILD file looks like this
cc_library(
name = "ApproxMVBB-lib",
srcs = glob(["**/*.a"])+glob(["**/*.so"]),
hdrs = glob(["**/*.hpp"]),
includes = ["include", "build/include", "external/Diameter/include", "external/GeometryPredicates/include"],
visibility = ["//visibility:public"],
)
And the cc_binary I am trying to run looks like this
cc_binary(
name = "TestMVBB",
srcs = [
"src/test_approxmvbb.cpp",
],
deps = [
"#ApproxMVBB//:ApproxMVBB-lib",
],
linkopts = ["-shared"],
)
The source code for the binary src/test_approvmvbb.cpp
#include <iostream>
#include "ApproxMVBB/ComputeApproxMVBB.hpp"
int main(int argc, char** argv)
{
ApproxMVBB::Matrix3Dyn points(3,10000);
points.setRandom();
ApproxMVBB::OOBB oobb = ApproxMVBB::approximateMVBB(points,0.001,500,5,0,5);
oobb.expandToMinExtentRelative(0.1);
return 0;
}
I found my mistakes. First, I was changing a lot of things and forgot to rebuild the external package, so the libraries didn't exist... oops.
But more importantly, when the external package is built, it outputs library files that have file extensions other than .o and .so so I had to change the following line in the cc_library target
srcs = glob(["**/*.a"])+glob(["**/*.so"])+glob(["**/*.so.2.1.1"]),
Hope this helps someone in the future!!

How to build in a separate directory with autotool

I have a working directory as below:
./
|----HelloWorld/
|----|----main.cpp
|----|----Makefile.am
|----Pet/
|----|----Pet.h
|----|----Pet.cpp
|----build/
|----configure.ac
|----Makefile.am
I would like to use the autotool to construct makefile and then build the project in the build directory.
The ./configure.ac is
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([Hello], [1.0], [qub#oregonstate.edu])
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
AC_CONFIG_SRCDIR([HelloWorld/main.cpp])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CXX
AC_PROG_CC
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
The ./Makefile.am is
include HelloWorld/Makefile.am
Note that I'm using the include to make sure the exe locates at the directory where the make command runs.
The ./HelloWorld/Makefile.am is
AM_CPPFLAGS=-I%D%/../Pet/ -I%D% -I%C%
#VPATH = ./HelloWorld ./Pet
bin_PROGRAMS=hello
hello_SOURCES=%D%/../Pet/Pet.h
hello_SOURCES+=%D%/../Pet/Pet.cpp
hello_SOURCES+=%D%/main.cpp
In case some people would like to try on their own computer, I attach other source codes here:
main.cpp
#include <stdio.h>
#include <vector>
#include "Pet.h"
int main() {
printf("Hello World\n");
std::vector<Pet*> all_pets;
Pet *dog = new Pet(string("Apple"));
all_pets.push_back(dog);
Pet *cat = new Pet(string("Pear"));
all_pets.push_back(cat);
for (int i = 0; i < all_pets.size(); i++) {
all_pets[i]->showName();
}
return 0;
}
**Pet.h**
#pragma once
#include <string>
using namespace std;
class Pet
{
public:
Pet(string name);
~Pet();
void showName();
void showIndex();
string _name;
int _index;
};
Pet.cpp
#include "Pet.h"
Pet::Pet(string name)
{
_name = name;
srand(2345);
_index = (rand() % 100);
}
Pet::~Pet()
{
}
void Pet::showIndex()
{
printf("Index is %d\n", _index);
}
void Pet::showName()
{
printf("Name is %s\n", _name.c_str());
}
Problem Statement
Can successfully create makefile by run
./ $autoreconf --install
Can successfully build the project at root directory with using following commands
./ $./configure
./ $make
Get error when building in directory ./build. Commands are:
./build/ $../configure
./build/ $make
Got an error as below image shows:
build error image
I think this error is caused by the compiler cannot successfully find the header files. My first question is Why the AM_CPPFLAGS=-I%D%/../Pet/ -I%D% -I%C% in makefile.am cannot solve this problem?
Since the compiler will create the .o files in the build directory with making the build tree has the same subdirectory layout as the source tree. So I can fix this problem by copy the Pet.h file to \build\Pet. However, this means I always need to copy the header files to the build directory, which is not convenient.
I find some info about VPATH. So I commented out #VPATH = ./HelloWorld ./Pet in ./HelloWorld/Makefile.am. However, it will give me a new problem:
automake error image
My assumption is the VPATH setting somehow conflicts with the include makefile.am. My second question is How can I use the VPATH correctly with using include makefile?
Why the AM_CPPFLAGS=-I%D%/../Pet/ -I%D% -I%C% in makefile.am cannot solve this problem?
Because %D% and %C% produce paths to the included makefile fragment relative to the makefile that includes it, not relative to the build directory. They are not intended or suited for handling out-of-source building, though when used correctly, they do not interfere with that.
How can I use the VPATH correctly with using include makefile?
You are overthinking the problem. Automake supports out-of-source building automatically. You don't need to (and shouldn't) set up VPATH yourself.
You are also making trouble for yourself with the Makefile include directive. That directive definitely has good uses, but you would do better here by either consolidating everything into the top-level Makefile.am or by setting up for recursive make. You shouldn't need that %D% and %C% stuff.
Automake will set up VPATH for you, and that takes care of locating prerequisites when you perform an out-of-source build. For the most part, you just specify paths to sources and targets relative to the location of your Makefile.am and / or configure.ac.
Occasionally you do need to refer to the source directory, and in that case you should use the appropriate one of $(srcdir), $(top_srcdir), $(abs_srcdir), or $(abs_top_srcdir) to ensure that out-of-source builds work correctly.
Your project layout is a bit odd, but either one of these alternatives ought to do it:
Recursive
Makefile.am
SUBDIRS = HelloWorld
HelloWorld/Makefile.am
# VPATH helps *make* identify prerequisites, but the compiler doesn't know about it.
# We therefore need to give compiler options with real paths. But we shouldn't need
# any extra options to support sources that #include headers via (correct) paths expressed
# relative to the sources' own location.
AM_CPPFLAGS = -I$(srcdir)/../Pet
# Note: builds 'hello' in subdirectory HelloWorld/ of the build directory
bin_PROGRAMS = hello
hello_SOURCES = \
../Pet/Pet.h \
../Pet/Pet.cpp \
main.cpp
Non-recursive
Makefile.am
AM_CPPFLAGS = -I$(srcdir)/Pet
# Builds 'hello' directly in the build directory
bin_PROGRAMS = hello
hello_SOURCES = \
Pet/Pet.h \
Pet/Pet.cpp \
HelloWorld/main.cpp
HelloWorld/Makefile.am
(none)
Either way, you perform an out-of-source build just as you were trying to do: change to the wanted build directory, creating it first if necessary, run the configure script from there via an appropriate path, and then proceed with make.
$ mkdir build
$ cd build
$ path/to/configure
$ make
I accidently fix the problem by changing the ./HelloWorld/Makefile.am to
AM_CPPFLAGS=-I%D%/../../Pet/ -I%D% -I%C%
#VPATH = ../Pet
#srcdir = #srcdir#
#VPATH = %D/Pet/
bin_PROGRAMS=hello
hello_SOURCES=%D%/../../Pet/Pet.h
hello_SOURCES+=%D%/../Pet/Pet.cpp
hello_SOURCES+=%D%/main.cpp
Note that the path of hello_SOURCES are changed and header path is different from source path. But why would this solve the problem?

Linking a dynamic lib using Bazel on MacOS

I'm compiling my program using Bazel, and I have a dependency on Intel TBB.
Intel TBB only provide dynamic libraries (no static) for good reasons (if you are curious: ctrl+f static here).
In my bazel WORKSPACE I defined that rule :
new_local_repository(
name = "inteltbb",
path = "./third_party/intel_tbb",
build_file = "./third_party/inteltbb.BUILD",
)
and in my "inteltbb.BUILD" I have:
cc_library(
name = "dynamic_lib",
srcs = ["build/macos_intel64_clang_cc8.1.0_os10.12.5_debug/libtbb_debug.dylib"],
hdrs = glob(["include/**/*.h"]),
visibility = ["//visibility:public"],
strip_include_prefix = "include/"
)
Then in my final program (under the cc_binary rule) I have:
deps = [
"#inteltbb//:dynamic_lib", [...]
It compile properly, find the headers successfully but at runtime it crashes saying:
____Running command line: bazel-bin/build-game
dyld: Library not loaded: #rpath/libtbb_debug.dylib
Referenced from: /private/var/tmp/_bazel_dmabin/526b91f44cfc47d856222c6b20765cc8/execroot/__main__/bazel-out/darwin_x86_64-fastbuild/bin/build-game
Reason: image not found
I check under the "bazel-bin" folder (where the executable is symlink for runtime execution: bazel-bin/build-game.runfiles/main/) and I do have:
the symlink for the executable (build-game)
a folder called (brace yourself): _solib_darwin_x86_64/_U#inteltbb_S_S_Cdynamic_Ulib___Uexternal_Sinteltbb_Sbuild_Smacos_Uintel64_U
clang_Ucc8.1.0_Uos10.12.5_Udebug that contain my libtbb_debug.dylib for intel tbb.
Also when I run: otool -l build-game | grep LC_RPATH -A2 the result is:
cmd LC_RPATH
cmdsize 152
path $ORIGIN/_solib_darwin_x86_64/_U#inteltbb_S_S_Cdynamic_Ulib___Uexternal_Sinteltbb_Sbuild_Smacos_Uintel64_Uclang_Ucc8.1.0_Uos10.12.5_Udebug (offset 12)
I don't understand why my executable doesn't find my dylib. I can't find anything wrong about the otool output but I'm not a mac expert (at all).
Any idea is welcome.
[edit]
If I edit the executable using otool to replace the path to the dylib like that:
#executable_path/_solib_darwin_x86_64/_U#inteltbb_S_S_Cdynamic_Ulib___Uexternal_Sinteltbb_Slib/libtbb_debug.dylib
Then it works fine. I doesn't feel right that bazel force me to do that at every compilation :/
[edit 2]
A few people asked me the line I used to modify the path of the lib in the executable.
First run:
otool -L build-game
To spot the path of the lib you want to change. In my case it was: #rpath/libtbb_debug.dylib.
After that run:
install_name_tool -change #rpath/libtbb_debug.dylib #executable_path/_solib_darwin_x86_64/_U#inteltbb_S_S_Cdynamic_Ulib___Uexternal_Sinteltbb_Slib/libtbb_debug.dylib build-game
to change the path. Note that you can use #executable_path to make it relative to the binary path or you can put an absolute path, up to you.
I think this is already a known issue, and it was just fixed. Sorry for the trouble.
[edit: updated after submitting the fix]

Building external code trees with SCons

I'm trying to use SCons for building a piece of software that depends on a library that is available in sources that are installed in system. For example in /usr/share/somewhere/src. *.cpp in that directory should be built into static library and linked with my own code. Library sources have no SConscript among them.
Since library is in system directory I have no rights and don't want to put build artefacts somewhere under /usr. /tmp or .build in current working directory is OK. I suspect this can be done easily but I've got entangled by all these SConscripts and VariantDirs.
env = Environment()
my_things = env.SConscript('src/SConsctipt', variant_dir='.build/my_things')
sys_lib = env.SConscript(????)
result = env.Program('result', [my_things, sys_lib])
What is intended way to solve the problem with SCons?
You could use a Repository to do this. For example, in your SConstruct you could write:
sys_lib = env.SConscript("external.scons", variant_dir=".build/external")
Then in the external.scons file (which is in your source tree), you add the path to the external source tree and how to build the library therein.
env = Environment()
env.Repository("/usr/share/somewhere/src")
lib = env.Library("library_name", Glob("*.cpp"))
Return("lib")