Adam
Adam

Reputation: 2334

c++ modules and "multiple definition of"

I'm trying to learn a little bit about c++ modules. I wrote simple source code which I'm trying to compile without luck. For some reason I'm experiencing linker issues with multiple definitions but I don't understand the reason. My g++ version is 11.2 from cygwin. Do I have a bug in my code? Is it something else?

$ g++ -std=c++20 -fmodules-ts module_a.cpp module_b.cpp main.cpp
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/ld: /tmp/ccfWIJyE.o:module_b.cpp:(.text+0xc): multiple definition of `std::string::_Alloc_hider::~_Alloc_hider()'; /tmp/cc8Ygf2b.o:module_a.cpp:(.text+0xc): first defined here
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/ld: /tmp/ccfWIJyE.o:module_b.cpp:(.text+0xc): multiple definition of `std::string::_Alloc_hider::~_Alloc_hider()'; /tmp/cc8Ygf2b.o:module_a.cpp:(.text+0xc): first defined here
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/ld: /tmp/ccfWIJyE.o:module_b.cpp:(.text+0x28): multiple definition of `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()'; /tmp/cc8Ygf2b.o:module_a.cpp:(.text+0x28): first defined here
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/ld: /tmp/ccfWIJyE.o:module_b.cpp:(.text+0x28): multiple definition of `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()'; /tmp/cc8Ygf2b.o:module_a.cpp:(.text+0x28): first defined here
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/ld: /tmp/ccfWIJyE.o:module_b.cpp:(.text+0x82): multiple definition of `std::string::_Alloc_hider::_Alloc_hider(char*, std::allocator<char> const&)'; /tmp/cc8Ygf2b.o:module_a.cpp:(.text+0x82): first defined here
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/ld: /tmp/ccfWIJyE.o:module_b.cpp:(.text+0x82): multiple definition of `std::string::_Alloc_hider::_Alloc_hider(char*, std::allocator<char> const&)'; /tmp/cc8Ygf2b.o:module_a.cpp:(.text+0x82): first defined here
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/ld: /tmp/ccfWIJyE.o:module_b.cpp:(.text+0xb8): multiple definition of `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string<std::allocator<char> >(char const*, std::allocator<char> const&)'; /tmp/cc8Ygf2b.o:module_a.cpp:(.text+0xb8): first defined here
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/ld: /tmp/ccfWIJyE.o:module_b.cpp:(.text+0xb8): multiple definition of `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string<std::allocator<char> >(char const*, std::allocator<char> const&)'; /tmp/cc8Ygf2b.o:module_a.cpp:(.text+0xb8): first defined here
collect2: error: ld returned 1 exit status

main.cpp:

import module_a;
import module_b;

int main()
{
    test_a();
    test_b();
}

module_a.cpp:

module;

import <iostream>;

export module module_a;

export void test_a()
{
    std::cout << std::string("test module a\n");
}

module_b.cpp:

module;

import <iostream>;

export module module_b;

export void test_b()
{
    // std::cout << "test module b\n";           // <- this works
    std::cout << std::string("test module b\n"); // <- this cause the issue
}

Upvotes: 2

Views: 1022

Answers (1)

alexpanter
alexpanter

Reputation: 1578

I'm not exactly sure what went wrong in your example, likely several things (check my comment to the question). In any case, this code should work fine:

// module_a.cpp
export module module_a;

import <iostream>;
import <string>;

export void test_a()
{
    std::cout << std::string("test module a\n");
}
// module_b.cpp
export module module_b;

import <iostream>;
import <string>;

export void test_b()
{
    std::cout << std::string("test module b\n");
}
// main.cpp
import module_a;
import module_b;

int main()
{
    test_a();
    test_b();

    return 0;
}
# Makefile
GCC=g++-11 -std=c++20 -fmodules-ts

all: std_headers module_a.o module_b.o main

std_headers:
    $(GCC) -xc++-system-header iostream
    $(GCC) -xc++-system-header string

module_a.o: module_a.cpp
    $(GCC) -c $< -o $@

module_b.o: module_b.cpp
    $(GCC) -c $< -o $@

main: main.cpp module_a.o module_b.o
    $(GCC) $^ -o $@

clean:
    rm -f *.o
    rm -rf gcm.cache/
    rm -f main

If I should take a guess, it could be that you import iostream in the global module fragment instead of inside the module declaration, in which case the definitions of iostream, e.g. "std::cout", are not exported as well.

$ make
g++-11 -std=c++20 -fmodules-ts -xc++-system-header iostream
g++-11 -std=c++20 -fmodules-ts -xc++-system-header string
g++-11 -std=c++20 -fmodules-ts -c module_a.cpp -o module_a.o
g++-11 -std=c++20 -fmodules-ts -c module_b.cpp -o module_b.o
g++-11 -std=c++20 -fmodules-ts main.cpp module_a.o module_b.o -o main

$ ./main
test module a
test module b

$ g++-11 --version | head -n 1
g++-11 (Ubuntu 11.1.0-1ubuntu1~20.04) 11.1.0

Upvotes: 1

Related Questions