Currently, I try to bazelize a library. Let's call this library lib_foo.
The setup is similar to this minimal example. My main application tries to use a function form lib_foo.
main.cpp:
#include "lib_foo/header.h"
#include <iostream>
int main() {
std::cout << foo<2>() << std::endl;
}
lib_foo/header.h:
#pragma once
#include "impl.inc" // works
lib_foo/impl.inc:
template <int number>
int foo() {
return number;
}
BUILD.bazel:
cc_library(
name = "lib_foo",
srcs = [
"lib_foo/header.h",
"lib_foo/impl.inc",
],
)
cc_binary(
name = "HelloWorld",
srcs = [
"main.cpp",
],
deps = [":lib_foo"],
)
There is also an empty WORKSPACE file.
If I run bazel run //:HelloWorld everything works as expected.
If I rename the file impl.inc to impl.cpp (and change this accordingly in BUILD and include file, etc.). I run in the following problem (on Ubuntu 20.04):
In file included from main.cpp:1:
lib_foo/header.h:3:10: fatal error: impl.cpp: No such file or directory
3 | #include "impl.cpp"
| ^~~~~~~~~
Also replacing the include path with a relative one to the WORKSPACE file does not help here.
It seems that it is a general problem to include cpp files in Bazel. Since the third party library I try to bazelize does include several times cpp files I wonder what a proper workaround here is.
Any ideas?
(I am using Bazel 3.7.2 on Ubuntu 20.04)
The normal workaround is to put includable cpp files in the textual_hdrs attribute of cc_library.
Related
I am trying to port an existing code tree to the meson build system on a centos 7 machine. Meson configure works fine, but when I try to compile, it fails. The code is proprietary, so I have created an example that illustrates the problem (accurately enough, I hope.) I am not at liberty to restructure the directory tree.
Here's the tree:
mesonex/
alpha/
beta/
alpha/
inc/
funcs.h
numbers.h
src/
numbers.cpp
funcs.cpp
src/
example.cpp
meson.build
My meson.build:
project('example', 'cpp')
srcs=['example.cpp']
srcs+='../beta/alpha/src/funcs.cpp'
srcs+='../beta/alpha/src/funcs.cpp'
incdirs=include_directories('../beta/alpha/inc')
executable('example', srcs, include_directories: incdirs)
here is the main example.cpp file:
#include <iostream>
#include "../beta/alpha/inc/numbers.h"
#include "../beta/alpha/inc/funcs.h"
int main()
{
std::cout << "Hello" << std::endl;
std::cout << interestingNumber() << std::endl;
std::cout << interestingFunc() << std::endl;
}
These are the supporting cpp files:
// funcs.cpp
#include "../inc/numbers.h"
float interestingFunc()
{
return (interestingNumber()+1)/2;
}
// numbers.cpp
float interestingNumber()
{
return 11.3355;
}
And these are the header files:
// funcs.h
float interestingFunc();
// numbers.h
float interestingNumber();
Please note that the duplication in directory names is intentional. Maybe this confuses meson in figuring out how to handle the #includes?
This is just one example of many different build strategies I have tried.
I see right off the bat an issue that might just be an issue with your example, and not with your actual code: Meson considers the meson.build file with the project() call to be the "root" of the source directory structure. You cannot ask it to include files outside of the root. It would be about like cp /../foo . on a Unix-like OS. This may just be a mistake in your example, since this isn't the real code of course.
So, if we rewrite this as (mesonex/alpha/meson.build):
# no project(), that would be in mesonex/meson.build)
sources = files(
'example.cpp',
'../beta/alpha/src/funcs.cpp',
'../beta/alpha/src/numbers.cpp', # you have a typo in your example, funcs.cpp is listed twice.
)
executable(
'example',
sources,
include_directories : include_directories('../beta/alpha/inc'),
)
Should work.
Note, that you might want to consider using a convenience static library instead of reaching back to the code, as this is best practice, you could write something like (mesonex/alpha/beta/meson.build):
lib_beta = static_library(
'beta',
['src/funcs.cpp', 'src/numbers.cpp']
)
idep_beta = declare_dependency(
link_with : lib_beta,
include_directories : include_directories('.'),
)
and then in (src/meson.build):
executable(
'example',
'source.cpp',
dependencies : idep_beta
)
is all you need, as the idep_beta carries both the linkage and the include information.
This is a follow on - the solution worked for my example but not for the actual code. My model must have been incomplete (in a way I haven't determined yet.) The configuration stage works, but in the compile stage the #includes in the cpp source are flagged with a "File or directory does not exist." How does meson reconcile the specified include directories with #include statements in the source? The #include paths may be relative to the actual directory of the actual cpp source. Does this mean I have to edit all the #includes in all the sources - that would be a real negative. We work with some VERY large code bases.
Currently, I try to build a library with Bazel (5.1.0) that originally uses CMake as a build system.
I am running into a problem when trying to include a generated a header file using a relative path (in the CMake build it uses configure_file):
(The following example can also be found here)
WORKSPACE.bazel:
workspace(name = "TemplateRule")
main.cpp:
#include "kernels/bvh/some_header.h"
#include <iostream>
int main() {
std::cout << VERSION_STR << std::endl;
}
kernels/bvh/some_header.h:
#pragma once
// include config.h using a relative path
// if changed to kernels/config.h everything works as expected
// unfortunately, this is legacy code that I cannot change
#include "../config.h"
config.h.in:
#pragma once
#define VERSION_STR "#VERSION_STR#"
BUILD.bazel
load("//bazel:expand_template.bzl", "expand_template")
expand_template(
name = "config_h",
template = "config.h.in",
out = "kernels/config.h",
substitutions = {
"#VERSION_STR#": "1.0.3",
},
)
cc_binary(
name = "HelloWorld",
srcs = [
"main.cpp",
"kernels/bvh/some_header.h",
":config_h",
],
)
bazel/BUILD.bazel: < empty >
bazel/expand_template.bzl:
# Copied from https://github.com/tensorflow/tensorflow/blob/master/third_party/common.bzl with minor modifications
# SPDX-License-Identifier: Apache-2.0
def expand_template_impl(ctx):
ctx.actions.expand_template(
template = ctx.file.template,
output = ctx.outputs.out,
substitutions = ctx.attr.substitutions,
)
_expand_template = rule(
implementation = expand_template_impl,
attrs = {
"template": attr.label(mandatory = True, allow_single_file = True),
"substitutions": attr.string_dict(mandatory = True),
"out": attr.output(mandatory = True),
},
output_to_genfiles = True,
)
def expand_template(name, template, substitutions, out):
_expand_template(
name = name,
template = template,
substitutions = substitutions,
out = out,
)
When I run bazel build //...
I get the error:
In file included from main.cpp:1:
kernel/some_header.h:3:10: fatal error: ../config.h: No such file or directory
3 | #include "../config.h"
| ^~~~~~~~~~~~~
When I include config.h in main.cpp and remove it from kernel/bvh/some_header.h everything works as expected.
Any ideas how to the relative path .../config.h working?
Creating the file config.h and compiling the code manually works as expected:
g++ main.cpp kernel/bvh/some_header.h config.h
According to the Best Practices relative paths using .. should be avoided, but you can find such things in legacy code that uses CMake to build. Is this a restriction of Bazel? or is there a workaround?
While behaviour and order of search for file while using quotes is technically platform defined, most common principle in case of use path relative to file from which inclusion happens. For kernel/bvh/some_header.h the path ../config.h is resulting in searching ONLY in kernel folder, working folder or kernel/bvh/ will not be checked. Some compilers check alternative locations. The order of search is part of compiler documentation.
I once saw use of ../../config.h inside of another header kernel.h in situation like this and it worked. It was a maintenance liability. The kernel.h was moved to different location and it picked up a wrong folder and wrong file, which resulted in ODR breach much later in project's timeline. One who had committed the move had left ../../config.h in place and made a copy. Some units were using old header while other started to use modified one at new location.
For that reason the use reverse relative paths outside of library infrastructure is not recommended. Instead partial relative paths, e.g. kernel/config.h are preferred, assuming that core folder would be in list of include paths. In practice real projects can use preprocessor macros, e.g.#include KERNEL_CONFIG_FILE. An illustration can be seen in freetype, boost, etc.
I'm trying to use clang-tidy to parse my project, compiled by arm-none-eabi-g++.
Unfortunately, clang-tidy is not able to find compiler headers, even when given the include path to them.
My compile_commands.json is
[
{
"directory": "C:/LMA/repo/clang-tidy",
"arguments": [
"arm-none-eabi-c++",
"-IC:/nxp/MCUXpressoIDE_11.2.1_4149/ide/tools/arm-none-eabi/include/c++/9.2.1",
"-IC:/nxp/MCUXpressoIDE_11.2.1_4149/ide/tools/arm-none-eabi/include/c++/9.2.1/arm-none-eabi/arm/v5te/hard",
"test.cpp"
],
"file": "./test.cpp" } ]
And the example test.cpp file is:
#include <cstdint>
#include <cstdlib>
int test()
{
int temp;
return 0;
}
Clang-tidy shows error:
C:/nxp/MCUXpressoIDE_11.2.1_4149/ide/tools/arm-none-eabi/include/c++/9.2.1\cstdlib:75:15: error: 'stdlib.h' file not found [clang-diagnostic-error]
#include_next <stdlib.h>
So, it properly finds and includes cstdlib, however it is not able to find stdint.h, which is located in the exactly same folder. What's even more irritaiting, it does not include stdlib.h, even when I add
-include C:/nxp/MCUXpressoIDE_11.2.1_4149/ide/tools/arm-none-eabi/include/c++/9.2.1/stdlib.h
to compiler arguments in order to force preinclude.
Any suggestions how to fix this issue are very much appreciated.
This is a bit old, but I was having a similar issue so I figured I'd report an answer here in case anyone else comes across this while searching. It appears clang doesn't know where to find the standard library headers when compiling using arm-none-eabi. I succeeded by simply adding them.
In your case you're still missing the C headers directory, so you need to add this:
C:/nxp/MCUXpressoIDE_11.2.1_4149/ide/tools/arm-none-eabi/include/
(assuming the directory structure is similar to mine).
So your compile_commands.json would be:
[ {
"directory": "C:/LMA/repo/clang-tidy",
"arguments": [
"arm-none-eabi-g++",
"-IC:/nxp/MCUXpressoIDE_11.2.1_4149/ide/tools/arm-none-eabi/include",
"-IC:/nxp/MCUXpressoIDE_11.2.1_4149/ide/tools/arm-none-eabi/include/c++/9.2.1",
"-IC:/nxp/MCUXpressoIDE_11.2.1_4149/ide/tools/arm-none-eabi/include/c++/9.2.1/arm-none-eabi/arm/v5te/hard",
"test.cpp"
],
"file": "./test.cpp"
} ]
You should also have arm-none-eabi-g++ instead of arm-none-eabi-c++ I believe.
I want to develop a small application which uses some libraries. So I downloaded them and placed the include files in a folder called include.
For my application, I used cpprestsdk, but my question shouldn't be limited only to this library.
This is a rough example of my folder Structure:
myproject
include
cpprest
...
pplx
...
test.cpp
And this is my Code:
#include <iostream>
#include "include/cpprest/http_client.h"
#include "include/cpprest/filestream.h"
#include "include/cpprest/json.h"
int main() {
// code
std::cout << "Hello World!";
return 0;
}
which results in followin error code when compiling (g++ test.cpp -o test) with g++ or gcc (on Ubuntu):
<error needed>
What have I done wrong? when I inspect the file mentioned in the error message, then I notice, that all includes in the library are like so #include "cpprest/asyncrt_utils.h". As you can see, it refers to the file as it were in a subfolder called cpprest, which it is not. It is located with the other file in the same folder. I guess that results in my problem. My question now is: how do I fixe this issue?
I have the above error and have followed all solutions but does not fix.
This is my stdafx.h file. I have it in the target directory, I can see the file and the full path goes to there. In addition, I have created a win32 project. Why is my code not working?
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
// TODO: reference additional headers your program requires here
ACTUAL CODE:
// ConsoleApplication1.cpp : Defines the entry point for the console application. //
#include "stdafx.h"
#include <iostream>
int main() { std::cout << "Hello world!" << std::endl; return 0; }
For the record, I had this problem when cloned a repo using git from the Ubuntu shell in Windows 10.
After I cloned the repo to a different location usin git from a Windows shell, the problem went away and the solution builds fine.
The issue was that the build scripts were looking for 'stdafx.cpp' in a folder with uppercase name (C:\GIT\LIBRARYX\SRC\) and this path did not work if the solution was cloned using git from Ubuntu bash.