Docker image for building solution with both C++ and C# projects - c++

I had a docker file that used to successfully build a VS2019 solution containing C++ and C# projects. Then recently it stopped working.
I've been investigating and trying various combinations of docker images, without success.
I've now got a test VS2019 solution with one C++ hello world console project and one C# .NET5 hello world console project. This does not compile using the following docker file:
e# escape=`
FROM mcr.microsoft.com/dotnet/framework/sdk:4.8
SHELL ["cmd", "/S", "/C"]
# Copy our Install script.
COPY Install.cmd C:\TEMP\
# Download collect.exe in case of an install failure.
ADD https://aka.ms/vscollect.exe C:\TEMP\collect.exe
ADD https://aka.ms/vs/16/release/vs_buildtools.exe C:\Temp\vs_buildtools.exe
ADD https://aka.ms/vs/16/release/channel C:\Temp\VisualStudio.chman
RUN C:\Temp\vs_buildtools.exe `
--quiet --wait --norestart --nocache `
--installPath C:\BuildTools `
--channelUri C:\Temp\VisualStudio.chman `
--installChannelUri C:\Temp\VisualStudio.chman `
--add Microsoft.VisualStudio.Workload.VCTools;includeRecommended `
--add Microsoft.Component.MSBuild `
|| IF "%ERRORLEVEL%"=="3010" EXIT 0
WORKDIR /src
ENTRYPOINT ["powershell.exe", "-NoLogo", "-ExecutionPolicy", "Bypass"] && CMD "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Commom7\Tools\VsDevCmd.bat"
The compiler error is
C:\src\dockertest\ConsoleApplications\ConsoleApplicationCpp\ConsoleApplicationCpp.vcxproj(28,3): error MSB4019: The imp
orted project "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\MSBuild\Microsoft\VC\v170\Microsoft.Cpp.D
efault.props" was not found. Confirm that the expression in the Import declaration "C:\Program Files (x86)\Microsoft Vi
sual Studio\2022\BuildTools\MSBuild\Microsoft\VC\v170\Microsoft.Cpp.Default.props" is correct, and that the file exist
s on disk.
Interestingly, this installs MSBuild for VS2022, despite the aka.ms/vs/16 link requesting VS2019.
Interestingly, this installs .NET SDK 6.0.101, despite the FROM line asking for 4.8
But the main problem is the VC tools are not installed. The folder C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\MSBuild\Microsoft does not contain the VC folder.
I've followed various examples but they don't appear to work any more with the recent docker images.

Try this:
# escape=`
FROM mcr.microsoft.com/dotnet/framework/sdk:4.8
SHELL ["cmd", "/S", "/C"]
ADD https://aka.ms/vs/17/release/vs_buildtools.exe C:\vs_buildtools.exe
RUN C:\vs_buildtools.exe `
--quiet --wait --norestart --nocache modify `
--installPath "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\BuildTools" `
--add Microsoft.VisualStudio.Workload.ManagedDesktopBuildTools;includeRecommended `
--add Microsoft.VisualStudio.Workload.MSBuildTools;includeRecommended `
--add Microsoft.VisualStudio.Workload.VCTools;includeRecommended `
|| IF "%ERRORLEVEL%"=="3010" EXIT 0
RUN del C:\vs_buildtools.exe
COPY . .
RUN nuget restore
RUN MSBuild GameClient.sln /t:Rebuild /p:Configuration=Release /p:Platform=x64
WORKDIR /Product
ENTRYPOINT ["C:\\Product\\WOTS.exe", "&&", "powershell.exe", "-NoLogo", "-ExecutionPolicy", "Bypass"]

Related

Use Docker-Windows for Gitlab-runner

