Search code examples
c++c++20c++23

How to use global functions inside a module without using a header file


update: the fix is shown in the code.

I have a function defined in main.cpp. I want to call it inside module Hello. The file Hello.cppm exports module Hello with the implementation in hello.cpp. The files are cut and pasted from larger files so compilation errors may occur. They should be close. (Compiler Explorer IDE wouldn't do modules for me.)

The question is, where can I put the extern declaration in hello.cpp or maybe (it doesn't seem likely) Hello.cppm? I've tried positions before and after the various module statements. Most generate compiler errors. Where it is now, it compiles but won't link. I suspect it is considered a non-exported module Hello function.

It should work in a header file, but can it work without a header file? This a learning experiment. In a header, everything works, but it shouldn't be necessary for a single function.

Using GCC 14.2 and CMake 2.38.2 on Ubuntu 24.04

The linker error.

function `main':
main.cpp:(.text.startup+0x1c): undefined reference to `mod::HelloAgain@Hello::operator()() const'
/usr/bin/ld: libHello.a(hello.cpp.o): in function `mod::Hello@Hello::operator()() const':
hello.cpp:(.text+0x1d): undefined reference to `hello_func_global@Hello[abi:cxx11]()'

main.cpp

#include <iostream>
#include <string>
using namespace std::literals;

auto hello_func_global() -> std::string {
   return "Hello from a global  function."s;
}
import Hello;

auto main() -> int {
   mod::Hello();
   constexpr mod::Hello hello;

   constexpr mod::HelloAgain hello_again;
   hello_again();

   std::cout << hello_func() << '\n';
   return 0;
}

Hello.cppm

module ;

#include <string>

export module Hello;

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

hell0.cpp

module Hello;
extern auto hello_func_global() -> std::string; // <=== the fix

using namespace std::literals;

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

The CMake file that builds the module.

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
               hello_again.cpp
)

set_target_properties(Hello PROPERTIES CXX_MODULE_TYPE GLOBAL)

Solution

  • I suspect it is considered a non-exported module Hello function.

    Exactly.

    The question is, where can I put the extern declaration in hello.cpp or maybe (it doesn't seem likely) Hello.cppm?

    You don't have any choice but to put it after module Hello;.

    To tell the compiler that it is not attached to the module, use a linkage-specification extern "C++".

    extern "C++" auto hello_func_global() -> std::string;