Skip to content

Forward <linkflags> from using msvc toolset options to the linker#606

Open
uilianries wants to merge 3 commits into
bfgroup:mainfrom
uilianries:fix/msvc-link-options
Open

Forward <linkflags> from using msvc toolset options to the linker#606
uilianries wants to merge 3 commits into
bfgroup:mainfrom
uilianries:fix/msvc-link-options

Conversation

@uilianries

Copy link
Copy Markdown
Contributor

Proposed changes

Greetings! 👋

While working through a Windows/MSVC debug-build issue in the Boost Conan recipe, I found that <linkflags> passed through a using msvc : version : command : options ; toolset-configuration statement is silently dropped, so it never reaches link.exe.

However, the documentation has a standard for options:
https://www.bfgroup.xyz/b2/manual/release/index.html#b2.overview.configuration:

Many of toolsets have an options parameter to fine-tune the configuration. All of B2’s standard compiler toolsets accept four options cflags, cxxflags, compileflags and linkflags as options specifying flags that will be always passed to the corresponding tools.

And it uses the example:

using gcc : 3.4 : : <compileflags>-m64 <linkflags>-m64 ;

Doing a quick search, the common.jam always stores <linkflags> into a variable named OPTIONS, scoped to <toolset>.link

Based on the documetation example, gcc.jam reads that $(OPTIONS):

actions link bind LIBRARIES
{
    "$(CONFIG_COMMAND)" @($(<[1]:T).rsp:O=FC:<=@":>=":E=-L"$(LINKPATH)" -Wl,$(RPATH_OPTION)$(SPACE)-Wl,$(RPATH) -Wl,-rpath-link$(SPACE)-Wl,"$(RPATH_LINK)" -o "$(<:T)" $(START-GROUP) "$(>:T)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) -l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) $(OPTIONS) $(USER_OPTIONS))
}

actions link.dll bind LIBRARIES
{
    "$(CONFIG_COMMAND)" @($(<[1]:T).rsp:O=FC:<=@":>=":E=-L"$(LINKPATH)" -Wl,$(RPATH_OPTION)$(SPACE)-Wl,$(RPATH) -Wl,-rpath-link$(SPACE)-Wl,"$(RPATH_LINK)" -Wl,-rpath-link$(SPACE)-Wl,"$(RPATH_LINK)" -Wl,$(IMPLIB_OPTION:E=--out-implib),"$(<[2]:T)" -o "$(<[1]:T)" $(HAVE_SONAME)-Wl,$(SONAME_OPTION)$(SPACE)-Wl,"$(SONAME_PREFIX:E=)$(<[1]:D=)" $(SHARED_OPTION:E=-shared) $(START-GROUP) "$(>:T)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) -l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) $(OPTIONS) $(USER_OPTIONS))
}

However, the msvc.jam only reads $(LINKOPT) and $(LINKFLAGS), but does not list $(OPTIONS) there:

actions link bind DEF_FILE LIBRARIES_MENTIONED_BY_FILE MANIFEST_FILE
{
    $(.SETUP) $(.LD) @($(<[1]:W).rsp:O=FC:<=@":>=":E="$(>)" $(LIBRARIES_MENTIONED_BY_FILE) $(LIBRARIES) "$(LIBRARY_OPTION)$(FINDLIBS_ST).lib" "$(LIBRARY_OPTION)$(FINDLIBS_SA).lib" $(LINKOPT) $(LINKFLAGS) $(OPT_OUT)"$(<[1]:W)" $(OPT_LIBPATH)"$(LINKPATH:W)" $(OPT_MANIFESTINPUT)"$(MANIFEST_FILE)")
}

So on msvc, <linkflags> supplied via a using statement is silently dropped at link time, while the same flag supplied as b2 command line property works fine, since that path populates LINKFLAGS directly.

In practice this meant things like /DEBUG silently never reached link.exe when passed manually.


This PR adds $(OPTIONS) to msvc.jam, we can use a user-config.jam like:

import os ;
local cflags = [ os.environ CFLAGS ] ;
local cxxflags = [ os.environ CXXFLAGS ] ;
local ldflags = [ os.environ LDFLAGS ] ;
using msvc : : cl.exe : <compileflags>$(cflags) <cxxflags>$(cxxflags) <linkflags>$(cxxflags) <linkflags>$(ldflags) ;

The ldflags passed to <linkflags> will correctly passed to msvc toolset in this case. This behavior is working already for GCC.

I also added a new regression test to validate what is passed via <linkflags> will be listed in the linker command for msvc.

Steps to Reproduce

Minimal reproduction without Boost:

echo 'using msvc : : cl.exe : <linkflags>/SOMETHING ;' > user-config.jam
echo 'exe hello : hello.cpp ;' > Jamroot.jam
echo '#include <iostream>' > hello.cpp
echo 'int main() { std::cout << "Hello World"; }' >> hello.cpp
b2 --user-config=user-config.jam -d2

The link command should be similar to:

 link /NOLOGO /INCREMENTAL:NO "bin\msvc-14.3\debug\threading-multi\hello.obj"      /DEBUG /MANIFEST:EMBED /MACHINE:X64 /subsystem:console /out:"bin\msvc-14.3\debug\threading-multi\hello.exe"

The /SOMETHING flag is missing. You can check my full build log: b2-test-output.log

Environment

  • B2: 5.5.2
  • Host OS: Windows 10
  • Compiler: MSVC (Visual Studio 2022, cl 19.44)

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Code style update (formatting, renaming)
  • Refactoring (no functional changes, no api changes)
  • Documentation content changes
  • Other (please describe):

Checklist

Further comments

Let me know if you'd like the test extended to cover clang-win/intel-win explicitly, or if a different regression-test shape is preferred. Regards!

Signed-off-by: Uilian Ries <uilianries@gmail.com>
Signed-off-by: Uilian Ries <uilianries@gmail.com>
Signed-off-by: Uilian Ries <uilianries@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant