conan-io / docs

conan.io reStructuredText documentation
http://docs.conan.io
MIT License
110 stars 361 forks source link

[question] How to correctly setup comaptibility() for msvc compiler #3840

Open ibrawada opened 2 months ago

ibrawada commented 2 months ago

What is your question?

Hello,

I am using Conan v1.62.0 on Windows 10 I have an upstream mylibrary that i compile for following configuration: shared=true with msvc v193 compiler (in VS2022). I have a downstream application that links against mylibrary. The application must be built with msvc v190 (also in VS2022). I have tried to link everything manually and it compiled and worked.

Inside the upstream mylibrary i have following compatibility function:

def compatibility(self):
    if self.settings.compiler == "msvc":
        return [{"settings": [("compiler.version", v)]}
                for v in ("190", "191", "192")]    

running conan install give me following error:

Configuration:
[settings]
arch=x86_64
build_type=Debug
compiler=msvc
compiler.cppstd=14
compiler.runtime_type=Debug
compiler.version=190
os=Windows
[options]
[build_requires]
[env]
[conf]
tools.microsoft.msbuild:vs_version=17

mylibrary/0.1.0: Compatible package ID 88ae9566af1a1f2192bd6d37261db5b8ec0258f8 equal to the default package ID
conanfile.py: Installing package
Requirements
    mylibrary/0.1.0 from local cache - Cache
Packages
    mylibrary/0.1.0:88ae9566af1a1f2192bd6d37261db5b8ec0258f8 - Missing

Installing (downloading, building) binaries...
ERROR: Missing binary: mylibrary/0.1.0:88ae9566af1a1f2192bd6d37261db5b8ec0258f8

mylibrary/0.1.0: WARN: Can't find a 'mylibrary/0.1.0' package for the specified settings, options and dependencies:
- Settings: arch=x86_64, build_type=Debug, compiler=msvc, compiler.cppstd=14, compiler.runtime=dynamic, compiler.runtime_type=Debug, compiler.version=190, os=Windows
- Options: shared=True
- Dependencies:
- Requirements:
- Package ID: 88ae9566af1a1f2192bd6d37261db5b8ec0258f8

ERROR: Missing prebuilt package for 'mylibrary/0.1.0'
Use 'conan search mylibrary/0.1.0@ --table=table.html -r=remote' and open the table.html file to see available packages
Or try to build locally from sources with '--build=mylibrary'

It seems that Conan recognizes that msvc v193 package is compatible but for some reason still doesn't want to use it. Any idea how to rewrite compatibility() in order to tell Conan that package built in v193 is compatible for app built with v190?

Thanks

Have you read the CONTRIBUTING guide?

memsharded commented 2 months ago

Hi @ibrawada

Thanks for your question.

The compatibility() defines a fallback configuration for the current package.

That means, that in your case you have compiler.version=190 in your profile. Conan will try to find a binary built with it, and if it fails, it will go a look for a binary built with 191 first then look for a binary built with 192 (it will skip the 190, because it had already checked it). But you built your binary with 193 but you are not defining the compatibility to be able to fall back to 193. So you need to add it:

def compatibility(self):
    if self.settings.compiler == "msvc":
        return [{"settings": [("compiler.version", v)]}
                for v in ("190", "191", "192", "193")]  

Please try that and let us know.

ibrawada commented 2 months ago

Hello @memsharded Thanks for the explanation. It makes much more sense now. May i suggest that the documentation get your explanation above instead of what is currently written. It would be better to understand it if the explanation is showing the consumers perspective.

I have also around with the method and had following findings. The output of the function has the following format:

[
    {'settings': [('compiler.version', '190')]},
    {'settings': [('compiler.version', '191')]}, 
    {'settings': [('compiler.version', '192')]}, 
    {'settings': [('compiler.version', '193')]}
]

Different from what is expected according to this documentation. Something like the following:

[
    {
        'settings': [('compiler.version', '190'), ('compiler.version', '191'), ('compiler.version', '192'), ('compiler.version', '193')]
    }
]

Both of the formats work.

What doesn't work for some reason is compatibility for build_type

def compatibility(self):
    return [{"settings": [("build_type", v) for v in ("Release", "Debug")]}]

outputs:

[
    {'settings': [('build_type', 'Release'), ('build_type', 'Debug')]}
]

Conan doesn't identify the package as compatible at all

If i rewrite the compatibility method to

def compatibility(self):
    return [{"settings": [("build_type", v)]} for v in ("Release", "Debug")]

outputs:

[
    {'settings': [('build_type', 'Release')]}, 
    {'settings': [('build_type', 'Debug')]}
]
mylibrary/0.1.0: Compatible package ID e1116f03e16ee904707b5ae9ade03ef90d200128 equal to the default package ID

Conan identifies the package as compatible but still cannot use the built Debug package for the Release consumer.

If i try the compatibility() with "Visual Studio" compiler, then Conan doesn't identify the package as compatible at all

    def compatibility(self):
        return [{"settings": [("compiler.toolset", v)]}  for v in ("v140", "v141", "v142", "v143")]

outputs:

[
    {'settings': [('compiler.toolset', 'v140')]}, 
    {'settings': [('compiler.toolset', 'v141')]}, 
    {'settings': [('compiler.toolset', 'v142')]}, 
    {'settings': [('compiler.toolset', 'v143')]}
]

Sorry for the long analysis, but im getting quite confused here.

memsharded commented 2 months ago

Different from what is expected according to this documentation. Something like the following:

The documentation is kind of correct, but a bit poorly explained. They aim to be different settings, not the same setting with different values. I agree that adding some more explicit example might help.

That means the correct way is the second one:

def compatibility(self):
    return [{"settings": [("build_type", v)]} for v in ("Release", "Debug")]

Put it other way: The compatibility() returns a list of potential compatible variants, each element of the list represents 1 package_id variant, and it will define the changes in settings and options for that variant. It doesn't make sense that the seme element in the list contains 2 values for the same setting, like build_type.

Conan identifies the package as compatible but still cannot use the built Debug package for the Release consumer.

Yes, this is generally expected in Windows, there is no binary compatibility between Debug and Release artifacts, so the above is not true and cannot be used, it will be incorrect telling they are compatible if they are not.

Please let me know if this clarifies the issue.

ibrawada commented 2 months ago

Thanks for even more explanation it makes now perfect sense. Your explanation should definitely go into the offcial documentation. Regarding mixing Release and Debug libs on Windows. It might be considered a bad practice but it works. We constantly use 3rd party libs in Release while building own applications in Debug.

Thanks again, I will close this issue tomorrow

memsharded commented 2 months ago

Regarding mixing Release and Debug libs on Windows. It might be considered a bad practice but it works. We constantly use 3rd party libs in Release while building own applications in Debug.

It might depend also on the artifacts types (shared libs, static libs), the language (C or C++), and the VS runtime linkage. In many situations the VS compiler will directly refuse to link. If you have a setup that you can do it, it sounds more like the exception than the general case. So it is not only that is "bad practice", is that it will directly not work in many cases.

Thanks again, I will close this issue tomorrow

Do not close the ticket please, I will transfer it to the "docs" repo to try to do some improvements there in the docs.

Thanks very much for the feedback!