Visual Studio incremental build: XML documentation file is created too late - visual-studio

I have a DLL project for Visual Studio 2005 that has "XML documetation file" turned on.
Whenever I do an incremental build, during post-build event execution there is no XML documentation file in the output directory.
If I pause the build during post-build event (using sleep utility from GnuWin32 CoreUtils), I can see the file in the output directory with a name like vs5BB5.tmp. But this file is not renamed to MyLib.xml until post-build event (and "AfterBuild" target, as I have some customizations there) are finished.
For a clean build in Studio and for MSBuild started from a command line everything works as expected - XML documentation file is created before post-build events.
Why this happens, and how do I fix incremental builds?

Was just having the same issue. This is a known problem with Visual Studio and incremental builds. See this post on microsoft connect.
I solved it with a conditional xcopy like the one below:
if exist "$(TargetDir)$(TargetName).xml" xcopy $(TargetDir)$(TargetName).xml $(ProjectDir)......\bin\ /C /I /R /Y
SF

Just having this problem myself....
what I found is that the xml file is named a .tmp file, so you can copy this tmp file to where you want, its just a bit of a "messy" work around.
I'm also quite tempted to write myself a command line tool thats called something like :-
WaitForThenCopy <source path> <target path> <milliseconds to wait>
only problem is it would have to be non blocking and you wouldn't know if it worked or not.

I'm using a simple batch file to do the copying instead of the default copy command that detects the tmp file and copies/renames this instead.
REM There is a bug in VS where the xml documentation is written to a tmp file
REM during incremental builds, preventing access during post-build events.
REM See http://connect.microsoft.com/VisualStudio/feedback/details/470485/strange-file-not-found-error-xml-documentation-file-renamed-during-incremental-build
REM As a work around for following script tries to catch this situation and copys/remanes
REM this tmp-file instead.
REM .SYNOPSIS
REM CopyXmlDocumentation "X:\path\to\source.xml" "Y:\target\dir"
if exist "%~1%" (
REM if the file exists, copy it as-is
copy /Y "%~1" "%~2"
) else (
REM else we try to copy the .tmp file and rename it to the desired target name
REM we assume that the tmp file is named "vsXXXX.tmp" where XXXX is an arbitrary string
copy /Y "%~d1\%~p1\vs*.tmp" "%~2\%~n1%~x1"
)

Related

copy +,, not working as expected: file is touched but also copied

In the pre-build event, VS2017, I added the following lines to "touch" my program so it would compile and get the date/time of compilation for my "build info" that is shown in my about infobox.
copy /b "$(ProjectDir)\MyAbout.cs"+,,
echo %date% %time% > "$(ProjectDir)\Resources\BuildDate.txt"
This has been working perfectly but I noticed I have a copy of "MyAbout.cs" in the binary directory where the executable resides. I was under the impression that the copy would not take place if no arguments were supplied.
Windows 10
The file is copied instead of touched if the destination directory does not match the source directory. The default destination is the current directory.
The solution is simple:
copy /b "$(ProjectDir)\MyAbout.cs"+,, "$(ProjectDir)"
or
pushd "$(ProjectDir)"
copy /b MyAbout.cs+,,
popd

failure multiple projects doing xcopy to same folder in visual studio

