Как создать многоразовые библиотеки на основе qmake?

У меня есть несколько приложений, которые будут использовать одну или несколько общих библиотек. Даже мои библиотеки могут зависеть друг от друга.

Вот дерево файлов:

Libaries/
   Library1/
       Library1.pro
       Library1.cpp
       Library1.h
   Library2/
       Library2.pro
       Library2.cpp
       Library2.h
Applications/
   App1/
       App1.pro
       main.cpp
   App2/
       App2.pro
       main.cpp

Приложение 1 зависит от библиотеки 1. Приложение 2 зависит от Library1 и Library2.

Я хотел бы иметь возможность легко разрабатывать в Qt creator, когда я открываю Application1, у меня следующее поведение:

  • Код Application1, доступный в Qt creator
  • Код Library1 доступен в создателе Qt
  • Компиляция Application1 автоматически компилирует Library1 и помещает выходной файл.dll /.so в тот же каталог, что и Application1.exe.

Это в основном то, что Visual Studio может делать годами, и мне кажется, что это такая базовая вещь, что я не понимаю, что у меня одна такая проблема.

Есть ли у вас какие-либо подсказки, как это сделать? Я пробовал разные решения, основанные на SUBDIRS, но я никогда не доходил до всех 3 пунктов выше.

РЕДАКТИРОВАТЬ: Чтобы уточнить немного, я хотел бы иметь возможность сделать что-то вроде:

Application1.pro

include("Library1")

Application2.pro

include("Library1")
include("Library2")

И все работает автоматически. Я нашел решение, которое требует, чтобы файлы в библиотеках знали, что "родитель" делает, включая некоторые, что для меня не имеет смысла, библиотека не должна знать о программе, использующей ее.

3 ответа

Решение

Вы можете сделать проект, как это: MyProject:

  • project.pro
    • Приложение
      • App.pro
      • main.cpp
    • lib1
      • lib1.pro
      • lib1.pri
      • lib1.h
      • lib1.cpp
    • lib2
      • lib2.pro
      • lib2.pri
      • lib2.h
      • lib2.cpp

project.pro

TEMPLATE = subdirs
CONFIG += ordered

SUBDIRS += \
    lib1 \
    lib2 \
    App

App.pro

QT       += core

QT       -= gui

include(../lib1/lib1.pri)
include(../lib2/lib2.pri)

TARGET = App
CONFIG   += console
CONFIG   -= app_bundle

TEMPLATE = app


SOURCES += main.cpp

main.cpp

#include <QCoreApplication>
#include "lib1.h"
#include "lib2.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    Lib1 lib1();

    return a.exec();
}

lib1.pro

QT       -= gui

TARGET = lib1
TEMPLATE = lib

DEFINES += LIB1_LIBRARY

SOURCES += lib1.cpp

HEADERS += lib1.h\
        lib1_global.h

DESTDIR = ../libs

unix {
    target.path = /usr/lib
    INSTALLS += target
}

OTHER_FILES += \
    lib1.pri

lib1.pri

INCLUDEPATH += $$PWD/
LIBS += -L$$OUT_PWD/../libs/ -llib1

lib2.pro

QT       -= gui

TARGET = lib2
TEMPLATE = lib

DEFINES += LIB2_LIBRARY

SOURCES += lib2.cpp

HEADERS += lib2.h\
        lib1_global.h

DESTDIR = ../libs

unix {
    target.path = /usr/lib
    INSTALLS += target
}

OTHER_FILES += \
    lib2.pri

lib2.pri

INCLUDEPATH += $$PWD/
LIBS += -L$$OUT_PWD/../libs/ -llib2

В дополнение к ответу Тома, полезно иметь возможность ссылаться на заголовки библиотек, используя квалифицированные префиксы - #include "lib1/lib1.h" вместо #include "lib1.h", В противном случае практически невозможно использовать библиотеки, разработанные независимо, вы всегда будете сталкиваться с конфликтами заголовков.

Есть два способа сделать это.

Во-первых, вы можете добавить общую переменную к каждому файлу проекта верхнего уровня, которая указывает его глубину в дереве проекта, ссылаясь на корень дерева. Затем вы добавляете корень дерева в пути включения и зависимости.

App.pro

ROOT = ..
include($$ROOT/lib1/lib1.pri)
include($$ROOT/lib2/lib2.pri)

INCLUDEPATH += $$ROOT
DEPENDPATH += $$ROOT

...

Таким образом, отдельные библиотечные проекты не должны указывать свои включения вообще.

В качестве альтернативы INCLUDEPATH в каждой библиотеке должна быть указана одна папка вверх - не забудьте DEPENDPATH!

lib1.pri

ROOT = ..
INCLUDEPATH += $$PWD/$$ROOT
DEPENDPATH += $$PWD/$$ROOT

...

Тогда внутри main.cpp, вы можете иметь разумные префиксы, которые не будут конфликтовать, даже если lib1 а также lib2 оба предоставляют один и тот же файл:

main.cpp

#include "lib1/easy.h"
#include "lib2/easy.h"
...

App1Solution.pro:

TEMPLATE = subdirs
CONFIG += ordered

SUBDIRS += \
    ../../Libaries/Library1 \
    ../App1

Место рядом App1.pro

App2Solution.pro:

TEMPLATE = subdirs
CONFIG += ordered

SUBDIRS += \
    ../../Libaries/Library1 \
    ../../Libaries/Library2 \
    ../App2

Место рядом App2.pro

и помещает выходной файл.dll/.so в тот же каталог, что и Application1 .exe

Это должно быть сделано по-другому:

  1. Вы могли бы установить DESTDIR из Library<i> в зависимости от какой-то переменной.
  2. Вы можете добавить команду copy-lib в App<i> профиль.
Другие вопросы по тегам