In this post I’d like to share my experiences of linking an external library and code files to an X-Code and Qt project. This task, more than anything, requires a good deal of “glue” information, that is, knowing how and when to do this or that little task to get to the next stage. It’s not too hard, but can be quite time consuming as you scour the net for hints. Hopefully this single write-up will help others.
The task at hand is to use the Boost GIL library to convert JPEG images to RGB if needed, as well as to resize them.
This resizing task is part of a larger set of tasks which is wrapped into a larger Qt project. It should be noted however, that at this point we’re only going to focus on the linking process, not the actual code.
This task, linking to a library, will be a very common task for most projects. It’s also interesting because we’ll be using something other than the Standard Library, which means we need to link and talk to other library and code files. This is the ‘glue’ I mention above, in that making these connections isn’t always obvious.
I chose the GIL library over using Qt’s QProcess class mainly for the purposes of learning more about linking. QProcess, for what it’s worth, could have made linking to something like ImageMagik quite simple, but again, in this case it was my wanting to learn which prompted me to chose the ‘tough’ path.
As it is, the first step for me was to research what would be needed to get this done. The first thing I found was that I would need the libjpeg library, as JPEG files are what i want to convert.
It’s a simple download, and can had from here.
To keep things clean, I uncompressed the folder into a directory called /libs in my /Documents directory. You may want to do the same, as we’ll also be putting the boost library there too.
This download contains a set of makefiles, source code, and instructions. As I’m on a Mac I didn’t have the luxury of using say, Ubuntu’s Software Center. If I was, getting this file and installing it is as simple as downloading its package. (the same goes for Boost)
No such luck though, so we need to build it. The good news is this package, at least on OSX 10.6, was very easy to use. All I needed to do was to open a command prompt and cd into the uncompressed folder in /libs/jpeg-8b, and then issue the standard set of build instructions:
./configure make make test sudo make install
This does a few things. First, it runs the configure script to inspect our system and create a make file. We then issue make to compile the project. During this stage you’ll see all sorts of files being created in the jpeg directory. make test does a quick test to make sure the created files work, and sudo make install moves the compiled files to our system directories.
It’s important to note that this final install step moves two sets of files around:
The first set is a group of small application files to /usr/local/bin
We will actually ignore these, as for our project, they are not used.
The important part is the moving of the library files.
Here the install process will create and move two files and a symlink to /usr/local/lib/:
libjpeg.8.dylib
libjpeg.a
libjpeg.dynlib (the symlink)
These are the guys we care about, as this is what we link our application too. It’s important to point out though, that Qt and X-Code use two different methods to create this linkage. More on that in a bit.
For now we need to download and decompress the Boost library. I put mine in the same place as my jpeg library files in /Users/{user-name}/Documents/libs/
The full path would thus be:
/Users/{user-name}/Documents/libs/boost_1_44_0
Within the boost_1_44_0 folder we will have several files and folders. The important bit is /boost directory. This is where the code we include into a project resides, and what we point our IDE/Linker towards to build the program.
More on the Boost install Process.
We’re close now, but before we’re done we need to download and install one more file.
On that page we want to download a file called numeric.zip, the link should be near the bottom.
Extract the file and place it into:
/Users/{user-name}/Documents/libs/boost_1_44_0/boost/gil/extension/
Right, so now we have the needed files on our system, this means it’s time to get linking.
As mentioned above, this process differs for X-Code and Qt.
Adding Boost and libjpeg
The first thing we want to do is make sure Boost works. To do so we’ll grab a chunk of code from here:
#include <boost/lambda/lambda.hpp>
#include <iostream>
#include <iterator>
#include <algorithm>
int main()
{
using namespace boost::lambda;
typedef std::istream_iterator<int> in;
std::for_each(
in(std::cin), in(), std::cout << (_1 * 3) << " " );
}
X-Code
Create an X-Code Console C++ project and paste the above code into main.cpp.
Try to compile it: it should fail. This is because we need to tell X-Code where the Boost library files are.
Click on the project window (the one that shows all files)
Right Click on the top icon (the one with the projects name)
Select Get Info
This is a multi-tab window, click on the Build tab.
Scroll down until you find the Search Paths section, which is one of main headers in gray.
A sub area of this guy will be a setting called Header Search Paths
Double click the white space next to the setting name and a sheet will appear, click the plus button and add the path to the root of the boost directory.
When done you should have:
Notice how we didn’t use the full path to the code files, we stop at the boost root directory, that is:
/Users/grdinic/Documents/libs/boost_1_44_0
This is because when we:
#include <boost/lambda/lambda.hpp>
…we are saying: “go into the /boost directory starting from the Header Search Path base”.
In other words, we combine the Header Search Path and <boost.. (the last / is implicit). to make:
/Users/grdinic/Documents/libs/boost_1_44_0 <boost/lambda/lambda.hpp>
While we’re here, let’s also quick add the jpeg-8b path to the Header Search Path:
/Users/grdinic/Documents/libs/jpeg-8b
We could do this later, but getting it out of the way now seems prudent, as we know we’ll need it soon anyway.
Now when we recompile we should get no errors, as the Boost code files are being found.
Of course we can test this by running the program. Thing is, this program expects input, so we need to make sure to open the GDB console to supply it.
If you have not used this before (the console in X-Code), you can find it’s button after you’ve started the program(!) as seen below, right in the middle of the screen next to the word __kill:
When the console window opens you can type in a number, and the program will multiply it by 3 and show the result. Boost Works!
Qt
To do the same in Qt we have a slightly easier task:
We define the include path to our code libraries by opening the .pro file for our project and adding:
INCLUDEPATH += \
/Users/grdinic/Documents/libs/boost_1_44_0 \
/Users/grdinic/Documents/libs/jpeg-8b \
With this done we have included the Boost and libjpeg code files.
Linking libjpeg
The next step is to make sure Boost+GIL works. As we already have Boost working you’d think this would be a given, but now we need to add our libjpeg library into the mix, which complicates things a bit.
First, we start with the docs page, where we find this bit of code*:
#include <boost/gil/image.hpp> #include <boost/gil/typedefs.hpp> #include <boost/gil/extension/io/jpeg_io.hpp> #include <boost/gil/extension/numeric/sampler.hpp> #include <boost/gil/extension/numeric/resample.hpp> int main() { using namespace boost::gil; rgb8_image_t img; jpeg_read_image("test.jpg",img); // test resize_view // Scale the image to 100x100 pixels using bilinear resampling rgb8_image_t square100x100(100,100); resize_view(const_view(img), view(square100x100), bilinear_sampler()); jpeg_write_view("out-resize.jpg",const_view(square100x100)); return 0; }
*Please note I have removed the header comments for the sake of clarity.
If we try to compile this code now we’ll get errors. We get these errors because we need to link the libjpeg.a file to our project.
It’s important to note that the Boost and libjpeg pieces are really just code files (well, not all, but for us in this project they are), so the inclusion process is just telling the linker where they are.
However, library files are different animals altogether, so they need to be linked to our project in similarly different manner.
As you might expect, the process of creating this library link differs between the two editors.
X-Code
X-Code expects library files to be selectable in the GUI under the Targets > Link Binary with Libraries > Add area:
This is a problem however, because the path the lib files were installed too above:
/usr/local/lib
…is not accessible through the X-Code GUI.
The fix is to simply open a terminal and cp the files to our project directory:
cp /usr/local/lib/libjpeg.a /Users/grdinic/Documents/X-Code/boost/
With that done, we can now use the GUI interface to select the library file, which should add the library to our project and makes it available for the linking step:
Now when we build, the project should do so without error**.
Qt
Qt, thankfully, is a bit more simple. To add a proper link to the library file we simple add this to the .pro file:
LIBS += -L/usr/local/lib -ljpeg
It is worth pointing out however, that their are some real subtleties going on here.
The LIBS+ part is all Qt, and should be strait forward. The trick is the -L switch, which is actually a GCC directive. The other tricky bit is the -ljpeg.
To be honest, this is one of those things that drives you batty if you don’t know what to look for. It’s great when you know sure, but man, during…
The -l means library, and the jpeg seems strait forward enough…until you look at the library files on your system and only see a libjpeg.a Where in the heck does jpeg come from?
Ah you see, the trick is that during the linking process the lib is removed for you, as is the .a. Thus, -ljpeg really means get libjpeg.a.
Again, it’s nice when you think about it for the simplicity it offers, but it’s a real bear if you didn’t know that going on!
**Other Issues
At this point I wish could say ‘all done’, but cannot. My OSX machine compiles this code as expected, but the situation is not so rosy on Ubuntu 10.4.
When we try to compile I get an error:
/home/matt/Qt Projects/boost/../../libs/boost_1_44_0/boost/gil/extension/numeric/sampler.hpp:104: error: no matching function for call to ‘boost::gil::point2<int>::point2(boost::gil::point2<long int>)’
A quick look at the trunk shows that newer versions of GCC and gil don’t always play together so well. The good news is so long as we used the plain download of Boost 1_44_0 a simple change of:
point2<int> p0(ifloor(p)); // the closest integer coordinate top left from p
to:
point2<long> p0(ifloor(p)); // the closest integer coordinate top left from p
…should do the trick for this particular issue.
So as simple as that was, that’s the thing about library files. When something goes wrong, it can really, really go wrong. This is because the type of programming the GIL and Boost developers are using is called Template Metaprogramming, and is for all practical purposes the most advanced form of programming I’ve ever come across.
Some of this complexity in implementation is somewhat alleviated by the use of C++ Template Concepts, a feature that while not part of the C++ standard just yet, is implemented in spirit by the GIL developers. However, when things go wrong your error list could very well be undecipherable. It’s the price we pay for the power of templates.
The last interesting idea here is that if you want to actually run this program, you’ll need to specify the image file path to something real, else we’ll get a hard crash in our Qt app, or an error in the X-Code version.
Final Words
This post was all about linking two code libraries and one actual ‘library’ file to a small project so that we save ourselves the time and effort of writing image processing code ourselves. In the world of C++ application development this is an absolutely necessary skill.
The big takeaways are that most of what we did was actually quite simple, but also, in many places and ways, subtle.
Of course their is more to learn: We have yet to deal with portability, in that one of the primary goals of creating Qt apps is the effortless cross-platform distribution. As soon as we start adding external libraries we need to be aware of the extra time and effort getting these guys to play nice with our systems will be.
We also left out the idea of the two types of linking, static and shared. For OS X developers, we left out the concept of frameworks. In short, we’ll leave this as an exercise for you for now, though may revisit these topics and other at a later time.
My final point will be to play it safe. You can download a newer version of the gil library from Adobe’s website if you like, but my time with doing so was spent running down and fixing various template issues, and all to no avail. In short, stick with the version that comes in the official Boost package!



