Ty Deuty
Ty Deuty

Reputation: 137

How can I use Conan to both provide dependencies for the Visual Studio IDE and create a package of the same project, again using Conan dependencies?

In the documentation for Conan, I found this page: https://docs.conan.io/en/latest/howtos/visual_studio_packages.html

This page steps through 2 examples, one is using Conan to generate a .props file to point the Visual Studio IDE to dependencies for your project, and the other is creating a package of a Visual Studio solution/project(s) that has dependencies using Conan. Both of these work for me separately, however combining them to both be able to use VS IDE with Conan dependencies and package the VS solution fails for the following reason:

When using Conan (or the Conan extension for VS) to handle dependencies while using the IDE, the visual studio project files (.vcxproj) are modified to include and import call to the Conan-generated .props files. The project files are source-controlled through Git. Then when calling conan create on the same conanfile.py, my source method clones down the repo at the specified tag. This will include project files that are told to import the Conan-generated build files, and then the build method in conanfile.py will "inject" its own .props file to serve the same purpose. I see two issues here:

  1. The build fails because the project files fail to load, because I do not commit the Conan-generated .props files to the repo. Those are considered temporary build files. (You can change my mind here but please look at #2)
  2. Even if I commit the Conan-generated props to the repo, and then they will be cloned down and allow msbuild to load the project files, then the Conan msbuild helper is trying to load its own dependencies, and that will cause to doubly-defined symbols and other issues.

Is there some way to have the MSBuild helper (in the build() method of the conanfile.py) use the same .props that would be generated by the conan install command instead of its own when using a command line arg to msbuild as part of the conan create command? Or a better solution than that?

I tried to be as clear as possible but please let me know if I can clarify the issue further. Any help is appreciated.

Below is an example conanfile.py trying to accomplish this:

from conans import ConanFile, MSBuild, tools
from conans.tools import load, save
import re, os

class TestConan(ConanFile):
    name = "test"
    version = "1.1.2"
    settings = "os", "compiler", "build_type", "arch"
    generators = "visual_studio_multi", "visual_studio"
    requires = "snappy/1.1.8", "boost/1.73.0", "rapidjson/1.1.0"
    options = {"shared": [True, False]}
    default_options = {"shared": True, "boost:shared" : "True", "snappy:shared" : "True"}

    def source(self):
        git = tools.Git(folder=self.name)
        git.clone("http://path/to/test/repo/testrepo.git", branch="1.1.2")

    def build(self):
        msbuild = MSBuild(self)
        msbuild.build("testrepo/testrepo.sln", platforms={"x86":"Win32"}, upgrade_project=False)

    def package(self):
        self.copy("*.h", dst="include/testrepo", src="testrepo")
        self.copy("*.hpp", dst="include/testrepo", src="testrepo")
        self.copy("*.lib", dst="lib", keep_path=False)
        self.copy("*.dll", dst="bin", keep_path=False)

    def package_info(self):
        self.cpp_info.libs = ["test"]
        self.cpp_info.includedirs = ["include"]
        self.cpp_info.bindires = ["bin"]
        self.cpp_info.libdirs = ["lib"]

EDIT: Potential Workaround

The Visual Studio Project files allow you to conditionally import projects. I adjusted them to only import if the Conan property sheets were found. This made it so that when creating the package using the conanfile.py above, the cloned repo would correctly load for msbuild and then Conan could inject the dependencies accordingly. The Conan extension for Visual Studio doesn't override the conditions so you can still run conan install and use the IDE for development, then clean the temporary build files (prop sheets) and commit. In my case I just added the .conan folder the extension creates to .gitignore.

Example code for the workaround:

  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <Import Project=".conan\conanbuildinfo.props" Condition="exists('.conan\conanbuildinfo.props')" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <Import Project=".conan\conanbuildinfo.props" Condition="exists('.conan\conanbuildinfo.props')" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <Import Project=".conan\conanbuildinfo.props" Condition="exists('.conan\conanbuildinfo.props')" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <Import Project=".conan\conanbuildinfo.props" Condition="exists('.conan\conanbuildinfo.props')" />
  </ImportGroup>

Warning: I am not a project file xml expert, there might be a better way to accomplish the same as above, but this worked for me.

This is a workaround. What I have found is the examples in the Conan how-tos docs I have at the beginning of this post use "exports_sources" for obtaining their source. It seems that Conan correctly handles this case, but not the case where you instead obtain your source (using the source() method) from SCM, in my case git cloning a specific tag. I tested this with my project repo but for our development flow we prefer the ability to package a tagged git commit.

Upvotes: 1

Views: 3764

Answers (1)

Sully7
Sully7

Reputation: 13

Take a look at the new "msbuild" generator. I found that it fixes a lot of the issues I was having with this, because it changes the architecture a bit.

At the top-level, it creates a conan_deps.props file (that could(?) be committed to the repo.

From there, when you perform a conan install, it creates one "top-level" .props file per dependency, with individual .props files below it for each of the configurations.

I've found that this has worked much better for me, as it gave me much more flexibility in my dev environment as well.

The only problem I'm having now is that the VS Extension hasn't 'officially' been updated to support it yet... but I've been getting around that by simply using the embedded Developer Command Prompt for now :)

EDIT (11/4/2020): I actually opened a Github issue in the VS Extension Repository, and the devs got back super quickly! Looks like they are waiting for things to stabilize a bit before making changes to the extension.

Upvotes: 1

Related Questions