Search code examples
c++macosclangc++20clion

How to support C++20 modules on CLion for Mac


I can't use the Clion 2023.3 to compile cpp20 modules code successfully. Here is the code:

//Hello.cppm
#include <iostream>
export module Hello;
export void hello() {
    std::cout << "Hello World!\n";
}
//main.cpp
import Hello;
int main() {
    hello();
    return 0;
}

when I build these code, some errors come out:

error: module interface compilation requires '-std=c++20' or '-fmodules-ts'
error: unknown type name 'import'
error: use of undeclared identifier 'hello'

I searched on some site and decide to build it in Clion's terminal First build the module:

clang++ -std=c++20 -fmodules-ts Hello.cppm --precompile -o Hello.pcm  

Hello.pcm was generated with no error, then build the main.cpp:

clang++ -std=c++20 main.cpp -fmodule-file=Hello=Hello.pcm Hello.pcm -o Hello.out

errors comes again:

error: unknown type name 'import'
error: use of undeclared identifier 'hello'

my os version is macOS Sonoma 14.2.1, clang version 15 clion toolchains used Bundled(cmake 3.27.8)

Anybody can help? Thx!


Solution

  • As far as compiler switches go, use either -std=c++20 or -fmodules-ts, but do not use both. The modules TS has been superseded by C++20, so I recommend the former.

    The only mistake I saw in the program itself was to omit the global module fragment. That comes first in a module unit, and begins with the module; declaration.

    Old-school include directives belong in the global module fragment.

    // hello.cppm
    // Clang uses the file extension `.cppm` for "module interface units."
    
    module;               // "global module fragment" begins here
    // Include directives belong in the global module fragment.
    #include <iostream>
    
    // The global module fragment ends when a module declaration is encountered.
    export module Hello;  
    
    export void hello() {
        std::cout << "Hello World!\n";
    }
    // end file: hello.cppm
    

    According to the Clang documentation for modules:

    The file name of an importable module unit should end with .cppm (or .ccm, .cxxm, .c++m). The file name of a module implementation unit should end with .cpp (or .cc, .cxx, .c++).

    If the file names use different extensions, Clang may fail to build the module.

    So, make sure the file name of your module interface unit ends with .cppm.

    Non-module files, such as main.cpp are regular C++ translation units. So, they should use the file name extension .cpp.

    Your file main.cpp looks fine.

    // main.cpp
    import Hello;
    int main() {
        hello();
        return 0;
    }
    // end file: main.cpp
    

    I am not a Clang user, so I ran your program under MSVC. Might be irrelevant as far as Clang is concerned, but the program above ran correctly in Visual Studio (although I did use Microsoft's ixx file name extension for the module interface unit).

    Note: the program above is very similar to one given in the Clang documentation. For that program, the docs recommend the following compilation commands:

    $ clang++ -std=c++20 Hello.cppm --precompile -o Hello.pcm

    $ clang++ -std=c++20 main.cpp -fmodule-file=Hello=Hello.pcm Hello.pcm -o Hello.out

    $ ./Hello.out

    Hello World!

    These are identical to what you are using, except -fmodules-ts has been omitted.

    Modules all the way

    You might also try a "modules-only" approach. This places function main into a module, and also uses header units, rather than include files, for access to the Standard Library. Downstream, you may be able to switch to C++23's import std; (which I have been using in Microsoft projects for six months now).

    // Hello.cppm
    export module Hello;  
    import <iostream>;   // "header unit"
    
    export void hello() {
        std::cout << "Hello World!\n";
    }
    // end file: Hello.cppm
    
    // main.cppm
    export module main;
    import Hello;
    
    export int main()
    {
        hello();
        return 0;
    }
    // end file: main.cppm
    

    Check the Clang documentation for more information about how to compile header units.