QtCreator、Visual Studio使用CMake与Vcpkg集成

基于c/c++的运行时库MT、MTd、MD、MDd的多样性的以及涉及到相关复杂的第三方库依赖,有过一次项目引用openssl的痛苦经历;另外还会涉及到平台相关的arm-uwp arm64-windows x64-linux x64-osx x64-uwp x64-windows-static x64-windows x86-windows等配置起来相对繁琐且容易出错,最为头疼的是会牵扯一些运行时错误;主要原因也是使用过很长一段时间的C#,那么c/c++是否也有和c#、python、java等语言一样的包管理软件呢,推荐使用vcpkg - Open source C/C++ dependency manager from Microsoft,关于更多的TRIPLET可以通过vcpkg help triplet查看

平台工具链

Windows10、Qt5.12.12、Visual Studio 2017、Visual Studio 2022、CMake 3.24.0、git 2.36.1.windows.1

工具安装与部署

  1. Vcpkg

    vcpkg.exe integrate install
    Applied user-wide integration for this vcpkg root.
    CMake projects should use: "-DCMAKE_TOOLCHAIN_FILE=D:/vcpkg/scripts/buildsystems/vcpkg.cmake"All MSBuild C++ projects can now #include any installed libraries. Linking will be handled automatically. Installing new libraries will make them instantly available.

    设置系统环境变量CMAKE_TOOLCHAIN_FILED:/vcpkg/scripts/buildsystems/vcpkg.cmake

  2. 安装Visual Studio 2017/2022、CMake,安装2017的目的是提供给Qt MSVC

  3. 使用Vcpkg安装Boost、log4cplus、fmt来验证集成效果

    vcpkg install boost:x86-windows boost:x64-windows fmt:x86-windows fmt:x64-windows log4cplus[core,unicode]:x86-windows log4cplus[core,unicode]:x64-windows
    ......
    The package fmt provides CMake targets:
    find_package(fmt CONFIG REQUIRED)
    target_link_libraries(main PRIVATE fmt::fmt)
    # Or use the header-only version
    find_package(fmt CONFIG REQUIRED)
    target_link_libraries(main PRIVATE fmt::fmt-header-only)
    log4cplus provides CMake targets:
    # this is heuristically generated, and may not be correct
    find_package(log4cplus CONFIG REQUIRED)
    target_link_libraries(main PRIVATE log4cplus::log4cplus)
  4. 这边的Vcpkg配置使用基于MSVC的Triplet所以使用Qt创建的工程使用MSVC 2017来进行创建,工程创建后CMakeLists.txt内容如下

    cmake_minimum_required(VERSION 3.14)
    project(IntegrateVcpkgWithCmake LANGUAGES CXX)
    set(CMAKE_INCLUDE_CURRENT_DIR ON)
    set(CMAKE_AUTOUIC ON)
    set(CMAKE_AUTOMOC ON)
    set(CMAKE_AUTORCC ON)
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
    find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core REQUIRED)
    add_executable(IntegrateVcpkgWithCmake main.cpp)
    target_link_libraries(IntegrateVcpkgWithCmake Qt${QT_VERSION_MAJOR}::Core)
  5. 接下来添加fmtboostlog4cplus并应用起来

    • 编辑CMakeLists.txt如下

      cmake_minimum_required(VERSION 3.14)
      project(IntegrateVcpkgWithCmake LANGUAGES CXX)
      set(CMAKE_INCLUDE_CURRENT_DIR ON)
      set(CMAKE_AUTOUIC ON)
      set(CMAKE_AUTOMOC ON)
      set(CMAKE_AUTORCC ON)
      # 设置头文件与源文件
      file(GLOB INCLUDES *.h *.hpp)
      file(GLOB SOURCES *.c *.cpp *.cxx)
      # 设置头文件、源文件在IDE中的节点
      source_group("INCLUDES" FILES ${INCLUDES})
      source_group("SOURCES" FILES ${SOURCES})
      # 开启c++17支持
      set(CMAKE_CXX_STANDARD 17)
      set(CMAKE_CXX_STANDARD_REQUIRED ON)
      find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
      find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core REQUIRED)
      # 引入QNetwork验证
      find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Network REQUIRED)
      # 引入QWidgets验证
      find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)
      # 引入fmt验证
      find_package(fmt CONFIG REQUIRED)
      # 引入log4cplus作为日志模块
      find_package(log4cplus CONFIG REQUIRED)
      # 引入boost验证
      find_package(Boost REQUIRED)
      add_executable(IntegrateVcpkgWithCmake
      ${INCLUDES}
      ${SOURCES}
      )
      # 连接设置
      target_link_libraries(IntegrateVcpkgWithCmake
      PRIVATE fmt::fmt
      PRIVATE log4cplus::log4cplus
      Qt${QT_VERSION_MAJOR}::Core
      Qt${QT_VERSION_MAJOR}::Widgets
      Qt${QT_VERSION_MAJOR}::Network
      )

