Clang 在我的 CMake 项目中看不到模块接口

问题描述 投票:0回答:1

我有一个小项目,我已将其重构为 C++ 模块。以下是CMakeLists.txt

cmake_minimum_required(VERSION 3.28)
project(myengine LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_SCAN_FOR_MODULES ON)
set(PREBUILT_MODULE_PATH ${CMAKE_BINARY_DIR}/engine/modules)

find_package(Vulkan REQUIRED)

if(APPLE)
    add_subdirectory("libs/metal-impl")
endif()

set(ROOT_DIST_DIR ${CMAKE_SOURCE_DIR}/dist)

if(CMAKE_BUILD_TYPE STREQUAL "Debug")
    set(DIST_DIR ${ROOT_DIST_DIR}/debug)
else()
    set(DIST_DIR ${ROOT_DIST_DIR}/release)
endif()

file(GLOB_RECURSE MDLS *.ixx)
file(GLOB_RECURSE SRCS *.cxx)

# This is the "object library" target: compiles the sources only once
add_library(objlibmyengine OBJECT)

target_sources(objlibmyengine PUBLIC FILE_SET CXX_MODULES FILES ${MDLS} ${SRCS})

# Shared libraries need PIC
set_property(TARGET objlibmyengine PROPERTY POSITION_INDEPENDENT_CODE 1)

# Shared and static libraries built from the same object files
add_library(${PROJECT_NAME} SHARED $<TARGET_OBJECTS:objlibmyengine>)
add_library(${PROJECT_NAME}static STATIC $<TARGET_OBJECTS:objlibmyengine>)

if (APPLE)

set_target_properties(${PROJECT_NAME} PROPERTIES
    LIBRARY_OUTPUT_DIRECTORY ${DIST_DIR}/lib/macos/
)

endif(APPLE)

include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR}/engine/src)

if (VULKAN_FOUND)
    message(STATUS "Found Vulkan. Including and linking...")
    target_link_libraries(objlibmyengine Vulkan::Vulkan)
    target_link_libraries(${PROJECT_NAME} Vulkan::Vulkan)
    target_link_libraries(${PROJECT_NAME}static Vulkan::Vulkan)
endif(VULKAN_FOUND)

if(APPLE)
    message(STATUS "Found Metal. Including and linking...")
    target_link_libraries(objlibmyengine metalimpl)
    target_link_libraries(${PROJECT_NAME} metalimpl)
    target_link_libraries(${PROJECT_NAME}static metalimpl)
endif()

到底是什么?嗯...之前我有一个典型的 headers+sources C++ 项目,它生成我的引擎的共享库和静态库(用于视觉引擎编辑器的静态库和用于目标游戏编译的共享库)。好的,但是为什么要有对象库呢?不要编译两次源码(我没有找到更好的解决方案)。

它适用于标头和源代码,现在我需要通过模块实现类似的功能。

好吧,让我们深入研究这个问题...但首先,我在 macOS v14 (aarch64)CMake v3.28.3 上使用 Clang v16,因此它 100% 支持 C++ 模块。

当我尝试构建引擎时,它失败并出现错误:

[main] Building folder: my 
[build] Starting build
[proc] Executing command: /opt/homebrew/bin/cmake --build /Users/denis/Projects/b3/build --config Debug --target all --
[build] [2/11   9% :: 0.043] Scanning /Projects/my/engine/src/my.ixx for CXX dependencies
[build] [2/11  18% :: 0.043] Scanning /Projects/my/engine/src/my.platform.ixx for CXX dependencies
[build] [3/11  27% :: 0.053] Generating CXX dyndep file engine/CMakeFiles/objlibmyengine.dir/CXX.dd
[build] FAILED: engine/CMakeFiles/objlibmyengine.dir/CXX.dd /Projects/my/build/engine/CMakeFiles/objlibmyengine.dir/CXXModules.json engine/CMakeFiles/objlibmyengine.dir/src/my.ixx.o.modmap engine/CMakeFiles/objlibmyengine.dir/src/my.platform.core.ixx.o.modmap engine/CMakeFiles/objlibmyengine.dir/src/my.platform.darwin.ixx.o.modmap engine/CMakeFiles/objlibmyengine.dir/src/my.platform.ixx.o.modmap engine/CMakeFiles/objlibmyengine.dir/src/my.platform.core.cxx.o.modmap engine/CMakeFiles/objlibmyengine.dir/src/my.platform.darwin.cxx.o.modmap 
[build] /opt/homebrew/Cellar/cmake/3.28.3/bin/cmake -E cmake_ninja_dyndep --tdi=engine/CMakeFiles/objlibmyengine.dir/CXXDependInfo.json --lang=CXX --modmapfmt=clang --dd=engine/CMakeFiles/objlibmyengine.dir/CXX.dd @engine/CMakeFiles/objlibmyengine.dir/CXX.dd.rsp
[build] CMake Error: Output engine/CMakeFiles/objlibmyengine.dir/src/my.platform.core.cxx.o is of type `CXX_MODULES` but does not provide a module interface unit or partition
[build] CMake Error: Output engine/CMakeFiles/objlibmyengine.dir/src/my.platform.darwin.cxx.o is of type `CXX_MODULES` but does not provide a module interface unit or partition
[build] ninja: build stopped: subcommand failed.
[proc] The command: /opt/homebrew/bin/cmake --build /Projects/my/build --config Debug --target all -- exited with code: 1
[driver] Build completed: 00:00:00.066

我不明白为什么 Clang 看不到模块接口。有问题的模块示例如下:

my.platform.core.ixx:

export module my.platform.core;

#include <string>

export namespace my 
{

enum class EWindowMode {
    DEFAULT     = 0,
    CUSTOM      = 1,
    MINIMIZED   = 2,
    MAXIMIZED   = 3,
    FULLSCREEN  = 4,
};

struct Rect 
{
    int x;
    int y;
    unsigned int width;
    unsigned int height;

    Rect(int x, int y, unsigned int width, unsigned int height);
};

struct WindowOptions {
    std::string title;
    EWindowMode mode = EWindowMode::DEFAULT;
    bool resizable = true;
    bool closable = true;
    bool minimizable = true;
    bool borderless = false;

    WindowOptions(std::string title);
};

class BaseApp
{
    public:
        BaseApp(std::string name);
        virtual ~BaseApp() {}

        virtual int run() = 0;

        void windowOption(WindowOptions options);

    protected:
        std::string name;
        WindowOptions window_options;
};

}

my.platform.core.cxx:

module;

module my.platform.core;

using namespace my;

Rect::Rect(int x, int y, unsigned int width, unsigned int height):
    x(x), y(y), width(width), height(height)
{
    
}

WindowOptions::WindowOptions(std::string title):
    title(std::move(title))
{
}

BaseApp::BaseApp(std::string name):
    name(std::move(name)),
    window_options(WindowOptions(name))
{
}

void BaseApp::windowOption(WindowOptions options) {
    this->window_options = options;
}

P.S. 模块对我来说是 C++ 中的一个新范例,所以也许我错误地声明了它们。

c++ cmake clang c++20 c++-modules
1个回答
0
投票

如果有人遇到同样的麻烦,让我们在该答案中继续我的问题:

  1. Clang 无法将

    *.ixx
    (MS 变体)识别为模块(在模块的情况下,扩展确实发挥了作用,正如@Larry 在评论中注意到我一样)。所以,我已经切换到
    *.cxxm

  2. 我应该使用如下写法:

     cmake_minimum_required(VERSION 3.28) project(myengine LANGUAGES CXX)
    
     set(CMAKE_CXX_STANDARD 20)
     set(CMAKE_CXX_STANDARD_REQUIRED ON)
     set(CMAKE_CXX_SCAN_FOR_MODULES ON)
     set(PREBUILT_MODULE_PATH ${CMAKE_BINARY_DIR}/engine/modules)
    
     find_package(Vulkan REQUIRED)
    
     if(APPLE)
         add_subdirectory("libs/metal-impl")
     endif()
    
     set(ROOT_DIST_DIR ${CMAKE_SOURCE_DIR}/dist)
    
     if(CMAKE_BUILD_TYPE STREQUAL "Debug")
         set(DIST_DIR ${ROOT_DIST_DIR}/debug) 
     else()
         set(DIST_DIR ${ROOT_DIST_DIR}/release) 
     endif()
    
     file(GLOB_RECURSE MDLS *.cxxm) file(GLOB_RECURSE SRCS *.cxx)
    
     # This is the "object library" target: compiles the sources only once
     add_library(objlibmyengine OBJECT)
    
     # FIX HERE:
     target_sources(objlibmyengine PUBLIC ${SRCS})
     target_sources(objlibmyengine PUBLIC FILE_SET CXX_MODULES FILES ${MDLS})
    
     # Shared libraries need PIC 
     set_property(TARGET objlibmyengine PROPERTY POSITION_INDEPENDENT_CODE 1)
    
     # Shared and static libraries built from the same object files
     add_library(${PROJECT_NAME} SHARED $<TARGET_OBJECTS:objlibmyengine>)
     add_library(${PROJECT_NAME}static STATIC $<TARGET_OBJECTS:objlibmyengine>)
    
     if (APPLE)
    
         set_target_properties(${PROJECT_NAME} PROPERTIES
     LIBRARY_OUTPUT_DIRECTORY ${DIST_DIR}/lib/macos/ )
    
     endif(APPLE)
    
     include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR}/engine/src)
    
     if (VULKAN_FOUND)
         message(STATUS "Found Vulkan. Including and linking...")
         target_link_libraries(objlibmyengine Vulkan::Vulkan)
         target_link_libraries(${PROJECT_NAME} Vulkan::Vulkan)
         target_link_libraries(${PROJECT_NAME}static Vulkan::Vulkan)
     endif(VULKAN_FOUND)
    
     if(APPLE)
         message(STATUS "Found Metal. Including and linking...")
         target_link_libraries(objlibmyengine metalimpl)
         target_link_libraries(${PROJECT_NAME} metalimpl)
         target_link_libraries(${PROJECT_NAME}static metalimpl) 
     endif()
    

将模块文件重命名为

*.cxxm
并修复
CMakeLists.txt
Clang 可以构建库,但我遇到了新问题:

  1. VS Code 对模块的语法突出显示很糟糕,至少在我的例子中它无法正常工作。我认为这是可以解决的,但你需要深入研究 VS Code 设置。
  2. 我的根
    CMakeLists.txt
    包含
    set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64")
    并且Clang抱怨它无法为两种架构构建C++模块。它也有一个解决方法,例如,我可以编写一个 shell 脚本来使用不同的架构标志或其他东西运行我的 CMake 两次。

有点题外话:所有这些问题和大量的教程让我明白C++模块仍然是一个太年轻的技术,它的支持还不是很好。我决定将我的库恢复为传统的源代码和标头。也许稍后当模块支持更加成熟时我会再次尝试切换到 C++ 模块。

© www.soinside.com 2019 - 2024. All rights reserved.