C++ modules: compiler reports multiple definition - c++

I'm in the process of migrating a C++ graphics application from header files to modules. A problem with circular dependencies (C++ modules and circular class reference) has been resolved initially. But now I'm stuck in a slightly more complicated situation.
I have a module with three partitions: Part1, PartBase and PartDerived. Two of the participants (PartBase and Part1) have a mutual dependency, which is resolved by means of a forward declaration. In addition, PartBase and PartDerived have an inheritance relationship. The real situation is of course more complex, but this is a stripped down configuration, where I can reproduce the issue.
export module Module:Part1;
// :import PartBase would create circular dependency
class PartBase; // forward declaration is ok
export class Part1
{
PartBase * pBase;
};
export module Module:PartBase;
import :Part1;
export class PartBase
{
Part1 * pPart1;
};
export module Module:PartDerived;
import :PartBase;
export class PartDerived : public PartBase {};
export module Module;
export import :Part1;
export import :PartBase;
export import :PartDerived;
The module compiles without any problems.
However, when a refer to classes defined in the module from an outside client module
import Module;
export class Client
{
PartDerived* pDerived;
PartBase* pPartBase;
};
the compiler reports an error in the line, where PartBase is used:
"unrecoverable error importing module 'Module': symbol 'PartBase' has already been defined"
I use Microsoft Visual Studio Community 2022 (64-bit) - Version 17.3.3.
I can't explain this message and suspect it's a compiler error. But I've learned that it's better to look for your own mistakes before blaming the tools. Does anyone have an idea?

Seems like a compiler bug, but it's really hard to validate since all compilers have bugs with modules.
With the current compilers, it worked for me to export the forward declaration in :Part1:
export class PartBase; // forward declaration is ok
export class Part1
{
PartBase * pBase;
};
Live example

Related

Templates Exports in Modules C++

I have a templated class in a module file and when exporting the module it works fine, however when importaing I get a COMDAT exception. Are there specific constraints on how to export templated classes out of modules. I saw this post, however it seems not to solve the COMDAT exception I receive. My code has the following Layout:
export namespace Foo {
template <typename T>
class Bar {
...
}
}
However, when I link it with my GoogleTest Project and compile that one I receive a:
LNK1179 invalid or corrupt file: duplicate COMDAT '??$_Allocate_manually_vector_aligned#U_Default_allocate_traits#std###std##YAPEAX_K#Z' ...
Finally, I tried a template class<std::string> at the end of the namespace but that seems
Not working first off, still same exception
Not expandable if I have to modify my .ixx for everything
Lastly, I'm using C++ 20 with MSVC v143 compiling to a static library. Is there anything I'm missing?

Difference between `import` and `#include`? cpp20

