最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c++ - Cannot make this C++20 module test project build - Stack Overflow

programmeradmin1浏览0评论

I cannot understand what I am doing wrong in this simple test project using C++20 modules (available here):

# CMakeList.txt

cmake_minimum_required (VERSION 3.29)

project (ModulesGoogleTest LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 23)

add_executable(mgtest)

target_sources(mgtest
    PUBLIC
    main.cpp
)

target_sources(mgtest
    PUBLIC
    FILE_SET mgtest_modules TYPE CXX_MODULES FILES sample.cppm sample.cpp)

target_compile_features(mgtest PUBLIC cxx_std_23)

.

/// main.cpp

import testmodule;

int main()
{
    Counter c;
    c.Print();
    c.Increment();
    c.Print();

    return 0;
}

.

/// sample.cppm

module;    // necessary?

module testmodule;
export module testmodule;

export class Counter
{
private:
  int count;

public:
  Counter() : count(0) {}

  int Increment();
  int Decrement();
  void Print() const;
};

.

/// sample.cpp

#include <iostream>

module testmodule;

//import <iostream>;    // same result

int Counter::Increment() { return ++count; }

int Counter::Decrement() {
  if (count == 0) return count;
  return --count;
}

void Counter::Print() const
{
    std::cout << count << std::endl;
}

This is the error I get:

FAILED: ...
CMake Error: Output CMakeFiles/mgtest.dir/sample.cppm.o is of type `CXX_MODULES` but does not provide a module interface unit or partition
CMake Error: Output CMakeFiles/mgtest.dir/sample.cpp.o is of type `CXX_MODULES` but does not provide a module interface unit or partition
ninja: build stopped: subcommand failed.

I get exactly the same error building with Visual C++ 2022 and with Clang trunk.

I cannot find what is missing...

I cannot understand what I am doing wrong in this simple test project using C++20 modules (available here):

# CMakeList.txt

cmake_minimum_required (VERSION 3.29)

project (ModulesGoogleTest LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 23)

add_executable(mgtest)

target_sources(mgtest
    PUBLIC
    main.cpp
)

target_sources(mgtest
    PUBLIC
    FILE_SET mgtest_modules TYPE CXX_MODULES FILES sample.cppm sample.cpp)

target_compile_features(mgtest PUBLIC cxx_std_23)

.

/// main.cpp

import testmodule;

int main()
{
    Counter c;
    c.Print();
    c.Increment();
    c.Print();

    return 0;
}

.

/// sample.cppm

module;    // necessary?

module testmodule;
export module testmodule;

export class Counter
{
private:
  int count;

public:
  Counter() : count(0) {}

  int Increment();
  int Decrement();
  void Print() const;
};

.

/// sample.cpp

#include <iostream>

module testmodule;

//import <iostream>;    // same result

int Counter::Increment() { return ++count; }

int Counter::Decrement() {
  if (count == 0) return count;
  return --count;
}

void Counter::Print() const
{
    std::cout << count << std::endl;
}

This is the error I get:

FAILED: ...
CMake Error: Output CMakeFiles/mgtest.dir/sample.cppm.o is of type `CXX_MODULES` but does not provide a module interface unit or partition
CMake Error: Output CMakeFiles/mgtest.dir/sample.cpp.o is of type `CXX_MODULES` but does not provide a module interface unit or partition
ninja: build stopped: subcommand failed.

I get exactly the same error building with Visual C++ 2022 and with Clang trunk.

I cannot find what is missing...

Share Improve this question edited Feb 24 at 10:26 prapin 6,8985 gold badges29 silver badges54 bronze badges asked Jan 30 at 23:41 PietroPietro 13.2k31 gold badges111 silver badges204 bronze badges 3
  • 1 I get a 404 from the CE link. – Rud48 Commented Jan 31 at 17:19
  • @Rud48 - It should work now. Can you please retry? – Pietro Commented Feb 2 at 21:40
  • Thanks for asking this question. I've been meaning to explore module support so this gave me a reason to dig into it. – Rud48 Commented Feb 3 at 1:56
Add a comment  | 

2 Answers 2

Reset to default 1

I'm adding another answer because I discovered more about modules. This won't be a direct answer to the OP. It will help others who find this question looking for information on modules.

