Why does Bazel under-link and how do I fix it? - bazel

I'm trying to build and package LCM with Bazel. This works for the "build" part, but the end result is a library not usable by external consumers (i.e. "package" fails, because the package is broken).
LCM uses glib, which I am importing with pkg_config_package (gory details). More particularly, LCM uses glib internally, but does not expose this to users. This means that consumers should not need to link glib; liblcm.so should do that, and consumers should only need to link to LCM itself.
This all works great with upstream (which uses CMake and Does The Right Thing). Bazel, however, seems to be not linking liblcm.so to glib, for some unknown reason. If I build an executable with Bazel within the same overall environment, Bazel seems to know that users of LCM also need to link to glib. However, when I try to package this LCM for external use, it is broken, because liblcm.so isn't linked to glib, which forces consumers to deal with LCM's private glib dependency.
Why is Bazel not linking the LCM library to glib, and how do I fix it?
(p.s. We have similar issues with libbot...)

Apparently, this is a known issue: https://github.com/bazelbuild/bazel/issues/492.
I can't just make the cc_library a cc_binary, either, because — while that would fix the under-linking — then I can't use the library in other Bazel targets. Nor can I make a cc_binary that wraps a cc_library, because then internal and external consumers aren't using the same library.

Static libraries do not link with other static libraries. When building through Bazel, Bazel keeps track of the dependencies and will link against all dependent libraries when building the executable.
There's more information here about linking static libraries:
Linking static libraries to other static libraries
One interesting suggestion brought up is unarchiving both libraries and then creating a new library with all the .o files. This could possibly be achieved in a genrule.

Related

Can I parallelize my build when linking against multiple interdependent static libraries?

I've built my app as a workspace containing one project with an app binary target and many projects containing static library targets. My app target links against all the static libraries. Some of my static libraries depend on each other, and I handle this by ordering the targets built in my scheme so that all dependencies are built before the libraries that depend on them.
What I'd like to accomplish is to use the 'Parallelize Build' feature to speed up building my app scheme. However I need to ensure that my static libraries are built with respect to their dependencies. It doesn't seem like I can set 'Target Dependencies' between these static library targets because they are not all in the same project (Is this the case or am I misunderstanding how this works? Is it possible to have cross project target dependencies)?
Is there any way to accomplish this? Thanks for any information!
After some research it does seem like the only way to get this working is to set up my app using nested subprojects instead of a workspace (so that I can create target dependencies between my dependent libraries). I'd love to be corrected on this point if anyone knows another way!

What is the correct process for linking static libraries that have common static libraries?

I am working on a static library, called Silicon, that I use for all of my iOS apps.
Because I don't want to create one massive static library that could become hard to maintain I create lots of smaller static libraries that I attach as submodules.
As of the time of this writing the dependency tree for Silicon is as follows:
Silicon
|
|==> FDKeychain
|==> FDDataClient
|
|=> FDRequestClient
|
|=> FDFoundationKit
|==> FDSQLiteDatabase
|
|=> FDFoundationKit
As you can see both FDRequestClient and FDSQLiteDatabase have FDFoundationKit as a common static library.
What seems to happen is that when a project using Silicon is built it builds all of Silicon's target dependencies to the projects build directory. The same thing happens for FDDataClient and FDSQLiteDatabase. So at some point FDFoundationKit from FDRequestClient is built and copied to the build directory as well as FDFoundationKit from FDSQLiteDatabase. Whichever one is built last just overwrites the previous one.
Just by sheer luck FDFoundationKit hasn't been changing in any serious ways such that FDRequestClient and FDSQLiteDatabase can't always be using the same version but I can't guarantee it will be like this forever.
I am trying to figure out if there is a way for Silicon to specify which version of FDFoundationKit to use so it can be Silicon's responsibility to ensure that the the version used will work for both FDRequestClient, FDSQLiteDatabase and any other dependencies I add in the future.
I know CocoaPods attempts to solve this problem but I do not want to make someone have to setup all of that just to get my library working. If I could just find someway of having Silicon define which version of FDFoundationKit to use everything would work perfectly.
You could (as we do) place all of your libraries into frameworks, as frameworks support versioning. Frameworks are just a directory tree configured in a common manner. Xcode does not directly support the creation of frameworks, so you have to create them in a script, typically as the last of your build phases. An example (thanks to jverkoey) can be found at IOS- framework
Within a framework you may store all versions of each static library within the
myLibrary.framework->Versions->n.n folders.
The myLibary.framework->Versions->Current is a link to the folder of the latest version.
Since you are using static libraries, Silicon itself cannot specify the versions (that would require dynamic libraries), however the build, linker or environment flags used for the building of Silicon certainly can.
In this manner, by default, Apps will always use the latest version of the library, but the actual version linked may be easily overridden by linker flags when building. Also, all users will simply include the Silicon framework in their project in the same manner as any other framework, so it's very simple for developers.
There looks to be only two answers to this problem:
1) Use a dependency manager like CocoaPods or Carthage.
2) Any static libraries or frameworks you release should not have any target dependencies. They should link against any dependencies you have and it is the responsibility of person integrating your library to also integrated the required dependencies.

Creating a single static library from several dependent projects

