Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect handling of MSVC versions #3573

Closed
DoDoENT opened this issue Sep 19, 2018 · 52 comments · Fixed by #8201
Closed

Incorrect handling of MSVC versions #3573

DoDoENT opened this issue Sep 19, 2018 · 52 comments · Fixed by #8201

Comments

@DoDoENT
Copy link
Contributor

DoDoENT commented Sep 19, 2018

I am using Conan v1.7.4.

I've created a static library Conan package using VS 2017 15.7 and updated my Visual Studio to 15.8. After the update, Conan failed to detect a change in the compiler version and did not perform recompilation of the static library. Instead, it just downloaded the same package that was built with VS 2017 15.7. However, when linking to that package from VS 2017 15.8, I am getting following linker error:

LINK : fatal error C1047: The object or library file 'C:\Users\dodo\.conan\data\LogAndTimer\1.0.1\microblink\stable\package\8b2772668ccbf879d34a70a9d54c78ce70f38a1b\lib\LogAndTimer.lib' was created with an older compiler than other objects; rebuild old objects and libraries
2>LINK : fatal error LNK1257: code generation failed

However, the debug build does work (details how to reproduce are below).

I think the problem is in how Conan handles MSVC versions - instead of using the actual compiler version (CMake detects MSVC 19.14.26431.0 in VS 2017 15.7 and MSVC 19.15.26729.0 in VS 2017 15.8), it uses the version of Visual Studio (VS 2017 is compiler version 15, according to Conan).

I suggest that Conan should use the MSVC compiler version under compiler.version setting and additionally have compiler.vs_version for Visual Studio version. The reason for that is that sometimes libraries built with one version of MSVC are not compatible with later versions of MSVC, especially if you use link time code generation flag (/LTCG link flag and /GL compile flag).

How to reproduce

  • Install Visual Studio 2017, but not the latest update (at the time of writing, this is 15.8.4). For example, use VS 2017 15.7.x or 15.6.x.
  • Create a conan package that contains a single static library. Make sure that Release build type of that package is compiled with /GL compile flag.
  • Create an application that consumes that static library and make sure it works in Release build type (the app should be linked with /LTCG linker flag).
  • Update Visual Studio 2017 to the latest version (15.8.4 at the time of writing).
  • Build your application

Expected behaviour

  • conan install after updating the VS should calculate different hash for the library and should rebuild it, thus making sure application linking will succeed

Actual behaviour

  • Conan does not detect version change in the MSVC compiler and uses the incompatible binary, thus causing linker error described above.

Now, the main question is - could this be fixed without breaking existing conan VS packages, or we need to wait for Conan 2.0 (and disable LTCG until this issue gets fixed).

Also, as a side question, is there a possibility to configure Conan to trigger rebuild of libraries even when a minor/bugfix version of the compiler changes, regardless of the compiler being used (e.g. if we update GCC from 8.1.0 to 8.1.1, we would like to rebuild all our binaries, even though they are link-compatible). This would get us the benefits of always having binaries built with the latest compiler to get the latest bugfixes and performance improvements - this benefit is also mentioned in conan documentation:

What happens if we have a library that we can be built with GCC 4.8 and will preserve the ABI compatibility with GCC 4.9? (This kind of compatibility is easier to achieve for example for pure C libraries).

Although it could be argued that it is worth rebuilding with 4.9 too -to get fixes and performance improvements-. Let’s suppose that we don’t want to create 2 different binaries, but just a single built with GCC 4.8 which also needs to be compatible for GCC 4.9 installations.

@DoDoENT
Copy link
Contributor Author

DoDoENT commented Sep 24, 2018

@memsharded, any hints on how this can be worked around?

@lasote
Copy link
Contributor

lasote commented Sep 24, 2018

Normally the base settings.yml file is designed as a minimum for the community and so far the visual studio segmentation by 14, 15 worked well.

If you need a more accurate model you could:

A) Introduce a subsetting. If the subsetting has a "None" value as a possible value it won't be required, and all the current conan center packages will be compatible. If you give a value to the subsetting, you will be generating a new package_id.

