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

Feature/msbuild toolchain generator #7754

Merged
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
9002d45
working in msbuild toolchain
memsharded Jul 9, 2020
e033754
Merge branch 'develop' into feature/msbuild_toolchain
memsharded Jul 18, 2020
32bfb9c
merged develop
memsharded Sep 7, 2020
d77f4d1
working...
memsharded Sep 7, 2020
d73f574
simple MSBuildToolchain
memsharded Sep 8, 2020
806f7ce
trying current dir path
memsharded Sep 8, 2020
56a740f
adding VSCMD_START_DIR
memsharded Sep 8, 2020
d48a530
fixing tests
memsharded Sep 8, 2020
b81831b
more tests
memsharded Sep 8, 2020
b6ed353
Merge branch 'develop' into feature/msbuild_toolchain
memsharded Sep 21, 2020
5561282
Merge branch 'develop' into feature/msbuild_toolchain
memsharded Sep 23, 2020
2844575
review
memsharded Sep 23, 2020
a1b8093
joing toolchain with customizable generator
memsharded Sep 25, 2020
d86459c
merged develop
memsharded Sep 25, 2020
b673c53
Merge branch 'develop' into feature/msbuild_toolchain_generator
memsharded Oct 13, 2020
eccf622
working
memsharded Oct 13, 2020
310fc41
merged develop
memsharded Oct 13, 2020
ab6f3b0
merged develop, working
memsharded Oct 13, 2020
413e2db
Merge branch 'develop' into feature/msbuild_toolchain_generator
memsharded Oct 14, 2020
841fd77
msbuild generator custom configs
memsharded Nov 5, 2020
0a3bbe5
Merge branch 'develop' into feature/generator_msbuild_custom_configs
memsharded Nov 5, 2020
3fa5b7a
fixing tests
memsharded Nov 5, 2020
b8263f2
added red warnings
memsharded Nov 21, 2020
8228222
added red warnings
memsharded Nov 21, 2020
46bad5c
fixing tests in Py2
memsharded Nov 21, 2020
1a932e2
fix tests
memsharded Nov 21, 2020
47fd550
fixing more tests
memsharded Nov 21, 2020
f90ef50
moving msbuild and gnu to tools
memsharded Nov 21, 2020
de7e50c
control import errors in Python 2.7
memsharded Nov 21, 2020
f5488ac
move MSBuildGenerator too
memsharded Nov 21, 2020
2724244
poc
memsharded Nov 23, 2020
7be4ea6
merged develop - Meson
memsharded Nov 23, 2020
06e3785
fixing pyinstaller
memsharded Nov 23, 2020
172ae6f
Merge branch 'feature/tools_cmake_no_breaking' into feature/generate
memsharded Nov 23, 2020
db535dd
migrating write_toolchain_files
memsharded Nov 23, 2020
cee39aa
merged develop
memsharded Nov 23, 2020
7ca8469
generate working
memsharded Nov 23, 2020
9cfc235
rebasing on feature/generate
memsharded Nov 23, 2020
76f0dab
review
memsharded Nov 24, 2020
8791b8e
Merge branch 'feature/generate' into feature/generator_msbuild_custom…
memsharded Nov 24, 2020
6f94959
merged generate() review, remove config_filename setter
memsharded Nov 24, 2020
a1747f5
updating to MSBuildDeps
memsharded Nov 24, 2020
1f1d742
fixing tests
memsharded Nov 24, 2020
d0f1a2d
fixing tests
memsharded Nov 24, 2020
625f8e2
merged develop
memsharded Dec 4, 2020
c85dc25
better tests
memsharded Dec 4, 2020
882e0e8
Merge branch 'develop' into feature/msbuild_toolchain_generator
memsharded Dec 4, 2020
bfcd4dd
fix test
memsharded Dec 4, 2020
e66563c
Merge branch 'develop' into feature/msbuild_toolchain_generator
memsharded Dec 11, 2020
98db92c
solved conflicts
memsharded Jan 7, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 6 additions & 3 deletions conans/client/generators/msbuild.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,18 @@ class MSBuildGenerator(Generator):
</Project>
""")

def __init__(self, conanfile):
super(MSBuildGenerator, self).__init__(conanfile)
self.configuration = conanfile.settings.build_type

@property
def filename(self):
return None

@ staticmethod
def _name_condition(settings):
def _name_condition(self, settings):
toolset = msvs_toolset(settings)

props = [("Configuration", settings.build_type),
props = [("Configuration", self.configuration),
# FIXME: This probably requires mapping ARM architectures
("Platform", {'x86': 'Win32',
'x86_64': 'x64'}.get(settings.get_safe("arch"))),
Expand Down
14 changes: 11 additions & 3 deletions conans/client/toolchain/msbuild.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import textwrap
from xml.dom import minidom

from conans.client.generators import MSBuildGenerator
from conans.client.tools import msvs_toolset
from conans.errors import ConanException
from conans.util.files import save, load
Expand All @@ -12,12 +13,13 @@ class MSBuildToolchain(object):
def __init__(self, conanfile):
self._conanfile = conanfile
self.preprocessor_definitions = {}
self.generator = MSBuildGenerator(conanfile)
self.configuration = conanfile.settings.build_type

@ staticmethod
def _name_condition(settings):
def _name_condition(self, settings):
toolset = msvs_toolset(settings)

props = [("Configuration", settings.build_type),
props = [("Configuration", self.configuration),
# FIXME: This probably requires mapping ARM architectures
("Platform", {'x86': 'Win32',
'x86_64': 'x64'}.get(settings.get_safe("arch"))),
Expand All @@ -33,6 +35,12 @@ def write_toolchain_files(self):
self._write_config_toolchain(config_filename)
self._write_main_toolchain(config_filename, condition)

self.generator.output_path = os.getcwd()
generator_files = self.generator.content
for generator_file, content in generator_files.items():
generator_file = os.path.abspath(generator_file)
save(generator_file, content)

def _write_config_toolchain(self, config_filename):

def format_macro(k, value):
Expand Down
145 changes: 123 additions & 22 deletions conans/test/functional/toolchain/test_msbuild.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import os
import platform
import shutil
import textwrap
import unittest


from conans.client.tools import chdir
from conans.util.files import mkdir
from conans.client.tools import vs_installation_path
from conans.test.utils.tools import TestClient

Expand All @@ -21,16 +24,10 @@
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
ReleaseShared|x64 = ReleaseShared|x64
ReleaseShared|x86 = ReleaseShared|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6F392A05-B151-490C-9505-B2A49720C4D9}.Debug|x64.ActiveCfg = Debug|x64
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why these removed lines?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They were unused. Seems a legacy from a refactor or something. Dead code.

{6F392A05-B151-490C-9505-B2A49720C4D9}.Debug|x64.Build.0 = Debug|x64
{6F392A05-B151-490C-9505-B2A49720C4D9}.Debug|x86.ActiveCfg = Debug|Win32
{6F392A05-B151-490C-9505-B2A49720C4D9}.Debug|x86.Build.0 = Debug|Win32
{6F392A05-B151-490C-9505-B2A49720C4D9}.Release|x64.ActiveCfg = Release|x64
{6F392A05-B151-490C-9505-B2A49720C4D9}.Release|x64.Build.0 = Release|x64
{6F392A05-B151-490C-9505-B2A49720C4D9}.Release|x86.ActiveCfg = Release|Win32
{6F392A05-B151-490C-9505-B2A49720C4D9}.Release|x86.Build.0 = Release|Win32
{B58316C0-C78A-4E9B-AE8F-5D6368CE3840}.Debug|x64.ActiveCfg = Debug|x64
{B58316C0-C78A-4E9B-AE8F-5D6368CE3840}.Debug|x64.Build.0 = Debug|x64
{B58316C0-C78A-4E9B-AE8F-5D6368CE3840}.Debug|x86.ActiveCfg = Debug|Win32
Expand All @@ -39,6 +36,11 @@
{B58316C0-C78A-4E9B-AE8F-5D6368CE3840}.Release|x64.Build.0 = Release|x64
{B58316C0-C78A-4E9B-AE8F-5D6368CE3840}.Release|x86.ActiveCfg = Release|Win32
{B58316C0-C78A-4E9B-AE8F-5D6368CE3840}.Release|x86.Build.0 = Release|Win32
{B58316C0-C78A-4E9B-AE8F-5D6368CE3840}.ReleaseShared|x64.ActiveCfg = ReleaseShared|x64
{B58316C0-C78A-4E9B-AE8F-5D6368CE3840}.ReleaseShared|x64.Build.0 = ReleaseShared|x64
{B58316C0-C78A-4E9B-AE8F-5D6368CE3840}.ReleaseShared|x86.ActiveCfg = ReleaseShared|Win32
{B58316C0-C78A-4E9B-AE8F-5D6368CE3840}.ReleaseShared|x86.Build.0 = ReleaseShared|Win32

EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -58,6 +60,14 @@
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="ReleaseShared|Win32">
<Configuration>ReleaseShared</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="ReleaseShared|x64">
<Configuration>ReleaseShared</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
Expand All @@ -78,6 +88,20 @@
<RootNamespace>MyApp</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseShared|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseShared|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
Expand Down Expand Up @@ -122,6 +146,16 @@
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')"
Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='ReleaseShared|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')"
Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='ReleaseShared|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')"
Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"
Expand All @@ -146,6 +180,12 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseShared|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseShared|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
Expand All @@ -161,6 +201,43 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseShared|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseShared|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
Expand Down Expand Up @@ -230,17 +307,25 @@ class WinTest(unittest.TestCase):
class App(ConanFile):
settings = "os", "arch", "compiler", "build_type"
requires = "hello/0.1"
generators = "msbuild"
options = {"shared": [True, False]}
default_options = {"shared": False}
def toolchain(self):
tc = MSBuildToolchain(self)
if self.options["hello"].shared and self.settings.build_type == "Release":
tc.configuration = "ReleaseShared"
tc.generator.configuration = "ReleaseShared"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A Question: the generator configuration should follow always the configuration of the project or not necessarily? Should be the same by default or not really?
In other words, if the generator configuration is different, will the dependencies will be found for the configuration specified in the project?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, after conversation with users, it is very typical that the configuration of the project refers to the way it is linking dependencies. It could be both, of course, but users can do:

  • ReleaseStatic: I am building my app executable, linking it statically with its dependencies
  • ReleaseShared: My app executable links with shared libs.

While other users or other projects could define:

  • ReleaseDLL: I am building a shared library myself
  • ReleaseStatic: I am building a static library myself

So it seems that the system should be flexible to let the users define the logic they want differently to generators and toolchains.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mhhh, so answering my questions...

  • The tc.configuration and tc.generator.configuration might be different.
  • We don't want to default the tc.generator.configuration with the value adjusted in the tc.configuration.

Did you mean the matrix is the following?:

  • ReleaseStatic (tc.configuration): I am building my app executable, linking it statically with its dependencies
  • ReleaseShared (tc.generator.configuration) : My app executable links with shared libs.

While other users or other projects could define:

  • ReleaseDLL (tc.configuration): I am building a shared library myself
  • ReleaseStatic (tc.generator.configuration): I am building a static library myself

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in the second case, it would be both tc.configuration, assuming that dependencies in both cases do not change at all.

In the first case, it seems that tc.generator.configuration => "tc.configuration", in most cases both should be used, as it sounds difficult to consume that specific dependencies configuration unless your current project doesn't define that configuration. Though it might be possible to use the same toolchain file for different configurations, so maybe not in all cases.

Copy link
Contributor

@lasote lasote Sep 30, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm so sorry but I don't get it hahahah. Could you do a Matrix of possible values of tc.configuration and tc.generator.configuration and the meaning?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name of the config is irrelevant, it is just something a user will define. So lets define it from the other side:

  • toolchain() defines tc.configuration only. This means that generators will keep generating the same standard files, like zlib_release.cmake or zlib_release_x86_v140.props. The dependencies will be exactly the same, using standard Conan build_type settings.
    This would be the case if the current project have several custom configurations in cmake or Visual for building different variants, like building a shared library or a static library. The dependencies are the same (static, shared, or whatever), they do not change, but the current project build from the IDE can be different.

  • toolchain() defines generator.configuration only. This means that dependencies change based on some inputs, for example if the user wants to be creating an executable linked with static deps or with shared deps. The current toolchain files could be identical, and do not depend on the configuration, like building an executable, maybe the toolchain doesn't change at all: same generator, same architecture, etc.

  • toolchain() defines both generator.configuration and tc.configuration: Both the dependencies and the current toolchain will change based on the current configuration. Like if the previous case, but building that executable against shared or static libraries would require some extra flags to be defined by the toolchain, e.g. passing -PIE or some LinkTimeOptimization flag when building against static or shared libraries.

Please let me know if this makes sense.


tc.preprocessor_definitions["DEFINITIONS_BOTH"] = "True"
if self.settings.build_type == "Debug":
tc.preprocessor_definitions["DEFINITIONS_CONFIG"] = "Debug"
else:
tc.preprocessor_definitions["DEFINITIONS_CONFIG"] = "Release"
tc.write_toolchain_files()

def imports(self):
self.copy("*.dll", src="bin",
dst="%s/%s" % (self.settings.arch, self.settings.build_type),
keep_path=False)
""")