I am attempting to create a static library wrapping the SQL Cipher functionality along with all of the associated dependencies i.e. OpenSSL, SQLite and some other wrapper e.g. FMDB.
The problem is the complete lack of documentation from Apple. The example they provide at https://developer.apple.com/library/ios/technotes/iOSStaticLibraries/iOSStaticLibraries.pdf is miserly and useless in all but the most simple of circumstances.
The issue I have revolves around the concept of creating a static library that links to multiple other dependent Xcode projects. I have the following structure in Xcode within a Static Library project:
I have created all of the necessary links etc and utilise LIPO to create a universal binary. The problem is that the output generates a library class for each of the projects so I end up with the following:
I may be entirely missing the point but I was expecting a single entry point library and not the individual libraries.
I have read that Xcode project resources will not be included in the Static Library build and will still have to be handled by the consuming application/project i.e. by adding them individually! Does this rule apply in this case?
Upon further investigation it would appear this is the desired outcome.
To resolve, I utilised the libtool command to combine the libraries.

How to use open source iOS libraries without collisions?

I'm writing an iOS library (SDK) and I need JSON decoding support. There are lots of choices, but the problem is upstream collisions.
If I add, say, JSONKit to my library, and another third party library does the same, then the upstream user who wants to use both my library and the other library will experience a collision.
It would appear then that it's impossible for me to add any third party libraries into my library because of the risk of collisions. How can I use iOS libraries as dependencies of mine without causing collisions for upstream developers?
How can I use iOS libraries as dependencies of mine without causing collisions for upstream developers?
Just specify that that third party library is a dependency of your library, provide appropriate links to the project, and any necessary instructions, version info, etc..
If that package/distro is not well-suited for distribution (e.g. they just have a pile o' source files), then create a public project (fork) which includes a proper static library target.
We're having this same issue. Here's my thoughts on how to solve it (perhaps we can figure out a robust solution together). For versioning control, we're using Git:
One option is simply to prefix all classes within your library with your own identifier. In such, even if the class is part of JSONKit, I'd still prefix it with my own identifier ("JG") to get the classname "JGJSONKit.h". In this manner, it's much less likely that a collision would occur.
This method has the drawback that should a third party repository (such as JSONKit) be updated, however, it's more difficult to pull these changes into our library's version of JSONKit.
This may be acceptable, however, if this code is intended to be exported as a static library (as you'd still maintain full control over the code, and you'd be able to manually pull changes to third party repositories and rename them appropriately, if you should so choose to do such in future updates of the static library).
Another option I've considered is using Git submodules. This solution seems to be better should your library be open source (or at least open source to the developers that have access to it -- not necessarily available publicly). In such, developers could choose to simply not include any submodule that they were already using within their own project.
Ideas?
Edit:
Here's the solution that we came up with:
1) We encapsulated our shared code (which we'd written- not a third party) into a project with a static library target and our shared resources (xibs and images) into a bundle following this tutorial:
https://github.com/jverkoey/iOS-Framework
2) We created a Git repository that included said static library and bundle.
3) We forked all desired third party libraries (so we could make changes to them if desired) and also added the original repos as another remote within each forked repo (so that should changes be made upstream, we could easily pull them into our own fork)
4) We added -objc to the "other linker" flags (important) so that all categories would work correctly during runtime.
All in all, the solution is near perfect for us:
We avoid collisions by either hiding the third party libraries (not including them in the public headers but private instead), or we warn that those libraries are used within the project for publicly exposed headers and that developers should not add them again (they can use the already included code instead, which is kept up-to-date via the simplicity of including them via said Git submodule method)
I hope this helps your efforts too!
I had a look at JSONKit and i see that it isn't a Static Library, it is a src file to copy into your project.
All Classes, etc. in your project must be prefixed with your (cough) globally unique two letter prefix, including classes you copy and paste off the internet.
You would be better off if JSONKit was a library. Your library would depend on JSONKit, but not contain it, and it would be up to whoever building an app with your library to make sure JSONKit was also included and linked against - no collisions (although distributing a library that is dependent on other third party libraries that aren't yours to distribute is inherently somewhat tricky).
If other people are pasting this JSONKit file into their libraries and then distributing them you have only two options*
Modify JSONKit.h & .m, prefixing all symbols (you must do this with any code you include as source)
or choose something else (NSJSONSerialization?).
This doesn't mean you can't have third party library dependencies (or that doing so is dangerous), just that copying a source file into your project is not the same as adding a library dependency.
*arghh, ok 3.. you could weak link all the symbols from JSONKit and leave it up to the library user to supply JSONKit.m, but then still the problem is the other libraries..
TLDR.. avoid JSONKit, it isn't suitable to use 'as is' in a library that you want to distribute.

Prefix Static Library iOS

I'm building an iOS static library (as per https://github.com/jverkoey/iOS-Framework). I depend on SBJson and AFNetworking. I would like to include these libraries to avoid version issues and for installation simplicity; to do so, I need to prefix these libraries to avoid naming conflicts.
How can I prefix other static libraries in a simple way?
Ideally, it would be part of my build process. Less ideally, but acceptable, are tips on how to refactor and rename in a sane manner.
The only safe solution (other than not doing this at all) is to build any dependencies with a prefix on all symbols.
The easiest method of prefixing is the classic "find-and-replace". This is error-prone, so it's a good idea to hit the .a with nm -a and scour the results for any non-prefixed symbols.
A second, much safer method is to use a two-pass compilation process.
The first pass builds the dependent project and runs nm to dump all symbols into a header file.
The second pass builds the dependent project again, but this time with the generated prefix header file imported in the precompiled header. This prefix header must be used anywhere you reference symbols from the dependency in your framework in order to properly refer to the renamed symbols.
For reference, we use this with Nimbus to generate the Nimbus prefix headers:
https://github.com/jverkoey/nimbus/blob/master/scripts/generate_namespace_header
This allows you to distribute a .framework with a prefixed version of Nimbus embedded.
You can now link the resulting .a into your framework and safely avoid any linker conflicts when a third party developer inevitably links their own version of the dependency into their project.

Resources