I’ve been developing C++ applications (using Eclipse CDT) for quite some time now, but recently I tried to link a previously developed C++ project as a library into a newly created C++/Qt project. The Eclipse Qt integration is a bit dated, but still works with Qt 4.8.1 on my Ubuntu 12.04 machine. However, it uses qmake, which is not configureable from Eclipse in a straightforward way. This post describes some tips and tricks – for my own future reference, but also for anyone out there experiencing similar difficulties.
(I’m assuming you’ve got Eclipse CDT installed for C++ support in Eclipse. If not: please see the Eclipse CDT documentation for further instructions)
Step 1: install Qt integration for Eclipse
At the time of writing, the Qt Eclipse integration plugin can be downloaded from the Nokia website: http://qt.nokia.com/products/eclipse-integration. Even though the version number suggests that this will only work with Qt 4.6.1 (at the time of writing), it works perfectly fine with my Qt 4.8.1. on Ubuntu 12.04. Just follow the instructions on the website (which are also included in the archive).
Step 2: create a Qt project in Eclipse
Open the New Project Wizard in Eclipse (File -> New… -> Project) and select Qt -> Qt Gui Project from the list. Configure the project to your own needs, there’s nothing special to be configured yet. The project (let’s call it QtTest) will show up in the Project Explorer, and will contain a number of files. Most noticeably, there’s a file called “QtTest.pro”, which is the qmake project file for the project. We’ll edit that file later
Step 3: build a library from your existing project
If the existing project you’re trying to link (let’s callit libtest) currently builds to an executable, you need to create an additional build configuration to build your code into a library. If you’re already building your project into a library (either dynamically linked or statically linked), you can skip this step.
Eclipse refers to the result of the build process as “build artifacts”. Edit the project properties of libtest, and select “Settings” under “C/C++ build”. Click on “Build Configurations” and create two new configurations: “Debug-library” (copy settings from existing configuration “Debug”) and “Release-library” (copy settings from existing configuration “Release”). After having created the configurations, configure both to build into either a “Static Library” or “Shared Library” on the “Build Artifact” tab. In case you’re not familiar with the terms “static” and “shared” (or “dynamic”), read this Wikipedia page.
Rebuild the library project libtest by right-clicking on project in the Project Explorer and selecting Build Configurations -> Build all.
Note: depending on your code and the type of library you’re building, the build process might result in an error like:
/usr/bin/ld: ./src/util/PerformanceTimer.o: relocation R_X86_64_32S against `vtable for PerformanceTimer' can not be used when making a shared object; recompile with -fPIC
./src/util/PerformanceTimer.o: could not read symbols: Bad value
collect2: ld returned 1 exit status
make: *** [libtest.so] Error 1
In this case, you should enable the -fPIC flag to create Position Independent Code. You can find this setting on the Tool Settings tab in the Project Settings dialog, under C/C++ Build -> Settings. Select GCC C++ Compiler -> Miscellaneous.
At the end of this step, you should either have a libtest.so (dynamically linked library, libtest.dll under Windows) or a libtest.a sitting in the project directory of the libtest project. Depending on your project configuration, it might be in a subdirectory.
Step 4: point the QtTest project to libtest
In order to be able to use classes from libtest when building QtTest, two things are required at compile time:
- the header (*.h) files of libtest
- the libtest.so or libtest.a files
Qt’s qmake tool has taken over control of creating Makefiles, and at the time of writing, Eclipse doesn’t quite now how to configure qmake to construct the appropriate makefile(s). If you don’t tell qmake about your libtest, it won’t know where to find the header files of libtest and will complain:
main.cpp:2:64: fatal error: algorithms/MyClass.h: No such file or directory
Alternatively, if we do point it to the header files, but not to the libtest.so, libtest.dll or libtest.a, the linker (often called ‘ld’) will compile that it can’t find the source code that implements the signatures from the header files:
/home/bas/Eclipse-workspace/QtTest/main.cpp:10: undefined reference to `MyClass::MyClass()'
collect2: ld returned 1 exit status
make: *** [DAGger_PD] Error 1
make: *** [debug] Error 2
This is all solved by editing QtTest.pro which can be found in the Project Explorer under the QtTest project. It will contain some default settings (TEMPLATE, TARGET, QT, HEADERS, SOURCES, …), and we will tell it to statically link libtest by adding the following:
INCLUDEPATH += ../KMedoids/src
LIBS += -L../libtest/Debug-Library -Wl,-Bstatic -ltest
LIBS += -L../libtest/Release-Library -Wl,-Bstatic -ltest
LIBS += -Wl,-Bdynamic -lboost_thread
If you’d like to link libtest dynamically, remove the -Wl,-Bstatic from the snippet above. Note that this configuration assumes that the libtest project is located in the same Eclipse workspace, next to the QtTest project. Also, it assumes that the libtest.so (or libtest.dll, libtest.a) are located in subdirectories Debug-Library and Release-Library. Last, but not least, it will also dynamically link the boost_thread library. Yes, you can mix dynamically and statically linked libraries!
This should get you going. If it still doesn’t work: Google is your friend. Good luck!