Build rules involving a backwards dependency in a shared, third party library

246 views
Skip to first unread message

Chet Gnegy

unread,
Aug 5, 2016, 12:30:01 AM8/5/16
to bazel-discuss
I am trying to get my various projects (C++) set up with Bazel and have had no issues so far in getting the bits of my code that don't rely on any third party libraries to build. However, quite a lot of my code is dependent on the Juce libraries, which aren't built in Bazel. I will be using Juce for multiple different projects, call them FirstProject and SecondProject. My directory structure looks like this:

root
 |--WORKSPACE
 
|--FirstProject
 
|  |--BUILD
 
|  |--AppConfig.h
 |  |--More Code...
 |
  |--SecondProject
 
|  |--BUILD
 
|  |--AppConfig.h
 
|  |--More Code...
 |
 |--
ThirdPartyCode
   
|--Juce
       
|--BUILD

What I would like is to have one target for Juce and have the targets in FirstProject and SecondProject depend on it.

cc_library (
    name
= "MyJuceTarget",
   
...
    deps
= [ /* Lots of Juce library submodules */]
)

The complication is that each project that uses Juce has a header called AppConfig.h with a bunch of #defines in it. Juce needs AppConfig.h at compile time to do some project specific configuration, so there's this awkward backwards dependency. MyJuceTarget has lots of dependencies, and I would like to reduce the redundancy in the BUILD files as much as possible such that for each project, all I have to do is depend on MyJuceTarget (without re-listing all of Juce's deps) and tell it once where that header is.

I believe I can see a way to make this work by making a FirstProjectJuce and SecondProjectJuce target in the projects that list all of MyJuceTarget's deps as their own deps, and include AppConfig.h in the hdrs, which is messy. Any suggestions on a clean way to do this? Can we tell MyJuceTarget that it still is waiting on a header file and depend on it directly provided we supply the header?

Thanks,
Chet

Chet Gnegy

unread,
Aug 6, 2016, 12:08:14 PM8/6/16
to bazel-discuss
It looks as if the correct way to do this is to use textual_hdrs. I wrote a glob in my Juce rule's textual_hdrs for all of Juce's source files. I can depend on that in a FirstProjectJuce rule with hdrs = ["AppConfig.h"] and point to it in the includes. That way Juce isn't built until it knows where to find AppConfig.h.

# in FirstProject/BUILD
load
("//path/juce.bzl", "juce_library")
juce_library
(
    name
= "FirstProjectJuce",
    app_config_path
= "path/to/appconfig/"
)

# in //path/juce.bzl
def juce_library(name, app_config_path):
 
native.cc_library (
    name
= name,
    hdrs
= ["AppConfig.h"],
    includes
= [app_config_path],
    deps
= [
     
"//Path/To:MyJuceTarget",
   
],
    visibility
= ["//visibility:public"],
 
)

# in ThirdPartyCode/Juce/BUILD

cc_library
(
    name
= "MyJuceTarget",
   
...

    textual_hdrs
= glob([
        "path/to/juce/**/*h",
       
"path/to/juce/**/*cpp",
   
])
)

Brian Silverman

unread,
Aug 6, 2016, 3:20:06 PM8/6/16
to Chet Gnegy, bazel-discuss
Does that ever actually build the Juce *.cpp files? I don't think it does because textual_hdrs is documented as being source files which will be #included by other files, and never compiled by themselves.

The best way I see of doing this is similar, but with MyJuceTarget in the juce_library macro too and all the .cpp files in its srcs. You could probably combine the two cc_librarys the macro creates too. ThirdPartyCode/Juce/BUILD can export a filegroup of hdrs and another one for all the srcs which the macro can use.

Also, Bazel treats a directory named third_party at the top level somewhat specially. In particular, it requires license declarations for everything. I'm having trouble finding where that's documented right now, but I think it's somewhere... You should consider renaming ThirdPartyCode to third_party.

--
You received this message because you are subscribed to the Google Groups "bazel-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bazel-discuss+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/bazel-discuss/bb37d68f-a5d1-4343-8ac8-aa69a0f0e8b1%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Chet Gnegy

