C++/CMake 构建系统:(二)包管理

共享公共包 用过 npm、pip 或是 go 等的包管理系统就知道,对于工程来说,除了工程目录下的依赖包,还可以有一些系统范围共享的依赖包,以便减少重复包所占用的空间。 CMake 也提供了这个功能,允许设置全局范围的默认包搜索路径。 在系统范围内设置 CMAKE_PREFIX_PATH 环境变量可以指定包管理的前缀路径。而 CMAKE_INSTALL_PREFIX 环境变量可以指定安装和搜索包的前缀路径,所以这里优先使用后者方便同时设置安装和搜索包路径。 安装一个包到公共目录 对于可执行文件,可以简单的统一安装到公共目录的 bin 文件夹下。 install(TARGETS base_test DESTINATION bin)对于库文件,这里希望可以按工程区分不同的包,方便管理。 install(TARGETS libbase ARCHIVE DESTINATION "${PROJECT_NAME}/lib")install(FILES ${public_headers} DESTINATION "${PROJECT_NAME}/include/libbase")区分接口文件包含路径 如果需要安装的库包含接口目录,则有可能因为安装路径变化,导致头文件搜索错误。 这里需要区分构建和安装时的接口文件路径。 target_include_directories(libbase INTERFACE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}> $<INSTALL_INTERFACE:${PROJECT_NAME}/include>)安装时导出目标 为了方便其他工程引用安装到公共目录的包,可以使用 install 命令增加导出。 install(FILES ${public_headers} EXPORT "${PROJECT_NAME}Targets" DESTINATION "${PROJECT_NAME}/include/libbase")对于导出的包,需要增加一个 cmake 文件方便其他工程使用。 安装时导出配置 为了方便 find_package 命令导入包,还需要生成 Config 文件。CMake 提供了脚本来自动生成导出的 Config。 include(CMakePackageConfigHelpers)configure_package_config_file( "${PROJECT_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in" "${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}Config.cmake" INSTALL_DESTINATION "${PROJECT_NAME}/cmake")write_basic_package_version_file( "${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}ConfigVersion.cmake" VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}" COMPATIBILITY AnyNewerVersion)同时要提供配置文件模板 LibBaseConfig.cmake.in。 @PACKAGE_INIT@ include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")check_required_components(@PROJECT_NAME@)最后把生成好的文件也安装到全局目录下。 install(DIRECTORY "${PROJECT_BINARY_DIR}/cmake" DESTINATION ${PROJECT_NAME})使用包 安装好的包,其他工程就可以通过 find_package 命令直接使用了。...

December 24, 2022 · 1 min · lyincc

C++/CMake 构建系统:(一)基本工程结构

主工程文件 首先要创建工程的主要入口,也就是一个 CMakeLists.txt 文件。 构建工程时就需要指定这个文件的所在目录。 CMake 版本和策略 主工程文件首先要描述的就是对 CMake 的版本选择和全局策略开关。 主要涉及 cmake_minimum_required 和 cmake_policy 两个命令。 对整个工程使用的 CMake 特性进行约定。 cmake_minimum_required(VERSION 3.24)全局变量 这部分定义工程需要的全局变量,如工程名、版本号等。 可以直接用 project 命令定义,也可以用 set 命令对变量进行指定。 project("base" VERSION 0.0.1)将全局变量同步到 C++ 代码 如果有些全局变量希望可以共享给 C++ 代码,比如工程版本号,可以使用 configure_file 修改部分文件的代码,将全局变量赋给文件中的指定占位符。 创建一个 project_config.h.in 文件,写入以下内容。 constexpr int kBaseVersionMajor = @Base_VERSION_MAJOR@; constexpr int kBaseVersionMinor = @Base_VERSION_MINOR@; constexpr char kBaseVersion = @Base_VERSION@; 在 CMakeLists.txt 中增加生成文件的命令。 configure_file(global_config.h.in global_config.h)构建后就会自动生成解析后的 global_config.h 文件供其他 C++ 源码使用。 全局编译选项 修改全局编译器配置,也可以使用默认配置不做修改。 这里指定默认的 C++ 语言标准版本。 set(CMAKE_CXX_STANDARD 20)set(CMAKE_CXX_STANDARD_REQUIRED True)添加自定义命令 如果有些构建的准备工作需要处理,比如将配置阶段生成的 project_config....

December 18, 2022 · 1 min · lyincc

C++/WinUI 3 技术笔记:(二)框架代码分析