B) Change the list of versions including the minor (15.8) but keeping the "15" value. So the old packages will still be "usable" if a user specifies just "15" but you can generate more accurate binaries for the users specifying "15.8". But probably we would need to check the conan code to search all the Visual Studio version setting comparison to ensure "15.8" is processed correctly, the CMake checks etc.

I think the correct is the B) and might be the way to go, even if by default Conan detects "15" instead of "15.8".

BUT, of course, this is something the community can give feedback, I see many upvotes. Are they friends/colleagues of you? or is the whole community really demanding a better approach? ;)

@memsharded feedback is needed here too.

@DoDoENT
Copy link
Contributor Author

DoDoENT commented Sep 24, 2018

Hi @lasote, thank you for the tip. I'll try that and see if it works for me.

However, in general, I think the approach of using VS version as MSVC version is fundamentally wrong. You can use VS with any compiler, MSVC being only one of the possibilities. Currently, this can be distinguished using toolsets, but this still lacks another configuration dimension, as a specific toolset can have their own versions. This is currently worked around by having "different" toolsets, such as v140 (indicating MSVC from VS 2015 used within VS 2017), v120, etc. However, this is not very practical, as you can have lots of toolsets with different compilers and compiler versions.

Therefore, I think it would be a better approach for Conan to treat MSVC in the same way as it treats GCC and Clang - as the compiler, not as the IDE. Its subsettings would be version and runtime and possibly other things that are specific to the MSVC compiler, not to the VS IDE. Such an approach would also cover combinations where MSVC is used in non-MSBuild build systems. For example, if you use VS 2017's feature open folder to open a folder containing CMakeLists.txt file, it will generate a build directory with MSVC and Ninja build system. Besides that, Conan also uses the same philosophy for Apple Clang, which it treats as a separate compiler, not as the "Xcode IDE" (which can use a non-clang compiler, just as VS can use non-MSVC compilers).

I think the correct is the B) and might be the way to go, even if by default Conan detects "15" instead of "15.8".

Although this may work (I still need to check that), what would then mean to have version "15.8" and toolset "vs140_xp"? Would that be different from version "15.7" and same toolset? It shouldn't be, but Conan would calculate different package ID for that combination.

... and so far the visual studio segmentation by 14, 15 worked well.

This segmentation works well until you enable the link time code generation (link time optimization). I guess that industry that uses that feature of the compiler/linker still hasn't made the transition to C++ package managers (I still need to check how vcpkg works with that) and that open source projects and teams that are using Conan either do not target Windows as their main platform or is not aware of the /LTCG optimization, so they still haven't stumbled upon that issue.

Also, I am not entirely sure that current visual studio segmentation works well in cases when you change the version of the Visual Studio (for example from VS 2015 to VS 2017), but keep using the same toolset (e.g. vs_140) - will Conan calculate new package ID in that case? It shouldn't because the compilers used for creating the binaries have not changed - only the code editor has.

I would really like to see what other people think about that, especially all those who gave a thumbs up.

Maybe for Conan v2.0 (breaking release), it would make sense for Conan to treat MSVC as the compiler, not as the IDE (i.e. as "Visual Studio").

@memsharded
Copy link
Member

Yes, we could revise this for 2.0. However, one thing is that it could be changed, and the other is the massive impact that it could have on existing packages in bintray.

In any case, maybe by conan 2.0, Msft has estabilized a bit and we have better idea of their plans regarding compiler minor updates too.

@memsharded memsharded added this to the 2.0 milestone Sep 24, 2018
@memsharded
Copy link
Member

Actually.... this could and probably should be discussed earlier. If anything, it could make sense to introduce a new compiler in the setting, to replace the old one, but without replacing. Conan 2.0 would deprecate the previous one (without removing), maybe Conan 3.0 could remove the old one. Lets discuss.

@memsharded memsharded modified the milestones: 2.0, 1.9 Sep 24, 2018
@psiha
Copy link

psiha commented Sep 24, 2018

In any case, maybe by conan 2.0, Msft has estabilized a bit and we have better idea of their plans regarding compiler minor updates too.