unread,
Aug 6, 2016, 5:14:03 PM8/6/16
to bazel-discuss, chet...@gmail.com
It seems you're correct. Bazel will say that they are built, but when I go to run them, symbols are missing. Juce does some pretty strange things to get everything working. In particular, it has a bunch of internal "modules" where cpp files include other cpp files so I think that having all but the top level cpp's in the textual_headers might be the right thing to do. If the files are in the srcs, will it build it as soon as it can or will it wait until the headers are used? The cpp files are dependent on AppConfig.h's content as well. Can I have srcs with paths that are relative to the root and not in the directory/subdirectory of the build file? I'm not sure I can. 

I couldn't find the third_party documentation either. If it's "different" in a way that is useful, I'm fine with the rename. It's likely not anything that helps alleviate these integration issues, if I had to guess.

I'll try your suggestion. I made a few quick attempts at it just now that didn't work, but I haven't exhausted all of my ideas yet.

Thanks for the reply.
To unsubscribe from this group and stop receiving emails from it, send an email to bazel-discus...@googlegroups.com.

Brian Silverman

unread,
Aug 6, 2016, 5:29:37 PM8/6/16
to Chet Gnegy, bazel-discuss
On Sat, Aug 6, 2016 at 2:14 PM, Chet Gnegy <chet...@gmail.com> wrote:
It seems you're correct. Bazel will say that they are built, but when I go to run them, symbols are missing. Juce does some pretty strange things to get everything working. In particular, it has a bunch of internal "modules" where cpp files include other cpp files so I think that having all but the top level cpp's in the textual_headers might be the right thing to do. If the files are in the srcs, will it build it as soon as it can or will it wait until the headers are used? The cpp files are dependent on AppConfig.h's content as well. Can I have srcs with paths that are relative to the root and not in the directory/subdirectory of the build file? I'm not sure I can. 

Correct, textual_hdrs is the right place for the non-top-level .cpp files which are #included by other files. Non-header files (.c, .cpp, .cc, etc) in srcs are each compiled as part of building the library (exactly when is complicated, and can be more than once, but it's basically when something with the relevant cc_library in its transitive deps needs to be built).

You can specify srcs in another package (relative to the root or not) by either grouping them in a filegroup or using exports_files in the package with the source files.

I couldn't find the third_party documentation either. If it's "different" in a way that is useful, I'm fine with the rename. It's likely not anything that helps alleviate these integration issues, if I had to guess.

Yes, I don't see the differences being helpful with this either. 

Chet Gnegy

unread,
Aug 6, 2016, 11:56:26 PM8/6/16
to bazel-discuss
I am now exporting the cpp files and using them as srcs in my macro as you suggested. It's definitely trying harder to look at them now. However, it doesn't build because I'm getting all kinds of errors from files in Cocoa (that are included by Juce). It does recognize things ObjectiveC code like
@class NSString, Protocol;

I didn't expect to have to worry about low level things like Cocoa or anything else that is included as a system header <Cocoa/Cocoa.h>. How do I link in Cocoa and other frameworks? I assume it's using linkopts or copts (there isn't an sdk_frameworks attribute for cc_libraries). I tried 
copts =["-framework Cocoa"]
just like XCode does (and linkopts), but no luck.

I'm hoping that it's safe to ignore these as well (maybe this is ignored if I use third_party?):
WARNING: /FirstProject/BUILD:15:1: in srcs attribute of cc_library rule //FirstProject:FirstProjectJuce please do not import '//ThirdParty/Juce:lib/modules/juce_gui_basics/juce_gui_basics.cpp' directly. You should either move the file to this package or depend on an appropriate rule there. Since this rule was created by the macro 'juce_library', the error might have been caused by the macro implementation in ThirdParty/Juce/juce.bzl:10:12.

Thanks again for the help, I'm spectacularly bad at linking bits of software together.

On Thursday, August 4, 2016 at 9:30:01 PM UTC-7, Chet Gnegy wrote:
Reply all
Reply to author
Forward
0 new messages