Generating an installer using CMake + CPack + Wix - windows

Summary:
How to generate Wix installer with CMake/CPack?
Details:
I am trying to generate an installer out from a project that uses Wix, but apparently, cmake/cpack insist to use nsis, for example, from the repo https://github.com/ngladitz/cmake-wix-testsuite
I picked the first example "basic" folder with the following contents for CMakeLists.txt
add_executable(hw hw.cpp)
install(TARGETS hw DESTINATION bin)
install(FILES hw.cpp DESTINATION src)
set(CPACK_WIX_UPGRADE_GUID "F9AAAAE2-D6AF-4EA4-BF46-B3E265400CC7")
include(CPack)
After generating the cmake:
cd <basic-root-folder>
mkdir MY_BUILD
cd MY_BUILD
cmake ..
I tried to run the package.vcxproj generated with
msbuild package.vcxproj
and got the error
"C:\src\Samples\CPack\cmake-wix-testsuite-master\basic\MY_BUILD\PACKAGE.vcxproj
" (default target) (1) ->
(PostBuildEvent target) ->
EXEC : CPack error : Cannot find NSIS compiler makensis: likely it is not ins
talled, or not in your PATH [C:\src\Samples\CPack\cmake-wix-testsuite-master\ba
sic\MY_BUILD\PACKAGE.vcxproj]
So it looks like it insist in using the NSIS generator.

Simply add following line before include(CPack)
set(CPACK_GENERATOR WIX)

You can also do this:
cmake ..
cpack -G WIX
By default, CPack uses the NSIS Generator on Windows.

Ok, I found how
By specifying the CPack generator like
cmake -DCPACK_GENERATOR=WIX ..
Then running
msbuild package.vcxproj
Invokes wix like this extract from the log (and a bunch of .wixobj files)
PostBuildEvent:
setlocal
cd C:\src\Samples\CPack\cmake-wix-testsuite-master\basic\MY_BUILD.wix
if %errorlevel% neq 0 goto :cmEnd
C:
if %errorlevel% neq 0 goto :cmEnd
"C:\Program Files (x86)\CMake 3.1.3\bin\cpack.exe" -C Debug --config ./CPackC
onfig.cmake
if %errorlevel% neq 0 goto :cmEnd
:cmEnd
endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone
:cmErrorLevel
exit /b %1
:cmDone
if %errorlevel% neq 0 goto :VCEnd
:VCEnd
CPack: Create package using WIX
CPack: Install projects
CPack: - Install project: Project
CPack: Create package
CPack: - package: C:/src/Samples/CPack/cmake-wix-testsuite-master/basic/MY_BU
ILD.wix/Project-0.1.1-win32.msi generated.
FinalizeBuildStatus:
Deleting file "Win32\Debug\PACKAGE\PACKAGE.tlog\unsuccessfulbuild".
Touching "Win32\Debug\PACKAGE\PACKAGE.tlog\PACKAGE.lastbuildstate".
Done Building Project "C:\src\Samples\CPack\cmake-wix-testsuite-master\basic\MY
_BUILD.wix\PACKAGE.vcxproj" (default targets).
Build succeeded.
0 Warning(s)
0 Error(s)
Also the .wix source files are generated at C:\src\Samples\CPack\cmake-wix-testsuite-master\basic\MY_BUILD.wix\\_CPack_Packages\win32\WIX
I found out about this arg (CPACK_GENERATOR) by inspecting CPackConfig.cmake generated by the original cmake.

Related

CGAL - building INSTALL .sln faild

I have a problem while compiling CGAL I followed the steps here : http://www.cse.msu.edu/~ytong/CGAL_installation.ppt
I'm using VS2013 , cgal 4.9.1 , BOOST 1.59.0 ,Qt5.7.1
but when I reach at building INSTALL .sln step it show the following error:
Error 1 error MSB3073: The command "setlocal
"C:\Program Files\CMake\bin\cmake.exe" -DBUILD_TYPE=Debug -P cmake_install.cmake
if %errorlevel% neq 0 goto :cmEnd
:cmEnd
endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone
:cmErrorLevel
exit /b %1
:cmDone
if %errorlevel% neq 0 goto :VCEnd
:VCEnd" exited with code 1. C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\Microsoft.CppCommon.targets 132 5 INSTALL
output message :
file INSTALL cannot find
1> "C:/dev/CGAL-4.9.1/build/bin/Debug/CGAL-vc120-mt-gd-4.9.1.dll".
1> Call Stack (most recent call first):
1> src/cmake_install.cmake:32 (include)
1> cmake_install.cmake:91 (include)
any help please?
Please use CGAL 4.12 and use installation instructions given on www.cgal.org

