-
Notifications
You must be signed in to change notification settings - Fork 1.7k
draft pr for build UX #14551
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
base: feature/wsl-for-apps
Are you sure you want to change the base?
draft pr for build UX #14551
Changes from 9 commits
635f324
208e9ec
af041e4
e5f990d
e00d4ed
16dbf44
f5c1c75
14e0dbf
9554539
d3dc0e6
1c29367
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,4 +7,121 @@ | |
| <ItemGroup> | ||
| <ReferenceCopyLocalPaths Include="$(MSBuildThisFileDirectory)..\runtimes\win-$(WSLCSDK_Platform)\wslcsdk.dll" /> | ||
| </ItemGroup> | ||
|
|
||
| <!-- ================================================================== --> | ||
| <!-- Container Image Build Targets --> | ||
| <!-- ================================================================== --> | ||
|
|
||
| <!-- Default properties --> | ||
| <PropertyGroup> | ||
| <WslcImageOutputDir Condition="'$(WslcImageOutputDir)' == ''">$(OutDir)</WslcImageOutputDir> | ||
| <WslcCliPath Condition="'$(WslcCliPath)' == '' AND Exists('$(ProgramW6432)\WSL\wslc.exe')">$(ProgramW6432)\WSL\wslc.exe</WslcCliPath> | ||
| <WslcCliPath Condition="'$(WslcCliPath)' == ''">wslc</WslcCliPath> | ||
| </PropertyGroup> | ||
|
|
||
| <!-- Default metadata for WslcImage items --> | ||
| <ItemDefinitionGroup> | ||
| <WslcImage> | ||
| <Tag>latest</Tag> | ||
| <OutputDir>$(WslcImageOutputDir)</OutputDir> | ||
| </WslcImage> | ||
| </ItemDefinitionGroup> | ||
|
|
||
| <!-- Auto-detection fallback: if no WslcImage declared, detect container/Dockerfile --> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we should do that. The developer is not required to build their container images here.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, this is just fallback, will remove it later. |
||
| <ItemGroup Condition="'@(WslcImage)' == '' AND Exists('$(ProjectDir)container\Dockerfile')"> | ||
| <WslcImage Include="$(MSBuildProjectName)" | ||
| Dockerfile="$(ProjectDir)container\Dockerfile" | ||
| Context="$(ProjectDir)container" | ||
| Sources="$(ProjectDir)container" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup Condition="'@(WslcImage)' == '' AND Exists('$(ProjectDir)docker\Dockerfile')"> | ||
| <WslcImage Include="$(MSBuildProjectName)" | ||
| Dockerfile="$(ProjectDir)docker\Dockerfile" | ||
| Context="$(ProjectDir)docker" | ||
| Sources="$(ProjectDir)docker" /> | ||
| </ItemGroup> | ||
|
|
||
| <!-- Check that wslc CLI is installed --> | ||
| <Target Name="WslcCheckDependencies" | ||
| BeforeTargets="WslcBuildAllImages" | ||
| Condition="'@(WslcImage)' != ''"> | ||
|
|
||
| <Exec Command=""$(WslcCliPath)" --version" | ||
| IgnoreExitCode="true" | ||
| ConsoleToMSBuild="true" | ||
| StandardOutputImportance="low" | ||
| StandardErrorImportance="low"> | ||
| <Output TaskParameter="ExitCode" PropertyName="_WslcExitCode" /> | ||
| </Exec> | ||
|
|
||
| <Error Condition="'$(_WslcExitCode)' != '0'" | ||
| Code="WSLC0001" | ||
| Text="The WSLC runtime was not found. Install WSL by running: wsl --install --no-distribution" /> | ||
shuaiyuanxx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| </Target> | ||
|
|
||
| <!-- Outer target: dispatch each WslcImage to inner target via MSBuild task --> | ||
| <Target Name="WslcBuildAllImages" | ||
| AfterTargets="Build" | ||
| DependsOnTargets="WslcCheckDependencies" | ||
| Condition="'@(WslcImage)' != ''"> | ||
|
Comment on lines
+64
to
+67
|
||
|
|
||
| <MSBuild Projects="$(MSBuildProjectFullPath)" | ||
| Targets="_WslcBuildSingleImage" | ||
| Properties="Configuration=$(Configuration);Platform=$(Platform);_WslcName=%(WslcImage.Identity);_WslcTag=%(WslcImage.Tag);_WslcDockerfile=%(WslcImage.Dockerfile);_WslcContext=%(WslcImage.Context);_WslcSourceDir=%(WslcImage.Sources);_WslcOutput=%(WslcImage.OutputDir)" /> | ||
shuaiyuanxx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| </Target> | ||
|
Comment on lines
+69
to
+72
|
||
|
|
||
| <!-- | ||
| Collect source files for incremental check. | ||
| Wildcards are expanded here in ItemGroup Include (not in Inputs attribute or MSBuild task Properties, | ||
| where they get escaped). Sources can be semicolon separated directory paths; | ||
| each is expanded with **\* to collect all files recursively. | ||
| --> | ||
| <Target Name="_WslcCollectSources" BeforeTargets="_WslcBuildSingleImage"> | ||
| <ItemGroup> | ||
| <_WslcSourceDirs Include="$(_WslcSourceDir.Split(';'))" /> | ||
| <_WslcSourceFiles Include="$(_WslcDockerfile)" /> | ||
| <_WslcSourceFiles Include="%(_WslcSourceDirs.Identity)\**\*" Condition="'%(_WslcSourceDirs.Identity)' != ''" /> | ||
| </ItemGroup> | ||
| </Target> | ||
|
|
||
| <!-- Inner target: build a single image with incremental check --> | ||
| <Target Name="_WslcBuildSingleImage" | ||
| DependsOnTargets="_WslcCollectSources" | ||
| Inputs="@(_WslcSourceFiles)" | ||
| Outputs="$(IntDir)wslc_$(_WslcName).marker"> | ||
|
|
||
|
Comment on lines
+91
to
+93
|
||
| <MakeDir Directories="$(IntDir)" /> | ||
|
|
||
| <Message Importance="high" | ||
| Text="WSLC: Building image '$(_WslcName):$(_WslcTag)'..." /> | ||
|
|
||
| <Exec Command=""$(WslcCliPath)" image build -t "$(_WslcName):$(_WslcTag)" -f "$(_WslcDockerfile)" "$(_WslcContext)"" | ||
| ConsoleToMSBuild="true" /> | ||
|
|
||
| <!-- | ||
| Uncomment when wslc image save is available: | ||
| <MakeDir Directories="$(_WslcOutput)" /> | ||
| <Exec Command=""$(WslcCliPath)" image save -o "$(_WslcOutput)\$(_WslcName).tar" "$(_WslcName):$(_WslcTag)"" | ||
| ConsoleToMSBuild="true" /> | ||
| --> | ||
|
|
||
| <Touch Files="$(IntDir)wslc_$(_WslcName).marker" AlwaysCreate="true" /> | ||
|
|
||
| <Message Importance="high" | ||
| Text="WSLC: [$(_WslcName)] Image '$(_WslcName):$(_WslcTag)' built successfully." /> | ||
| </Target> | ||
|
|
||
| <!-- Clean container artifacts --> | ||
| <Target Name="WslcClean" | ||
| AfterTargets="Clean" | ||
| Condition="'@(WslcImage)' != ''"> | ||
|
|
||
| <Delete Files="$(IntDir)wslc_%(WslcImage.Identity).marker" /> | ||
| <!-- | ||
| Uncomment when wslc image save is available: | ||
| <Delete Files="%(WslcImage.OutputDir)\%(WslcImage.Identity).tar" /> | ||
| --> | ||
| </Target> | ||
|
|
||
| </Project> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
| <Import Project="$(MSBuildThisFileDirectory)..\build\Microsoft.WSL.Containers.common.targets" /> | ||
| </Project> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
| <Import Project="$(MSBuildThisFileDirectory)..\..\build\native\Microsoft.WSL.Containers.targets" /> | ||
| </Project> |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -55,3 +55,94 @@ unset(_wslcsdk_arch) | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| unset(_wslcsdk_root) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| unset(_wslcsdk_include_dir) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| unset(_wslcsdk_lib_dir) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # ============================================================================ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Container Image Build Targets | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # ============================================================================ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Provides the wslc_add_image() function for declaring container image | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # build targets with incremental rebuild support. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Usage: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # find_package(Microsoft.WSL.Containers REQUIRED) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # wslc_add_image( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # NAME my-server | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we have separate target name and image registry/name:tag here?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now NAME is specifically used for CMake target names, and the newly added optional parameter IMAGE is used for the image registry/name. If IMAGE is omitted, it will automatically fall back to NAME. Does this make sense? |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # DOCKERFILE container/Dockerfile | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # CONTEXT container/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # SOURCES container/src/*.cpp container/src/*.h | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # TAG latest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # OUTPUT ${CMAKE_BINARY_DIR}/images | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # # With explicit image registry/name (IMAGE defaults to NAME if omitted): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # wslc_add_image( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # NAME my-server | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # IMAGE ghcr.io/myorg/my-server | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # TAG v1.2.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # DOCKERFILE container/Dockerfile | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # CONTEXT container/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function(wslc_add_image) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cmake_parse_arguments( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PARSE_ARGV 0 ARG | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "" # options (none) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "NAME;IMAGE;TAG;DOCKERFILE;CONTEXT;OUTPUT" # one-value keywords | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "SOURCES" # multi-value keywords | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Validate required arguments | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(NOT ARG_NAME) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message(FATAL_ERROR "wslc_add_image: NAME is required") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| endif() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(NOT ARG_DOCKERFILE) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message(FATAL_ERROR "wslc_add_image: DOCKERFILE is required") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| endif() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(NOT ARG_CONTEXT) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message(FATAL_ERROR "wslc_add_image: CONTEXT is required") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| endif() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Defaults | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(NOT ARG_IMAGE) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set(ARG_IMAGE "${ARG_NAME}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| endif() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(NOT ARG_TAG) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set(ARG_TAG "latest") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| endif() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(NOT ARG_OUTPUT) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set(ARG_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| endif() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Find wslc CLI | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(NOT WSLC_CLI_PATH) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| find_program(WSLC_CLI_PATH wslc PATHS "$ENV{ProgramW6432}/WSL" "$ENV{ProgramFiles}/WSL") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(NOT WSLC_CLI_PATH) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message(FATAL_ERROR "wslc CLI not found. Install WSL by running: wsl --install --no-distribution") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| endif() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| endif() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set(_image_ref "${ARG_IMAGE}:${ARG_TAG}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set(_marker "${CMAKE_CURRENT_BINARY_DIR}/wslc_${ARG_NAME}.marker") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Uncomment when wslc image save is available: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # set(_tar_output "${ARG_OUTPUT}/${ARG_NAME}.tar") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Resolve source globs to file lists | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| file(GLOB_RECURSE _resolved_sources CONFIGURE_DEPENDS ${ARG_SOURCES}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+129
to
+130
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Resolve source globs to file lists | |
| file(GLOB_RECURSE _resolved_sources CONFIGURE_DEPENDS ${ARG_SOURCES}) | |
| # Resolve source globs to file lists (if any were provided) | |
| if(ARG_SOURCES) | |
| file(GLOB_RECURSE _resolved_sources CONFIGURE_DEPENDS ${ARG_SOURCES}) | |
| else() | |
| set(_resolved_sources) | |
| endif() |
Copilot
AI
Mar 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SOURCES is optional, but incremental rebuild correctness depends on it. If callers omit SOURCES (as in the second usage example), this glob resolves to an empty list and the build won’t rerun when other context files change. Either require SOURCES or default it to include the full CONTEXT directory contents.
| file(GLOB_RECURSE _resolved_sources CONFIGURE_DEPENDS ${ARG_SOURCES}) | |
| if(ARG_SOURCES) | |
| file(GLOB_RECURSE _resolved_sources CONFIGURE_DEPENDS ${ARG_SOURCES}) | |
| else() | |
| # If SOURCES is not provided, default to the full CONTEXT directory contents | |
| file(GLOB_RECURSE _resolved_sources CONFIGURE_DEPENDS "${ARG_CONTEXT}/*") | |
| endif() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to save the image to the output folder.
TODO: Which compression method to use for the tar file? Is ztsd supported in the wslc session?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also need to save the digest file along with the image if we decide to provide a fast path for image id check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to use the flag file for cmake. We can just use the produced files (the image tar file).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, once we confirmed how to export the image file to build folder, then this line can be removed.
Copilot
AI
Mar 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The custom command invokes wslc ... -f "${ARG_DOCKERFILE}" "${ARG_CONTEXT}" without setting WORKING_DIRECTORY or converting these to absolute paths. With common usage like DOCKERFILE container/Dockerfile and CONTEXT container/, the build tool typically runs commands from the build directory, so these relative paths can fail to resolve. Consider setting WORKING_DIRECTORY to ${CMAKE_CURRENT_SOURCE_DIR} (or the context dir) and/or normalizing ARG_DOCKERFILE/ARG_CONTEXT to absolute paths before use.
| # Resolve source globs to file lists | |
| file(GLOB_RECURSE _resolved_sources CONFIGURE_DEPENDS ${ARG_SOURCES}) | |
| add_custom_command( | |
| OUTPUT "${_marker}" | |
| COMMAND "${WSLC_CLI_PATH}" image build -t "${_image_ref}" -f "${ARG_DOCKERFILE}" "${ARG_CONTEXT}" | |
| # Uncomment when wslc image save is available: | |
| # COMMAND ${CMAKE_COMMAND} -E make_directory "${ARG_OUTPUT}" | |
| # COMMAND "${WSLC_CLI_PATH}" image save -o "${_tar_output}" "${_image_ref}" | |
| COMMAND ${CMAKE_COMMAND} -E touch "${_marker}" | |
| DEPENDS ${_resolved_sources} "${ARG_DOCKERFILE}" | |
| # Normalize paths to be independent of the build directory. | |
| get_filename_component(_dockerfile_path "${ARG_DOCKERFILE}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") | |
| get_filename_component(_context_path "${ARG_CONTEXT}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") | |
| # Resolve source globs to file lists | |
| file(GLOB_RECURSE _resolved_sources CONFIGURE_DEPENDS ${ARG_SOURCES}) | |
| add_custom_command( | |
| OUTPUT "${_marker}" | |
| COMMAND "${WSLC_CLI_PATH}" image build -t "${_image_ref}" -f "${_dockerfile_path}" "${_context_path}" | |
| # Uncomment when wslc image save is available: | |
| # COMMAND ${CMAKE_COMMAND} -E make_directory "${ARG_OUTPUT}" | |
| # COMMAND "${WSLC_CLI_PATH}" image save -o "${_tar_output}" "${_image_ref}" | |
| COMMAND ${CMAKE_COMMAND} -E touch "${_marker}" | |
| DEPENDS ${_resolved_sources} "${_dockerfile_path}" |
shuaiyuanxx marked this conversation as resolved.
Show resolved
Hide resolved
Copilot
AI
Mar 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NAME is used verbatim in the generated custom target name (wslc_image_${ARG_NAME}), so names containing spaces or path separators can make CMake error out during generation. Consider validating NAME against a safe pattern (or normalizing it) and emitting a clear FATAL_ERROR when it isn’t usable as a target name.
Uh oh!
There was an error while loading. Please reload this page.