We have several projects that have a "templates" folder that all get copied to the same "templates" folder in our shared bin directory. Intermittently we get xcopy failures.
C:\Program Files (x86)\MSBuild\12.0\bin\Microsoft.Common.CurrentVersion.targets(4429,5): error MSB3073: The command "xcopy /s /y /r "E:\Source\DotNet\Service Providers\ActionScheduler\Templates" "E:\Source\DotNet\bin\x64\Release\Service Providers..\Templates\"" exited with code 4
These are post build steps that are being run in devenv.
I'm wondering if anyone has a suggestion to reduce or remove these errors.
Perhaps there is an alternative to xcopy which is more robust?
All of the templates folders that get copied have a subfolder "EN" and some files under that directory.
Additional information:
<message>98> Sharing violation</message>
<message>98> 0 File(s) copied</message>
<message>98> Unable to create directory - E:\Source\DotNet\bin\x64\Release\Templates</message>
<message>98>C:\Program Files (x86)\MSBuild\12.0\bin\Microsoft.Common.CurrentVersion.targets(4429,5): error MSB3073: The command "xcopy /s /y /r "E:\Source\DotNet\Service Providers\ActionScheduler\Templates" "E:\Source\DotNet\bin\x64\Release\Service Providers\..\Templates\"" exited with code 4.</message>
The error still occurred after adding /d. I also tried pre-creating the folder in a prebuild step of a project that would get build earlier. But I still got the following error:
98> Sharing violation
98> Unable to create directory - E:\Source\DotNet\bin\x64\Release\Templates
98> 0 File(s) copied
98>C:\Program Files (x86)\MSBuild\12.0\bin\Microsoft.Common.CurrentVersion.targets(4429,5): error MSB3073: The command "xcopy /s /y /r /d "E:\Source\DotNet\Service Providers\ActionScheduler\Templates" "E:\Source\DotNet\bin\x64\Release\Service Providers\..\Templates\"" exited with code 4.
You'll need to look in the Output window for a diagnostic message from XCopy when this error occurs. "Intermittent" is pretty hard to explain without that diagnostic.
There is certainly a good way to greatly reduce the chances for this going wrong. You are copying these files over and over again for no good reason. Add the /D option, that only copies when a file does not yet exist or has changed. So you basically only copy these files once and about never again, can't fail that way :)
After edit: yeah, that sure looks like two post-builds trying to copy the same file at the same time. Unlucky timing, anti-malware has a knack for extending it too long while it scans the file. You need to fix that, one is enough. With very high odds that /D already fixes it.
Code 4 means:
"Initialization error occurred. There is not enough memory or disk space, or you entered an invalid drive name or invalid syntax on the command line."
Is E:\Source\DotNet\bin\x64\Release\Service Providers..\Templates\
OK? dotdot???
If you have several projects building the same output named support files you could try to turn off parallel builds. MSDN link for setting this option
However this looks like a system wide setting an not just for that project. As a last resort you could attempt to stop the copying of the files for all but one project by setting the "Copy to Output Directory" to "Do not copy".
I had a very similar issue, from the MSDN documentation here we added the following switches. Im my case the I switch seemed to do the trick.
Xcopy /Y /I /S
https://technet.microsoft.com/en-us/library/cc771254.aspx

Why would a post-build step (xcopy) occasionally exit with code 2 in a TeamCity build?

A few projects in my client's solution have a post-build event: xcopy the build output to a specific folder. This works fine when building locally. However, in TeamCity, I occasionally get
xcopy [...] exited with code 2
If I use regular copy, it exits with code 1. I expect this has something to do with file locks, although the specific files being copied are not the same, so perhaps just locking on the shared destination directory. I use /y to not prompt on overwriting files.
Why this fails in TeamCity but not locally?
Even if you provide the /Y switch with xcopy, you'll still get an error when xcopy doesn't know if the thing you are copying is a file or a directory. This error will appear as "exited with code 2". When you run the same xcopy at a command prompt, you'll see that xcopy is asking for a response of file or directory.
To resolve this issue with an automated build, you can echo in a pre-defined response with a pipe.
To say the thing you are copying is a file, echo in F:
echo F|xcopy /y ...
To say the thing you are copying is a directory, echo in D:
echo D|xcopy /y ...
Sometimes the above can be resolved by simply using a copy command instead of xcopy:
copy /y ...
However, if there are non-existent directories leading up to the final file destination, then an "exited with code 1" will occur.
Remember: use the /C switch and xcopy with caution.
I fixed the error code 2 by adding a \ at the end of my path, without it, xcopy will think that it is a file instead of a folder.
If you are using xcopy in a post build event use the /Y switch in addition to the /C.
/C Continues copying even if errors occur.
/Y Suppresses prompting to confirm you want to overwrite an existing file.
My fix for this issue was to go into the target bin folder, and ensure that the proper subfolder exists there. Once that subfolder was manually created, the build process completed successfully.
copy fixed it for me. xcopy with /c /y did not work. I was getting an exit 4 so I went with xcopy, but turned out I needed quotes around ($TargetPath).
My script:
if $(ConfigurationName) == Debug copy "$(TargetPath)" "$(SolutionDir)\Folder\bin\Debug\$(TargetFileName)"
Probably you using TeamCity with git. If yes, check that folders you want to copy are exists in git repository. Usually git aviod adding empty project folders to repository, so xcopy fails to find it and generates a error.
You can add some empty text file to empty folder, commit and see folder appears in repository.

