diff --git a/conan/tools/microsoft/msbuilddeps.py b/conan/tools/microsoft/msbuilddeps.py
index 4c3b6a03ee5..d6ca1adb11a 100644
--- a/conan/tools/microsoft/msbuilddeps.py
+++ b/conan/tools/microsoft/msbuilddeps.py
@@ -1,7 +1,9 @@
+import fnmatch
import os
import textwrap
from xml.dom import minidom
+from jinja2 import Template
from conans.errors import ConanException
from conans.model.build_info import DepCppInfo
@@ -38,31 +40,34 @@ class MSBuildDeps(object):
- True
+ True
- PATH=%PATH%;$(Conan{name}BinaryDirectories)$(LocalDebuggerEnvironment)
+ PATH=%PATH%;$(Conan{{name}}BinaryDirectories)$(LocalDebuggerEnvironment)
WindowsLocalDebugger
+ {% if ca_exclude -%}
+ $(Conan{{name}}IncludeDirectories);$(CAExcludePath)
+ {%- endif %}
- $(Conan{name}IncludeDirectories)%(AdditionalIncludeDirectories)
- $(Conan{name}PreprocessorDefinitions)%(PreprocessorDefinitions)
- $(Conan{name}CompilerFlags) %(AdditionalOptions)
+ $(Conan{{name}}IncludeDirectories)%(AdditionalIncludeDirectories)
+ $(Conan{{name}}PreprocessorDefinitions)%(PreprocessorDefinitions)
+ $(Conan{{name}}CompilerFlags) %(AdditionalOptions)
- $(Conan{name}LibraryDirectories)%(AdditionalLibraryDirectories)
- $(Conan{name}Libraries)%(AdditionalDependencies)
- $(Conan{name}SystemDeps)%(AdditionalDependencies)
- $(Conan{name}LinkerFlags) %(AdditionalOptions)
+ $(Conan{{name}}LibraryDirectories)%(AdditionalLibraryDirectories)
+ $(Conan{{name}}Libraries)%(AdditionalDependencies)
+ $(Conan{{name}}SystemDeps)%(AdditionalDependencies)
+ $(Conan{{name}}LinkerFlags) %(AdditionalOptions)
- $(Conan{name}IncludeDirectories)%(AdditionalIncludeDirectories)
+ $(Conan{{name}}IncludeDirectories)%(AdditionalIncludeDirectories)
- $(Conan{name}IncludeDirectories)%(AdditionalIncludeDirectories)
- $(Conan{name}PreprocessorDefinitions)%(PreprocessorDefinitions)
- $(Conan{name}CompilerFlags) %(AdditionalOptions)
+ $(Conan{{name}}IncludeDirectories)%(AdditionalIncludeDirectories)
+ $(Conan{{name}}PreprocessorDefinitions)%(PreprocessorDefinitions)
+ $(Conan{{name}}CompilerFlags) %(AdditionalOptions)
@@ -75,6 +80,15 @@ def __init__(self, conanfile):
'x86_64': 'x64'}.get(str(conanfile.settings.arch))
# TODO: this is ugly, improve this
self.output_path = os.getcwd()
+ # ca_exclude section
+ self.exclude_code_analysis = None
+ ca_exclude = self._conanfile.conf["tools.microsoft.msbuilddeps"].exclude_code_analysis
+ if ca_exclude is not None:
+ # TODO: Accept single strings, not lists
+ self.exclude_code_analysis = eval(ca_exclude)
+ if not isinstance(self.exclude_code_analysis, list):
+ raise ConanException("tools.microsoft.msbuilddeps:exclude_code_analysis must be a"
+ " list of package names patterns like ['pkga*']")
def generate(self):
# TODO: Apply config from command line, something like
@@ -165,7 +179,7 @@ def add_valid_ext(libname):
'definitions': "".join("%s;" % d for d in cpp_info.defines),
'compiler_flags': " ".join(cpp_info.cxxflags + cpp_info.cflags),
'linker_flags': " ".join(cpp_info.sharedlinkflags),
- 'exe_flags': " ".join(cpp_info.exelinkflags)
+ 'exe_flags': " ".join(cpp_info.exelinkflags),
}
formatted_template = self._vars_conf_props.format(**fields)
return formatted_template
@@ -178,7 +192,18 @@ def _pkg_props(self, name_multi, dep_name, vars_props_name, condition, cpp_info)
else:
content_multi = self._dep_props
- content_multi = content_multi.format(name=dep_name)
+ # TODO: This must include somehow the user/channel, most likely pattern to exclude/include
+ # Probably also the negation pattern, exclude all not @mycompany/*
+ ca_exclude = False
+ if isinstance(self.exclude_code_analysis, list):
+ for pattern in self.exclude_code_analysis:
+ if fnmatch.fnmatch(dep_name, pattern):
+ ca_exclude = True
+ break
+ else:
+ ca_exclude = self.exclude_code_analysis
+
+ content_multi = Template(content_multi).render(name=dep_name, ca_exclude=ca_exclude)
# parse the multi_file and add new import statement if needed
dom = minidom.parseString(content_multi)
@@ -228,7 +253,7 @@ def _content(self):
direct_deps = self._conanfile.dependencies.direct_host_requires
result[general_name] = self._deps_props(general_name, direct_deps)
for dep in self._conanfile.dependencies.host_requires:
- cpp_info = DepCppInfo(dep.cpp_info) # To account for automatic component aggregation
+ cpp_info = DepCppInfo(dep.cpp_info) # To account for automatic component aggregation
# One file per configuration, with just the variables
vars_props_name = "conan_%s%s.props" % (dep.name, conf_name)
vars_conf_content = self._pkg_config_props(dep.name, cpp_info)
diff --git a/conans/test/functional/toolchains/microsoft/test_msbuilddeps.py b/conans/test/functional/toolchains/microsoft/test_msbuilddeps.py
index 132dc0baf2f..373bfb14a69 100644
--- a/conans/test/functional/toolchains/microsoft/test_msbuilddeps.py
+++ b/conans/test/functional/toolchains/microsoft/test_msbuilddeps.py
@@ -5,6 +5,8 @@
import pytest
+from parameterized import parameterized
+
from conans.test.assets.cpp_test_files import cpp_hello_conan_files
from conans.test.assets.genconanfile import GenConanfile
from conans.test.assets.sources import gen_function_cpp
@@ -607,3 +609,53 @@ def build(self):
self.assertIn("conan_tool.props", deps)
client.run("create . pkg/0.1@")
self.assertIn("Conan_tools.props in deps", client.out)
+
+ @parameterized.expand([("['*']", True, True),
+ ("['pkga']", True, False),
+ ("['pkgb']", False, True),
+ ("['pkg*']", True, True),
+ ("['pkga', 'pkgb']", True, True),
+ ("['*a', '*b']", True, True),
+ ("['nonexist']", False, False),
+ ])
+ def test_exclude_code_analysis(self, pattern, exclude_a, exclude_b):
+ client = TestClient()
+ client.save({"conanfile.py": GenConanfile()})
+ client.run("create . pkga/1.0@")
+ client.run("create . pkgb/1.0@")
+
+ conanfile = textwrap.dedent("""
+ from conans import ConanFile, MSBuild
+ class HelloConan(ConanFile):
+ settings = "os", "build_type", "compiler", "arch"
+ requires = "pkgb/1.0@", "pkga/1.0"
+ generators = "msbuild"
+ def build(self):
+ msbuild = MSBuild(self)
+ msbuild.build("MyProject.sln")
+ """)
+ profile = textwrap.dedent("""
+ include(default)
+ [conf]
+ tools.microsoft.msbuilddeps:exclude_code_analysis = %s
+ """ % pattern)
+
+ client.save({"conanfile.py": conanfile,
+ "profile": profile})
+ client.run("install . --profile profile")
+ depa = client.load("conan_pkga.props")
+ depb = client.load("conan_pkgb.props")
+
+ if exclude_a:
+ inc = "$(ConanpkgaIncludeDirectories)"
+ ca_exclude = "%s;$(CAExcludePath)" % inc
+ assert ca_exclude in depa
+ else:
+ assert "CAExcludePath" not in depa
+
+ if exclude_b:
+ inc = "$(ConanpkgbIncludeDirectories)"
+ ca_exclude = "%s;$(CAExcludePath)" % inc
+ assert ca_exclude in depb
+ else:
+ assert "CAExcludePath" not in depb