Closed matbech closed 1 year ago
I just added the std.ixx file directly to my project, I didn't need a separate library.
I'll cheekily add my question here. If i do
#include <string>
import std;
should I expect it to work?
@davidhunter22 Assuming you meant import std;
and not using std;
that was not working with the legacy modules (std.core) either because the #include comes after the import. However, the following where the #include comes before the import was working:
#include <type_traits>
import std;
std::vector<int> items;
which now fails to compile:
C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.35.32019\include\xtr1common(42,47): error C2572: 'std::enable_if': redefinition of default argument: parameter 1
Thanks @matbech I updated my question
Is there another way?
I think you don't need another static library project. Just add std.ixx
to your Source Files
and it works.
(Add -> Existing Item... -> C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.35.32019\modules\std.ixx)
should I expect it to work?
@davidhunter22 , probably it should work, but the compiler has bugs.
I have found in the Discord channel:
One sad thing I noticed with adding the .ixx file to a project. If you have a solution with 200 projects and all of them add the .ixx file then you compile the standard library module 200 times. This does only happen on the first build but :-( Hopefully MS will tell us a better way than this so that you only build it once per solution
Not being able to mix "import std" with classic includes is a real pain. Any large body of code these days probably uses third party libraries, in my case from vcpkg. Almost all of them will #include standard library header in their headers. So you can't migrate your code to use import std until every library you depend on either has a build varaint that uses the std module or has a macro to guard #includes in it's headers. As in
`
#incldue <string>
`
One sad thing I noticed with adding the .ixx file to a project. If you have a solution with 200 projects and all of them add the .ixx file then you compile the standard library module 200 times. This does only happen on the first build but :-( Hopefully MS will tell us a better way than this so that you only build it once per solution
I believe using a static library (add the std.ixx) which is then referenced by the other projects in your solution is the right approach.
For the mixed headers issue, I hope @StephanTLavavej can provide some guidance.
Thanks for trying to use the Standard Library Modules as soon as possible! :heart_eyes_cat:
We're still working on adding build system support so import std;
will work automatically. (I believe I'll need to set an environment variable indicating where the modules
directory is, and add a JSON file indicating how std.compat
depends on std
.) My apologies for not getting to this yet - it was important to merge the library and test code as early as possible to prevent regressions from ongoing compiler work, but then I got busy with other tasks (e.g. the big /clr
PR #3194). At this point, I'm not sure if we can add build system support in time for the production release of VS 2022 17.5, but I hope everything will be ready for VS 2022 17.6 (at which point the compiler should also be working much more robustly).
Answering specific questions/topics (please let me know if I missed anything; thanks @fsb4000 for quoting an earlier reply of mine from Discord):
/experimental:module
compiler option and the "C++ Modules for v143 build tools (x64/x86 - experimental)" VS installer component are not needed for the C++23 Standard modules.#include <meow>
and import std;
in any order should work, according to the Standard. However, this is an extremely stressful scenario for the compiler (as it involves noticing that the classic header and the named module are providing the same machinery, and that they should be considered identical instead of duplicate definitions). I've been told by our modules dev @cdacamar to expect that this will totally fail until major compiler work happens, so I have not added any test coverage for this scenario.
std.ixx
into std.ifc
and std.obj
. Note that, as long as the command lines match, you can build it once, and then consume it from a hundred projects. Centralizing this depends on what build system you are using, but there should be no fundamental challenge to making this work. Arranging for a static library to be produced seems reasonable. (You can build both std.ifc
and std.compat.ifc
, and create a .lib
containing std.obj
and the near-empty std.compat.obj
, so that projects can consume either import std;
or import std.compat;
as they see fit.)I have a work around for including third party libraries that then do old style #includes of standard library headers. If you have the tiniest shred of dignity you may want to look away now.
So the MS standard library headers still use old style macro include guards not #pragma once. So you can simply define all these macro guards yourself and then include the header file that does things like "#include
I have a work around for including third party libraries that then do old style #includes of standard library headers. If you have the tiniest shred of dignity you may want to look away now.
So the MS standard library headers still use old style macro include guards not #pragma once. So you can simply define all these macro guards yourself and then include the header file that does things like "#include ". Attached is a header that defines all the ones I think you need. Oddly you can't upload .h files so I renamed it to .txt
This does not work at all. If you define the guards then any C++ headers won't get included and the 3rd party headers which require those will not compile. E.g.
#include "MacroGuards.h"
#include <atlbase.h>
atlbase.h includes
I am including the headers in my code which has an "import std;" so all the standard library types are aready declared before I include the third party header. I should have mentioned you need to do
import std;
#include "MacroGuards.h"
#include <atlbase.h>
I am already using this successfully for a number of libraries, such as type_safe, pugxml and catch2 that I use via vcpkg without modfiying them in any way. Sometimes the third party header you include assumes some things are in the global namespace like uint8_t. I also add a using std::uint8_t before I do the include to fix those. You could also "import std.compat" but I am keen to avoid that as not getting all the legacy junk is one of the reasons I am doing this.
It doesn't work for me when importing the std module in a precompiled header (e.g. pch.h) and I do include the 3rd party libraries there.
Ah good point. I switched off pch stuff in my build before trying this out mostly because I feel the standard library module is sort of a replacement for a PCH containing the standard library stuff. If you have PCH files including third party library stuff that then include standard library stuff I am well out of my depth! I am sure there are other corner cases where this hackery does not work but as I said it does work for reasonably complex headers like those from catch2
Instead of defining our preprocessor guard macros to suppress classic includes, there's a less-wacky (still fairly wacky) technique that may work: create a bunch of fake headers named algorithm
, bitset
, etc. (one for every Standard header) whose content is simply #pragma once
followed by import std;
. You should then be able to use /I
pointed to that directory, which will be looked up before the toolset include directories (this is a little-known but useful property of /I
). This should non-intrusively "overlay" the import std;
declarations for third-party libraries to pick up, and should interact reasonably with PCHes (although I haven't tested any of this). Good luck! :smile_cat:
I have given this a try, however without success. The compiler gets confused after it encounters an import std; statement in the PCH and it will start throwing errors like:
1>C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.35.32019\include\vector(2212,36): error C2440: 'static_cast': cannot convert from 'std::_Iterator_base12' to 'std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<_Ty>>> &'
1> with
1> [
1> _Ty=int
1> ]
for code which compiles fine otherwise:
#include "pch.h"
import std;
int main()
{
std::vector<int> test;
test.resize(5);
}
pch.h
#pragma once
// All CRT headers must be included before the first import statement
#include <crtheaders.h>
import std;
This problem was found in trying to build the google_test library with the std module
I found a specific issue of mixing the std
module and header files that I am finding hard to work around. In most cases I can just not include the old header file and things are fine however I can't do this with crtdbg.h
.
crtdbg.h
eventually inludes vcruntime_new.h
This contains the following
namespace std
{
enum class align_val_t : size_t {};
}
which then causes a type redefinition error. I could try to do some hideous macro stuff to work around this but am wondering if anyone has a good solution.
Ideally the vcruntime_new.h
would use the _BUILD_STD_MODULE macro to guard this but I guess it's a VC runtime header so maybe that isn't allowed
Automatic MSBuild suuport was implemented with "Scan Sources for Module Dependencies".
Great! Any idea when this will land?
Great! Any idea when this will land?
@MikeGitb If I get it right it's already there - Project properties -> C/C++ -> General -> Scan Sources for Module Dependencies
Thx, will have a look during the weekend.
Edit: Can confirm with 17.7.4 - great stuff. Thanks. Now, if we get mix and match with standard library headers somehow, I could start using it in my hobby projects.
Great! Any idea when this will land?
@MikeGitb If I get it right it's already there - Project properties -> C/C++ -> General -> Scan Sources for Module Dependencies
What should I do to use this in CMake?
Something like this worked for me:
std/CMakeLists.txt
cmake_minimum_required(VERSION 3.26)
project(std)
add_library(${PROJECT_NAME} STATIC)
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23)
# hacky :/
string(REGEX REPLACE "\/bin\/Hostx(64|86)\/x(64|86)\/cl\.exe" "" MSVC_ROOT ${CMAKE_CXX_COMPILER})
# std.ixx
configure_file("${MSVC_ROOT}/modules/std.ixx" "${PROJECT_BINARY_DIR}/std.ixx" COPYONLY)
string(JOIN " " STD_REF_PARAM /reference "${PROJECT_BINARY_DIR}/CMakeFiles/${PROJECT_NAME}.dir/std.ifc")
set(STD_REFERENCE ${STD_REF_PARAM} CACHE INTERNAL "std.ifc compiler parameter")
# std.compat.ixx
configure_file("${MSVC_ROOT}/modules/std.compat.ixx" "${PROJECT_BINARY_DIR}/std.compat.ixx" COPYONLY)
set(STD_COMPAT_REFERENCE /reference "${PROJECT_BINARY_DIR}/CMakeFiles/${PROJECT_NAME}.dir/std.compat.ifc" CACHE INTERNAL "std.compat.ifc compiler parameter")
target_sources(${PROJECT_NAME}
PUBLIC
FILE_SET cxx_modules TYPE CXX_MODULES BASE_DIRS ${PROJECT_BINARY_DIR}
FILES ${PROJECT_BINARY_DIR}/std.ixx ${PROJECT_BINARY_DIR}/std.compat.ixx
)
target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR})
myproject/CMakeLists.txt
cmake_minimum_required(VERSION 3.26)
project(myproject)
add_library(${PROJECT_NAME} STATIC)
target_sources(${PROJECT_NAME} ...)
target_compile_options(${PROJECT_NAME} PUBLIC ${STD_REFERENCE})
target_link_libraries(${PROJECT_NAME} PUBLIC std)
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23)
As per the Changelog, Standard Library Module std is available in VS 2022 17.5 Preview 1. Is there something special that needs to be done as it doesn't seem to be working out of the box. I'm getting the following compile error when importing std:
error C2230: could not find module 'std'
with /experimental:module The "V143 modules (experimental)" individual feature is installed as well. Importing the legacy std.core module works without any errors though.I got it working by creating a new C++ static library project, then I added the std.ixx module file from the modules folder: C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.35.32019\modules $(VCToolsInstallDir)modules\std.ixx and then I referenced this new project.
Is there another way?