Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
479 views
in Technique[技术] by (71.8m points)

c++ - Bazel & automatically generated cpp / hpp files

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"

int 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).

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Question (A)

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"

int foo() { return 2017; }" >> $1/file.cpp

Question (B)

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"],

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...