[MUSIC]
>> Hi everyone. My name is Erika Sweet.
I work on the C++ Team and I'm here to share what's new for
C++ cross platform developers and Visual Studio 2022.
If you're a C++ developer who is building four,
or looking to add support for more than one platform,
or if you're developing with an eye to open source,
then this talk is for you.
Maybe you target both Windows and Linux,
but your team isn't as familiar or
productive with command line tools like GDB.
Maybe you maintain different workflows or configuration files
for every combination of
target platform and development environment,
and you're looking to streamline that process
while still supporting a diverse set of tools,
or maybe you only build locally for Windows and you
rely on your CI pipeline to check non-Windows builds.
If you don't target Windows at all,
then stay tuned as we discuss
C++ cross-platform dependency management
and build and debug
a Linux GUI application natively on Windows with WSL.
I'm starting with a CMake project,
open in Visual Studio.
CMake is an open source
cross-platform build system generator that's supported
natively in Visual Studio and is
our recommendation for C++ cross-platform development.
If you don't use CMake,
then Visual Studio has remote debugging tools for
you that we'll cover in the second half of this demo.
One piece of feedback that we received on Visual Studio 2019,
was that it could be difficult to reproduce
CMake builds outside of Visual Studio.
To address this, we work closely with the maintainers of CMake
to develop a new file called CMakePresets.json.
That's supported directly by CMake and can be used to drive
CMake generation and build both with and without our tools.
That means your team can use it from Visual Studio, from VS Code,
from the CMake GUI and a CI pipeline,
or from the command line on a Windows,
Linux, and Mac.
Visual Studio's CMake presets integration
is automatically enabled for me
because I have the CMakePresets.json
file at the root of my open folder.
But if I didn't have that file,
then I could enable the integration by going
to Tools, Options, CMake,
checking prefer, using CMake presets for Configure build and test,
and then closing and reopening the folder in Visual Studio.
CMake presets is the recommended alternative
to CMake settings and will be
the default configuration method in
future releases of Visual Studio 2022.
You might realize across the menu bar
that I now have three drop-downs.
The drop-down on the left is my active
target system,so because CMake is cross-platform,
I can build and debug this project on
my local machine on any number of WSL
distros that Visual Studio will automatically pick
up on or on SSH connections.
These can be connections to servers,
desktop, it doesn't matter.
I can target all of these systems from
the same instance of Visual Studio.
The drop down in the middle is my active configure preset,
which drives CMake cash generation and
corresponds to the CMake configure step from the command line.
The drop-down on the right is my active build preset,
which drives CMake builds and
corresponds to the CMake build step from the command line.
I can select manager build presets
to open up my CMakePresets.json file and take a closer look.
In this file, I can define any number
of configure presets, build presets,
or test presets, which encode
the information that I would normally
pass to CMake from the command line.
In my configure preset,
that's things like my generator and my build directory.
I've already set up my presets file so I can go ahead
and kick off cash generation on Windows.
For lots more information on CMakePresets.json,
as well as its companion user-level file,
CMakeUserPresets.json, you can check out aka.ms/CMakepresetsVS.
It looks like cash generation has finished,
but it was unsuccessful because I'm missing a dependency.
CMake cannot find glad.
As a C++ developer,
you might be used to copying and pasting dependencies
around and resolving any transitive dependencies by hand,
or you might be used to platform
specific solutions like a system package manager.
To help mitigate this,
I'm using VC package,
which is an open-source cross-platform dependency management tool
for C and C++.
Because one, I have this
VCpackage.json file adjacent to my roots CMake list.
Two I'm passing the VC package toolchain file to CMake,
then when I configure this project,
VC package will automatically bring
down and build all of the dependencies that I
listed here from source or download them if I'm using
binary caching and install them in
a subdirectory of this projects output directory.
The only thing that I need to do to add this missing dependency,
is add glad to this list and reconfigure the cache.
None of this is Visual Studio specific at all.
Reproach from the command line if you're
using CMake and VC package,
which I'll take a closer look at in just a few minutes.
For more information on VC package,
you can check out aka.ms/vcpackage.
It looks like CMake generation has
finished and this time it was successful.
As I scroll up in the CMake output window,
you can see that the installation of glad and it's
two dependencies took 73 milliseconds,
265 milliseconds,
and the entire operation took less than five seconds.
That's because I'm using VC package of binary caching.
The binaries that I'm downloading and installing
locally are cached in GitHub packages for
other developers on my team to pull down and use on
their local dev boxes and to use in my CI pipeline.
Before I check in these changes that I just
made to vcpackage.json,
I'm going to quickly verify that those changes also work on Linux.
All I need to do is change my active target system in
Visual Studio to a WSL distribution and reconfigure the cache.
This is a really easy way to
verify that any change that you make works
on both Windows and Linux locally
from Visual Studio using Windows and WSL.
Again, it looks like CMake generation was successful,
so at this point I'm ready to check in those changes
I made to vcpackage.json.
We added glad to our list of dependencies.
I will commit those changes and then push them to the remote.
This project is using GitHub Actions and I've authored
a workflow file that will automatically kick off
a CI run on both Windows and Linux on push.
That's getting started now and we'll come
back and take a look at it in just a few minutes.
Because CMake generation was successful,
I can now leverage all the Visual Studio's CMake features.
That's things like CMake targets
view over here in the solution explorer,
which is a more CMake centric way of viewing your code.
In editor documentation for CMake,
which surfaces official CMake docs in
the IDE and language services for CMake.
I can do things like right click and find all references,
go to definition or Peak Definition on
CMake variables, targets, and functions.
As an existing Visual Studio customer,
you might already be familiar with
the Windows development experience,
so I'm going to continue to focus this demo
on local development with WSL2.
Right now, my active target system is a WSL2 distro.
When I build this project,
Visual Studio is actually making a copy of my storage tree in
the Linux file system and building with
native Linux build tools like GCC or Clang.
The reason for this is that WSL2 is a lot faster,
anywhere from three to 20 times faster when it's accessing
source files in the Linux file system
rather than the Windows file system,
which can lead to significant performance gains for you.
This is all done using Visual Studio's native support for WSL2,
which is brand new in Visual Studio 2022,
and will be used automatically anytime that you're
targeting a WSL2 distribution.
When I start debugging,
I'll have the full suite of Visual Studio debugging
features available to me backed by GDP.
To help illustrate this,
I'm going to walk through a bug that I
encountered when I was preparing for this demo.
If you take a look at the solution explorer over to the right,
you can see that this project contains four targets,
including a physics library and a samples executable.
I had samples running as a nice visual demo.
But when I went to run the project for a second time,
it behaved just like that in exe as soon as it was launched,
so it was time to start debugging.
The first thing that I did was look for
the program's main function or the entry point to the program.
As I was scrolling through main,
I got to this update loop that
handles all of the input and rendering,
and the condition that is checked before this loop is
executed is the return value of this window should close function,
which checks the close flag of the main window.
Because I'm seen that main window closed on me,
I thought this would be a good place to set
a break point and see what was happening.
I'll set a break point,
press "F5" to relaunch the debugger and
now I can press "F11" to
step into this window should close function.
This function is just checking if this window
should close flag has been set.
I can run the cursor down to
this return statement and it looks like
right now the value of Windows should close is zero or false,
meaning this window should not close.
But because I am seen that main window close on me,
I'm going to set a new data breakpoint that will hit
if the value of Windows should close changes.
We'll go over to break points,
add a new data breakpoint for the address of window should close.
What's cool here is that I don't need to look at memory at all,
I can just reference the name of the variable directly.
Press, "Okay, shift
F11" to step out of this function back into main,
F5 to continue execution and sure enough,
our data breakpoint was hit.
The value of Windows should close is now one or true,
this Window should close.
I wanted to take a look at the call stack
to see what was calling this function.
I can see that the program is pulling for events,
processing events and in this case,
that event is a keyboard event and specifically the escape key.
This program is behaving as if I had press the Escape key.
To fast-forward a little bit,
I did a bit more debugging and found out that the program was
always remembering the last event from the previous session.
The first thing I tried to do was processed that stale event
before this keyboard event handler
was set up and that did not work.
But when I set a breakpoint at
that location to debug and take a look at what was happening,
the program did behave as expected,
which led me to believe it might be
some sort of timing issue and perhaps
that stale event was coming in
just after the start of the program.
What I ended up doing was adding
just a half second sleep before processing that stale event.
We'll all uncomment out my solution,
remove the breakpoints that I had set,
stop debugging, and then relaunch by pressing "F5".
This time, instead of exiting immediately,
we'll be able to interact with samples
and play with all of our physics demos.
Now, what we see here is actually pretty cool.
This is a Linux application running
natively on Windows with WSL G,
the G stands for graphics and Windows 11.
You might notice the Linux-based tiling up here in the corner,
which indicates that we are indeed running
this in a native Linux instance.
When I was debugging,
I had the full Visual Studio experienced backed by GDB,
which shows that graphical expression that you just
can't really get when you're debugging
with GDB from the command line.
Another thing I want to underscore is that nothing that I've
done so far locks you into Visual Studio.
I'm building with CMake,
VC package and GCC,
I'm debugging with GDB,
so there's nothing visual Studio specific.
This is a great option for teams who like
to maintain a diverse set of tools.
To take a closer look at that,
I'm going to hop on over to that
GitHub Actions run where we reproduce
our builds using the same tools in our CI pipeline.
Here's GitHub Actions,
here's our most recent run that was started six minutes ago.
It was successful on both Windows and
Linux and if I take a closer look at that Linux run,
the thing that I really want to show you is that I'm using
the exact same CMake presets dot JSON file
to drive CMake generation and build that I was using locally.
Here I'm passing in the name of my configure
preset and build preset to CMake,
which really ensures that your team can
maintain that single source of truth that
you can use to drive builds both locally
from an IDE like Visual Studio,
from the command line or from your CI pipeline.
In the same vein,
VC package is downloading and installing
the exact same binaries that I was
using in Visual Studio for
local development when I was targeting both Windows and WSL.
Finally, if you're not using CMake,
then Visual Studio has remote debugging tools that you
can use to debug on both Linux and Mac.
Brand new and Visual Studio 2022 is the ability to attach to
a remote process and debug it with
the LLDB debugger from Visual Studio.
This feature is supported on both Linux and Mac,
but for the sake of the demo,
my process will be running on WSL.
As I mentioned earlier with Visual Studio support for WSL2,
Visual Studio maintains a copy of
your build tree in the Linux file system.
Over into Ubuntu, you can see that I'm working on WSL now,
this is the Ubuntu 2004 distro.
I've navigated into that build directory.
I'm going to start associate and launch samples.
This is the exact same binary that we are building
and debugging from visual studio just a few minutes ago.
Back in VS, you can use
the same attach workflow that you might already be familiar with,
so Debug attached to process.
We want connection type SSH.
The connection target is Erika at local host.
Because I haven't added
this connection to the connection manager,
I am being prompted to authenticate and then trust
the authenticity of the connection and once it's done connecting,
then Visual Studio will prompt me with
a list of all the processes that are running
on that WSL distro so I want to attach to samples.
The last thing I need to do is say, well,
they're all be debugging with GDB or LLDB.
Again, support for LLDB is brand new in Visual Studio 2022,
but I could follow this exact same workflow with the GDB debugger.
I will select that and then when I hit Okay,
Visual Studio will attach to that process with
the LLDB debugger and when I press "pause",
I will see the current line of execution,
as well as my variables,
the call stack, and I'm ready to start debugging.
One thing that I want to emphasize
about this workflow is that it doesn't
matter how you build the binary
that you're attaching to from Visual Studio.
You can the ability with a custom build script with make,
with Xcode, with CMake,
it does not matter,
you can still attach to it and debug it using the front end of
the Visual Studio debugger backed by either GDB or LLDB.
For example, the Office team at Microsoft
primarily uses Windows and Visual Studio for
their local development and they're excited to use
this feature to remote debug Mac failures.
Previously, they might sift through
log files to try and understand what's happening,
or for a particularly bad issue,
they might spin up a Mac machine for native debugging,
which is both time-consuming and
a less familiar debugging experience.
For more information on this workflow including
how to get started with the LLDB debugger,
you can check out aka.ms/lldb.
For more information on
other build system agnostic remote debugging
workflows like debugging a Linux core dump from Visual Studio,
you can check out our C++ team blog at aka.ms/cpp blog.
That pretty much wraps up
all the new features that I wanted to show you today.
To quickly recap what we covered,
we use steaming presets and VC package to
build a CMake project both with and without visual Studio.
Our local builds targeting both Windows and
WSL can be reproduced in
a CI pipeline or from
the command line as we saw with our GitHub Actions workflow.
This can help your team
ensure that you maintain that single source of
truth and that you're not locked into any specific tools.
We also showed how the local Visual Studio development experience
now applies to Linux with
Visual Studio's native support for WSL 2.
It is just as easy to build and debug a Linux GUI application
locally from Visual Studio
as it is to build and debug for Windows.
Finally, no matter how you're
building your cross-platform application,
Visual Studio offers the best debugging experience
for debugging with GDB or LLDB,
which can save a ton of time compared to
using those same tools from the command line.
To get in contact with our team or to stay up to
date with what's new for cross platform developers,
you can check out our team blog,
which again can be reached at
akr.ms/cpp blog. Thanks for tuning in.