I don't understand why
I saw import std.core; here
I can't import std;
I can't import std.iostream;
I can #include <iostream>
Can you explain why above is happening? Maybe i guess std.iostream is not a module. Then why 1. works?
#Someprogrammerdue provided this reference, and its says
import <iostream>; // import declaration
When I run following in my compiler
import <iostream>;
int main()
{
return 0;
}
I get
main.cpp:1:8: error: 'iostream' was not declared in this scope
1 | import<iostream>;
Why is this happening?
I don't understand why
I saw import std.core; here
You saw what you did because you read the page and that's what was written there.
I can't import std;
This is because the C++20 standard library doesn't define modules. And because no other library can (or shouldn't) define module std because that module name is reserved for language implementation / future standardisation.
I can't import std.iostream;
See 2.
I can #include <iostream>
That header is part of the C++20 standard library.
Then why 1. works?
The MSVC documentation explains:
Although not specified by the C++20 standard, Microsoft enables its implementation of the C++ Standard Library to be imported as modules.
P.S. Support for modules is at the moment of writing only partially implemented by all major compilers with the exception of MSVC which appears to have full implementation since 19.28 (the modular standard libary is not a requirement for this).
P.P.S. Modular standard library is planned for C++23.
import std;
Improvement in compilation time.
According to ISO C++23, there is also import std.compat;.
Differences between the two are as follows (extracted from P2465R3):
import std; imports everything in namespace std from C++ headers (e.g. std::sort from <algorithm>) and C wrapper headers (e.g. std::fopen from <cstdio>). It also imports ::operator new etc. from <new>.
import std.compat; imports all of the above, plus the global namespace counterparts for the C wrapper headers (e.g. ::fopen).
import ... is said to be much faster to compile than #include ....
Interview with Bjarne Stroustrup (InfoWorld): C++ 23 to introduce module support.
P.S. Modules are not supported fully by most compilers yet. For MSVC users, please, refer to this link.
(https://learn.microsoft.com/en-us/cpp/cpp/tutorial-import-stl-named-module?view=msvc-170).

How to export functions and classes from module not using `export` keyword?

I'm investigating an opportunity of using C++ Modules TS in my pet project. One of the important use cases for me is wrapping of legacy headers.
Suppose I have a header file with some functions and classes, std.io.ixx:
int f(int x)
{
return 2 + x;
}
According to this article, I compile the module using the following command:
cl /c /experimental:module /module:name std.io /module:export std.io.ixx
Which gives me a new file std.io.ifc. Then I use this module in another source file, main.cxx:
import std.io;
int main()
{
f(5);
}
Which is compiled with the following command:
cl /c /experimental:module main.cxx
The compilation gives me a following error:
main.cxx(5): error C3861: 'f': identifier not found
So, as we can see, the identifiers from the module were not exported. I could fix this by manually adding export keyword before each identifier I want to export, but this is impossible for the use case of wrapping the legacy headers.
What I'm doing wrong? How to export all possible identifiers from a header?
I believe there are two things wrong:
The module name must not start with std.. When I attempted to do that, I got the error
error C3674: could not find standard library module 'std.io'
This error might not appear if you haven't installed the Standard Library Modules component for Visual Studio. I'm not sure about this, though.
In the blog post you linked to, there's this note:
Note that you currently have to include your header in a .cpp file (or rename your header) because of a limitation in our compiler’s file handling.
That indeed appears to be the case because when I tried with the extension ixx, I got the same error as you.
But after fixing both of the above issues, it worked fine.

LNK2005 error in debug mode only

Usually I eventually manage to sort out these LNK2005 (symbol already defined in object) errors but this one has me beat. I have a VS2010 solution containing several projects among them a project outputting an executable. This executable depends on libraries contained within the same solution thus I have added them into the "References" list for the executable project so that they get linked in automatically.
Now what happens when I try to build my executable (Server.exe) is that everything builds successfully when the release configuration is selected, but if I switch over to debug I get the following LNK2005 error:
error LNK2005: "public: class ACE_SOCK_Stream & __thiscall ACE_Svc_Handler<class ACE_SOCK_Stream,class ACE_NULL_SYNCH>::peer(void)const " (?peer#?$ACE_Svc_Handler#VACE_SOCK_Stream##VACE_NULL_SYNCH####QBEAAVACE_SOCK_Stream##XZ) already defined in Shell.obj network.lib(network.dll) Server (server\Server)
As can be seen in the error the projects use the ACE library.
I have had a look at ACE_Svc_Handler<class ACE_SOCK_Stream,class ACE_NULL_SYNCH> that is mentioned in the error and found out that one exported class in the network.dll inherits from it:
class DLL_API NetHandler : public ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_NULL_SYNCH >
{
...
}
...and in the Server.exe there is also one class inheriting from it:
class Shell : public ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_NULL_SYNCH >
{
...
}
The peer() method mentioned in the error is then used by both the NetHandler and Shell classes.
I am not sure if, and if so why, this would cause a LNK2005 error? What confuses me even more is that I only get the linker error in debug mode. I should also mention that the NetHandler class exported by network.dll is not used by the Server.exe, other projects that also depend on the network.dll do however.
Any ideas what could be causing this and how it can be solved? I am not sure where I should continue to investigate.
UPDATE: If I don't export the NetHandler class in my network.dll the linker error goes away, but I need to export that class.
UPDATE 2: I found this link in a different question about LNK2005 and although the link doesn't describe my scenario exactly I tried the proposed solution and I managed to get rid of the linker error if I place the following line before class Shell... in my Server.exe project:
extern template class __declspec(dllimport) ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_NULL_SYNCH >;
So what does this line do exactly? Does it tell the Server project to not define ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_NULL_SYNCH > itself but instead import it from one of the linked in libraries?

Cryptopp in multi-threaded DLL, VS2010

I'm trying to use Cryptopp 5.6.2 on XPSP3 using VS 2010. New to this...
I need to use the mult-threading DLLs as that is what my application uses, so I changed all references in the Crypto++ project properties from /MT[d] to /MD[d]. All Crypto++ seems to build OK.
However, all is not happy with my C++ console app - I have the standard GetNewAndDeleteForCryptoPP and that seems to be called OK (remove it and cryptopp gives an error, include it and cryptopp doesn't print warnings).
All seems fine until I add in the line PKCS5_PBKDF2_HMAC<SHA256>. It compiles fine but causes two LNK2001 errors for unresolved symbols for CryptoPP::ThreadUserTimer::GetCurrentTimerValue(void) and
CryptoPP::ThreadUserTimer::TicksPerSecond(void).
Running out of ideas here - I can't paste the code due to arcane rules at the place I work, however I have included dll.h, cryptlib.h, osrng.h, aes.h, sha.h, hex.h, integer.h, modes.h and pwdbased.h.
Am I missing something blindingly obvious?
I was having this issue too, it doesn't look like that class is being exported. Adding CRYPTOPP_DLL to the declaration of ThreadUserTimer in hrtimer.h will fix it.
user1520427 provided you the answer. You need to add CRYPTOPP_DLL for a few classes and functions.
PKCS5_PBKDF2_HMAC<SHA256> is a header only implementation, so it does not need CRYPTOPP_DLL. See pwdbased.h.
However, ThreadUserTimer is not header only, so you need to modify hrtimer.h:
OLD:
00042 class ThreadUserTimer : public TimerBase
00043 {
00044 ...
00048 };
NEW:
00042 class CRYPTOPP_DLL ThreadUserTimer : public TimerBase
00043 {
00044 ...
00048 };