Qt包含工程集subdirs的使用

    xiaoxiao2022-06-27  247

    Qt包含工程集subdirs的使用

    2017年09月07日 10:14:00 struggle6688 阅读数:1963

    https://blog.csdn.net/struggle6688/article/details/77877751

    相信大家很多和我一样,用多了微软给的便利,用人家的就十分不习惯.于是就琢磨原来用到的功能现在要整顺手来,不然可让人怎么活啊! 本篇主要介绍实践使用,并非一篇完整教程,有待读者补充.^_^

        我们原本在VS上有一个大工程sln,里面有lib,有dll有exe,甚至还混搭了C#.用起来一点不觉得水土不服.现在要用QT重整,并且需要处处考虑换个平台不要让我改东西.作为探路先锋,先挑了几个基础工程出来做实验:

        ↑当然,图中是已经成事之后了.想在qtcreator中弄一个工程集还真不是那么方便,我到处找过了,压根没有创建工程集的办法.纵使你可以一个pro一个pro的拖进去,最后也没法保存,下次打开还得重新一个一个pro的拖,没哪个傻蛋总这么干吧..所以首先就是要手动创建一个subdirs型的pro做为工程集,也就是上面看到的 **CloudBoard_win32.pro**(subdirs举例)

     

    TEMPLATE = subdirs

     

    SUBDIRS =\

    raknet\

    onetengine \

    omisc \

    testDebugShow

     

    onetengine.depends = raknet omisc

    testDebugShow.depends = omisc

    #CONFIG += ordered

        关于这个pro的详细写法,感觉qt文档写的很细碎,反正我是没看明白.就着广大网友的例子才有了上面一段.TEMPLATE=subdirs这是固定写法,声明是做工程集目录的.SUBDIRS是指明目录中有哪些项,可以嵌套另一个subdirs型的pro. 接下来可以详细定义其中的项目.如.depends表示左边的依赖=后面的项目.

    .subdir指定子项的目录,不使用子项本身的名字..file明确指定该子项使用的pro文件,默认是根据名字自动找的,该项不和.subdir同时使用.conditionSpecifies a bld.inf define that must be true for subproject to be built. Available only on Symbian platform..depends该子项依赖指定的子项,只在使用makefiles的平台有效.makefile该子项的makefile,只在使用makefiles的平台有效.target该子项的TARGET,只在使用makefiles的平台有效  

        以上翻译可能有问题.重新总结一下.使用subdirs =a b c d声明的其实是4个子项的名字.默认你不多做说明的话,qmake根据名字自动去找子目录,启用子目录中的pro文件(名字优先匹配).如果你特别说明a.subdir=./z或者a.file=./z/z.pro就可以不受名字限制. 至于.makefile,应该是你混用第三方库的时候才有必要手动指定使用的makefile. target可以在子pro中指定,除非你觉得这里比较统一方便修改.其余的未实践不多说.

    **omisc.pro**(staticlib举例)

       

    QT -= gui ①

     

    TARGET = misc ②

    TEMPLATE = lib #固定写法

    CONFIG += staticlib #静态库固定写法

    #DEFINES += ③

    DESTDIR = $$_PRO_FILE_PWD_/../lib ④

    SOURCES += \

    ostatic.cpp \

    odebugoutput.cpp

     

    HEADERS += omisc.h \

    ostatic.h \

    ostringmap.hpp \

    odebugoutput.h

    unix:!symbian { ⑤

    maemo5 {

    target.path = /opt/usr/lib

    } else {

    target.path = /usr/lib

    }

    INSTALLS += target

    }

    ①"QT"是使用的QT库,从平时向导创建工程可以看出,QT默认是包含gui和core,如果你不用,他自动生成的就是  QT-=core gui.此处QT-=gui表示我们还用了core  ②TARGET是生成目标,名字不做修饰(不加.a/.lib/.dll)的好处是让qt帮我们加,在不同平台不用我们考虑差别.  同时这里的名字是可以前置路径的,如../lib/misc.它会生成在相对生成目录上一级的lib下.不过我劝你还是不要写相对路径了,因为在windows下会多出debug/release目录,目录深度不同,你换一个平台得重写.这还有更好的办法,后面继续.  ③DEFINES是VS里面的预定义头,就是定义宏,哎哟总算见着熟人了~  ④DESTDIR就是刚才②说的好办法.它控制最终的输出,相当于VS的OurDir.此处我们控制它输出到

    PROFILEPWD/../lib.前面PROFILEPWD/../lib.前面

    开头的是一个pro变量 ,存放的是工程路径,就是CloudBoard_win32.pro的路径,还有更多的定义参考Qt助手. 你可以用类似message($$_PRO_FILE_)的语句测试变量到底是什么值.具体使用是:写在pro中,右键pro的工程执行qmake.从编译输出中可以看到.

    ⑤最后这段是自动产生的,本人实在没有仔细研究,看样子应该是一种指定target目录的办法.而unix:!symbian让人不难想到,这是在筛选特定平台.具体的欢迎您测试后补充^_^

        raknet相信很多童鞋了解,本案简单将其代码编译成staticlib,DESTDIR=$$_PRO_FILE_PWD_/../lib完工

    **onetengine.pro**(动态库举例)

     

     

    include( ../common.pri ) { ①

    error(" Couldn't find the common.pri file! ")

    }

     

    QT -= gui

    QT += network xml

     

    TARGET = netengine

    TEMPLATE = lib

    DESTDIR = ../bin #基于生成目录

     

    INCLUDEPATH += ../omisc ../raknet/source ②

    DEPENDPATH += ../omisc ../raknet/source #基于工程目录

    win32:LIBS += -lWs2_32 ③

    LIBS += -lmisc -lraknet

     

    DEFINES += ONETENGINE_LIBRARY ④

     

    SOURCES += onetengine.cpp \

    netengine_export.cpp

     

    HEADERS += onetengine.h\

    onetengine_global.h \

    ../include/macrodefine.h \

    ../interface/isinkfornetengine.h \

    ../interface/inetengine.h

    **common.pri**(pro包含举例)

    INCLUDEPATH += ../interface ../include ⑤

    #LIBS += -L$$QTDIR/lib

    LIBS += -L../../src/lib

    LIBS += -L../lib

     

    **common.pri**(pro包含举例)

     

     

    INCLUDEPATH += ../interface ../include ⑤

    #LIBS += -L$$QTDIR/lib

    LIBS += -L../../src/lib

    LIBS += -L../lib

     

     

    ①没错,pro中也是可以include的,以当前文件为起点将上一层的common.pri包含进来.common.pri中的相对路径依然以当前pro路径为基础. 

    ②INCLUDEPATH是包含目录,类似于VS中的附加包含目录.至于 DEPENDPATH本人实事求是没有研究不明白有什么用.欢迎补充^_^

    ③使用筛选器,仅在win32下增加Ws2_32.lib的导入. LIBS相当于VS中的附加依赖库,不同的是可以通过-L指定库目录,-l指定库名.其间没有空格的哦.例如上面的LIBS+=-L../lib -lmisc就是可以到../lib中找misc库.misc没有说明.a还是.lib是让qt帮我们做.你也可以指定.lib,然后通过筛选器把其他平台的也写一下. ④提供宏定义ONETENGINE_LIBRARY是因为在向导创建动态库的时候qtcreator帮我们定义了这样的

     

     

    #ifndef ONETENGINE_GLOBAL_H

    #define ONETENGINE_GLOBAL_H

     

    #include <QtCore/qglobal.h>

     

    #if defined(ONETENGINE_LIBRARY)

    # define ONETENGINESHARED_EXPORT Q_DECL_EXPORT

    #else

    # define ONETENGINESHARED_EXPORT Q_DECL_IMPORT

    #endif

     

    #endif // ONETENGINE_GLOBAL_H

     

     

    提供宏定义ONETENGINE_LIBRARY决定了该工程的作用是导出动态库的. ⑤最后common.pri只是定义了几项公共的没有平台差异的信息

        好了,testDebugShow的工程pro就不多说了,它和动态库的很相似,只有TEMPLATE=app没有XXXX_LIBRARY的宏定义而已.

        最后补充一点,为什么总的工程名要叫CloudBoard_win32呢,明眼人一看就知道这是要分平台了呢.没错,一开始我也觉得一个pro就搞定了,里面可以有筛选器,一份pro足以应付.但是实际是qtcreator会为pro产生同名的.user文件,qtcreator的一些配置会写在.user里面,例如最关键的qtSDK位置,编译工具,构建/生成设置等.这些必须根据生成所处的环境区别设置. 所以当你原样跑到Linux下,启动pro就会告诉你配置是别处读来的,是否使用?是:配置一定是错的,否:配置被清洗.这都不是我们希望的.所以唯有分平台建总pro了.

     

    Qt动态库静态库的创建、使用、多级库依赖、动态库改成静态库等详细说明

    https://www.cnblogs.com/liushui-sky/p/9487583.html

    本文描述的是windows系统下,通过qtcreator在pro文件中添加动态库与静态库的方法:

    1、添加动态库(直接添加动态库文件.dll,非子项目)

    通过qtcreator创建动态库的方法就不在此处赘述了。

    唯一值得强调的是动态库与静态库的创建在pro文件中配置的区别在于静态库多了

    CONFIG += staticlib ,如下图所示(稍安勿躁,以下示例的工程代码最后会统一打包上传)

    注:mingw32编译器生成的动态库文件包括一个***.dll和一个***.a文件(这里的.a文件为导入库,类似于vc动态库生成的lib文件, .dll.a类型文件是MinGW下的DLL文件的imp-lib,即与MSVS下DLL文件附带了一个引入库.lib类似。在MSVS下编程,当要使用DLL文件时,在开发时必须要有.lib文件才能链接通过。在MinGW无需imp-lib库文件的帮助,可直接与.dll文件链。在大多数情况下,.dll.a文件不起作用。具体见https://www.cnblogs.com/liushui-sky/articles/9488020.html),vc编译器生成的动态库文件包含一个***.dll和一个***.lib文件

     

    接下来言归正传,如何添加动态库,右击工程名,选择“添加库”,由于是添加外部的库,就选择“外部库”,如果是子项目的生成的动态库,则选择“内部库”,系统库就不在此介绍了。

    这里需要吐槽下,貌似qtcreator添加外部库的步骤在windows下只能添加.lib文件,也就是说主要用于添加vc编译器生成的动态库文件,这个比较坑,linux下到是没有这个问题。

    那么qtcreator mingw32编译器生成的库如何添加呢,在看上面两幅图的第一幅,添加库的最终目的是“请将库和它的include路径添加到.pro文件中”,所以我们直接把库文件和include路径直接写到pro文件中即可。添加方法主要有以下几种,不赘述,直接看图

    这样动态库就添加好了。

    2、添加静态库(直接添加静态库文件.a,非子项目)

    与添加动态库类似,不详细说明,直接看图,相信聪明的你一看就明白

    pro文件:                              编译生成文件(静态库***.a文件):

                    

    接下来,如何添加静态库,右击工程名,选择“添加库”,由于是添加外部的库,就选择“外部库”,如果是子项目的生成的动态库,则选择“内部库”,系统库就不在此介绍了。

    还是得说声抱歉,貌似qtcreator添加外部库的步骤在windows下不管是动态库和静态库都只能添加.lib文件,也就是说主要用于添加vc编译器生成的动态库(库文件.dll和其引导文件.lib)和静态库文件(.lib文件),这个比较坑,linux下到是没有这个问题。

    那么上面qtcreator mingw32编译器生成的静态库如何添加呢,其实跟添加动态库是一样的,指定库文件和include路径,具体看第一节的图。

    3、添加动态库或静态库子项目

    当一个工程包含多个子项目时,往往一个带main主文件的项目作为主项目(即最后运行的程序),其它子项目以生成库(动态库或者静态库)的方式让主项目进行包含。

    未来调试方便,我们通过添加”内部库”的方式建立依赖关系,达到动态关联的目的。添加方法如下:

    最终在test_lib.pro的文件中添加了以上代码,但是由于mingw32生成的静态库不带lib文件,所以以上最后3行要删除,即下图中的注释部分不需要

    添加内部动态库更加简单,都不用删除,见下图:

     

     4、多级库依赖

    以下图中项目为例介绍,test_lib依赖test_lib.2,而test依赖test_lib,所以也要依赖test_lib2,记住不管动态库还是静态库子项目都要把多级依赖的库都添加上,而且还要注意顺利(具体如图中红线所示),否则哪怕编译未出错,也无法正常实现功能。也许有人先在test项目pro中加上了test_lib2的依赖,然后编译通过了,然后再注释掉重新编译还是可以正常运行,但是我想告诉你的是----这都是假象,不相信你把编译的文件都删掉再编译就不行了,这只不过是qtcreator重新构建的功能没有把一些编译文件清除干净而已,所以还是要求把依赖项都加上。这个依赖关系的学习可以具体看这篇文章https://www.cnblogs.com/liushui-sky/articles/9487600.html

     注意:这里包含的顺序与库依赖的顺序刚好相反,最底层的子项目在上面,最顶层的项目在下面

     

     

     

     

    5、动态库、静态库混合使用

    这个是否可以混合使用呢,答案当然是可以的了,为什么这么说呢,一个很简单的道理——动态编译的qt库本身都是dll的,而静态编译的子项目生成的库为静态库,既然这样可以 

    使用说明就可以一起混合使用。具体还是以上述项目为例:

     

     

    这里把test_lib2配置为生成静态库,test_lib不变,仍为动态库,test依次包含,运行结果OK,说明可行。

     项目示例代码位置:https://files.cnblogs.com/files/liushui-sky/TEST123.rar

    6.动态库改成静态库

     通过qtcreator创建的动态库项目中除pro文件中有专门的“DEFINES +=******* ”定义之外,还会有 ******_global.h的头文件生成。如以上TEST12项目中增加子项目(动态库)test_share_lib。

    如果项目后期需要改成静态库的话,除了pro中增加“CONFIG += staticlib”之外,还需要把这个头文件和DEFINES删除掉,并且在test_share_lib.h的头文件中把下图中的红色划线部分删除,否则当他还依赖其它几个静态库时会报找不到库(注:_imp__***相关的问题一般是动态库相关的问题)的报错及dllimport相关的报警,具体见下图,这个错误很隐蔽,切记,如果没有删除这些,有时候编译也能过,那是应该有些编译文件(还是动态库时候编译的文件)没有删除干净的原因,这个前面已经说明过类似的情况了,切记。

    未注释而报错的项目代码位置:https://files.cnblogs.com/files/liushui-sky/TEST123_2.rar

    你只需要按上删除pro中的内容和test_share_lib_global.h头文件,并按上修改test_share_lib.h,就不会报错,可以自己试一下吧。

     

     

     


    最新回复(0)