QGroundControl Options
关于stable/daily选项
option(QGC_STABLE_BUILD "Stable build option" OFF)
if(NOT QGC_STABLE_BUILD)
add_compile_definitions(DAILY_BUILD)
endif()
此版本顶层CMakeLists.txt默认QGC_STABLE_BUILD选项为OFF,如此将会向编译器添加一个定义符号DAILY_BUILD,使用vs code搜索DAILY_BUILD发现有几处源文件使用到了DAILY_BUILD作为一个开关,以QGCApplication.cc为例:
#ifdef DAILY_BUILD
// This gives daily builds their own separate settings space. Allowing you to use daily and stable builds
// side by side without daily screwing up your stable settings.
applicationName = QStringLiteral("%1 Daily").arg(QGC_APPLICATION_NAME);
#else
applicationName = QGC_APPLICATION_NAME;
#endif
如果QGC_STABLE_BUILD是ON,那么applicationName将设置为QGroundControl,否则applicationName为 QGroundControl Daily
关于Test选项
cmake_dependent_option(QGC_BUILD_TESTING "Enable testing" ON "CMAKE_BUILD_TYPE STREQUAL Debug" OFF)
if(QGC_BUILD_TESTING)
add_compile_definitions(UNITTEST_BUILD) # TODO: QGC_UNITTEST_BUILD
endif()
提供一个QGC_BUILD_TESTING选项,此选项在选择构建类型为Debug时设为ON,否则为OFF。含义是只在Debug时提供Unit Test。
如果QGC_BUILD_TESTING为ON,向编译器添加UNITTEST_BUILD宏定义,使用vs code搜索UNITTEST_BUILD,很多处源文件使用到此宏定义,以main.cc为例:
#ifdef UNITTEST_BUILD
if (runUnitTests) {
for (int i=0; i < (stressUnitTests ? 20 : 1); i++) {
if (!app->_initForUnitTests()) {
return -1;
}
// Run the test
int failures = UnitTest::run(unitTestOptions);
if (failures == 0) {
qDebug() << "ALL TESTS PASSED";
exitCode = 0;
} else {
qDebug() << failures << " TESTS FAILED!";
exitCode = -failures;
break;
}
}
} else
#endif
此处在app->exec()之前进行单元测试,对每个测试结果打印输出。
关于QML debug选项
cmake_dependent_option(QGC_DEBUG_QML "Build QGroundControl with QML debugging/profiling support." OFF "CMAKE_BUILD_TYPE STREQUAL Debug" OFF)
if(QGC_DEBUG_QML)
message(STATUS "To enable the QML debugger/profiler, run with: '-qmljsdebugger=port:1234'")
add_compile_definitions(QT_QML_DEBUG)
endif()
提供QGC_DEBUG_QML选项,用于QML在debug/profile时的支持,CMakeLists.txt这里无论构建方式是否为Debug都设置为OFF,Qt的QML debug参考官方文档:Debugging QML Applications | Qt 6.7
当Qt quick程序使用CMake构建方式,可以向编译器添加以下宏定义,实现QML debug:
QT_DECLARATIVE_DEBUG
QT_QML_DEBUG
QGroundControl Resources
设置QGC_RESOURCES变量,代表QGC使用到的资源文件:
set(QGC_RESOURCES
${CMAKE_SOURCE_DIR}/qgcimages.qrc
${CMAKE_SOURCE_DIR}/qgcresources.qrc
${CMAKE_SOURCE_DIR}/qgroundcontrol.qrc
${CMAKE_SOURCE_DIR}/resources/InstrumentValueIcons/InstrumentValueIcons.qrc
${CMAKE_SOURCE_DIR}/src/FirmwarePlugin/APM/APMResources.qrc
${CMAKE_SOURCE_DIR}/src/FirmwarePlugin/PX4/PX4Resources.qrc
)
关于UTMSP
if(CONFIG_UTM_ADAPTER)
list(APPEND QGC_RESOURCES ${CMAKE_SOURCE_DIR}/src/UTMSP/utmsp.qrc)
else()
list(APPEND QGC_RESOURCES ${CMAKE_SOURCE_DIR}/src/UTMSP/dummy/utmsp_dummy.qrc)
endif()
这里UTM是指无人机交通管理Unmanned Traffic Management,UTMSP是指Unmanned Traffic Management Service Providers。
在src/UTMSP/CMakeLists.txt中,定义QGC_UTM_ADAPTER选项:
option(QGC_UTM_ADAPTER "Enable UTM Adapter" OFF)
如果QGC_BUILD_TESTING为ON,将向QGC_RESOURCES这个list变量添加UnitTest.qrc:
if(QGC_BUILD_TESTING)
list(APPEND QGC_RESOURCES ${CMAKE_SOURCE_DIR}/test/UnitTest.qrc)
endif()
QGroundControl Target
创建可执行目标
qt_add_executable(${PROJECT_NAME}
src/main.cc
${QGC_RESOURCES}
)
qt_add_executable命令参考Qt官方文档:qt_add_executable | Qt Core 6.7.1
特别声明,此命令在除Android 以外的所有平台上,都将创建可执行目标。所有参数都将传递到标准 CMake add_executable() 命令,但MANUAL_FINALIZATION(qt_add_executable可选参数)除外。如果设置了MANUAL_FINALIZATION参数,则应该最后由qt_finalize_target确定target。
Qt6 LinguistTools翻译工具
if(Qt6LinguistTools_FOUND)
file(GLOB TS_SOURCES RELATIVE ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/translations/qgc_*.ts)
qt_add_translations(${PROJECT_NAME} TS_FILES ${TS_SOURCES}) # TODO: Update to new qt_add_translations form in Qt6.7
endif()
前面find_package(Qt6 REQUIRED COMPONENTS LinguistTools)
如果找到了Q6::LinguistTools,cmake将会产生一个BOOL变量Qt6LinguistTools_FOUND为TRUE,此时调用file(GLOB)命令,将translations目录下,所有符合qgc_开头,以.ts结尾的文件记录在TS_SOURCES变量中:

调用qt_add_translations命令,将这些.ts文件(xml格式),使用LinguistTools转换为.qm文件(二进制),最后应用程序将会使用installTranslator调用.qm文件,完成翻译工作。
关于qt_add_translations命令详细介绍,参考官方文档:qt_add_translations | Qt Linguist Manual
QGC这里有一个TODO标记,因为这是Qt6.2版本引入的的qt_add_translations命令,QGC4.3.0规定最低版本为Qt6.6.0,下一个版本将会使用Qt6.7定义新的qt_add_translations命令。
关于Qt国际化,.ts与.qm文件等内容,参考一篇知乎文章:
超越 C++ 的 Qt 翻译 - 知乎 (zhihu.com)
在src/QGCApplication.cc内有QGCApplication::setLanguage函数,其中部分代码如下:
if (_locale.name() != "en_US") {
QLocale::setDefault(_locale);
if(_qgcTranslatorQtLibs.load("qt_" + _locale.name(), QLibraryInfo::path(QLibraryInfo::TranslationsPath))) {
_app->installTranslator(&_qgcTranslatorQtLibs);
} else {
qCWarning(LocalizationLog) << "Qt lib localization for" << _locale.name() << "is not present";
}
if(_qgcTranslatorSourceCode.load(_locale, QLatin1String("qgc_source_"), "", ":/i18n")) {
_app->installTranslator(&_qgcTranslatorSourceCode);
} else {
qCWarning(LocalizationLog) << "Error loading source localization for" << _locale.name();
}
if(_qgcTranslatorJSON.load(_locale, QLatin1String("qgc_json_"), "", ":/i18n")) {
_app->installTranslator(&_qgcTranslatorJSON);
} else {
qCWarning(LocalizationLog) << "Error loading json localization for" << _locale.name();
}
}
根据机器所在的地区,确定本地应该使用的语言,随后调用installTranslator函数加载.qm文件。
预编译头文件
target_precompile_headers(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/src/pch.h)
对于很少更改的头文件,如Qt提供的库头文件、C++标准库头文件等,可以将其放在pch.h中进行预编译,更改源码后,保证编译速度不会像第一次那么慢。
关于target_precompile_headers命令,参考官方文档:
target_precompile_headers — CMake 3.29.2 Documentation
Qt资源
set_target_properties(${PROJECT_NAME} PROPERTIES QT_RESOURCE_PREFIX "/qgc")
关于QT_RESOURCE_PREFIX属性,参考QT官方文档:QT_RESOURCE_PREFIX | Qt Core 6.7.1
当使用qt_add_resources命令时,没有指明PREFIX参数,且QT_RESOURCE_PREFIX已被设置,则将会在资源文件路径前,自动加上${QT_RESOURCE_PREFIX},使用vs code搜索qt_add_resources,发现只有:
qt_add_resources(Joystick "gamecontrollerdb.txt"
PREFIX "/db/mapping/joystick"
FILES ${sdl_db_SOURCE_DIR}/gamecontrollerdb.txt
)
给出了PREFIX,似乎此set_target_properties并没有起到作用?
进行git submodule update
include(Git)命令将会调用cmake/Git.cmake模块,打开此模块有几行代码需要注意:
find_package(Git)
查找Git package,准备进行Git操作。
if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
option(GIT_SUBMODULE "Check submodules during build" ON)
if(GIT_SUBMODULE)
message(STATUS "Submodule update")
execute_process(
COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
RESULT_VARIABLE GIT_SUBMODULE_RESULT
OUTPUT_VARIABLE GIT_SUBMODULE_OUTPUT
ERROR_VARIABLE GIT_SUBMODULE_ERROR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(NOT GIT_SUBMODULE_RESULT EQUAL 0)
cmake_print_variables(GIT_SUBMODULE_RESULT GIT_SUBMODULE_OUTPUT GIT_SUBMODULE_ERROR)
message(FATAL_ERROR "git submodule update --init failed with ${GIT_SUBMODULE_RESULT}, please checkout submodules")
endif()
endif()
endif()
以上主要功能是:如果查找到Git包,且在顶层CMakeLists.txt同级目录存在.git文件(.gitmodules也算),执行git submodules,将子模块update。如果以下命令失败,将会输出日志信息:
git submodule update --init --recursive
添加编译器定义
add_compile_definitions(
QGC_APPLICATION_NAME="QGroundControl"
QGC_ORG_NAME="QGroundControl.org"
QGC_ORG_DOMAIN="org.qgroundcontrol"
APP_VERSION_STR="${APP_VERSION_STR}"
)
主要作用是向编译器添加几个STRING类型的宏定义,在源码中均有用到,使用vs code搜索QGC_APPLICATION_NAME,在main.cc有:
QObject::tr("A second instance of %1 is already running. Please close the other instance and try again.").arg(QGC_APPLICATION_NAME)
添加src子目录到构建树
add_subdirectory(src)
src目录包含除test外几乎所有的源文件,此命令将src内源文件添加到构建树,src有CMakeLists.txt,通过add_subdirectory继续添加子目录到构建树:
add_subdirectory(ADSB)
add_subdirectory(AirLink)
add_subdirectory(AnalyzeView)
add_subdirectory(api)
add_subdirectory(Audio)
add_subdirectory(AutoPilotPlugins)
add_subdirectory(Camera)
add_subdirectory(comm)
add_subdirectory(Compression)
add_subdirectory(FactSystem)
add_subdirectory(FirmwarePlugin)
add_subdirectory(FlightDisplay)
add_subdirectory(FlightMap)
add_subdirectory(FollowMe)
add_subdirectory(Geo)
add_subdirectory(GPS)
add_subdirectory(Joystick)
add_subdirectory(MissionManager)
add_subdirectory(PlanView)
add_subdirectory(PositionManager)
add_subdirectory(QmlControls)
add_subdirectory(QtLocationPlugin)
add_subdirectory(Settings)
add_subdirectory(Terrain)
add_subdirectory(ui)
add_subdirectory(Utilities)
add_subdirectory(UTMSP)
add_subdirectory(Vehicle)
add_subdirectory(VehicleSetup)
add_subdirectory(VideoManager)
add_subdirectory(VideoReceiver)
add_subdirectory(Viewer3D)
添加链接库
target_link_libraries(${PROJECT_NAME}
PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Qml
Qt6::Quick
Qt6::QuickControls2
Qt6::Svg # Used to import QSvgPlugin
qgc
)
target_link_libraries作用是向可执行文件/库文件指定链接库,详细内容参考cmake官方文档:target_link_libraries — CMake 3.29.2 Documentation
关于Qt6::Core中::的作用,官方文档有一段描述:
Items containing ::, such as Foo::Bar, are assumed to be IMPORTED or ALIAS library target names and will cause an error if no such target exists. See policy CMP0028.
通过阅读cmake对于CMP0028的介绍:CMP0028 — CMake 3.29.2 Documentation
使用::是用于命名 IMPORTED 目标和 ALIAS 目标的常见模式。
此处尝试对Qt链接库文件的流程理解,以Core为例:
第一步调用find_package
find_package(Qt6
REQUIRED
COMPONENTS
Core …)
找到本机Qt安装目录下的.cmake文件并调用:
F:\QT\6.7.0\mingw_64\lib\cmake\Qt6Core\Qt6CoreConfig.cmake
查看此.cmake文件,当Qt6Core_FOUND为TRUE时有以下一行代码:
include("${CMAKE_CURRENT_LIST_DIR}/Qt6CoreTargets.cmake")
第二步调用Qt6CoreTargets.cmake
查看Qt6CoreTargets.cmake有一行代码:
# Create imported target Qt6::Core
add_library(Qt6::Core SHARED IMPORTED)
添加本机上的Qt6::core,根据这个动态库信息,可以得知其将会链接到Qt6Core.dll,但是一个很重要的问题是:怎么知道要链接的Qt6Core.dll在Qt安装目录下的bin目录呢?
第三步定位库路径
在Qt6CoreTargets.cmake有一行代码:
include("${CMAKE_CURRENT_LIST_DIR}/Qt6CoreAdditionalTargetInfo.cmake")
打开Qt6CoreAdditionalTargetInfo.cmake:
if(_qt_imported_location_default)
set_property(TARGET Qt6::Core PROPERTY IMPORTED_LOCATION "${_qt_imported_location_default}")
endif()
if(_qt_imported_implib_default)
set_property(TARGET Qt6::Core PROPERTY IMPORTED_IMPLIB "${_qt_imported_implib_default}")
endif()
设置IMPORTED_LOCATION为${_qt_imported_location_default},搜索_qt_imported_location_default,发现:Qt6CoreTargets.cmake调用include(Qt6CoreTargets-relwithdebinfo.cmake)
Qt6CoreTargets-relwithdebinfo.cmake设置了变量IMPORTED_LOCATION_RELWITHDEBINFO如下:
set_target_properties(Qt6::Core PROPERTIES
IMPORTED_IMPLIB_RELWITHDEBINFO "${_IMPORT_PREFIX}/lib/libQt6Core.a"
IMPORTED_LOCATION_RELWITHDEBINFO "${_IMPORT_PREFIX}/bin/Qt6Core.dll"
)
最后调用target_link_libraries
link Qt6::Core,将Qt6Core.dll添加为链接库文件。
注意观察target_link_libraries链接一个库为qgc,使用vs code搜索add_library,发现在src/CMakeLists.txt有:
qt_add_library(qgc STATIC
CmdLineOptParser.cc
CmdLineOptParser.h
QGCApplication.cc
QGCApplication.h
QGCConfig.h
QGCToolbox.cc
QGCToolbox.h
)
1733

被折叠的 条评论
为什么被折叠?