There really is nothing to stabilize here - Visual Studio and the Visual C++ (AKA MSVC) have always been separate products (one is an IDE and the other a compiler - e.g. you can get the compiler w/o the IDE through the Windows SDK) and their separate versioning schemas used currently have been in place for quite some time - it is just plain wrong to 'guess' or 'tie' the version of the compiler to the version of the IDE (not just because, as DoDoENT already pointed out, you can have multiple toolchains and compiler versions 'within' one IDE version).
IOW&IMNHO there should be no question of whether this needs to be fixed ... only when and how...

With that said, given that it is already creating problems or even showstoppers for MSVC users, it would be nice if you could come up with some kind of a workaround until it gets 'officially fixed'...

@DoDoENT
Copy link
Contributor Author

DoDoENT commented Sep 24, 2018

If anything, it could make sense to introduce a new compiler in the setting, to replace the old one, but without replacing.

I like the idea - introduce new compiler msvc in Conan 1.9.x, but keep Visual Studio a default choice for Windows with the same behaviour as current. The msvc would behave in the same way as gcc and clang. Then, in v2.0 switch the windows default from Visual Studio to msvc, but keep Visual Studio as a legacy option. Finally, remove Visual Studio in Conan v3.0 and keep it only as the generator, not as the "compiler".

I think this should be accompanied by appropriate updates in cmake-conan project, but I think this should not be difficult (such a change is even within my capabilities :P )

The introduction of msvc in v1.9.0 would enable those that have the same problem as we do to circumvent them almost immediately, without waiting for breaking change - although using prebuilt packages from bintray would require some additional code in consumer's conanfiles** (let's discuss that as well - I think that would also require some backwards-compatible additions to conanfiles).

Then, with v2.0 users that were already using msvc instead of Visual Studio compiler would not have a breaking change and v2.x series would give a plenty of time to everyone to switch their packages to msvc compiler. In v3.0 Visual Studio could be removed just to reduce the code bloat, if necessary. If not, it can remain eternally for backwards compatibility if Conan adopts policies in the way similar to how CMake does***).

** Here I generally think of a way for the consumer to "override" the calculation of the package ID of the package being consumed. The idea here is for the consumer to be able to "tell" Conan that if it uses, e.g. compiler msvc 19.15 that it can safely consume a specific package built for Visual Studio 15 (something like how you tell the versioning schema) - to avoid rebuilding the package for compiler the author of the package didn't anticipate. This is especially useful for binary-only packages built with earlier versions of Conan.

*** I think policies are a good way to keep backward compatibility while providing new features. Yes, it causes bloatware, but I think it is essential for package management software to be as backwards-compatible as possible. Also, as I already mentioned, a recipe should be able to specify the minimum required version of Conan for a recipe to be parsed. This would enable much easier development of packages that support wide range of Conan versions.

@sigiesec
Copy link
Contributor

To my knowledge, MSVC relies much more on LTCG (and PGO) to generate optimal code than other compilers (in particular gcc and clang) do, even though they also provide comparable features. But as @DoDoENT said, maybe not everyone is aware of that. I have found build files of many open source libraries that were not enabled for LTCG.

MS never guaranteed binary compatibility for .lib files between different toolset versions, but in many cases it worked anyway (or at least it did not obviously not work). However, before Visual Studio 2017 there haven't been multiple toolset versions for the same major Visual Studio version, or at least they did not exhibit such obvious incompatibilities.

Also, not all users of Visual Studio will have already migrated to Visual Studio 2017. This is also true for us. We have prepared new versions of several components that are built with the VS2017 toolsets already, and during development we already stumbled upon this problem where a mismatch between the toolset used on the CI and locally caused problems. But the products using these components still use VS2015 as of now. I am somewhat scared of what will happen when they start to use VS2017, and get compilation failures because of mismatches in the toolset versions.

Just for information, I am not a coworker of @DoDoENT (since @lasote was asking).

@lasote
Copy link
Contributor

lasote commented Sep 25, 2018

Hi all! Thanks for the feedback.
About the compatibility between the old Visual Studio setting and the new one, it is not that easy, we would need to think about it carefully but it is not going to be solved in the firsts versions.
By the way, it cannot be in 1.8, it is already packaged and struggling to release it, so anyway this will wait for 1.9. Sorry.

@DaniCybereason
Copy link

