How do I handle CMake.exe errors - batch-file

I have a batch file that starts CMake.exe with some arguments and I need to break the execution if there were any errors in CMake (that's a part of product build process). The problem is that %ERRORLEVEL% from CMake.exe process seems to be always is 0 whereas stadard error output might contain errors such as
...
-- Configuring done
CMake Error at CMakeConfigs/My.cmake:77 (add_library):
Cannot find source file:
Resources/ActionIcons/ActionIcon_ABC.png
Tried extensions .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp
.hxx .in .txx
Call Stack (most recent call first):
My/Path/CMakeLists.txt:149 (my_add_target)
-- Generating done
...
I plan to dump standard error output to a file and grep/findstr error, but can error handling be done more elegantly?
Thanks.

The most often mistake is using %ERRORLEVEL% in a command block starting with ( and ending with matching ).
The entire command block is preprocessed by Windows command interpreter before running any command in the command block or the IF or FOR command usually used on line with opening (. During this preprocessing all %variable% references are replaced by current values of the referenced environment variables. Then the command block is executed with the preprocessed code.
This behavior can be seen by removing #echo off at top of the batch file, or modify it to #echo on or rem #echo off and run the batch file from within a command prompt window. Now Windows command interpreter outputs to console window every command line and command block after preprocessing as really executed next.
The help of command SET output on running set /? in a command prompt window explains on an IF and a FOR example how to reference an environment variable within a command line or command block modified in same command line or command block on execution using delayed environment variable expansion.
But for this case there is no need for %ERRORLEVEL% expanded during preprocessing phase or delayed expanded using !ERRORLEVEL! at all.
There is the good old IF ERRORLEVEL X ... syntax working since MS-DOS up to currently latest Windows 10.
CMake exits with exit code 0 on success and a greater number on error as nearly all console applications.
IF ERRORLEVEL X ... means IF exit code (return value of function main) assigned to environment variable ERRORLEVEL is greater or equal X THEN ...
Then I suggest to look on:
What are the ERRORLEVEL values set by internal cmd.exe commands?
Which cmd.exe internal commands clear the ERRORLEVEL to 0 upon success?
A successful IF does not modify value of ERRORLEVEL. And EXIT /B without a number also does not modify ERRORLEVEL.
So on next line after the command line running CMake there is only this command line needed to exit the processing of current batch file and return to calling batch file or process on any error encountered by CMake:
if errorlevel 1 exit /B
The calling batch file or process gets the exit code of CMake as a result of the batch file execution because IF and EXIT don't modify ERRORLEVEL in this case. It's really so easy!

Related

Batch file variable substitution

I was trying this (very rudimentary) command in a batch file
takeown.exe /F c:\WINDOWS\SYSTEM32\%1%
ICACLS C:\WINDOWS\SYSTEM32\%1% /grant MY\PC:F
And when I run it from an admin CMD prompt as:
c:\Data>takeownscript.bat drivers\netbio.sys
It throws an error saying:
c:\Data>takeown.exe /F c:\WINDOWS\SYSTEM32\drivers\netio.sys
SUCCESS: The file (or folder): "c:\WINDOWS\SYSTEM32\drivers\netio.sys"
now owned by user "MY\PC".
c:\Data>ICACLS C:\WINDOWS\SYSTEM32\drivers\netio.sysF
C:\WINDOWS\SYSTEM32\drivers\netio.sysF: The system cannot find the
file specified. Successfully processed 0 files; Failed processing 1
files
How/why is the F getting appended to the driver path ? I am suspecting that I am not using the correct replacement syntax.
Just to finish up so the community knows there is an answer.
Command-line arguments are used as %n(n represents which argument) in a batch file.
Another thing for precaution is that one should use %~1 at all times. %~1 strips off quotes from %1. Note that this won't work: %~yourVariable%.

CMD file will not run my command in the else block

I'm writing a CMD script to execute a Java program. The program requires at least one argument so I created an if else block to check that argument one %1 is not blank. When I run the script without providing argument one I get the expected you must provide an argument to run. But when I do provide the argument the program does not execute. Additionally if I don't have #echo off set, the entire script prints out as text in the window when I do provide the proper argument.
Here's the full script:
set APP_HOME=C:\Temp\Hammer
rem Set APP_HOME to the place where you installed Hammer
if ["%1"] == [""] (
echo you must provide a python script to run
) else (
java -cp %APP_HOME%\lib\jython.jar;%APP_HOME%\lib\hammer.jar;%CLASSPATH% bridenstine.hammer.main.Main %1 %2
)
I think this is a problem with the script and not the program itself because when I run the line that's in the else block by itself without the script,
java -cp C:\Temp\Hammer\lib\jython.jar;C:\Temp\Hammer\lib\hammer.jar;%CLASSPATH% bridenstine.hammer.main.Main argument1
The program executes normally. I've been looking at example scripts and cross referencing this site for CMD files and what I have seems to be valid. Do I have a syntax error?
Update:
I'm running the script like so,
cd C:\Temp\Hammer
bin\ProgramScript.cmd argument1
Update 2:
Someone pointed out that when they run this script they get an error message saying Java is not recognized as an internal or external command (the expected message when Java is not set on their PATH) But they made a good point that this means the script is in fact getting inside the else block. I then pointed out the following,
After I run the script with a valid argument it prints out the entire script as text on the command prompt. I am then able to mark the line from inside the else statement (that was printed), copy it, paste it, and it runs the program fine. So the Java command seems to be valid. But you make a good point that the script is obviously getting inside the else block...something is still going wrong here and it doesn't seem to be the program.
Note:
If relevant I am using Windows 8.1 and I am using the standard command prompt, not one that has administrative privileges (the results remained the same regardless of using a command prompt with administrative privileges).
I suggest to use
set APP_HOME=C:\Temp\Hammer
rem Set APP_HOME to the place where you installed Hammer.
if "%~1"=="" (
echo You must provide a Python script to run.
pause
) else (
java.exe -cp "%APP_HOME%\lib\jython.jar;%APP_HOME%\lib\hammer.jar;%CLASSPATH%" bridenstine.hammer.main.Main %*
)
It is always better to enclose an argument string in double quotes if it contains environment variables like CLASSPATH which might have a string value containing 1 or more spaces.
%* is expanded by all arguments passed to the batch file as argument, i.e. %1 %2 ...
It is best to always specify an application like java with full path and file extension as otherwise Windows has to search for a file with a file extension as defined in environment variable PATHEXT in current working directory and all directories defined in environment variable PATH. At least the file extension should be in the batch file if the program files directory of the application varies.
I can only offer a suggestion; I've not tried this.
I would try escaping each ; with a caret ^ thus:
java -cp %APP_HOME%\lib\jython.jar^;%APP_HOME%\lib\hammer.jar^;%CLASSPATH% bridenstine.hammer.main.Main %1 %2
(But I'll admit it's clutching at straws...)
You are missing you she-bang at the top of the script
#!/bin/bash

Batch command exit

I have to rewrite an old Batch file into Powershell script.
one line is
directory1\nunit-console.exe file1.dll /xml:results.xml
exit %%ERRORLEVEL%%
I am a bit confused about the "exit %%ERRORLEVEL%%" bit
Normally, just type in command line >>exit and enter. It will shut the screen.
What does %%ERRORLEVEL%% bit mean?
thanks
In "DOS" shells (i.e. COMMAND.COM, CMD.EXE), variables are defined as %VAR%. %ERRORLEVEL% represents the return value of the last-executed command; it is like $? in Bash or Perl.
In this case, exit %%ERRORLEVEL%% appears to be an attempt to exit the batch script with the return value from the call to nunit-console.exe. (This script looks quite old, as both exit and the need for double-percent symbols has changed slightly between MS-DOS and the later shells in Windows 2000 and later.)
See this page for a discussion of how exit is used in the various shell versions.
This MS KB article talks about using the % character in batch files. It was written for MS-DOS, but most of the same principles apply to later shells.

Jenkins always considers a build successful using batch/bat

I just joined a company that uses batch files to build a C++ project. The batch does all sorts of things (updates svn, which is now done by jenkins), creates build folders, deletes unnecessary files after building, copies library files to the build folder, etc.
My problem is Jenkins always considers the build successful, even when it´s not. The .bat file creates a file called errormake.txt when something goes wrong. How do I make jenkins read that and mark the build as a failure?
Also, is there any way I can find out the build folder Jenkins created from inside the .bat file (maybe send a variable when I call the batch file)?
This is the single line I'm currently using to call the .bat file:
call "C:\Source\BuildVersion\AppName\build_version.bat"
Edit: Also, this project is split up into several SVN repositories. %SVN_REVISION% is blank. How can I get the correct %SVN_REVISION% from the first repository (the main one)?
To answer each of your questions -
Jenkins always return "SUCCESS", even when the Job actually failed:
Jenkins sets the status of the Job, based on the return-code of the last command
that ran in each "Execute windows batch command" block.
If your last command is copy some.log D:,
Jenkins thinks everything is OK
(If the 'copy' command went fine...)
Use EXIT xx or EXIT /B xx, depending on your OS,
where 'xx' is some integer greater than zero.
How do I make Jenkins mark the build as a failure, based on a log-file:
Use the Text-finder Plugin, as mentioned by sdmythos_gr .
Is there any way I can find out the build folder Jenkins created:
There are a few parameters that are available as environment-variables
for each script that runs under Jenkins - see here for the list of those parameters:
Jenkins Environment Variables.
To your question:
%WORKSPACE% - The absolute path of the workspace
%BUILD_NUMBER% - The current build number, such as "153"
%BUILD_ID% - The current build id, such as "2005-08-22_23-59-59"
(YYYY-MM-DD_hh-mm-ss)
How can I get the correct %SVN_REVISION% from the first repository:
This answer is from the same link:
%SVN_REVISION% - For Subversion-based projects,
this variable contains the revision number of the module.
If you have more than one module specified, this won't be set.
Hope that helps
Jenkins use the windows error code to know whether a build failed or not.
You should return a value different from 0 when your build failed, with "exit /B 1" for example.
On "newer" versions of Windows (I tested on Server 2012 R2), put the following at the end of each Windows batch command:
#EXIT /b %ERRORLEVEL%
This will pass the error code that the cmd.exe received back to the caller (i.e. Jenkins). The "#" turns off echoing so you don't clutter up your log.
If you have multiple lines in the command and want to stop after the first failure, put the following after each line that you want to check (yes, this is not pretty):
#IF NOT %ERRORLEVEL% == 0 EXIT /b %ERRORLEVEL%
For example:
step1.exe
#IF NOT %ERRORLEVEL% == 0 EXIT /b %ERRORLEVEL%
step2.exe
#IF NOT %ERRORLEVEL% == 0 EXIT /b %ERRORLEVEL%
call "C:\Source\BuildVersion\AppName\build_version.bat"
#EXIT /b %ERRORLEVEL%
I'm also going to answer just part of your question.
There is a Text Finder plugin for Jenkins that you could use.
https://wiki.jenkins-ci.org/display/JENKINS/Text-finder+Plugin
You can mark the build as unstable or failed at the end of the build depending on the contents of a file or the console output.
Maybe this could help...
I know the question is quite older but may be useful to some people. To execute your bat file, instead of using following line,
call "C:\Source\BuildVersion\AppName\build_version.bat"
You can use below format,
<someRelativeOrAbsolutePath>\<.batFileName> <param1> <param2> <and so on>
Executing the command in this way inside Execute Windows Batch Command of Build section of Jenkins will use your last return code of the command. ${BUILD_STATUS} will depend on that. And you will not have to modify your script to return some condition based error codes.
As other users have stated your batch files should use "exit /B 1". Here is a trick to chain together your calls causing Jenkins to return a failure if one fails:
call a.bat &&^
echo "a success" &&^
call b.bat &&^
echo "b success"
"&&" denotes that the next action should only run on success (exit code 0). "^" lets us split the command into multiple lines. The downside to this approach is the build progress bar doesn't display accurately.

DOS CMD send failure to Autosys

In Autosys, I have a job that executes a fairly simple DOS batch file (.CMD). How do I communicate back to Autosys if the job has conditionally failed? If it runs and terminates, Autosys reports a success no matter what. I would like to programmatically tell Autosys if the script failed based on conditions determined within.
Any help would be appreciated. Thanks in advance.
You can use ERRORLEVEL, open a DOS box and type 'help if'
These bits are relevant:
C:\help if
Performs conditional processing in batch programs.
IF [NOT] ERRORLEVEL number command
IF [NOT] string1==string2 command
IF [NOT] EXIST filename command
NOT Specifies that Windows should carry out
the command only if the condition is false.
ERRORLEVEL number Specifies a true condition if the last program run
returned an exit code equal to or greater than the number
specified.
%ERRORLEVEL% will expand into a string representation of
the current value of ERRORLEVEL, provided that there is not already
an environment variable with the name ERRORLEVEL, in which case you
will get its value instead. After running a program, the following
illustrates ERRORLEVEL use:
goto answer%ERRORLEVEL%
:answer0
echo Program had return code 0
:answer1
echo Program had return code 1
What you need to do is the last line of your .bat file should say the following:
EXIT /B %ErrorLevel%

Resources