[Jenkins]Build c++ solution file using devenv.com

I have a VS2008 solution file named MySolution.sln containing three projects ProjectName1, ProjectName2, ProjectName3 and ProjectName4. I am using jenkins to build the solution(to built only ProjectName1/2/3 and not ProjectName4). Below is the batch which has been provided to jenkins.
The issue is whenever lets say, the statement "%VSDIR%\devenv.com" "MySolution.sln" /Build "Release|x64" /Project ProjectName1 failed to build the particular project my %errorlevel% is not updated to non negative integer (>0). Irrespective of pass/fail the %errorlevel% is always "0"
The way jenkins calls this is
cmd /c call C:\Users\John\AppData\Local\Temp\hudson343434346343.bat
Any ideas on this?
Batch script:
#ECHO OFF
set VSDIR=C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE
"%VSDIR%\devenv.com" "MySolution.sln" /Clean "Release|x64"
"%VSDIR%\devenv.com" "MySolution.sln" /Build "Release|x64" /Project ProjectName1
IF %ERRORLEVEL% EQU 0 (
"%VSDIR%\devenv.com" "MySolution.sln" /Build "Release|x64" /Project ProjectName2
IF %ERRORLEVEL% EQU 0 (
"%VSDIR%\devenv.com" "MySolution.sln" /Build "Release|x64" /Project ProjectName3
IF %ERRORLEVEL% EQU 0 (
) ELSE (
echo "Failed to build ProjectName3"
)
) ELSE (
echo "Failed to build ProjectName2"
)
) ELSE (
echo "Failed to build ProjectName1"
)
unset VSDIR
just use MSBuild plug-in. You are all set.
I have several suggestions to make this simpler and more reliable.
You do not need to do a separate call to devenv.com in order to do a /Clean. Simply replace the /Build command in subsequent devenv.com calls with /Rebuild, which will clean before building from scratch.
After each call to devenv.com immediately do:
if ERRORLEVEL 1 echo Error building Solution X & goto some-label
This will detect any ERRORLEVEL of 1 or higher. This approach will not require any parentheses or ELSE clauses, and avoid the need to nest the subsequent IF statements.
You can also build the 3 (out of 4) projects with a single devenv.com call. This would require you to specify a solution build configuration that excludes (skips) the fourth project. For example:
"%VSDIR%\devenv.com" "MySolution.sln" /Rebuild "Release-Jenkins|x64"
The above approach requires first loading the solution in the Visual Studio IDE, going into the Configuration Manager, and creating a new solution build configuration (based on a copy of the existing Release build configuration). Name the new solution build configuration Release-Jenkins (or whatever), then make sure the project you wish to exclude is unchecked for each of the variations of Win32/x64/AnyCPU. Also, be sure to UNCHECK the checkbox to Create new project configurations, as you do not require any new project configurations. Also create a corresponding solution build configuration for Debug builds, i.e. Debug-Jenkins.
The unset command works in bash, but not for cmd.exe shells. To undefine the variable, do:
set VSDIR=
with nothing following the = sign. Or even better, add the command SETLOCAL on its own line immediately after #ECHO OFF. The SETLOCAL statement will ensure any environment variable changes are discarded when the batch file exits.

Folder operation in .bat is unstable?

