Enough with the political posts!
Making libraries that are both API and libtool versioned with qmake, how do they do it?
I started a project on github that will collect what I will call “doing it right” project structures for various build environments.
With right I mean that the library will have a API version in its Library name, that the library will be libtoolized and that a pkg-config .pc file gets installed for it.
I have in mind, for example, autotools, cmake, meson, qmake and plain make. First example that I have finished is one for qmake.
Let’s get started working on a libqmake-example-3.2.so.3.2.1
We get the PREFIX, MAJOR_VERSION, MINOR_VERSION and PATCH_VERSION from a project-wide include
include(../../../qmake-example.pri)
We will use the standard lib template of qmake
TEMPLATE = lib
We need to set VERSION to a semver.org version for compile_libtool (in reality it should use what is called current, revision and age to form an API and ABI version number. In the actual example it’s explained in the comments, as this is too much for a small blog post).
VERSION = $${MAJOR_VERSION}"."$${MINOR_VERSION}"."$${PATCH_VERSION}
According section 4.3 of Autotools’ mythbusters we should have as target-name the API version in the library’s name
TARGET = qmake-example-$${MAJOR_VERSION}"."$${MINOR_VERSION}
We will write a define in config.h for access to the semver.org version as a double quoted string
QMAKE_SUBSTITUTES += config.h.in
Our example happens to use QDebug, so we need QtCore here
QT = core
This is of course optional
CONFIG += c++14
We will be using libtool style libraries
CONFIG += compile_libtool
CONFIG += create_libtool
These will create a pkg-config .pc file for us
CONFIG += create_pc create_prl no_install_prl
Project sources
SOURCES = qmake-example.cpp
Project’s public and private headers
HEADERS = qmake-example.h
We will install the headers in a API specific include path
headers.path = $${PREFIX}/include/qmake-example-$${MAJOR_VERSION}"."$${MINOR_VERSION}
Here put only the publicly installed headers
headers.files = $${HEADERS}
Here we will install the library to
target.path = $${PREFIX}/lib
This is the configuration for generating the pkg-config file
QMAKE_PKGCONFIG_NAME = $${TARGET}
QMAKE_PKGCONFIG_DESCRIPTION = An example that illustrates how to do it right with qmake
# This is our libdir
QMAKE_PKGCONFIG_LIBDIR = $$target.path
# This is where our API specific headers are
QMAKE_PKGCONFIG_INCDIR = $$headers.path
QMAKE_PKGCONFIG_DESTDIR = pkgconfig
QMAKE_PKGCONFIG_PREFIX = $${PREFIX}
QMAKE_PKGCONFIG_VERSION = $$VERSION
# These are dependencies that our library needs
QMAKE_PKGCONFIG_REQUIRES = Qt5Core
Installation targets (the pkg-config seems to install automatically)
INSTALLS += headers target
This will be the result after make-install
├── include
│ └── qmake-example-3.2
│ └── qmake-example.h
└── lib
├── libqmake-example-3.2.so -> libqmake-example-3.2.so.3.2.1
├── libqmake-example-3.2.so.3 -> libqmake-example-3.2.so.3.2.1
├── libqmake-example-3.2.so.3.2 -> libqmake-example-3.2.so.3.2.1
├── libqmake-example-3.2.so.3.2.1
├── libqmake-example-3.la
└── pkgconfig
└── qmake-example-3.pc
ps. Dear friends working at their own customers: when I visit your customer, I no longer want to see that you produced completely stupid wrong qmake based projects for them. Libtoolize it all, get an API version in your Library’s so-name and do distribute a pkg-config .pc file. That’s the very least to pass your exam. Also read this document (and stop pretending that you don’t need to know this when at the same time you charge them real money pretending that you know something about modern UNIX software development).