The environment is CLion, GCC 14.2, and CMake 28.3. This is the earliest version of CMake that supports modules.

This a more complex scenario. The directory structure is:

../modules
├── CMakeLists.txt
└── hello_modules
    ├── CMakeLists.txt
    ├── hello
    │   ├── CMakeLists.txt
    │   ├── hello.cpp
    │   └── hello.cppm
    └── main.cpp

I explored how to do a separate compilation of the module's body and work with separate directories. In short, simulating a large project.

The top-level CMakeLists is nothing unusual:

# top level CMakeLists.txt
cmake_minimum_required(VERSION 3.28.3)
project(modules)

add_compile_options(-std=c++23
                    -Werror -Wpedantic -Wall -Wno-unused-variable
                    -fno-exceptions
)

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_SCAN_FOR_MODULES ON)    
 
add_subdirectory(hello_modules)

The property CMAKE_CXX_STANDARD_REQUIRED needs to be on to trigger CMake to request scanning of the C++ files for module information. This is a significant reason for the delay in getting Modules to work with CMake, requiring coordination between the compiler suppliers and CMake.

The next level down, CMakeLists, creates the executable, including linking the modules. The module Hello is in the subdirectory hello and has been added to the file.

# hello_modules
cmake_minimum_required(VERSION 3.28.3)
project(ModuleTest)

add_subdirectory(hello) # build the module

add_executable(ModuleTest main.cpp)
target_link_libraries(ModuleTest Hello)

It wasn't clear whether CMake would treat modules as a library via the target_link_libraries command, but it does. The add_subdirectory appears before the add_executable to ensure the module is built before the executable.

Next, the module

# hello    
cmake_minimum_required(VERSION 3.28.3)
project(Hello)

add_library(Hello)

target_sources(Hello
               PUBLIC
                 FILE_SET CXX_MODULES
                 FILES hello.cppm
               PRIVATE
                 hello.cpp # build body with module interface
)

set_target_properties(Hello PROPERTIES CXX_MODULE_TYPE GLOBAL)

One of the key learnings was to include the body with the target_sources so that all the module files are built together. Again, CMake treats a module like a library with the add_library command.

The main.cpp is straightforward. The only thing unique is the import Hello, which accesses the module.

#include <iostream>

import Hello;

auto main() -> int {
   constexpr mod::Hello hello;
   std::cout << hello();
   return 0;
}

Now the module interface, hello.cppm:

export module Hello;

export namespace mod {
    struct Hello {
      auto operator()() const -> int;
   };
}

The two exports create the module, hello, and put struct Hello in public view. The namespace mod illustrates that everything within it can be exported with a single export. Similarly, export {...} exports all within the braces.

And, finally, the body of the module, 'hello.cpp:`

module;
#include <iostream>

module Hello;

namespace mod {
   auto Hello::operator()() const -> int {
      std::cout << "Hello modules" << '\n';
      return 42;
   }
}

The file starts with Module; to indicate this is part of a module. The module Hello tells which module. Again, the class method is inside the namespace, as usual. This file has no export because the interface source made it available.

This version builds on Compiler Explore with GCC 14.2 and CLang 19.1. It doesn't run properly for some reason. A similar project on my machine runs okay but this may be something about the CE environment.

The actual problem may have been the Counter methods not having definitions, only declarations. I didn't notice this until my desktop version was working with this slightly different CMake file.

// main.cpp
import testmodule;

int main() {
    Counter c;
    c.Print();
    c.Increment();
    c.Print();

    return 0;
}


// sample.cppm
export module testmodule;

export class Counter {
   private:
    int count;

   public:
    Counter() : count(0) {}

    int Increment(){return 0;};
    int Decrement(){return 0;};
    void Print() const{};
};

// CMakeLists.txt
cmake_minimum_required(VERSION 3.29)
project(SampleClassModuleExample)

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Enable module dependency scanning
set(CMAKE_CXX_SCAN_FOR_MODULES ON)

# Define the executable target
add_executable(SampleClassApp main.cpp)

# Register the module interface file separately
target_sources(SampleClassApp 
    PRIVATE
        FILE_SET CXX_MODULES FILES sample.cppm
)
发布评论

评论列表(0)

  1. 暂无评论