From 9540e69b3ff89da704731c31472fa91ffda8f3ad Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Sat, 9 Mar 2019 10:49:13 -0700 Subject: [PATCH 1/3] Clean up msvc initialization. * If the user provided a command, don't try to use the autodetected command as well. The fixes errors caused by passing too many arguments. * If the user provided a command, but not a version, try to detect the version from the command. This code already existed, but was useless because it was run too late. It also failed for 14.1+ because of incorrect escaping for MATCH. * When handling duplicate initialization, make sure that we compare the original user options to the new user options. Previously, we compated the new user options to the auto-detected command which makes no sense at all. * If the user specified a command, always search for it in PATH, instead of also searching version specific locations. --- src/tools/msvc.jam | 156 ++++++++++++++++++++------------------------- 1 file changed, 68 insertions(+), 88 deletions(-) diff --git a/src/tools/msvc.jam b/src/tools/msvc.jam index 185f5f2a1..dda22b4c5 100644 --- a/src/tools/msvc.jam +++ b/src/tools/msvc.jam @@ -1126,12 +1126,15 @@ local rule set-setup-command ( targets * : properties * ) # local rule configure-really ( version ? : options * ) { - local v = $(version) ; + local command = [ feature.get-values : $(options) ] ; - # Decide what the 'default' version is. - if ! $(v) + if ! $(version) && ! $(command) { + # We were given neither a command, nor a version. # Take the best registered (i.e. auto-detected) version. + # FIXME: consider whether an explicitly specified setup script + # should disable this logic. We already won't get here if + # there is a user specified command. version = [ $(.versions).all ] ; for local known in $(.known-versions) { @@ -1141,59 +1144,31 @@ local rule configure-really ( version ? : options * ) break ; } } + # version might still have multiple elements if no versions + # were auto-detected, but an unknown version was configured + # manually. version = $(version[1]) ; - v = $(version) ; - - # Note: 'version' can still be empty at this point if no versions have - # been auto-detected. - version ?= "default" ; } - # Version alias -> real version number. - version = [ resolve-possible-msvc-version-alias $(version) ] ; - - # Check whether the selected configuration is already in use. - if $(version) in [ $(.versions).used ] + # Handle a user-provided command, and deduce the version if necessary. + # If the user-requested version was not autodetected and no command + # was given, attempt to find it in PATH + if $(command) || ! ( $(version:E=default) in [ $(.versions).all ] ) { - # Allow multiple 'toolset.using' calls for the same configuration if the - # identical sets of options are used. - if $(options) && ( $(options) != [ $(.versions).get $(version) : options ] ) + local found-command = [ common.get-invocation-command-nodefault msvc : cl.exe : $(command) ] ; + + if $(found-command) { - import errors ; - errors.error "MSVC toolset configuration: Toolset version" - "'$(version)' already configured." ; + command = $(found-command) ; + if ! $(command:D) + { + local path = [ common.get-absolute-tool-path $(command) ] ; + command = $(command:R=$(path)) ; + } } - } - else - { - # Register a new configuration. - $(.versions).register $(version) ; - - # Add user-supplied to auto-detected options. - options = [ $(.versions).get $(version) : options ] $(options) ; - - # Mark the configuration as 'used'. - $(.versions).use $(version) ; - - # Generate conditions and save them. - local conditions = [ common.check-init-parameters msvc : version $(v) ] - ; - - $(.versions).set $(version) : conditions : $(conditions) ; - - local command = [ feature.get-values : $(options) ] ; - - # For 14.1+ we need the exact version as MS is planning rolling updates - # that will cause our `setup-cmd` to become invalid - exact-version = [ MATCH "(14\.[1-9][0-9]\.[0-9\.]+)" : $(command) ] ; - - # If version is specified, we try to search first in default paths, and - # only then in PATH. - command = [ common.get-invocation-command msvc : cl.exe : $(command) : - [ default-paths $(version) ] : $(version) ] ; - - if ( ! $(version) || $(version) = "default" ) && ! $(command:D) + else { + # If we still failed to find cl.exe, bail out. ECHO ; ECHO warning\: "Did not find command for MSVC toolset." @@ -1204,21 +1179,20 @@ local rule configure-really ( version ? : options * ) "build from the 'Visual Studio Command Prompt for VS 2017'." ; ECHO ; + command ?= cl.exe ; } - common.handle-options msvc : $(conditions) : $(command) : $(options) ; - if ! $(version) { # Even if version is not explicitly specified, try to detect the # version from the path. # FIXME: We currently detect both Microsoft Visual Studio 9.0 and # 9.0express as 9.0 here. - if [ MATCH "(MSVC\\14.2)" : $(command) ] + if [ MATCH "(MSVC\\\\14.2)" : $(command) ] { version = 14.2 ; } - else if [ MATCH "(MSVC\\14.1)" : $(command) ] + else if [ MATCH "(MSVC\\\\14.1)" : $(command) ] { version = 14.1 ; } @@ -1264,6 +1238,44 @@ local rule configure-really ( version ? : options * ) version = 6.0 ; } } + } + + # Version alias -> real version number. + version = [ resolve-possible-msvc-version-alias $(version) ] ; + + # Check whether the selected configuration is already in use. + if $(version) in [ $(.versions).used ] + { + # Allow multiple 'toolset.using' calls for the same configuration if the + # identical sets of options are used. + if $(options) && ( $(options) != [ $(.versions).get $(version) : options ] ) + { + import errors ; + errors.user-error "MSVC toolset configuration: Toolset version" + "'$(version)' already configured." ; + } + } + else + { + # Register a new configuration. + $(.versions).register $(version) ; + $(.versions).set $(version) : options : $(options) ; + + # Mark the configuration as 'used'. + $(.versions).use $(version) ; + + # Generate conditions and save them. + local conditions = [ common.check-init-parameters msvc : version $(version) ] ; + + $(.versions).set $(version) : conditions : $(conditions) ; + + command ?= [ $(.versions).get $(version) : default-command ] ; + + # For 14.1+ we need the exact version as MS is planning rolling updates + # that will cause our `setup-cmd` to become invalid + exact-version = [ MATCH "(14\.[1-9][0-9]\.[0-9\.]+)" : $(command) ] ; + + common.handle-options msvc : $(conditions) : $(command) : $(options) ; # Generate and register setup command. @@ -1458,7 +1470,7 @@ local rule configure-really ( version ? : options * ) { for local cpu-condition in $(cpu-conditions) { - ECHO "notice: [msvc-cfg] condition: '$(cpu-condition)', setup: '$(setup-$(c))'" ; + ECHO "notice: [msvc-cfg] condition: '$(cpu-condition)', setup: '$(setup-$(c):J= )'" ; } } @@ -1536,15 +1548,7 @@ local rule configure-really ( version ? : options * ) # local rule default-path ( version ) { - # Use auto-detected path if possible. - local result = [ feature.get-values : [ $(.versions).get $(version) - : options ] ] ; - - if $(result) - { - result = $(result:D) ; - } - else + local result ; { # try to use vswhere local pseudo_env_VSCOMNTOOLS ; @@ -1611,28 +1615,6 @@ local rule default-path ( version ) } -# Returns either the default installation path (if 'version' is not empty) or -# list of all known default paths (if no version is given) -# -local rule default-paths ( version ? ) -{ - local possible-paths ; - - if $(version) - { - possible-paths += [ default-path $(version) ] ; - } - else - { - for local i in $(.known-versions) - { - possible-paths += [ default-path $(i) ] ; - } - } - - return $(possible-paths) ; -} - rule get-rspline ( target : lang-opt ) { @@ -1908,7 +1890,7 @@ local rule register-configuration ( version : path ? ) } $(.versions).register $(version) ; - $(.versions).set $(version) : options : $(command) ; + $(.versions).set $(version) : default-command : $(command) ; } } } @@ -1992,8 +1974,6 @@ if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ] .version-alias-11 = 11.0 ; .version-alias-12 = 12.0 ; .version-alias-14 = 14.0 ; -.version-alias-14.1 = 14.1 ; -.version-alias-14.2 = 14.2 ; # Names of registry keys containing the Visual C++ installation path (relative # to "HKEY_LOCAL_MACHINE\SOFTWARE\\Microsoft"). From 42aeed7ff1d8f2554b57371604c33ed6b27d76ae Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Sat, 9 Mar 2019 14:00:21 -0700 Subject: [PATCH 2/3] Relative paths for --prefix, --libdir, etc. are now bound relative to the current working directory, instead of being relative to the Jamfile. --- src/tools/package.jam | 29 +++++++++++++++------- test/package.py | 57 +++++++++++++++++++++---------------------- 2 files changed, 48 insertions(+), 38 deletions(-) diff --git a/src/tools/package.jam b/src/tools/package.jam index 218e78712..d9adff3fb 100644 --- a/src/tools/package.jam +++ b/src/tools/package.jam @@ -66,13 +66,25 @@ class package-paths option.set datarootdir : ; } - self.prefix = [ path.make [ option.get prefix : $(default-prefix) ] ] ; - self.libdir = [ path.make [ option.get libdir : $(self.prefix)/lib ] ] ; - self.bindir = [ path.make [ option.get bindir : $(self.prefix)/bin ] ] ; - self.includedir = - [ path.make [ option.get includedir : $(self.prefix)/include ] ] ; - self.datarootdir = - [ path.make [ option.get datarootdir : $(self.prefix)/share ] ] ; + handle-path prefix : $(default-prefix) ; + handle-path libdir : $(self.prefix)/lib ; + handle-path bindir : $(self.prefix)/bin ; + handle-path includedir : $(self.prefix)/include ; + handle-path datarootdir : $(self.prefix)/share ; + } + + local rule handle-path ( option : default-value ) + { + local opt = [ option.get $(option) ] ; + if $(opt) + { + opt = [ path.root $(opt) [ path.pwd ] ] ; + } + else + { + opt = $(default-value) ; + } + self.$(option) = $(opt) ; } rule prefix ( ) @@ -118,8 +130,7 @@ class package-paths } local adjusted-default = [ path.join [ get $(relative-to) ] $(default-value) ] ; - self.$(option) = - [ path.make [ option.get $(option) : $(adjusted-default) ] ] ; + handle-path $(option) : $(adjusted-default) ; } return $(self.$(option)) ; } diff --git a/test/package.py b/test/package.py index 686118b44..7cc5e33c0 100644 --- a/test/package.py +++ b/test/package.py @@ -10,10 +10,11 @@ import BoostBuild import os def setup(): - t = BoostBuild.Tester(use_test_config=False) + t = BoostBuild.Tester(["p//install", "p//data"], + use_test_config=False) - t.write("jamroot.jam", "") - t.write("jamfile.jam", """\ + t.write("p/jamroot.jam", "") + t.write("p/jamfile.jam", """\ import package ; exe a : a.cpp ; lib b : b.cpp ; @@ -23,16 +24,16 @@ def setup(): : a.h ; package.install-data data : Test : a.txt ; """) - t.write("a.cpp", "int main() {}") - t.write("b.cpp", """ + t.write("p/a.cpp", "int main() {}") + t.write("p/b.cpp", """ int #ifdef _WIN32 __declspec(dllexport) #endif must_export_something; """) - t.write("a.h", "") - t.write("a.txt", "") + t.write("p/a.h", "") + t.write("p/a.txt", "") return t def test_defaults(): @@ -40,7 +41,7 @@ def test_defaults(): # Since the default install location is outside out test area, # we don't want to actually execute the build. - t.run_build_system(["-n", "-d1", "install", "data"]) + t.run_build_system(["-n", "-d1"]) installdir = "C:/Test" if os.name == 'nt' else "/usr/local" t.expect_output_lines([ @@ -64,7 +65,7 @@ def test_prefix(): option.set datarootdir : bad/share ; """) - t.run_build_system(["--prefix=installdir", "install", "data"]) + t.run_build_system(["--prefix=installdir"]) t.expect_addition("installdir/bin/a.exe") t.expect_addition("installdir/lib/b.dll") t.expect_addition("installdir/lib/b.lib") @@ -87,8 +88,7 @@ def test_subdirs(): t.run_build_system(["--libdir=installdir/lib64", "--bindir=installdir/binx", "--includedir=installdir/includex", - "--datarootdir=installdir/sharex", - "install", "data"]) + "--datarootdir=installdir/sharex"]) t.expect_addition("installdir/binx/a.exe") t.expect_addition("installdir/lib64/b.dll") t.expect_addition("installdir/lib64/b.lib") @@ -112,8 +112,7 @@ def test_subdirs_with_prefix(): "--libdir=installdir/lib64", "--bindir=installdir/binx", "--includedir=installdir/includex", - "--datarootdir=installdir/sharex", - "install", "data"]) + "--datarootdir=installdir/sharex"]) t.expect_addition("installdir/binx/a.exe") t.expect_addition("installdir/lib64/b.dll") t.expect_addition("installdir/lib64/b.lib") @@ -129,7 +128,7 @@ def test_prefix_config_file(): option.set prefix : installdir ; """) - t.run_build_system(["install", "data"]) + t.run_build_system() t.expect_addition("installdir/bin/a.exe") t.expect_addition("installdir/lib/b.dll") t.expect_addition("installdir/lib/b.lib") @@ -149,7 +148,7 @@ def test_subdirs_config_file(): option.set datarootdir : installdir/sharex ; """) - t.run_build_system(["install", "data"]) + t.run_build_system() t.expect_addition("installdir/binx/a.exe") t.expect_addition("installdir/lib64/b.dll") t.expect_addition("installdir/lib64/b.lib") @@ -163,8 +162,8 @@ def test_multiple(): install prefixes.''' t = BoostBuild.Tester(use_test_config=False) - t.write("jamroot.jam", "") - t.write("jamfile.jam", """\ + t.write("p/jamroot.jam", "") + t.write("p/jamfile.jam", """\ import package ; exe a : a.cpp ; lib b : b.cpp ; @@ -177,24 +176,24 @@ def test_multiple(): : b/static b/shared : a.h ; """) - t.write("a.cpp", "int main() {}") - t.write("b.cpp", """ + t.write("p/a.cpp", "int main() {}") + t.write("p/b.cpp", """ int #ifdef _WIN32 __declspec(dllexport) #endif must_export_something; """) - t.write("a.h", "") - t.run_build_system(["installx", "instally"]) - t.expect_addition("xxx/bin/a.exe") - t.expect_addition("xxx/lib/b.dll") - t.expect_addition("xxx/lib/b.lib") - t.expect_addition("xxx/include/a.h") - t.expect_addition("yyy/bin/a.exe") - t.expect_addition("yyy/lib/b.dll") - t.expect_addition("yyy/lib/b.lib") - t.expect_addition("yyy/include/a.h") + t.write("p/a.h", "") + t.run_build_system(["p//installx", "p//instally"]) + t.expect_addition("p/xxx/bin/a.exe") + t.expect_addition("p/xxx/lib/b.dll") + t.expect_addition("p/xxx/lib/b.lib") + t.expect_addition("p/xxx/include/a.h") + t.expect_addition("p/yyy/bin/a.exe") + t.expect_addition("p/yyy/lib/b.dll") + t.expect_addition("p/yyy/lib/b.lib") + t.expect_addition("p/yyy/include/a.h") def test_paths(): t = BoostBuild.Tester(pass_toolset=False) From f15a84a815bec7897d73fdace3bc4bcf219f9ccd Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Sun, 10 Mar 2019 07:20:51 -0600 Subject: [PATCH 3/3] Add missing path.make. --- src/tools/package.jam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/package.jam b/src/tools/package.jam index d9adff3fb..3950f4c77 100644 --- a/src/tools/package.jam +++ b/src/tools/package.jam @@ -78,7 +78,7 @@ class package-paths local opt = [ option.get $(option) ] ; if $(opt) { - opt = [ path.root $(opt) [ path.pwd ] ] ; + opt = [ path.root [ path.make $(opt) ] [ path.pwd ] ] ; } else {