前一节创建了一个 C++/WinUI 3 应用,接着分析默认生成的框架代码。框架代码中使用了大量 C++ 模板技术和新语言特性,发挥了 C++ 语言零开销抽象的优势,很值得学习。 App 应用入口 重新回到应用入口类 App。 struct App : AppT<App> { App(); void OnLaunched(Microsoft::UI::Xaml::LaunchActivatedEventArgs const&); private: winrt::Microsoft::UI::Xaml::Window window{ nullptr }; }; 应用的入口 App 类继承于一个代码生成的模板 AppT,这里用到的 C++ 奇异模板递归(CRTP)技术和 ATL 一脉相承。 template <typename D, typename ... Interfaces> struct AppT: public ::winrt::Microsoft::UI::Xaml::ApplicationT<D, ::winrt::Microsoft::UI::Xaml::Markup::IXamlMetadataProvider, Interfaces...> { using IXamlType = ::winrt::Microsoft::UI::Xaml::Markup::IXamlType; void InitializeComponent() { if (_contentLoaded) return; _contentLoaded = true; ::winrt::Windows::Foundation::Uri resourceLocator{ L"ms-appx:///App.xaml" }; ::winrt::Microsoft::UI::Xaml::Application::LoadComponent(*this, resourceLocator); } IXamlType GetXamlType(::winrt::Windows::UI::Xaml::Interop::TypeName const& type) { return AppProvider()->GetXamlType(type); } IXamlType GetXamlType(::winrt::hstring const& fullName) { return AppProvider()->GetXamlType(fullName); } ::winrt::com_array<::winrt::Microsoft::UI::Xaml::Markup::XmlnsDefinition> GetXmlnsDefinitions() { return AppProvider()->GetXmlnsDefinitions(); } private: bool _contentLoaded{false}; winrt::com_ptr<XamlMetaDataProvider> _appProvider; winrt::com_ptr<XamlMetaDataProvider> AppProvider() { if (!...

September 2, 2022 · 3 min · lyincc

C++/WinUI 3 技术笔记:(一)创建第一个 WinUI 3 项目

微软在 Windows 10 Version 1809 上正式发布了新的 UI 框架,命名为 WinUI 3。 这已经是微软发布的第不知道多少个 UI 框架了,但是微软宣称它将支持原生 C++ 和 Win32 应用。这引起了我的注意,因为微软已经很久没有为 Win32 提供新的技术了。 WinUI 3 与 Win32、UWP 按微软的说法,WinUI 3 是同时为 Win32 和 UWP 程序提供支持的,也就是说它应该允许独立运行在 Win32 框架上,不受 UWP 的权限管理限制。 对于 C++ 开发者,WinUI 3 借助 C++/WinRT 有完全的原生 C++ 支持,而不需要 C++/CX 或 C++/CLI 这样剑走偏锋的设计。这无疑对 GCC 或 Clang 上编译 WinUI 3 留下了可能。作为开发者,着实不希望微软带领技术走向分裂。 对于 UI 设计,WinUI 3 继承了 UWP 程序的 XAML 技术,为用户提供了 Fluent 风格的控件和交互体验。也就是说在核心的 UI 开发方式上,还是和 UWP 保持一致的,只是控件风格有所改变。但是 WinUI 3 不受 UWP 复杂的权限约束限制,可以说对 Win32 开发者十分友好了。...

February 3, 2022 · 3 min · lyincc

Flutter 引擎层

获取 源码位于 Github 仓库,但需要使用 gclient 组织工程 https://github.com/flutter/engine 部分依赖的 githook 脚本不支持 python3,需要强制 gclient 使用 python2 set GCLIENT_PY3=0 参考 https://github.com/flutter/flutter/wiki/Setting-up-the-Engine-development-environment 源码拉取后需要切换分支。需要对应 Flutter SDK 版本。在 %FLUTTER_SDK%\bin\internal\engine.version 中查看对应引擎版本。 拉取指定版本引擎配置: solutions = [ { "managed": False, "name": "src/flutter", "url": "https://github.com/flutter/engine.git@07c1eed46b9d9b58df78566e9b8b2e42e80d3380", "custom_deps": {}, "deps_file": "DEPS", "safesync_url": "", }, ] 执行 gclient sync 同步源码。 编译 参考 https://github.com/flutter/flutter/wiki/Compiling-the-engine#compiling-for-windows 切换到 src 目录,使用 .\flutter\tools\gn 脚本创建 ninja 工程。 编译 windowns-x64 release 版本 .\flutter\tools\gn --target-os=win --windows-cpu=x64 --runtime-mode=release 编译 debug 版本,可以使用 --unoptimized 关闭代码优化...

September 1, 2020 · 1 min · lyincc