Templates Exports in Modules C++ - 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?

Related

C++ modules: compiler reports multiple definition

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

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.

Visual Studio Incremental Linking Full Relinks With Templates

I have an issue with incremental linking in that when I change some code it sometimes does a full link. I have narrowed the code down to a specific piece and was wondering if anyone knows why.
I am using Visual Studio 2012 (it exhibits the same behavior in 2015).
I have created a blank solution with 2 projects in it (a lib and an exe). I have setup incremental linking to work properly (importing library outputs as well).
The exe simply has main call into 'UpdateFrame' which is listed below.
This is all the code from the library project itself.
struct TypeId
{
unsigned char myTypeId;
// Comment out this line and it links incrementally
TypeId() : myTypeId(0) {}
};
template<class Type>
struct TypeRegistrationHelper
{
static TypeId ourTypeId;
};
template<class Type> TypeId TypeRegistrationHelper<Type>::ourTypeId;
// Uncomment this line and it links incrementally
//template struct TypeRegistrationHelper<float>;
void UpdateFrame()
{
// Commenting/uncommenting this line causes a full link to happen
// unless you have changed 1 of the 2 lines listed above. Then it links
// incrementally as expected when changing this line.
TypeRegistrationHelper<float>::ourTypeId;
}
The problem comes up that if I comment out the line in UpdateFrame, it causes a full link to happen (unless I have modified one of the two lines that are commented in code -- then everything works fine)
I've enabled verbose output for incremental linking and this is the reason it lists as performing a full relink:
LINK : directives changed; performing full link
This is the MSDN page regarding this particular error (note it says its for VC 6.0)
Linker Tools Warning LNK6019
And this is the only information it contains
A directive was added or deleted since the last incremental linking session. A full link was required in order to recreate the incremental status (.ILK) file.
Here is my main function (in the application project obviously)
#include "Updater.h"
int main()
{
UpdateFrame();
return 0;
}

GCC - "has initializer but incomplete type" error when using macros for function attributes

I have a few header files with some simple glorified structs with just pure virtual methods defined within them. The code compiles fine on Windows with Visual Studio 2015, but GCC is getting stuck. First, the code:
Code Listing
namespace CustomUtils
{
interface API_ABSTRACT overriden
{
virtual int GetStatus() const = 0;
};
}
In an imported header file, interface is just defined as a stuct:
#define interface struct
And API_ABSTRACT is just a macro for nothing:
#define API_ABSTRACT
The interface typedef is part of inherited code I have no control over, and the API_ABSTRACT is in place so that I can define custom attributes in Windows and Linux to limit which API functions I export. While this builds in VS2015, on Linux, I get a build error:
error: variable 'API_ABSTRACT CustomUtils::overridden' has initializer but incomplete type
If I change the line:
interface API_ABSTRACT overriden
To what I presume it is being translated to:
struct overriden
The code will compile fine in Linux. I've tried compiling with gcc -E -dD to have the post-"pre-processed" source rendered to screen to see the typedef and #define substitutions, but it seems to only show the output for .cpp files, and not header (.h) files.
The Question
Why won't this code work when attempting to compile with GCC?
Thank you.
Edit #1
The output from gcc -E shows the offending line to be:
struct API_ABSTRACT overriden
So it seems the culprit is the API_ABSTRACT macro, which evaluates to nothing.
API_ABSTRACT was not defined anywhere (the corresponding file was not included). The way to check it is through tell-tale gcc -E:
struct API_ABSTRACT overriden
With -E, gcc would show preprocessed output, and having API_ABSTRACT in plain sight there means preprocessor knew nothing of it.
When C++ compiler have seen this construct (struct API_ABSTRACT overridden), it thought (according to grammar and if you grant compilers cognizance) that overriden is a variable of type API_ABSTRACT. Followed by braces, it turned the construct into initialization of said variable. However, type API_ABSTRACT was never defined, so compiler complained about initializing a variable of incomplete type.

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 };