c++ 20 module 模块使用 cmake

全中文网第一个讲清楚了module 与cmake结合使用

1、模块概述

ixx 声明文件
icc 实现文件
async_simple框架用的后缀是cppm

可以在模块中用模板,我是直接export的命名空间!!!
学习可以看看这篇博客学习

2、cmake 如何支持的?

cmake 官网文档链接:
https://cmake.org/cmake/help/latest/prop_tgt/CXX_MODULE_SETS.html

CXX_MODULE_SETS¶
New in version 3.25.

Note Experimental. Gated by CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API
Read-only list of the target's PRIVATE and PUBLIC C++ module sets (i.e. all file sets with the type CXX_MODULES). Files listed in these file sets are treated as source files for the purpose of IDE integration.

C++ module sets may be defined using the target_sources() command FILE_SET option with type CXX_MODULES.

See also CXX_MODULE_SET_, CXX_MODULE_SET and INTERFACE_CXX_MODULE_SETS.

1、必须是3.25以上的版本
2、模块文件使用target_sources()导入
3、需要设置CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API参数
4、linux 平台:必须使用ninja 1.11以上编译,github上有二进制包,单个文件的,clang大于15版本,cmake project name 必须等到CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API 设置完后才可以设置
6、windows平台mvsc可以直接使用,忽略以上3、4条,因为他可以自动扫描依赖没这么麻烦,但是必须保持最新版本

3、demo

CMakeLists.txt:

cmake_minimum_required(VERSION 3.25.2)

    
if (UNIX)
   
    set(CMAKE_GENERATOR "/usr/bin/ninja")
    set(CMAKE_C_COMPILER "clang-16")
    set(CMAKE_CXX_COMPILER "clang++-16")

   set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a")
   set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FORMAT "clang")
   set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG "@")
# 必须设置,否则他会去找gcc的头文件
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem /usr/lib/llvm-16/lib/clang/16/include -Wall -Wextra -Wunused-parameter")
 include(cxx_modules_rules_clang.cmake)
endif()

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

if (WIN32)
        add_definitions("/utf-8")
        add_definitions("/wd4828 /wd4267")
        #set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded")
        set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zf /O3 /openmp /MP /std:c++20 /bigobj /await:strict")
        set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Zf /O0 /openmp /MP /std:c++20 /bigobj /await:strict")
        set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zf /O3 /openmp /MP /std:c20 /bigobj /await:strict")
        set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Zf /O0 /openmp /MP /std:c20 /bigobj /await:strict")
        #[如果确认不需要PDB, 即不需要调试开源库, 完全可以在设置里将/Zi或/ZI去掉]

        # 文件utf-8
        add_compile_options("$<$:/utf-8>")
        add_compile_options("$<$:/utf-8>")

    else()
   
        # Wreturn-type 协程是空实现
        #-fmodules-ts 模块
        #-fcoroutines-ts 协程
        #-fconcepts-ts 概念
        #-fsanitize=address 检查内存溢出
        #-freport-bug 打印完整的编译 bug
        # -Wunused-result 忽略返回结果
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20  -fmodules-ts -fsanitize=address -fcoroutines-ts -fconcepts-ts -fpermissive -Wreturn-type -freport-bug -Wunused-result")
        set(CXX_FLAGS "${CXX_FLAGS} -std=c++20 -fmodules-ts -fsanitize=address -fcoroutines-ts -fconcepts-ts -fpermissive -Wreturn-typ -freport-buge -Wunused-result")

        #add_compile_options(-fmodules)
        #add_compile_options(-fbuiltin-module-map)
        #add_compile_options(-fimplicit-module-maps)
        #add_compile_options(-fprebuilt-module-path=${PREBUILT_MODULE_PATH})

    endif ()