Is there a way of checking file availability in a DOS script?

Background: I have a post-build process that copies a file to another location. It looks like this:
copy $(TargetPath) "%programfiles%\mypath"
This step can fail if the another process is using the file. The step is not critical, so if possible I would like to ignore the failure. To do this I need the script to check to determine if the file is being used by another process.
Question: Is there a way of testing a file in a DOS script to determine if it is being used by another process?
You can see if the file exists, then rename a .dll/.exe even if it is being executed. Might want to do .pdb files, too.
IF EXIST $(TargetName).deleted del $(TargetName).deleted
IF EXIST $(TargetName).pdb.deleted del $(TargetName).pdb.deleted
IF EXIST "%programfiles%\mypath\$(TargetName)$(TargetExt)" REN "%programfiles%\mypath\$(TargetName)$(TargetExt)" $(TargetName).deleted
IF EXIST "%programfiles%\mypath\$(TargetName)$(TargetExt)" REN "%programfiles%\mypath\$(TargetName)$.pdb" $(TargetName).pdb.deleted
copy $(TargetPath) "%programfiles%\mypath"
Ok, so I needed to check the errorlevel after performing the copy, so that I could handle the exit properly. The solution is below:
copy $(TargetPath) "%programfiles%\mypath"
if errorlevel 1 goto BuildProcessFailed
goto BuildProcessOK
:BuildProcessFailed
echo BUILDPROCESS FAILED FOR PROJECT $(ProjectName)
goto ExitBuildProcess
:BuildProcessOK
echo BUILDPROCESS OK FOR PROJECT $(ProjectName)
:ExitBuildProcess

batch file to merge .js files from subfolders into one combined file

I'm struggling to get this to work. Plenty of examples on the web, but they all do something just slightly different to what I'm aiming to do, and every time I think I can solve it, I get hit by an error that means nothing to me.
After giving up on the JSLint.VS plugin, I'm attempting to create a batch file that I can call from a Visual Studio build event, or perhaps from cruise control, which will generate JSLint warnings for a project. The final goal is to get a combined js file that I can pass to jslint, using:
cscript jslint.js < tmp.js
which would validate that my scripts are ready to be combined into one file for use in a js minifier, or output a bunch of errors using standard output.
but the js files that would make up tmp.js are likely to be in multiple subfolders in the project, e.g:
D:\_projects\trunk\web\projectname\js\somefile.debug.js
D:\_projects\trunk\web\projectname\js\jquery\plugins\jquery.plugin.js
The ideal solution would be to be able to call a batch file along the lines of:
jslint.bat %ProjectPath%
and this would then combine all the js files within the project into one temp js file. This way I would have flexibility in which project was being passed to the batch file.
I've been trying to make this work with copy, xcopy, type, and echo, and using a for do loop, with dir /s etc, to make it do what I want, but whatever I try I get an error.
You could create a batch file with the following contents:
#echo off
pushd "%~1"
for /r %%x in (*.js) do (
type "%%~x"
)
popd
and then run it via:
jslint.bat PATH > tmp.js
If you don't want to use redirection, you can try:
#echo off
pushd "%~1"
echo.>tmp.js
for /r %%x in (*.js) do (
copy tmp.js + "%%~x" tmp.js > NUL
)
popd
note that for simplicity, I haven't bothered doing any error-checking (e.g. checking whether an argument is supplied (although if one isn't, it'll just use the current directory), testing that tmp.js doesn't already exist, etc.).
A great place for tips on batch files is DosTips.com
Have a look at http://nefariousdesigns.co.uk/archive/2010/02/website-builds-using-make/
The post is written for Linux world but still you might be able to salvage something out of it.

Resources