I write a .bat to automate generating and compiling a cmake project. The batch file will
optional rmdir build
mkdir build if not exist
cd build
cmake .. generate a nmake project from upper folder
nmake compile project
the source:
#ECHO OFF
set "OpenCV_LIB=C:\Program Files (x86)\OpenCV2.1"
echo !! OpenCV Library: [ %OpenCV_LIB% ]
IF NOT EXIST "%OpenCV_LIB%" (
echo Can't find OpenCV Library, please change OpenCV_LIB setting
GOTO END
)
if %PROCESSOR_ARCHITECTURE%==x86 set BUILD_ARCH=x86
if %PROCESSOR_ARCHITECTURE%==AMD64 set BUILD_ARCH=x86_amd64
if %PROCESSOR_ARCHITECTURE%==IA64 set BUILD_ARCH=x86_IPF
echo !! Target architecture [ %BUILD_ARCH% ]
call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" %BUILD_ARCH%
cd "sikuli-script"
set /p answer=Do you want to make clean first? (Y/N):
if %answer% == Y ( IF EXIST build rmdir /s /q build )
if %answer% == y ( IF EXIST build rmdir /s /q build )
IF NOT EXIST build mkdir build
cd build
IF NOT EXIST CMakeCache.txt ( cmake -G "NMake Makefiles" -D CMAKE_BUILD_TYPE=Release -D "OpenCV_DIR=%OpenCV_LIB%" .. )
nmake
:END
pause
After i run this .bat over and over, i notice that cd build failed sometimes, so i change my code to test it:
#ECHO ON
set /p answer=Do you want to make clean first? (Y/N):
if %answer% == Y ( IF EXIST build rmdir /s /q build )
if %answer% == y ( IF EXIST build rmdir /s /q build )
:DO_MKDIR_CD
IF NOT EXIST build mkdir build
cd build
if errorlevel 1 (
pause
GOTO DO_MKDIR_CD
)
It comes out the error happens every time choose to clean up build, even the build is at small size (e.g. after interrupted compiling, size 3.08 MB, 183 files, 67 dirs).
!! OpenCV Library: [ C:\Program Files (x86)\OpenCV2.1 ]
!! Target architecture [ x86_amd64 ]
Setting environment for using Microsoft Visual Studio 2010 x64 cross tools.
D:\repo\sikuli>cd "sikuli-script"
D:\repo\sikuli\sikuli-script>set /p answer=Do you want to make clean first? (Y/N):
Do you want to make clean first? (Y/N):y
D:\repo\sikuli\sikuli-script>if y == Y (IF EXIST build rmdir /s /q build )
D:\repo\sikuli\sikuli-script>if y == y (IF EXIST build rmdir /s /q build )
D:\repo\sikuli\sikuli-script>IF NOT EXIST build mkdir build
D:\repo\sikuli\sikuli-script>cd build
Access is denied.
D:\repo\sikuli\sikuli-script>if errorlevel 1 (
pause
GOTO DO_MKDIR_CD
)
Press any key to continue . . .
So every time after remove and recreate build, the cd build fails, then cmake start messing up my source tree.
The error check and loop trying could fix this problem, but why is the file system not stable? or am i writing it in a wrong way?
That build directory check:
IF NOT EXIST build mkdir build
Will create the directory if both directory and file named "build" are not exist.
One way to check a directoy existence is:
if exist build\nul echo directory exist
If you want to make sure a directory exist use:
if not exist build\nul mkdir build
or better:
if not exist build\nul (
mkdir build
if not exist build\nul (
echo mkdir failed
goto :eof
)
)

How to find Windows SDK's SetEnv.cmd / SetEnv.cmd Does not work correctly