app = textwrap.dedent("""
Expand Down Expand Up @@ -285,12 +370,20 @@ def toolchain(self):
}
""")

def _run_app(self, client, arch, build_type, msg="App"):
def _run_app(self, client, arch, build_type, shared=None, msg="App"):
if build_type == "Release" and shared == "shared":
configuration = "ReleaseShared"
else:
configuration = build_type
if arch == "x86":
command_str = "%s\\MyApp.exe" % build_type
command_str = "%s\\MyApp.exe" % configuration
else:
command_str = "x64\\%s\\MyApp.exe" % build_type
client.run_command(command_str)
command_str = "x64\\%s\\MyApp.exe" % configuration
new_cmd = "conan\\%s\\%s\\MyApp.exe" % (arch, build_type)
with chdir(client.current_folder):
mkdir(os.path.dirname(new_cmd))
shutil.copy(command_str, new_cmd)
client.run_command(new_cmd)
if arch == "x86":
self.assertIn("AppArch x86!!!", client.out)
else:
Expand Down Expand Up @@ -398,12 +491,14 @@ def test_toolchain_win_multi(self):
"compiler.cppstd": "17"}
settings = " ".join('-s %s="%s"' % (k, v) for k, v in settings.items() if v)
client.run("new hello/0.1 -s")
configs = [("Release", "x86"), ("Release", "x86_64"), ("Debug", "x86"), ("Debug", "x86_64")]
for build_type, arch in configs:
configs = [("Release", "x86", "shared"), ("Release", "x86_64", "shared"),
("Debug", "x86", "static"), ("Debug", "x86_64", "static")]
for build_type, arch, shared in configs:
# Build the profile according to the settings provided
runtime = "MT" if build_type == "Release" else "MTd"
client.run("create . hello/0.1@ %s -s build_type=%s -s arch=%s -s compiler.runtime=%s"
% (settings, build_type, arch, runtime))
shared = "True" if shared == "shared" else "False"
client.run("create . hello/0.1@ %s -s build_type=%s -s arch=%s -s compiler.runtime=%s "
" -o hello:shared=%s" % (settings, build_type, arch, runtime, shared))

