Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using legacy header files as c++20 modules

I am in the process of converting my old code to something that is importable as c++-modules. The problem is that i would want it to still work and be easily maintained as the old header/source version. How do I do this (if possible).

Is it possible to create a module that export the content of a header? (Any other solution that lets you maintain old .cpp/.h files and module files is also accepted)

Toy example:

// In vector.h
template <typename T>
struct Vector {
    T x, y;
}

// In .cppm
export module vector;
// #include "vector.h"
// Export struct/class Vector from header

What i have tried is just export Vector in different versions, with and without templates etc.

Bonus question: Can you do this for the std lib? (for exmaple iostream, or string)

like image 858
Lasersköld Avatar asked Feb 17 '21 10:02

Lasersköld


People also ask

Why are modules better than headers?

Modules eliminate or reduce many of the problems associated with the use of header files. They often reduce compilation times. Macros, preprocessor directives, and non-exported names declared in a module aren't visible outside the module.

Does CMake support C++ modules?

CMake currently does not support C++20 modules. See also the relevant issue in the CMake issue tracker. Note that supporting modules requires far more support from the build system than inserting a new compiler option.


2 Answers

Recently I created two answers first one regarding how to create module (in CLang) out of any old-style header. Second one regarding how to create modules out of STD headers.

Using these two answers now you can just code as before, in old .hpp-based style. Then in usage code you can do following:

#if USE_MODULES
    import std_mod; // Module created out of all STD headers.
    import my_lib; // Module created out of my_lib.h.
#else
    #include <iostream>
    #include <vector>
    // ... All other tons of STD headers ...

    #include "my_lib.h"
#endif

int main() { use_my_lib(); }

Using headers as modules or as includes are totally interchangable, in both cases you'll have even macros, because CLang's header modules export macros as well.

Also you don't need any special syntax of creating my_lib library. You don't need to use export or module keywords at all, you just code as in old-style C++ without modules and then your headers are easily converted to modules.

I did such thing in my quite huge C++ project. It was coded totally without modules and then automatically in my build system I converted all headers to modules, which greatly improved compilation speed. Of cause I implemented my own build system that is aware of includes and modules and automatically does conversion on flight without changing original files.

like image 141
Arty Avatar answered Oct 04 '22 20:10

Arty


a) You want to keep your code (mostly) as-is, but put wrap it inside modules.

That would result in something similar to PCH, but standardized on a language level. Under the assumption that no code changes are neccessary, this has the following advantages:

  • Users can use your library both as header files as well as modules (if they themselves update to C++20)
  • If the library is consumed as modules, you might see benefits in compilation time (depends on the project though)

The most simple way to achieve this is putting all your public headers in a single module:

// your_lib.cppm
module;
// global module fragment here
#include "your_header1.hpp"
#include "your_header2.hpp"
// ...

export module your_lib;

You should read about importable headers (the syntax already shown in the comments, e.g. import <iostream>). As far as I know, what is an importable header is implementation defined. So in general, you would not have to use the global module fragment.

b) You want to modularize your code base, but allow others to still consume header files.

The only reason (which is a pretty good reason) to want something like this is to support the usage of your library for users that still use an older standard of C++20.

The solution you were hoping for is not really possible. Sorry. There is no way back from module to header. Everything internal to your library can be completely modularized. Then you have to make a decision. Keep the public interface as headers, or modularize it as well. In the first case, see a) on how you would consume your own public headers in your internal modules. In the second case you have to provide a second implementation of your interface as header files. As I said, you only choose b) to support older standard versions. So you'd also have to make sure to not to use any C++20 features in your (header based) public interface.

like image 22
flowit Avatar answered Oct 04 '22 20:10

flowit