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 @ 2022-08-25 16:32  非法关键字  阅读(2057)  评论(0)    收藏  举报