# Prepare the actual consumer package
client.save({"conanfile.py": self.conanfile,
Expand All @@ -413,22 +508,28 @@ def test_toolchain_win_multi(self):
clean_first=True)

# Run the configure corresponding to this test case
for build_type, arch in configs:
for build_type, arch, shared in configs:
runtime = "MT" if build_type == "Release" else "MTd"
shared = "True" if shared == "shared" else "False"
client.run("install . %s -s build_type=%s -s arch=%s -s compiler.runtime=%s -if=conan"
% (settings, build_type, arch, runtime))
" -o hello:shared=%s" % (settings, build_type, arch, runtime, shared))

vs_path = vs_installation_path("15")
vcvars_path = os.path.join(vs_path, "VC/Auxiliary/Build/vcvarsall.bat")

for build_type, arch in configs:
for build_type, arch, shared in configs:
platform_arch = "x86" if arch == "x86" else "x64"
if build_type == "Release" and shared == "shared":
configuration = "ReleaseShared"
else:
configuration = build_type
cmd = ('set "VSCMD_START_DIR=%%CD%%" && '
'"%s" x64 && msbuild "MyProject.sln" /p:Configuration=%s '
'/p:Platform=%s ' % (vcvars_path, build_type, platform_arch))
'/p:Platform=%s ' % (vcvars_path, configuration, platform_arch))
client.run_command(cmd)
self.assertIn("Visual Studio 2017", client.out)
self.assertIn("[vcvarsall.bat] Environment initialized for: 'x64'", client.out)
self._run_app(client, arch, build_type)

self._run_app(client, arch, build_type, shared)
self.assertIn("AppMSCVER 17!!", client.out)
self.assertIn("AppCppStd 17!!!", client.out)