Including (Only Part Of) an External Library

#1

I’ve been wanting to use some functions from a large external library (Crypto++ aka cryptopp) in a plug-in project.

I built cryptopp as a static library (libcryptopp.a), but at about 50MB, it’s bigger than the whole rest of the compiled plug-in. Doesn’t seem like the way to handle it.

I am admittedly over my head with this, but trying to learn. Aside from trial and error, what are some established techniques for finding and including all the dependencies of a single .cpp file within a large library? Is there a name for a type of script that traverses library source code and pulls together the list of dependencies for a given file? (Or, even more focused, for a given function within a file)?

For the record, I already tried just dragging the .cpp file to the list of project files in Projucer, and listing the library source code directory in the “Header Search Paths” field. It’s unfortunately not that easy.

#2

AFAIK the linker will only select object files that are actually required from a staticlib (on Mac, anyway). If you link against the full crypto++, does the final executable size actually increase by 50MB?

#3

Thanks for the reply. You could be totally right, as I said I’m over my head with knowing how a linker will handle an external library. I assumed that the object files (.o files) created when I built the library were just intermediate steps to building the big library file (the .a file). I didn’t know that Xcode’s linker might be able to go back a step and just grab the object files it needs.

I haven’t managed a successful build yet, unfortunately. I have the library’s directory listed in Projucer’s “Header Search Paths” and “Extra Library Search Paths”, but that’s not enough (I still get undefined symbol errors when building my plug-in in Xcode).

So I have been trying to add a linker search path in Projucer as well, putting something like this in the “Extra Linker Flags” field:

-L/Users/myname/git repos/crypto/cryptopp

However there seems to be some issue with the space in the path name. Whether I leave that path as-is, or I escape the space with a backslash, Xcode immediately complains clang: error: no such file or directory: 'repos/crypto/cryptopp' – meaning that it’s not reading that path correctly.

If I put quotes around the path name Xcode throws up a single “Workspace Integrity Error” as soon as I open the project in Xcode.

I’ll try messing with it more later, but any other suggestions in the meantime would be welcome.

#4

Unless you know exactly how to craft the linker flags, you should avoid using the “Extra Linker Flags” field. You can use the “External libraries to link” field and the “Extra library search paths” field (in the configuration).

#5

Thank you for this suggestion, @McMartin, I should no doubt keep away from the linker flags in that case.

Unfortunately, I’m still hitting a dead-end at every turn on getting the library to link.

I moved the path of the library on disk to one without a space in the path name, so I could eliminate that issue from the troubleshooting. Then I tried the new path name in the “Extra library search paths” and “External libraries to link” fields (one at a time), and Xcode still throws a ld: library not found error.

So then I cleared those fields in Projucer, and tried adding the library from within the Xcode project settings (following this example). Under “Build Phases”, I added a “Link Binary With Libraries” phase to the “Shared Code” section.

I then get these errors:

error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool:
can't locate file for: -lcryptopp
error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool: file:
-lcryptopp is not an object file (not allowed in a library)

So then I figure I made a mistake in compiling the library (I had just run the default make script from the library), because Xcode apparently doesn’t like the looks of it. I checked the cryptopp Install.txt file, and rebuilt the library using this option (since LLVM is Xcode’s compiler, I thought it might make it happier):

LLVM's libc++ is also supported, so you can:
    export CXXFLAGS="-std=c++11 -stdlib=libc++"
    make

Unfortunately, even after rebuilding the library, I’m still getting the same -lcryptopp is not an object file error when I try to compile the Xcode project.

???

#6

OK, one little Projucer hiccup ironed out: I had assumed that the “External libraries to link” field wanted a full path name to the library - it does not, it just wants the library name itself.

So, with the actual library path on disk being: /Users/username/crypto/cryptopp/libcryptopp.a
…this combination of values in the Projucer fields worked at last for Xcode to find the library.

Extra library search paths: /Users/username/crypto/cryptopp/
External libraries to link: cryptopp

So now it’s down to figuring out why I’m still getting Undefined symbols errors…

#7

OK, I got it working. I had to rebuild the cryptopp library again as a fat binary, since I was getting Undefined symbols for architecture i386 errors. Here’s a handy explanation about how to do that from the command line, using export CXXFLAGS:

Hope this saves the next poor soul some hair-pulling!

#8

OK, to loop back around to this - no, the final executable definitely did not increase by the size of the full static library (.a) file size! Thanks for your patience in fielding my naive question.

I am still wondering what makes for the best practice when including an external library however. For ease of maintenance and general sanity, if you’ve got a cross-platform (Mac/Win) JUCE project, does it make more sense to compile the external library on each platform, and then link against the static libraries when building your project?

Or is it more efficient to figure out which external library source files you need to include in your JUCE project, and then you can skip the separate steps of compiling the libraries on each platform?

I suspect the former is actually less of a headache, for only having to deal with one interface to the library rather than track a bunch of source files, but I did want to follow up on my original question about how to approach this. Thanks!