any workarounds meanwhile? I run and it doesn't detect VS 2017 at all after the latest 15.8.7 update..

@lasote
Copy link
Contributor

lasote commented Oct 17, 2018

@DaniCybereason it seems that it is a different issue. Could you please open a new one specifying the conan version you are using?

@claasd
Copy link
Contributor

claasd commented Oct 17, 2018

How about introducing a new compiler in conan 1.9, maybe called MSVC.
This could have the version 19.14, 19.15 and so on.

  • This would not break the current "Visual Studio" compiler.
  • It could be introduced as "experimental" for conan 1.9
  • The "Visual Studio" compiler could be deprecated for 2.0

@sigiesec
Copy link
Contributor

@claasd I think you are suggesting the same as @DoDoENT already did above (#3573 (comment))

@claasd
Copy link
Contributor

claasd commented Oct 18, 2018

@sigiesec True, i did not read carefully enough.

@lasote lasote modified the milestones: 1.9, 1.10 Oct 29, 2018
@lasote
Copy link
Contributor

lasote commented Oct 29, 2018

Hi all, I really would like to start with this because I agree it is something to fix and better to try it as you suggested before Conan 2.0 but we hadn't time enough this release either. :(

@claasd
Copy link
Contributor

claasd commented Oct 29, 2018

Hi,
we discussed this internally, and found out that CMake adressed this issue in CMake 2.13:
Some links:
https://cmake.org/cmake/help/latest/variable/CMAKE_VS_PLATFORM_TOOLSET_VERSION.html
https://gitlab.kitware.com/cmake/cmake/merge_requests/2093
https://gitlab.kitware.com/cmake/cmake/issues/17549
https://blogs.msdn.microsoft.com/vcblog/2017/11/15/side-by-side-minor-version-msvc-toolsets-in-visual-studio-2017/

So, with CMake supporting this (soon) as minor version of Visual Studio Compiler (beginning at 2017), I would suggest enhancing the current Visual Studio compiler with a minor_version subparam, that is only used for vs2017.

When installing VS2017 SideBySide, it will install multiple vcvars.bat, one for each installed compiler. This way, the minor version could also be implemented for the MsBuild Helper.

Of course, conan needs to check if the cmake-version supports this, if the vcvars are available and so on, but I think it is a better soulution that to introduce a fully new compiler.

@DoDoENT
Copy link
Contributor Author

DoDoENT commented Oct 29, 2018

@claasd, I disagree with you. Your proposal is tightly coupled with specific cmake version and msbuild build system.

What about other generators (vs, autotools, custom tools)? Also, how would your proposal work with MSVC+Ninja combination, as used by visual studio code and visual studio's "open folder" feature?

Isn't it much simpler to simply introduce msvc as the new compiler to Conan and eventually stop treating a specific code editor (VS) as compiler?

@memsharded memsharded modified the milestones: 2.0, 1.33 Nov 18, 2020
@puetzk
Copy link

puetzk commented Nov 30, 2020

as there will be a guarantee that each MSVC compiler version will have its own toolset, i.e. that there will be no MSVC compiler updates (at least incompatible ones, in terms of LTO) without changing the toolset version

This is not the case: e.g. the v141 toolset encompasses all VS2017 versions, the v142 all VS2019 versions, and yet there are LTO-incompatible changes the minor versions (in a semver-conforming way; the newer linker can read old libraries, but not vice-versa)

https://devblogs.microsoft.com/cppblog/side-by-side-minor-version-msvc-toolsets-in-visual-studio-2019/

@DoDoENT
Copy link
Contributor Author

DoDoENT commented Nov 30, 2020

@puetzk, if you refer to VS 16.7.0 vs 16.7.1 and so on - they are LTO link compatible - I've tested that.

There are incompatible changes between minor versions of v142 toolsets, as it always select the latest compiler from the v142 toolset branch. But you can select the exact compiler version with vcvarsall.bat. For example:

vcvarsall.bat amd64 -vcvars_ver=14.25

will select the MSVC 19.25 for current shell (to be used with ninja/make etc.), even if you have updated your VS up to 16.8 (you just need to install 14.25 build tools using VS installer tool). However, AFAIK, it's not possible to select that same compiler using VS project sheet in MSBuild project.

@memsharded
Copy link
Member

I am proposing some preliminary investigation in #8201. Some ideas:

  • Using the major toolset version "140", "141", "142" as the version, but adding a MSC_VER 19XX as an optional sub-setting for each one, for those that wan to manage different binaries (LTO) for minor MSC_VER values.

  • Changing MT, MTd, MDd, MD for "static", "dynamic" for the runtime, to avoid incompatible combinations with build_type.

@DoDoENT
Copy link
Contributor Author

DoDoENT commented Dec 14, 2020

Changing MT, MTd, MDd, MD for "static", "dynamic" for the runtime, to avoid incompatible combinations with build_type.

Actually, we are building our windows dev packages in release mode, but with MDd runtime. This enables both optimizations of the binary and the debug runtime (iterator checks and other). This is what we put in a "Debug" version of our windows conan package.

Although I completely agree with your statement for the general conan default, please don't prevent advanced users to still use the "unnatural combinations" as described above 😛

Using the major toolset version "140", "141", "142" as the version, but adding a MSC_VER 19XX as an optional sub-setting for each one, for those that want to manage different binaries (LTO) for minor MSC_VER values.

Seems completely reasonable.

@memsharded
Copy link
Member

Actually, we are building our windows dev packages in release mode, but with MDd runtime. This enables both optimizations of the binary and the debug runtime (iterator checks and other). This is what we put in a "Debug" version of our windows conan package.

Ok, this is very useful information. Some other users were reporting that they were totally incompatible, check #7019

@memsharded
Copy link
Member

Actually, we are building our windows dev packages in release mode, but with MDd runtime. This enables both optimizations of the binary and the debug runtime (iterator checks and other). This is what we put in a "Debug" version of our windows conan package.

@DoDoENT Can you please clarify, the "Debug" thing?. You say it is "windows dev packages in release mode", but then you say that you put it in the "Debug" version.

@SSE4
Copy link
Contributor

SSE4 commented Dec 14, 2020

Using the major toolset version "140", "141", "142" as the version, but adding a MSC_VER 19XX as an optional sub-setting for each one, for those that want to manage different binaries (LTO) for minor MSC_VER values.

is there any reason to complicate versioning so much? I mean getting one part of setting from the one place (toolset), and the second part of setting from the another (_MSC_VER but only two digits).

why not just use the compiler version like for all other compilers and be consistent?

also, this is a kinda time bomb, as soon as _MSC_VER runs out to 20XX or 21XX (it may happen eventually, and earlier than we can expect).

@DoDoENT
Copy link
Contributor Author

DoDoENT commented Dec 14, 2020

@DoDoENT Can you please clarify, the "Debug" thing?. You say it is "windows dev packages in release mode", but then you say that you put it in the "Debug" version.

This is what conan thinks to be the debug, although it's actually built with optimizations.

So, if you issue this command for our internal package: conan create ./conanfile.py user/testing -pr msvc-19.27 -s compiler.runtime=MDd -s build_type=Debug, the cmake invoked by our recipe's build method is will actually build the binary in release mode, but with debug runtime - we call this "dev-release" internally, but it's similar to CMake's RelWithDebugInfo, except that besides Debug Info it also contains debug runtime checks. This gives us both debugability and performance and our CI only has to build two types of packages: Release (i.e. what Conan sees as "the release" and is built in release mode with full optimizations and LTO, disabled asserts and with release runtime library (MD)) and "Debug" (i.e. what conan sees as "the debug", but is actually built with full optimizations without LTO, enabled asserts and with debug runtime library (MDd)).

And yes, we know that conan supports the "RelWithDebugInfo" build type, but as I said, our "DevRelease" build type is something in between "RelWithDebugInfo" and "Debug".

Some other users were reporting that they were totally incompatible, check #7019

MD and MDd are just two different c++ runtime libraries - both dynamic, i.e. provided as DLLs (unlike MT and MTd, which are static, provided as .lib file and end-up in your app's binary). By default VS links your app to MDd when building in debug mode and to MD when building in release mode, but nothing prevents you to enable compiler optimizations and then link to MDd or vice versa. It's just important not to mix binaries built with MD and binaries built with MDd in the same app - this will result with linker error (some symbols will be duplicated, some will be missing).

The difference between MD and MDd is similar to libc++ vs libstdc++ in the Linux world - they both provide the C++ runtime, but have different implementations and cannot be mixed together in the same app. The difference is that libc++ and libstdc++ are both optimized versions implemented by different teams, while MD and MDd are just different builds of the same runtime, but ABI-incompatible (MDd STL containers contain additional fields to aid debugging).

is there any reason to complicate versioning so much? I mean getting one part of setting from the one place (toolset), and the second part of setting from the another (_MSC_VER but only two digits).

I guess it's due to the compatibility with current packages in conan-center that are not aware of the MSVC versions.

why not just use the compiler version like for all other compilers and be consistent?

I actually want that too. It's more clean and elegant.

@Croydon
Copy link
Contributor

Croydon commented Dec 14, 2020

why not just use the compiler version like for all other compilers and be consistent?

I agree. MSVC presents itself with such a version number and CMake does too

> cl
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29335 for x86
-- Selecting Windows SDK version 10.0.18362.0 to target Windows 10.0.19042.
-- The C compiler identification is MSVC 19.28.29335.0
-- The CXX compiler identification is MSVC 19.28.29335.0

Though, CMake adds another .0 to it for some reason.

@memsharded
Copy link
Member

Can you please clarify (@SSE4 , @DoDoENT , @Croydon ) with an example the actual settings.yml that you would use?. Here is the rational that I am using:

  • I am proposing the 140, 141, 142, as they are aligned with the default binary compatibility model: binaries are compatible by default by the toolset version, not the full compiler version.
  • Then, for users that want finer control of the binaries, they can use the mscver.
  • It is not possible (maybe it is, but seems challenging), to have more than 1 mscver installed at the same time in one machine. So this is not actionable at all, it is just information about the version, but nothing that Conan can use to select one or other.

Maybe you mean just to change the names and use 140 => 19.0, 141 => 19.1, 142 => 19.2? And then leave the rest as a subsetting? If that is the case, yes, totally good for me.

@SSE4
Copy link
Contributor

SSE4 commented Dec 14, 2020

Can you please clarify (@SSE4 , @DoDoENT , @Croydon ) with an example the actual settings.yml that you would use?

    msvc: &msvc
        runtime: [MD, MT, MTd, MDd]
        version: ["14.00", "15.00", ...<many versions>, "19.26", "19.27", "19.28"]

the rational:

  • the setting is named compiler.version, so I would expect compiler version here (not an IDE version and not a toolset version), reported as is (e.g. from cl --version or _MSC_VER)
  • this aligns perfectly with clang and GCC versioning
  • this also aligns perfectly with apple-clang, where we never use IDE (Xcode) version, but the only compiler version
  • we already do partial binary compatibility for GCC and Clang (e.g. use major-only for some releases, major-minor for others)

otherwise, if you still want to use the toolset version, you'd better change the setting name to the toolset.version, to avoid the source of confusion for users.

I am proposing the 140, 141, 142, as they are aligned with the default binary compatibility model: binaries are compatible by default by the toolset version, not the full compiler version.

I am not sure it's the default compatibility mode for MSVC, given the comment from STL. see also:

It is not possible (maybe it is, but seems challenging), to have more than 1 mscver installed at the same time in one machine.

it is actually very possible. I have all of the versions installed in parallel, starting from 2005 to 2019. plus, there are compilers installed as part of Windows SDK and other Microsoft SDKs.

@jgsogo
Copy link
Contributor

jgsogo commented Dec 14, 2020

Just pointing that toolsets are more like v14.00, v14.10, v14.11, v14.12, v14.20, v14.21 than v141, v142. Now you can have all of them side by side, although the IDE lets you select only one for the same minor or you need to modify props files: https://devblogs.microsoft.com/cppblog/side-by-side-minor-version-msvc-toolsets-in-visual-studio-2019/ and then you have all the numbers required to match a specific MSVC compiler.version as @SSE4 proposes.

From my experience, I was more used to toolset versions that to MSVC compiler version (IDE Visual Studio)... although it is true that the macro you get in sources is the compiler and not the toolset.

@DoDoENT
Copy link
Contributor Author

DoDoENT commented Dec 14, 2020

Can you please clarify with an example the actual settings.yml that you would use?

I've actually described the settings.yml I use in this comment above.

I am proposing the 140, 141, 142, as they are aligned with the default binary compatibility model: binaries are compatible by default by the toolset version, not the full compiler version.

This seems reasonable for the default VS settings, where LTO is disabled. However, this is then not the msvc compiler - it's visual studio toolset - that should be different from msvc compiler.

Then, for users that want finer control of the binaries, they can use the mscver.

Here is where I would actually treat that as the separate compiler, for simplicity, not as the mscver subsetting. If you choose to use msvc compiler instead of visual studio toolset then you should probably have different binaries. Yes, sometimes they might match, but this is similar to how some GCC vs Clang binaries are compatible.

It is not possible (maybe it is, but seems challenging), to have more than 1 mscver installed at the same time in one machine. So this is not actionable at all, it is just information about the version, but nothing that Conan can use to select one or other.

Yes, it's possible and we have multiple msvc versions installed on our CI machines. I've even described in the comment linked above how you can force conan to select correct msvc version.

Maybe you mean just to change the names and use 140 => 19.0, 141 => 19.1, 142 => 19.2? And then leave the rest as a subsetting? If that is the case, yes, totally good for me.

For msvc compiler, the versions should definitely be in line with what compiler reports (19.25, 19.26, 19.27, ... ). The 140, 141, ... versions are in line with visual studio toolset and should not be used for msvc compiler.

So, to conclude:

  • the msvc compiler should have versioning in line with reported version of cl.exe and should not be related to version of Visual Studio nor it should require VS installation, imho
  • the visual studio toolset can have the versioning in line with versions of VS toolsets and can be used by people that don't want fine-grained control over msvc versions
  • the binaries produced by msvc and visual studio should in general have different ID and not be treated as compatible, however methods used for icc may be used to ensure compatibility between msvc and visual studio builds of the same package.

If all that seems too complicated (I'd guess most people will get confused by having both msvc and visual studio "compilers"), and if we just want to have only one msvc compiler, then I would definitely vote for the first option (msvc, not visual studio). The versions should then be in sync with versions reported by cl.exe and for general case (when LTO is not needed), the version should be parsed from major number (i.e. 19.1, 19.2, ...) and if someone needs LTO and fine-grained control, they can easily add versions 19.16, 19.17, 19.25, 19.26, ...) to their settings.yml.

This is not without precedent: the default settings.yml, shipped by conan, already has such versioning scheme for GCC: there is version 9, but also versions 9.1, 9.2 and 9.3. Version 9 is OK for general case, but if you use LTO, you need to use 9.1, 9.2 and 9.3.

We use the same trick also for Apple Clang - without LTO all compilers shipped with Xcode 11 produce link-compatible binaries, but if you enable LTO, there are actually two different versions of clang in Xcode 11 series: 11.0.0 and 11.0.3, which are not LTO-link compatible.

So, why not doing the same with MSVC as well?

@memsharded
Copy link
Member

I have updated #8201 to implement:

 msvc:
            version: ["19.0",
                      "19.1", "19.10", "19.11", "19.12", "19.13", "19.14", "19.15", "19.16",
                      "19.2", "19.20", "19.21", "19.22", "19.23", "19.24", "19.25", "19.26", "19.27", "19.28"]
            runtime: [static, dynamic]
            cppstd: [None, 14, 17, 20]

The mapping to default VS versions (to call cmake -G "Generator") is done dropping the latest digit if existing.
This is basically the same approach done for gcc and clang. Auto-detect (when this happens, Conan 2.0) will resolve to 19.1, 19.2, assuming that binary compatibility, and letting users to opt-in into the full versions for LTO and other binary-incompatible issues.

I still need to figure out the runtime and work on the migration plan for package_id compatibility with existing Visual Studio compiler.

@solvingj
Copy link
Contributor

Changing MT, MTd, MDd, MD for "static", "dynamic" for the runtime, to avoid incompatible combinations with build_type.

Actually, we are building our windows dev packages in release mode, but with MDd runtime. This enables both optimizations of the binary and the debug runtime (iterator checks and other). This is what we put in a "Debug" version of our windows conan package.

I don't think we can enforce the combination of runtime and build_type. Tons of companies build .dlls with MT. It works fine for so many people, they don't care that it's not safe or not recommended.

@solvingj
Copy link
Contributor

The version and cppstd look good. I would revert to the previous build_type and runtime. I admit that as a user, it's painful and frustrating to manage and work with the microsoft runtime settings. Sadly, I don't think it's something we can ever abstract away.

@memsharded
Copy link
Member

I am proposing this:

msvc:
            version: ["19.0",
                      "19.1", "19.10", "19.11", "19.12", "19.13", "19.14", "19.15", "19.16",
                      "19.2", "19.20", "19.21", "19.22", "19.23", "19.24", "19.25", "19.26", "19.27", "19.28"]
            runtime: [static, dynamic]
            runtime_type: [Debug, Release]
            cppstd: [None, 14, 17, 20]

The runtime_type will be filled automatically based on build_type, but the user always has the possibility of explicitly defining it. I am testing it for the CMake toolchain, seem to be a good approach so far.

@solvingj
Copy link
Contributor

Ahhhh, ok i think i see it now. This might work.

@memsharded
Copy link
Member

This has been implemented in #8201 and will be released as experimental in 1.33.

It is basic support:

  • It implements only versions 19.0, 19.1, 19.2 (and minors)
  • Each compiler version will map to its reference VS IDE (for calling the CMake generator for example). Toolset specification to change that is not possible yet.
  • It doesn't support compatibility with Intel compiler as "Visual Studio" does.
  • The binary compatibility with Visual Studio compiler is temporary, will be removed in Conan 2.0 (the whole Visual Studio might be removed in Conan 2.0)

More work will follow in next releases, specially the custom mapping to different Visual Studio versions with toolsets.

@DoDoENT
Copy link
Contributor Author

DoDoENT commented Mar 5, 2021

Oops, Microsoft did it again 🤦‍♂️

@SSE4 SSE4 mentioned this issue Aug 30, 2021
5 tasks
@schwaerz
Copy link

schwaerz commented Oct 12, 2021

@memsharded I am not sure whether I got you correct. You are planning to implement support for compiler minor versions in a way that the user will be able to choose which compiler to use during the build?
Actually I am almost 100% sure that this will not solve the issue completely. Actually we mostly will only have one compiler version installed per tool set. I am also not sure whether the installer would even allow me to install all available compiler versions in parallel.
However that still will be an issue for us.
On Jenkins our nodes currently have toolset v142 installed, compiler version 19.25.xxx
Locally I recently installed VS2019 and got compiler version 19.29.xxx for toolset v142.
Still they are not compatible when it comes to using /GL and /LTCG.

Not sure about the others. But what we need is a way to detect the compiler minor version during build time and place it somewhere into the settings or options in order to ensure that one cannot reuse pre-built binaries which are not compatible.

Something similar to my workaround would be highly appreciated for Conan 2.0. Will you think about implementing something like this in Conan natively?

def configure(self)
        if recipe.settings.os == "Windows" and recipe.settings.build_type == "Release":
            vcvars = tools.vcvars_command(recipe)
            output = StringIO()
            recipe.run(f"{vcvars} && cl.exe", output=output)
            regex = re.compile(r'Compiler Version [0-9]*\.(?P<minor>[0-9]*)\.[0-9]*')
            compiler_minor = regex.search(output.getvalue()).group("minor")
            recipe.output.info(f"Found compiler minor version {compiler_minor}. Updating ABI compatibility to ensure -GL / -LTCO builds will work.")
            recipe.options.compiler_minor = compiler_minor

@lasote
Copy link
Contributor

lasote commented Oct 22, 2021

You are planning to implement support for compiler minor versions in a way that the user will be able to choose which compiler to use during the build?

@schwaerz, No, the applied profile should declare which compiler are you using. If the xxx from the 19.29.xxx is a concern for you, you can always add the patch to the listed msvc versions at the settings.yml and distribute the configuration with conan config install.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.