中大型Qt项目目录组织


  • 网站研运

    Hi,很久都没有写一些经验文章了。最近终于空出时间,我开始静下心来,将自己过去遇到的各种问题总结一下,有关中大型基于Qt的项目目录的组织方法。
    817438194831.jpg
    如果您是第一次使用Qt,那么可能会按照自己的喜好去创建项目。这样创建的项目简单,更为使用者所理解。但是如果你是想创建一个长期的项目并且希望其他人与你一同协作,那么项目的组织就变得非常重要了。好的中大型项目必须做到以下几点:

    1、对持续集成友好

    何为“持续集成”?就是可持续构建、流水线操作的方式来处理软件系统。因为中大型项目的构建往往需要花费较长的时间,并且软件是一个系统中唯一需要人工开发部分(作为对比,硬件制作自动化程度非常高),所以为了满足快速发布的需要,我们必须构建一套持续集成的系统。以满足一日一版本甚至一日多版本的发布测试需要。举个例子:在固定的开发周期内(比方说三个月),手工构建的方式需要集合所有团队的成果,然后各个部门的成果集合起来,假设需要两天,那么以每个月22个有效工作日的情况下,最多只能构建33次版本,而且要让所有的团队成员做重复劳动至少33次。假设搭建了持续集成的环境,可以缩短到一个小时构建一次,那么以每天八个小时工作计算,理论上说可以构建66×8次版本,大大超出的了手工构建的方式。这对于测试部门和开发部门来说,节省了宝贵的时间用来测试和后续开发,都是大有意义的。

    2、配置型

    大型项目最好能够做到项目可配置。这是因为软件的运行依托的是硬件,硬件的配置千奇百怪,这需要相对完整的软件测试。我们的流程是根据不同硬件上的软件测试来针对我们的项目选择最优的策略。这个时候谁都不希望为一个小小的改动而返工,并且软件产品一旦发布到用户的手上了,那么在想引导它们重新安装就变得很难了。因此希望有一套策略,自适应客户的环境,并且给出最佳的使用方案。这也是为什么很多软件都有“设置”功能的原因。那么一些超出用户认知以外但是可能需要根据不同环境适配的内容,宜写成配置文件,配置文件为空,程序内部逻辑给出默认值。

    3、有多个测试案例

    大型项目往往是多个小功能聚集起来的,那么大型项目可能会遇到千奇百怪的情况,一般的方式很难检查出来,而且问题的复现路径将变得很长。那么为了尽量减少此类情况的发生,缩短问题的复现路径,找到问题的原因,主要也是为了复测遇到的问题,有必要构建多个测试案例。测试案例要尽量写得简单一些,能够直接验证问题是否解决为佳。

    4、模块化管理

    好的软件,都是利用模块化管理的。虽然模块化会导致应用程序安装包变得庞大,并且增加了进程注入的风险,但是这确是大规模协作可行的办法。试想一下,用户使用了发布的软件出了问题,假设不使用模块化的方式,那么出了问题,定位到问题点可谓十分困难,即使找到问题并且解决了,但是要客户重新安装并且部署软件,又是一个非常繁杂的过程。所以友好的方式是将各个功能分为不同的模块,出了问题的话,容易定位到哪个模块出了问题,并且可以通过替换有问题的模块来解决相应的问题。使用模块化的方式还有一个好处,那就是职责分明。将软件开发过程中形成的优秀代码打包出售,也可以将不合格的模块进行替换,不至于影响其他模块的正常工作。还可以以此评定成员在项目中的贡献。

    除此之外,还有很多优化的方法,比如说“开-闭原则”等等,都是方便用户使用或者方便开发者开发而采用的方法。

    那么,中大型Qt项目,究竟是怎么组织的?
    我们可以看看Qt作为一个二十多年产生的项目,它的代码是如何组织的。大家只要去Qt开源软件下载网站 去下载相应的源代码,就可以找到他的组织方法。以下是我们的商业软件代码的组织:

    8096b3ff-f871-4d9a-9d3a-3a3f19382b8e-image.png

    一般包括examples、src、test和其它文件。其中src里面包含的是源代码,非常重要。也是我们经常需要添砖加瓦的一个文件夹。此外,如果是QML插件模块,那么需要在src文件夹中添加一个imports文件夹,和Qt的命名风格保持一致。其中src中每一个子文件夹都是一个子项目,其中pro文件的编写都有相应的规则。这超出了本文介绍的范围,要单独一篇文章介绍才行。


Log in to reply
 

走马观花

