📜 ⬆️ ⬇️

Easily connect static libraries to a project using qmake

qbs is definitely coming, but for now we’re sitting on qmake (if we haven’t escaped CMake a long time ago). And, probably, anyone who has connected static libraries to the project will agree with me that this pleasure is well below average. Personally, I am too lazy for such a disgrace, and decided to automate the process. Under the cut - what I did.

A couple of comments. First, the format of the post will not allow me to explain in detail what many of the things mentioned below mean. If anyone is interested in these details, check out my blog , where I wrote a plump series of posts about qmake. Secondly, the following scripts will not work on Qt 4 without some rework. I completely switched to Qt 5. And yet - I am programming under Windows, in order to support other platforms, I will also need to make small changes.

Idea


Let all my static libraries have names. And in the project I will add them by simply adding this name to a variable, let it be MYLIBS. Like this:

MYLIBS += MyAwesomeLib 

The following should be done:
  1. A library must be linked that is compiled in the same configuration as the project is compiled.
  2. If the library uses other libraries, then they should link automatically - but only link, INCLUDEPATH should not be clogged.
  3. Rebuild any of the static libraries should lead to a relink project.

The third item is implemented simply, the second one is also simple, but the first one requires imposing some conditions on the organization of the source code. Personally, I always use shadow builds and leave the directory names as Qt Creator generates them. Then I can find the necessary library variant simply by a similar directory name.
')

Setting features


To implement the MYLIBS variable, I will use the features mechanism. The self-written feature can be thrown into the system catalog (mxpers / features), but this is a bad form. I acted differently: I created a .qmake.cache file in the root directory of my sources (all my projects are subdirectories of this directory) with the following content:

 #    ,       QMAKEFEATURES = D:/sources/sys/qmake/features 

In this directory, I created the file mylibs.prf, which contains the actual implementation of MYLIBS. In order for the MYLIBS variable to work, you need to add the following line in the project file:

 CONFIG += mylibs 

mylibs.prf


Comments should clarify what is happening. In short, libraries are processed recursively, first those specified in the MYLIBS variable, then those used by the processed libraries, etc.

 #      shadow build    __outpath = $$basename(OUT_PWD) MYLIB_CONFIG = $$section(__outpath, "-", 2) unset(__outpath) # -,     win32-msvc* { MYLIB_PREFIX = MYLIB_EXT = .lib } else { #mingw MYLIB_PREFIX = lib MYLIB_EXT = .a } #     defineReplace(registerStandardMyLib) { libTargetName = $$1 libFolder = $$2 MYLIB_PATH = $${libFolder}/build-$${libTargetName}-$${MYLIB_CONFIG}/bin/$${MYLIB_PREFIX}$${libTargetName}$${MYLIB_EXT} isEmpty(MYLIB_NESTED) { INCLUDEPATH += $${libFolder}/$${libTargetName}/include export(INCLUDEPATH) } isEqual(TEMPLATE, app) { LIBS += $${MYLIB_PATH} PRE_TARGETDEPS += $${MYLIB_PATH} export(LIBS) export(PRE_TARGETDEPS) } return($$MYLIB_PATH) } #       MYLIBS #       .pri   lib #   mylib.prf.   =  . #     ,    # .pri        MYLIBS. #     ,      . # 100   -   __iterlist = 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 AAA MYLIB_NESTED = __handled_libs = for(__iter, __iterlist) { isEqual(__iter, AAA) { error(MYLIBS: level of nesting limit is reached!) } __mylibs = $$unique(MYLIBS) __mylibs -= __handled_libs isEmpty(__mylibs): break() clear(MYLIBS) for(__mylib, __mylibs) { !exists($${PWD}/lib/$${__mylib}.pri) { error(Libary $$__mylib is not configured.) } include($${PWD}/lib/$${__mylib}.pri) __handled_libs += __mylib } MYLIB_NESTED = 1 } unset(__mylib) unset(__iter) unset(__iterlist) unset(__handled_libs) 


The actual connection of libraries to the project occurs in the same .pri files, which should be located in the lib directory next to the mylibs.prf feature. If there is no such file for the connected library, then qmake will generate an error.

The MyAwesomeLib.pri file might look like this:

 MYLIB_PATH = D:/sources/libs/build-MyAwesomeLib-$${MYLIB_CONFIG}/bin/$${MYLIB_PREFIX}MyAwesomeLib$${MYLIB_EXT} #      INCLUDEPATH isEmpty(MYLIB_NESTED) { INCLUDEPATH += D:/sources/libs/MyAwesomeLib/include } #  -    isEqual(TEMPLATE, app) { LIBS += $${MYLIB_PATH} #     PRE_TARGETDEPS += $${MYLIB_PATH} } #  MyAwesomeLib   MyBeyondAwesomeLib,     MYLIBS += MyBeyondAwesomeLib 

As you can see, there is a lot of scribbling, you need to take into account different nuances like nesting processing. Given that I am pathologically lazy, and almost all of my libraries are organized in the same way, I wrote the registerStandardMyLib function, the code for which is given above in mylibs.prf. So the absolute majority of my .pri library files look like this:
 $$registerStandardMyLib(MyAwesomeLib, D:/sources/libs) MYLIBS += MyBeyondAwesomeLib 

That's all. I hope it will be useful to someone.

Source: https://habr.com/ru/post/180959/


All Articles