I'm trying to use Docker in Windows to create a Gitlab-Runner to build a C++ application. It works so far, but I guess there are better aproaches. Here's what I did:
Here's my initial Docker Container:
FROM mcr.microsoft.com/windows/servercore:2004
# Restore the default Windows shell for correct batch processing.
SHELL ["cmd", "/S", "/C"]
# Download the Build Tools bootstrapper.
ADD https://aka.ms/vs/16/release/vs_buildtools.exe C:\TEMP\vs_buildtools.exe
# Install Build Tools with the Microsoft.VisualStudio.Workload.AzureBuildTools workload, excluding workloads and components with known issues.
RUN C:\TEMP\vs_buildtools.exe --quiet --wait --norestart --nocache `
--installPath C:\BuildTools `
--add Microsoft.VisualStudio.Workload.VCTools `
--add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 `
--add Microsoft.VisualStudio.Component.VC.CMake.Project `
--add Microsoft.VisualStudio.Component.Windows10SDK.19041 `
--locale en-US `
|| IF "%ERRORLEVEL%"=="3010" EXIT 0
# Define the entry point for the docker container.
# This entry point starts the developer command prompt and launches the PowerShell shell.
ENTRYPOINT ["cmd","/k", "C:\\BuildTools\\VC\\Auxiliary\\Build\\vcvars64.bat", "&&", "powershell.exe", "-NoLogo", "-ExecutionPolicy", "Bypass"]
And my .gitlab-ci.yml looks like this:
build Docker Windows:
image: buildtools2019_core
stage: build
tags:
- win-docker
script:
- mkdir build
- cd build
- cmake -DCMAKE_BUILD_TYPE=Release -DenableWarnings=ON -G Ninja -DCMAKE_MAKE_PROGRAM=Ninja ../
- ninja
This works so far and everthing builds correctly. The main problem however is that if the build fails the job succeeds anyways. I suspect that my entrypoint is wrong because powershell is executed inside of a cmd and only the exit code of cmd is checked which always succeeds.
So I tried to use powershell directly as entrypoint. I need to set environment variables via vcvars64.bat but that is not that trivial to do. I tried to execute the "Developer Powershell for VS 2019" but I can't execute the link in the entrypoint directly and the link looks like this:
"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -noe -c "&{Import-Module """C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\Common7\Tools\Microsoft.VisualStudio.DevShell.dll"""; Enter-VsDevShell 6f66c5f6}"
Which I don't quit understand what it does and the hash also varies from installation to installation. Also simply using this as entrypoint didn't work.
I then tried to use the Invoke-Environment Script taken from "https://github.com/nightroman/PowerShelf/blob/master/Invoke-Environment.ps1". This allows me to execute the .bat file from powershell like this:
Invoke-Environment C:\\BuildTools\\VC\\Auxiliary\\Build\\vcvars64.bat
But to do this I need to add this function to my profile, as far as I understood. I did this by copying it to "C:\Windows\system32\WindowsPowerShell\v1.0\profile.ps1" so that it would be accessible by all users.
In my Docker file I added:
COPY Invoke-Environment.ps1 C:\Windows\system32\WindowsPowerShell\v1.0\profile.ps1
and replaced the entrypoint with:
ENTRYPOINT ["C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe", "-NoExit", "-NoLogo", "-ExecutionPolicy", "Bypass", "Invoke-Environment C:\\BuildTools\\VC\\Auxiliary\\Build\\vcvars64.bat"]
But that didn't initialize the environment variables correctly. Also "Invoke-Environment" is not found by the gitlab-runner. My last resort was to write a small script (Init64.ps1) that executes the Invoke-Environment function with vcvars64.bat:
function Invoke-Environment {
param
(
# Any cmd shell command, normally a configuration batch file.
[Parameter(Mandatory=$true)]
[string] $Command
)
$Command = "`"" + $Command + "`""
cmd /c "$Command > nul 2>&1 && set" | . { process {
if ($_ -match '^([^=]+)=(.*)') {
[System.Environment]::SetEnvironmentVariable($matches[1], $matches[2])
}
}}
}
Invoke-Environment C:\BuildTools\VC\Auxiliary\Build\vcvars64.bat
I copied this in docker via:
COPY Init64.ps1 Init64.ps1
and used this entrypoint:
ENTRYPOINT ["C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe"]
In my build script I need to manually call it to setup the variables:
build Docker Windows:
image: buildtools2019_core
stage: build
tags:
- win-docker
script:
- C:\Init64.ps1
- mkdir build
- cd build
- cmake -DCMAKE_BUILD_TYPE=Release -DenableWarnings=ON -G Ninja -DCMAKE_MAKE_PROGRAM=Ninja ../
- ninja
Now everything works as intended the build works and the job only succeeds if the build succeeds.
However, I would prefer to setup my environment in the entrypoint so that I don't have to do this in my build script.
Is there a better way to do this? Also feel free to suggest any improvements I could make.
Ok, after some struggling, here is my entry.bat that correctly loads the environment exports the error-level/return-value:
REM Load environment
call C:\\BuildTools\\VC\\Auxiliary\\Build\\vcvars64.bat
REM If there are no parameters call cmd
IF [%1] == [] GOTO NOCALL
REM If there are parameters call cmd with /S for it to exit directly
cmd /S /C "%*"
exit %errorlevel%
:NOCALL
cmd
exit %errorlevel%