# 源文件
file(GLOB_RECURSE SOURCE_FILES
        ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c
        ${CMAKE_CURRENT_SOURCE_DIR}/src/*.ui
        ${CMAKE_CURRENT_SOURCE_DIR}/src/*.qrc
        )

# 头文件
file(GLOB_RECURSE CURRENT_HEADERS
        ${CMAKE_CURRENT_SOURCE_DIR}/src/*.h
        ${CMAKE_CURRENT_SOURCE_DIR}/src/*.hpp
        ${CMAKE_CURRENT_SOURCE_DIR}/src/*.h
        ${CMAKE_CURRENT_SOURCE_DIR}/src/*.hpp)


#!!! 重点递归查找模板文件 FAST_MODULES保存所有的模块文件
file(GLOB_RECURSE FAST_MODULES
        ${CMAKE_CURRENT_SOURCE_DIR}/src/*.ixx
        ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cxx
        ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cppm)

# 构建可执行程序
add_executable(
${APP_NAME}#[[项目名称]] 
${SOURCE_FILES} #[[源文件]]
${CURRENT_HEADERS} #[[头文件]]
${CMAKE_CURRENT_SOURCE_DIR}/run/main.cpp #[[主函数入口]])

#!!!追加模板
target_sources(
        ${APP_NAME}
        PUBLIC
        ${FAST_MODULES}
)


什么是${CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS}

clang-scan-deps-${llvm版本号}

如何使用这个?

apt install clang-tools-16

获取不到这个版本?

https://apt.llvm.org/ 这个网址进去找到对应的扩展源

什么是CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API ?

cmake实验性的version号,github-cmake上可以找到这个东西

下面的string(…) 就是调用这个clang-scan-deps扫描工具

cxx_modules_rules_clang.cmake:

set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1)
string(CONCAT CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE
  "${CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS}"
  " -format=p1689"
  " --"
  "    "
  " -x c++  -c -o "
  " -MT "
  " -MD -MF "
  " > ")
set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FORMAT "clang")
set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG "@")

# Default to C++ extensions being off. Clang's modules support have trouble
# with extensions right now.
set(CMAKE_CXX_EXTENSIONS OFF)

4.测试文件

//声明是一个模板
module;

#include 
#include 
#include 
#include 

// 导出.hpp文件后,从这个模块开始,后面用这个文件智能import 
export import 

// 导出整个命名空间
export module tuple_utils;
namespace tuple_utils{
/***********递归+特化方式遍历打印tuple***************/
    template<typename Tuple, std::size_t N>
    struct tuple_printer {
        static void print(const Tuple &t) {
            tuple_printer<Tuple, N - 1>::print(t);
            std::cout << ", " << std::get<N - 1>(t);
        }
    };

    template<typename Tuple>
    struct tuple_printer<Tuple, 1> {
        static void print(const Tuple &t) {
            std::cout << std::get<0>(t);
        }
    };

    template<typename... Args>
    void print_tuple(const std::tuple<Args...> &t) {
        tuple_printer<decltype(t), sizeof...(Args)>::print(t);
        std::cout << std::endl;
    }

/***********使用流的方式,这里用到了C++14的index_sequence****************/
    template<typename Char, typename Traits, typename Tuple, std::size_t... Index>
    void print_tuple_impl(std::basic_ostream<Char, Traits> &os, const Tuple &t, std::index_sequence<Index...>) {
        using swallow = int[]; // guaranties left to right order
        (void) swallow{0, (void(os << (Index == 0 ? "" : ", ") << std::get<Index>(t)), 0)...};
    }

    template<typename Char, typename Traits, typename... Args>
    decltype(auto) operator<<(std::basic_ostream<Char, Traits> &os, const std::tuple<Args...> &t) {
        os << "(";
        print_tuple_impl(os, t, std::index_sequence_for<Args...>{});
        return os << ")";
    }

/***********将std::array转换成std::tuple,这里用到了C++14的index_sequence****************/
    template<typename Array, std::size_t... Index>
    decltype(auto) array2tuple_impl(const Array &a, std::index_sequence<Index...>) {
        return std::make_tuple(a[Index]...);
    }

    template<typename T, std::size_t N>
    decltype(auto) array2tuple(const std::array<T, N> &a) {
        return array2tuple_impl(a, std::make_index_sequence<N>{});
    }

/***********通过元素类型获取元素的值****************/
    template<typename T, std::size_t N, typename... Args>
    struct index_of;

    template<typename T, std::size_t N, typename... Args>
    struct index_of<T, N, T, Args...> : std::integral_constant<int, N> {
    };

    template<typename T, std::size_t N, typename U, typename... Args>
    struct index_of<T, N, U, Args...> : std::integral_constant<int, index_of<T, N + 1, Args...>::value> {
    };

    template<typename T, std::size_t N>
    struct index_of<T, N> : std::integral_constant<int, -1> {
    };

    template<typename T, typename... Args>
    T get_element_by_type(const std::tuple<Args...> &t) {
        return std::get<index_of<T, 0, Args...>::value>(t);
    };

/***********通过std::tuple作为参数调用函数****************/
    template<typename Function, typename Tuple, std::size_t... Index>
    decltype(auto) invoke_impl(Function &&func, Tuple &&t, std::index_sequence<Index...>) {
        return func(std::get<Index>(std::forward<Tuple>(t))...);
    };

    template<typename Function, typename Tuple>
    decltype(auto) invoke(Function &&func, Tuple &&t) {
        constexpr auto size = std::tuple_size<typename std::decay<Tuple>::type>::value;
        return invoke_impl(std::forward<Function>(func), std::forward<Tuple>(t), std::make_index_sequence<size>{});
    };

/***********make_from_tuple****************/
    template<typename T, typename Tuple, std::size_t... Index>
    decltype(auto) make_from_tuple_impl(Tuple &&t, std::index_sequence<Index...>) {
        return T{std::get<Index>(std::forward<Tuple>(t))...};
    };

    template<typename T, typename Tuple>
    decltype(auto) make_from_tuple(Tuple &&t) {
        constexpr auto size = std::tuple_size<typename std::decay<Tuple>::type>::value;
        return make_from_tuple_impl<T>(std::forward<Tuple>(t), std::make_index_sequence<size>{});
    };
}

你可能感兴趣的:(后端技术,c++20,c++)