We have a Team City Build Server running and want to compile a Visual C++ project. So far this would be easy, since I've setup our Windows Build Agent with the Windows SDK, but we don't have a solution / project file.
The project files are instead created with CMake. CMake seems to be a little bit dumb (can't generate Solution when Visual Studio is not installed), but with some tricks, I could get it to do it. The solution can then be built with MSBuild.
And here comes the problem. For this to work automatically, I need to call the Windows SDK's SetEnv.cmd. And I can't seem to find it automatically. It's in the bin sub directory of the Windows SDK, but neither bin nor the root are in the path, and the %mssdk% environment variable is set by the SetEnv.cmd and is not available beforehand!
Adding the Windows SDK\bin dir to the PATH leads to SetEnv.cmd no longer working (exits with a message like The x86 compilers are not currently installed and Jump target Set_x86 not found.
The start menu link is calling the SetEnv.cmd with the Windows SDK dir as working directory instead. But if I add the root directory to the PATH, Bin\SetEnv.cmd is not available.
How can I find SetEnv.cmd automatically? Even setting an environment variable to the full path of the setenv.cmd doesn't work, and when I define %mssdk% as the sdk dir, then call %mssdk%\bin\SetEnv doesn't work as well. I also tried to define %mssdk%, then cd %mssdk%, then calling bin\SetEnv. Also compilers not found in all these cases. It also doesn't work if I manually cd to the root or bin dir on a command line and then call SetEnv.cmd...
The start menu link works fine though.
For the record, my solution for now, as strange as this is, is the following:
I created a MSBuild file that creates the solution file with CMake on the command line, then invokes the created solution with a MSBuild task. The MSBuild file can be easily built from TeamCity, though I needed some additional tricks to satisfy CMake's stupid looking for the compiler, though I won't invoke it thing. Not really satisfying, but it works.
My solution (sets %WindowsSdkPath%, so that SetEnv.cmd could be found under %WindowsSdkPath%Bin\):
#ECHO OFF
IF "%WindowsSdkVersion%"=="" (
CALL :SetWindowsSdkVersionHelper HKCU > nul 2>&1
IF ERRORLEVEL 1 CALL :SetWindowsSdkVersionHelper HKLM > nul 2>&1
IF ERRORLEVEL 1 GOTO ERROR_NOWSDK
)
CALL :SetWindowsSdkPathHelper > nul 2>&1
IF ERRORLEVEL 1 GOTO ERROR_NOWSDK
GOTO END
:SetWindowsSdkPathHelper
SET WindowsSdkPath=
FOR /F "tokens=1,2*" %%i in ('REG QUERY "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\%WindowsSdkVersion%" /V InstallationFolder') DO (
IF "%%i"=="InstallationFolder" (
SET "WindowsSdkPath=%%k"
)
)
IF "%WindowsSdkPath%"=="" EXIT /B 1
EXIT /B 0
:SetWindowsSdkVersion
CALL :GetWindowsSdkVersionHelper HKCU > nul 2>&1
IF ERRORLEVEL 1 CALL :GetWindowsSdkVersionHelper HKLM > nul 2>&1
IF ERRORLEVEL 1 EXIT /B 1
EXIT /B 0
:SetWindowsSdkVersionHelper
SET WindowsSdkVersion=
FOR /F "tokens=1,2*" %%i in ('REG QUERY "%1\SOFTWARE\Microsoft\Microsoft SDKs\Windows" /V "CurrentVersion"') DO (
IF "%%i"=="CurrentVersion" (
SET "WindowsSdkVersion=%%k"
)
)
IF "%WindowsSdkVersion%"=="" EXIT /B 1
EXIT /B 0
:ERROR_NOWSDK
ECHO The Windows SDK %WindowsSdkVersion% could not be found.
EXIT /B 1
:END
I was inspired for this by the SetEnv.cmd itself...
Mac, nice answer!
Now I would like to run msbuild with my project file. But before I should run SetEnv.Cmd - right?
So, here we go:
run_Macs_code.bat REM see above
call "%WindowsSdkPath%\bin\Setenv.cmd" /Release /x86 /xp
cd E:\client
msbuild client.proj
Now it's working :)

Visual Studio, MS Build

I am trying to build multiple .sln files inside a batch file. Everything works great so far. I am trying to add a check inside the batch file, so if number of errors is greater than 0 then the batch file stops executing and doesn't build the next .sln files. How can I do that? Basically something like:
msbuild test.sln
(check if build error > 0
stop)
msbuild test2.sln
MSBUILD will set the ERRORLEVEL, so something along the lines of:
msbuild test.sln
IF NOT ERRORLEVEL 0 exit 1
Edit: Apparently it should be:
msbuild test.sln
IF ERRORLEVEL 1 exit 1
msbuild.exe test.sln
if errorlevel 1 goto :errors
msbuild.exe test2.sln
if errorlevel 1 goto :errors
:: ...
:: Everything was fine.
echo Build completed without errors.
goto :eof
:error
echo Build failed.
In my opinion it's much easier to use a custom msbuild file here and use the msbuild task with your set of solutions. See here for the details.

Resources