在QtCreator中编译运行

  1. 基于log4cplus的日志模块部分是先前写好,在这里可以作为验证使用,关于log4cplus是如何使用的这里就不做多余的介绍了,下面给出Logger的实现

    • Logger.h

      #ifndef LOGGER_H
      #define LOGGER_H
      #include <iostream>
      #include <log4cplus/loggingmacros.h>
      #include <log4cplus/logger.h>
      #include <log4cplus/consoleappender.h>
      #include <log4cplus/fileappender.h>
      #include <log4cplus/layout.h>
      #include <log4cplus/helpers/loglog.h>
      #include <log4cplus/helpers/stringhelper.h>
      #include <log4cplus/helpers/property.h>
      #include <boost/shared_ptr.hpp>
      class Logger
      {
      public:
      static boost::shared_ptr<Logger> getInstance() {
      std::call_once(of, [&]() {
      instance = boost::shared_ptr<Logger>(new Logger());
      });
      return instance;
      }
      // static std::shared_ptr<Logger> getInstance() {
      // std::call_once(of, [&]() {
      // instance = std::shared_ptr<Logger>(new Logger());
      // });
      // return instance;
      // }
      log4cplus::Logger getLogger(){
      return _logger;
      }
      ~Logger(){
      log4cplus::Logger::shutdown();
      }
      private:
      Logger(){
      #pragma region 文件载入
      //if (!exists("./Log/"))
      //{
      // create_directory("./Log/");
      //}
      //log4cplus::PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("log4cplus.cfg"));
      //_logger = log4cplus::Logger::getRoot();
      #pragma endregion
      #pragma region 代码载入
      log4cplus::initialize();
      log4cplus::helpers::Properties consoleProperties;
      consoleProperties.setProperty(LOG4CPLUS_TEXT("Encoding"), LOG4CPLUS_TEXT("UTF-8"));
      log4cplus::SharedAppenderPtr CA(new log4cplus::ConsoleAppender(consoleProperties));
      CA->setName(LOG4CPLUS_TEXT("CA"));
      log4cplus::tstring pattern = LOG4CPLUS_TEXT("[%D{%Y-%m-%d %H:%M:%S.%Q}] %-5p %m%n");
      CA->setLayout(std::unique_ptr<log4cplus::Layout>(new log4cplus::PatternLayout(pattern)));
      log4cplus::helpers::Properties timeBasedProperties;
      timeBasedProperties.setProperty(LOG4CPLUS_TEXT("FilenamePattern"), LOG4CPLUS_TEXT("Log/%d{yyyy-MM-dd}.log"));
      timeBasedProperties.setProperty(LOG4CPLUS_TEXT("Schedule"), LOG4CPLUS_TEXT("DAILY"));
      timeBasedProperties.setProperty(LOG4CPLUS_TEXT("Append"), LOG4CPLUS_TEXT("true"));
      timeBasedProperties.setProperty(LOG4CPLUS_TEXT("MaxHistory"), LOG4CPLUS_TEXT("365"));
      timeBasedProperties.setProperty(LOG4CPLUS_TEXT("RollOnClose"), LOG4CPLUS_TEXT("false"));
      timeBasedProperties.setProperty(LOG4CPLUS_TEXT("CreateDirs"), LOG4CPLUS_TEXT("true"));
      timeBasedProperties.setProperty(LOG4CPLUS_TEXT("MaxFileSize"), LOG4CPLUS_TEXT("10MB"));
      timeBasedProperties.setProperty(LOG4CPLUS_TEXT("MaxBackupIndex"), LOG4CPLUS_TEXT("10"));
      timeBasedProperties.setProperty(LOG4CPLUS_TEXT("Encoding"), LOG4CPLUS_TEXT("UTF-8"));
      log4cplus::SharedAppenderPtr MR(new log4cplus::TimeBasedRollingFileAppender(timeBasedProperties));
      pattern = LOG4CPLUS_TEXT("[%D{%Y-%m-%d %H:%M:%S.%Q}] %-5p %m%n");
      MR->setLayout(std::unique_ptr<log4cplus::Layout>(new log4cplus::PatternLayout(pattern)));
      #pragma endregion
      _logger = log4cplus::Logger::getRoot();
      _logger.setLogLevel(log4cplus::ALL_LOG_LEVEL);
      _logger.addAppender(CA);
      _logger.addAppender(MR);
      }
      private:
      log4cplus::Logger _logger;
      private:
      static boost::shared_ptr<Logger> instance;
      // static std::shared_ptr<Logger> instance;
      static std::once_flag of;
      };
      #define LOG_TRACE(log) LOG4CPLUS_TRACE(Logger::getInstance()->getLogger(), log)
      #define LOG_DEBUG(log) LOG4CPLUS_DEBUG(Logger::getInstance()->getLogger(), log)
      #define LOG_INFO(log) LOG4CPLUS_INFO(Logger::getInstance()->getLogger(), log)
      #define LOG_WARN(log) LOG4CPLUS_WARN(Logger::getInstance()->getLogger(), log)
      #define LOG_ERROR(log) LOG4CPLUS_ERROR(Logger::getInstance()->getLogger(), log)
      #define LOG_FATAL(log) LOG4CPLUS_FATAL(Logger::getInstance()->getLogger(), log)
      #define TRACE(log) LOG_TRACE(log)
      #define DEBUG(log) LOG_DEBUG(log)
      #define INFO(log) LOG_INFO(log)
      #define ERROR(log) LOG_ERROR(log)
      #define FATAL(log) LOG_FATAL(log)
      #endif // LOGGER_H
    • Logger.cpp

      #include "Logger.h"
      boost::shared_ptr<Logger> Logger::instance = nullptr;
      //std::shared_ptr<Logger> Logger::instance = nullptr;
      std::once_flag Logger::of;
  2. 接下来,在入口函数中使用验证的Vcpkg所管理的包,编译运行

    • main.cpp

      #include <QApplication>
      #include <QDebug>
      #include <QtNetwork/QTcpServer>
      #include <QWidget>
      #include <fmt/core.h>
      #include <iostream>
      #include <filesystem>
      #include <boost/any.hpp>
      #include "Logger.h"
      int main(int argc, char *argv[])
      {
      QApplication a(argc, argv);
      fmt::print("hello {} with {}\n", "vcpkg", "cmake");
      if (std::filesystem::exists("Info.log")){
      qDebug() << "not found Info.log";
      }
      boost::any arr = 1;
      qDebug() << boost::any_cast<int>(arr);
      LOG_INFO("上帝说,要有光,于是,就有了光.");
      QWidget w;
      w.show();
      QTcpServer tcpServer(&w);
      return a.exec();
      }
    • 编译运行非常顺利,执行结果如所料一般,查看日志Log/*.log: [2022-08-25 16:09:10.945.181] INFO 上帝说,要有光,于是,就有了光.

在Visual Studio 2022中编译运行

其实这部分也没有什么好说明的,从2017开始Visual Studio大力推行使用CMake来进行项目构建

  1. 使用Visual Studio 2022打开项目上面的项目文件夹, 这时Visual Studio会自动创建CMakeCache,查看CMake输出
  2. 配置CMake Settings,Viusal Studio提供的GUI方式配置和Json方式的配置,这里只需要将QT_Dir、Qt5_Dir配置为D:/Qt/5.12.12/msvc2017_64/lib/cmake/Qt5,这里需要注意,我在QtCreator中使用的是x86-Debug的环境,我在Visual Studio中使用的是x64-Debug的环境

结语

使用Vcpkg来进行c++项目的包管理十分方便,相同语言、不同语言的子项目管理、引入等都不在话下,另外CMake、Vcpkg跨平台特性对于技术猿来说也是一件一学永逸的事情

posted @   非法关键字  阅读(1841)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗
点击右上角即可分享
微信分享提示