最近的回复

  • C

    Qt for MCU需要商业授权的

    read more
  • Qt for MCUs

    搭建Qt for MCUs PC端开发环境。qt for mcus提供了一个完整的图形框架和工具包,包含了在MCUs上设计、开发和部署gui所需的一切。它允许您在裸机或实时操作系统上运行应用程序。

    先决条件

    开发主机环境支持仅限于Windows 10

    MSVC compiler v19.16 (Visual Studio 2017 15.9.9 or newer) x64

    CMake v3.13 or newer (you can install it using the Qt Online installer) x64

    使用Qt联机安装程序安装Qt for MCUs,该安装程序可通过Qt帐户下载

    安装Qt 5.14和Qt Creator 4.11 or higher

    安装链接

    › Qt: https://account.qt.io/downloads
    › CMake: https://cmake.org/download/
    › Python 2.7 32-bit: https://www.python.org/downloads/release/python-2716/
    › Arm GCC: https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnutoolchain/gnu-rm/downloads
    › J-Link Software Pack: https://www.segger.com/downloads/jlink/JLink_Windows.exe
    › J-Link OpenSDA Firmware: https://www.segger.com/downloads/jlink/OpenSDA_MIMXRT1050-EVKHyperflash
    › STM32CubeProgrammer: https://www.st.com/en/development-tools/stm32cubeprog.html
    › STM32 ST-LINK Utility: https://www.st.com/en/development-tools/stsw-link004.html​​​​​​​

    Qt Creator设置 启用Qt Creator插件 选择“帮助>关于插件”,然后从列表中选择“MCU支持(实验性)”插件,重新启动Qt Creator以应用更改
    替代文字 为MCU创建Qt工具包

    选择工具>选项>设备>MCU

    选择Qt for MCUs-Desktop 32bpp作为目标

    如果尚未设置,请提供Qt for MCUs安装目录的路径。

    单击Apply应用。

    替代文字

    替代文字
    替代文字

    注意:

    编译器要选X64,Qt版本要选64bit,CMake Tool选x64

    打开恒温器项目demo

    选择文件>打开文件或项目。。。

    打开CMakefiles.txt文件来自thermo文件夹的文件。

    选择Qt作为MCU-桌面32bpp套件。

    单击“配置项目”以完成。

    替代文字

    问题

    开发主机环境支持仅限于Windows 10

    C++编译失败,文本大字体.pixelSize.

    文本类型无法正确呈现需要复杂文本布局的unicode序列。对复杂文本使用StaticText

    read more
  • H

    hi 有问题请教你,方便加个联系方式吗

    read more
  • boost.asio是一个很棒的网络库,这回儿我也开始系统地学习起来了。想想当年接触boost,也有八年多了。这次开始接触boost,觉得既熟悉又陌生。熟悉的是小写字母+下划线的命名方式、晦涩的模板、很慢的编译速度以及较大的程序体积,陌生的是asio的各种概念:io服务、接收器、套接字等等:我之前对网络编程不是非常了解。

    于是根据我的理解,参考《Boost.Asio C++网络编程》实现了这样一个简单的客户端和服务端通信的例子,例子非常简单,还不完善,但是幸运的是,可以在本机上互通了。
    下面是客户端的代码:

    #include <iostream> #include <boost/asio.hpp> #include <boost/proto/detail/ignore_unused.hpp> using namespace std; using namespace boost::asio; using namespace boost::system; using namespace boost::proto::detail;// 提供ignore_unused方法 void writeHandler( const boost::system::error_code& ec, size_t bytesTransferred ) { if ( ec ) { cout << "Write data error, code: " << ec.value( ) << "transferred: " << bytesTransferred << endl; } else { cout << "OK! " << bytesTransferred << "bytes written. " << endl; } } int main(int argc, char *argv[]) { ignore_unused( argc ); ignore_unused( argv ); io_service service; ip::tcp::socket sock( service ); ip::tcp::endpoint ep( ip::address::from_string( "127.0.0.1" ), 6545 ); boost::system::error_code ec; sock.connect( ep, ec ); if ( ec ) { cout << "Connect error, code: " << ec.value( ) << ", We will exit." << endl; return ec.value( ); } else { char buf[1024] = "Hello world!"; sock.async_write_some( buffer( buf ), writeHandler ); sock.close( ); } return service.run( ); }

    下面是服务端的代码:

    #include <iostream> #include <boost/asio.hpp> #include <boost/proto/detail/ignore_unused.hpp> using namespace std; using namespace boost::asio; using namespace boost::system; using namespace boost::proto::detail;// 提供ignore_unused方法 void acceptHandle( const boost::system::error_code& code ) { cout << "Accepted." << endl; } int main(int argc, char *argv[]) { ignore_unused( argc ); ignore_unused( argv ); io_service service; ip::tcp::endpoint ep( ip::address::from_string( "127.0.0.1" ), 6545 ); boost::system::error_code ec; ip::tcp::socket sock( service ); ip::tcp::acceptor acceptor( service, ep ); acceptor.async_accept( sock, acceptHandle ); if ( ec ) { cout << "There is an error in server. code: " << ec.value( ) << endl; } return service.run( );// 阻塞运行 }

    运行结果是这样的:
    78448d7b-b3ae-42fc-9e2e-4dd2fbdac2c2-image.png

    我对boost.asio中几个概念的理解:

    io_service,这就是一个类似事件循环的东西,它为io设备提供服务,故名。不管是套接字、文件还是串口设备,都要使用它的服务。它的run()函数相当于启动了一个事件循环。一旦有消息了,即进行响应。这也是实现异步编程的重要基础。 socket,这个类则是套接字,可以处理TCP或者是UDP请求。有同步以及异步的处理方式,也有带异常以及不带异常的处理方式。 acceptor,接收器,仅仅是服务端使用。相当于其余框架中的listener,作接收用的。

    比较浅显,如果有不当之处,敬请指正。

    read more

关注我们

微博
QQ群