MSBuild fails to build Visual Studio Project due to missing property files (potentially IDE related)

I'm trying to get Jenkins running in a docker windows container and I've got most everything set up but I continue to run into a compilation error:
22:21:06 C:\JENKINS_HOME\workspace\iCEWav\src\engine\IceLibrary\IceLibrary.vcxproj(27,3): error MSB4019: The imported project "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Microsoft\VC\v160\Microsoft.Cpp.Default.props" was not found. Confirm that the path in the <Import> declaration is correct, and that the file exists on disk.
I installed MSBuild using this command:
RUN C:\TEMP\Install.cmd C:\TEMP\vs_buildtools.exe --quiet --wait --norestart --nocache `
--channelUri C:\TEMP\VisualStudio.chman `
--installChannelUri C:\TEMP\VisualStudio.chman `
--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended`
--remove Microsoft.VisualStudio.Component.Windows10SDK.10240 `
--remove Microsoft.VisualStudio.Component.Windows10SDK.10586 `
--remove Microsoft.VisualStudio.Component.Windows10SDK.14393 `
--remove Microsoft.VisualStudio.Component.Windows81SDK `
--installPath C:\BuildTools
It looks like the Visual Studio Project that I created in Visual Studio Community looks for a properties file here:
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
This builds fine on the local machine where the project was created but the file is missing in the docker container. I'm wondering if these files are generated once the IDE runs the first time or am I missing a step here?
So my boiled down question... Can I compile a Visual Studio Project File using only Visual Studio BuildTools? If so, how do I generate or ignore these property files.
Well that didn't take too long. According to documentation, MSBuild is actually not apart of the recommended or required workload for VCTools. The MSBuild that was already on the Docker container came from the base image provided by Micosoft and lacked the VC tools (mcr.microsoft.com/dotnet/framework/sdk:4.7.2-windowsservercore-ltsc2019).
I modified the install command to include MSBuild which ultimately downloaded the VC directories needed.
RUN C:\TEMP\Install.cmd C:\TEMP\vs_buildtools.exe --quiet --wait --norestart --nocache `
--channelUri C:\TEMP\VisualStudio.chman `
--installChannelUri C:\TEMP\VisualStudio.chman `
--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended`
--add Microsoft.Component.MSBuild `
--remove Microsoft.VisualStudio.Component.Windows10SDK.10240 `
--remove Microsoft.VisualStudio.Component.Windows10SDK.10586 `
--remove Microsoft.VisualStudio.Component.Windows10SDK.14393 `
--remove Microsoft.VisualStudio.Component.Windows81SDK `
--installPath C:\BuildTools
This installed the necessary files.

The system cannot find the file specified when trying to run vc_redist.x64 within nanoserver build using dockerfile

I am trying to setup a nanoserver container in order to run a C++ executable that was built with the /MD flag in Visual Studio 2017.
I know I need to install Microsoft Visual C++ Redistributable for Visual Studio 2017.
I managed to create the container, download the Redistributable and add it to the container at the root. however when build from the Dockerfile I get the following error message:
Exception(2) tid(360) 80070002 The system cannot find the file specified.
CallContext:[\Bridge_ProcessMessage\ComputeSystemManager_ExecuteProcess\VmHostedContainer_ExecuteProcess]
Provider: 00000000-0000-0000-0000-000000000000] extra info: {"CommandLine":"powershell -Command $ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue'; $verbosePreference='Continue'; Start-Process -filepath c:\\vc_redist.exe -ArgumentList \"/install\", \"/passive\", \"/norestart\", \"'/log a.txt'\" -PassThru | wait-process","User":"ContainerUser","WorkingDirectory":"C:\\","Environment":{"PSCORE":"C:\\Program Files\\PowerShell\\pwsh.exe","ProgramFiles":"C:\\Program Files","VS2017":"https://aka.ms/vs/16/release/vc_redist.x64.exe"},"CreateStdInPipe":true,"CreateStdOutPipe":true,"CreateStdErrPipe":true,"ConsoleSize":[0,0]}
here is my Dockerfile:
ARG FROM_IMAGE=microsoft/powershell:6.0.0-beta.9-nanoserver-1709
FROM ${FROM_IMAGE}
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue'; $verbosePreference='Continue';"]
ARG VS2017=https://aka.ms/vs/16/release/vc_redist.x64.exe
ADD ${VS2017} /vc_redist.exe
RUN Start-Process -filepath c:\vc_redist.exe -ArgumentList "/install", "/passive", "/norestart", "'/log a.txt'" -PassThru | wait-process
I tried removing last line from dockerfile and running it within the container after building I simply get no output.
also would like to avoid using windows server core as we are trying to keep the size as small as possible.
Any help greatly appreciated.

docker build failed : Not able to set the environment variables

I am trying to build a QT application using docker. I have visual studio 2015 build tools and QT 5.11.2 as base docker image. When I try to docker build QT application, I get this error.
C:\Qt\5.11.2\msvc2015_64\include\QtCore/qglobal.h(45): fatal error
C1083: Cannot open include file: 'type_traits': No such file or
directory
When I checked for this file 'type_traits', inside docker it exists inside this path:
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include
The docker build fails at this step:
RUN C:\\Qt\\Tools\\QtCreator\\bin\\jom.exe
This command RUN ["C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat", "x86_amd64"] sets up the environment variables, How to verify that these still exist for the rest of the RUN commands in dockerfile?
Below is my docker file:
#My base docker image containing QT5.11.2 and Visual build tools 2015
FROM qt
COPY ["./", "C:/app"]
RUN $env:PATH ='C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin;' + $env:PATH;\
[Environment]::SetEnvironmentVariable('PATH', $env:PATH, [EnvironmentVariableTarget]::Machine);
RUN $env:PATH ='C:\Qt\5.11.2\msvc2015_64\bin;' + $env:PATH;\
[Environment]::SetEnvironmentVariable('PATH', $env:PATH, [EnvironmentVariableTarget]::Machine);
RUN $env:PATH ='C:\Qt\Tools\QtCreator\bin\jom.exe;' + $env:PATH;\
[Environment]::SetEnvironmentVariable('PATH', $env:PATH, [EnvironmentVariableTarget]::Machine);
RUN $env:PATH ='C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include;' + $env:PATH;\
[Environment]::SetEnvironmentVariable('PATH', $env:PATH, [EnvironmentVariableTarget]::Machine);
WORKDIR C:\\app
RUN ["C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat", "x86_amd64"]
RUN qmake app.pro -spec win32-msvc "CONFIG+=debug" "CONFIG+=qml_debug"
RUN C:\\Qt\\Tools\\QtCreator\\bin\\jom.exe qmake_all
RUN C:\\Qt\\Tools\\QtCreator\\bin\\jom.exe
RUN C:\\Qt\\Tools\\QtCreator\\bin\\jom.exe install
RUN mkdir dist\debug_build\app_dist
RUN xcopy app_dist\dist_redist\*.* dist\debug_build\app_dist /E /Y >NUL
CMD cmd
How to verify that these still exist for the rest of the RUN commands in dockerfile?
They won't.
In the environment that exists here
RUN ["C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat", "x86_amd64"]
executes a process that executes the batch file with argument x86_amd64, creating new environment
settings for any child processes - of which there are none - then exits. Then:
RUN qmake app.pro -spec win32-msvc "CONFIG+=debug" "CONFIG+=qml_debug"
executes another process in the environment that existed there, which is still
the environment. And so on.
There's nothing specific to Docker, or Windows, about this behaviour. In any operating
system, a process cannot modify the environment of its parent, only the copy of
that environment that it inherits and passes to any child processes.
If you want all of the commands:
qmake app.pro -spec win32-msvc "CONFIG+=debug" "CONFIG+=qml_debug"
C:\\Qt\\Tools\\QtCreator\\bin\\jom.exe qmake_all
C:\\Qt\\Tools\\QtCreator\\bin\\jom.exe
C:\\Qt\\Tools\\QtCreator\\bin\\jom.exe install
to start in an environment modified by vcvarsall.bat x86_amd64, then you
have run all of them in the same shell as that command, e.g.
RUN "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat" x86_amd64 && ^
qmake app.pro -spec win32-msvc "CONFIG+=debug" "CONFIG+=qml_debug" && \
C:\\Qt\\Tools\\QtCreator\\bin\\jom.exe qmake_all && \
C:\\Qt\\Tools\\QtCreator\\bin\\jom.exe && \
C:\\Qt\\Tools\\QtCreator\\bin\\jom.exe install
See also the dockerfile ENV command
for a way of making global environment settings in a docker container.

Windows container fails to build VS 2013 C++ project with error MSB6006: “midl.exe” exited with code -2147024774

I should be able to build a C++ project on a windows docker container using MSBuild.exe
Command:
C:\'Program Files (x86)'\MSBuild\12.0\Bin\MSBuild.exe .\TestNative.sln /p:Configuration=Release /p:Platform=x64 /m /t:Build /p:ResGenExecuteAsTool=true /toolsversion:12.0
C++ Project fails to build with error:
Midl:
C:\Program Files (x86)\Windows Kits\8.1\bin\x86\midl.exe /W1 /nologo /char signed /env x64 /h “Enumglob.h” /tlb “x64\ReleaseMinDependency\TestNativeCore.tlb” Enumglob.idl
64 bit Processing .\Enumglob.idl
C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\Microsoft.CppCommon.targets(1178,5): error MSB6006: “midl.exe” exited with code -2147024774.
....
....
Build FAILED.
Information
This is my Dockerfile which already has the Visual C++ Redistributables installed and the project copied over using Docker cp command. I’m not sure what else is missing and the error message is not helpful.
FROM chemsorly/msbuilder:1.0.0-vsc
SHELL ["powershell"]
# Download VC++ 2010 SP1 Redistributable Package (x64)
RUN Invoke-WebRequest http://download.microsoft.com/download/1/6/5/165255E7-1014-4D0A-B094-B6A430A6BFFC/vcredist_x64.exe -OutFile "$env:TEMP\vc2010x64.exe" -UseBasicParsing
RUN Start-Process "$env:TEMP\vc2010x64.exe" '/features + /q' -wait
RUN Remove-Item "$env:TEMP\vc2010x64.exe"
# Download VC++ 2012 Update 4 Redistributable Package (x64)
RUN Invoke-WebRequest http://download.microsoft.com/download/1/6/B/16B06F60-3B20-4FF2-B699-5E9B7962F9AE/VSU_4/vcredist_x64.exe -OutFile "$env:TEMP\vc2012x64.exe" -UseBasicParsing
RUN Start-Process "$env:TEMP\vc2012x64.exe" '/features + /q' -wait
RUN Remove-Item "$env:TEMP\vc2012x64.exe"
# Download VC++ 2013 Redistributable Package (x64)
RUN Invoke-WebRequest http://download.microsoft.com/download/2/E/6/2E61CFA4-993B-4DD4-91DA-3737CD5CD6E3/vcredist_x64.exe -OutFile "$env:TEMP\vc2013x64.exe" -UseBasicParsing
RUN Start-Process "$env:TEMP\vc2013x64.exe" '/features + /q' -wait
RUN Remove-Item "$env:TEMP\vc2013x64.exe"
# Note: Add MSBuild to path
RUN setx PATH '%PATH%;C:\\Program Files (x86)\\MSBuild\\14.0\\Bin'
# Download VC++ 2015 Build Tools
RUN Invoke-WebRequest 'http://go.microsoft.com/fwlink/?LinkId=691126"&"fixForIE=.exe"&"__hstc=268264337.f43737e851d862336312053b3a368915.1511781465043.1511781465043.1511781465043.1"&"__hssc=268264337.1.1511781465043"&"__hsfp=1781426681' -OutFile "$env:TEMP\vc++2015bt.exe" -UseBasicParsing
RUN Start-Process "$env:TEMP\vc++2015bt.exe" '/features + /q' -wait
Question: I'm not sure what tools I'm missing on my container so what is the above error and how can I resolve it?