Пару замечаний. Во-первых, формат поста не позволит мне объяснить детально, что означают многие вещи из упомянутых ниже. Если кому интересны эти подробности — загляните в мой блог, где я написал пухлую серию постов о qmake. Во-вторых, приведенные ниже скрипты на Qt 4 без некоторых переделок работать не будут. Я полностью перешел на Qt 5. И еще — я программирую под Windows, для поддержки других платформы тоже нужно будет вносить небольшие изменения.
Идея
Пусть все мои статические библиотеки имеют имена. А в проект я буду добавлять простым добавлением этого имени в переменную, пусть MYLIBS. Вот так:
MYLIBS += MyAwesomeLib
При этом должно выполняться следующее:
- Должна прилинковываться библиотека, которая скомпилирована в той же конфигурации, в которой компилируется проект.
- Если библиотека использует другие библиотеки, то они должны прилинковаться автоматически — но только прилинковаться, INCLUDEPATH засоряться не должен.
- Ребилд любой из статических библиотек должен приводить к перелинковке проекта.
Третий пункт реализуется просто, второй тоже несложен, но первый требует наложить какие-то условия на организацию исходников. Лично я всегда использую shadow builds и оставляю имена каталогов в том виде, в котором их генерирует Qt Creator. Тогда нужный вариант библиотеки я могу найти просто по похожему имени каталога.
Настройка фичи
Для реализации переменной MYLIBS я воспользуюсь механизмом фич (features). Самописную фичу можно кинуть в системный каталог (mkscpes/features), но это дурной тон. Я поступил по-другому: создал файл .qmake.cache в корневом каталоге своих исходников (все мои проекты — подкаталоги этого каталога) следующего содержания:
# полный путь к каталогу, куда я кладу свои самописные фичи QMAKEFEATURES = D:/sources/sys/qmake/features
В этом каталоге я создал файл mylibs.prf, в котором находится собственно реализация MYLIBS. Для того, чтобы переменная MYLIBS заработала, в файле проекта нужно добавить следующую строку:
CONFIG += mylibs
mylibs.prf
Комментарии должны прояснить суть происходящего. Вкратце, библиотеки обрабатываются рекурсивно, вначале те, что указаны в переменной MYLIBS, потом те, что используются обработанными библиотеками, и т.д.
# определяю конфигурацию как имя каталога 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)
Собственно подключение библиотек к проекту происходит в одноименных .pri файлах, которые должны находиться в каталоге lib рядом с фичей mylibs.prf. Если такого файла для подключаемой библиотеки не найдется, то qmake выдаст ошибку.
Файл MyAwesomeLib.pri может выглядеть следующим образом:
MYLIB_PATH = D:/sources/libs/build-MyAwesomeLib-$${MYLIB_CONFIG}/bin/$${MYLIB_PREFIX}$${libTargetName}$${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
Как видно, писанины много, нужно учитывать разные нюансы вроде обработки вложенности. Учитывая, что я патологически ленив, и почти все мои библиотеки организованы одинаковым образом, я написал функцию registerStandardMyLib
, код которой приведен выше в mylibs.prf. Так что абсолютное большинство моих .pri файлов библиотек выглядят следующим образом:
$$registerStandardMyLib(MyAwesomeLib, D:/sources/libs) MYLIBS = MyBeyondAwesomeLib
На этом все. Надеюсь, пригодится кому.
ссылка на оригинал статьи http://habrahabr.ru/post/180959/
Добавить комментарий