How to create an installer with CMake + CPack + NSIS on Windows? - c++

I'd like to create a cross-platform installer for a C++ based system I am building.
I use CMake to build everything, and it would be great if I could use CPack to make the installer. I already have CPack working on OSX, but I cannot get it to work on Windows. To make things easier, I tried to get the example at http://www.cmake.org/Wiki/CMake:Packaging_With_CPack to work with the NSIS installer software. I cannot find the NSIS installer anywhere after configuring (with VS 2010 Win64 generator).
Maybe I am confused, but I thought it would be possible to create the installation package with only the source, CMake, CPack, and NSIS without any need for Visual Studio. Is this possible?
A link to a full tutorial (the one at http://www.cmake.org/Wiki/CMake:Component_Install_With_CPack skips over the relevant information to get NSIS working and doesn't mention generators or compilers) would be very helpful, or a basic explanation of how I can get to this mythical generated NSIS installer would be great.
Here is CMakeLists.txt for the example above:
cmake_minimum_required(VERSION 2.6.0 FATAL_ERROR)
project(StPMS)
add_library(mylib mylib.cpp)
add_executable(mylibapp mylibapp.cpp)
target_link_libraries(mylibapp mylib)
install(TARGETS mylib
ARCHIVE
DESTINATION lib
COMPONENT libraries)
install(TARGETS mylibapp
RUNTIME
DESTINATION bin
COMPONENT applications)
install(FILES mylib.h
DESTINATION include
COMPONENT headers)
set(CPACK_GENERATOR NSIS)
set(CPACK_PACKAGE_NAME "MyLib")
set(CPACK_PACKAGE_VENDOR "CMake.org")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "MyLib - CPack Component Installation Example")
set(CPACK_PACKAGE_VERSION "1.0.0")
set(CPACK_PACKAGE_VERSION_MAJOR "1")
set(CPACK_PACKAGE_VERSION_MINOR "0")
set(CPACK_PACKAGE_VERSION_PATCH "0")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "CPack Component Example")
SET(CPACK_NSIS_MODIFY_PATH ON)
INCLUDE(CPack)

... I thought it would be possible to create the installation package with only the source, CMake, CPack, and NSIS without any need for Visual Studio. Is this possible?
Kind of. It depends on what you mean by "without any need for Visual Studio". You need a build tool to actually create the lib and exe. On Windows, you need something like Visual Studio's msbuild, especially if you specified "Visual Studio 10 Win64" as the generator.
If you mean "without running Visual Studio", then the answer is yes. You can have CMake execute your chosen build tool using the --build argument.
After running CMake, you end up with a file PACKAGE.vcxproj in your build directory. It is building this which will create the installer. You can either build the PACKAGE project from inside Visual Studio, or you can invoke msbuild directly by doing:
msbuild /P:Configuration=Release PACKAGE.vcxproj
from your build directory in a VS command prompt.
This should yield your installer named MyLib-1.0.0-win64.exe, also in your build directory.
If you want to just use CMake, then an alternative to invoking msbuild is:
cmake --build . --target PACKAGE.vcxproj --config Release
Or you can build the solution first, then invoke CPack to create the installer:
cmake --build . --config Release
cpack -C Release

Related

How to install a cpp library using cmake on Windows x64?

I'm using CLion with MinGW-GCC on the Windows-x64 platform - This is the background of the problem.
I was trying to install gtest before. But a lot of confusion arose in the middle.
First time I ran those commands(in googletest-release-1.12.1\) according to the instructions of googletest-release-1.12.1\googletest\README.md:
mkdir build
cd build
cmake ..
But I got error messages like:
CMake Error at CMakeLists.txt:51 (project):
Failed to run MSBuild command:
C:/Windows/Microsoft.NET/Framework/v4.0.30319/MSBuild.exe
to get the value of VCTargetsPath:
Then I changed my last command to
cmake -G "MinGW Makefiles" ..
because I use make provided by MinGW. I don't know whether it's right but, it ran properly.
then I called
make
make install
make ran smoothly. But when I ran make install, I got these messages:
Install the project...
-- Install configuration: ""
-- Installing: C:/Program Files (x86)/googletest-distribution/include
CMake Error at googlemock/cmake_install.cmake:41 (file):
file INSTALL cannot make directory "C:/Program Files
(x86)/googletest-distribution/include": No such file or directory.
Call Stack (most recent call first):
cmake_install.cmake:42 (include)
make: *** [Makefile:109: install] Error 1
I have no idea at all this time. So I changed my way. According to this answer, I copied the whole library into my project and edited CMakeLists.txt like this:
cmake_minimum_required(VERSION 3.23)
project(gtest_study)
set(CMAKE_CXX_STANDARD 20)
add_subdirectory(googletest-release-1.12.1)
include_directories(googletest-release-1.12.1/googletest/include)
include_directories(googletest-release-1.12.1/googlemock/include)
add_executable(gtest_study main.cpp)
target_link_libraries(gtest_study gtest gtest_main)
target_link_libraries(gtest_study gmock gmock_main)
So my questions are:
Is there any difference between the two which build it using make and cmake metioned firstly, and just use commands like include_directories and target_link_libraries in CMakeLists.txt? (maybe like .h and .dll file? Or just completely the same? I don't know)
When I use make install to install a library on Windows, what should I do in particular? Specify some directory (I don't know which one) or what?
Although in my system environment I use MinGW-makefile, in CLion which the libraries are eventually used, I use ninja as the generator for CMake (it just comes with CLion, not installed for the system). Do I have to specify it and how? (-G "Ninja"doesn't work in my native env)
The difference between
cmake ..
and
cmake -G "MinGW Makefiles" ..
Is the choice of generator: The former uses the default generator, the latter uses the generator you specified. (cmake --help should put a * next to the default generator.)
Based on the error message I assume this is a visual studio generator and you may not be able to run that one properly from within a MinGW terminal.
In the latter case the default install directory seems to be based on the target OS (Windows) but does not seem to incorporate the fact that you're running from a MinGW terminal where the default install path (C:/Program Files (x86)/googletest-distribution) is not valid.
You could try to fix this by providing it during cmake configuration (passing -D 'CMAKE_INSTALL_PREFIX=/c/Program Files (x86)/googletest-distribution' before the source dir) or by providing the install directory during the installation.
The following process should allow you to install the lib. I'm using my preferred way of building here, i.e. not using build system dependent commands, but using cmake to run the build/install commands. I assume the working directory to be the root directory of the gtest sources:
cmake -G "MinGW Makefiles" -S . -B build
cmake --build build
cmake --install build --prefix '/c/Program Files (x86)/googletest-distribution'
The last command needs to be run with admin privileges, the first 2 I don't recommend running as admin. You could instead install to a directory where you do have the permissions to create directories even without admin privileges.
The difference between using the process described above and using add_subdirectory is that the former results in a installation on the system which can be used via find_package and the google test libs won't be rebuilt for every project where you do this.
...
project(gtest_study)
...
# you may need to pass the install location via -D CMAKE_PREFIX_PATH=<install_location> during configuration for this to work
find_package(GTest REQUIRED)
target_link_libraries(gtest_study PRIVATE GTest::gtest_main GTest::gmock)
The latter builds the google test project as part of your own project build and for every project where you use this approach a seperate version of the google test libs is built. Note: there should be no need to specify the include dirs yourself, since this kind of information is attached to the cmake target and gets applied to the linking target automatically:
#include_directories(googletest-release-1.12.1/googletest/include)
#include_directories(googletest-release-1.12.1/googlemock/include)
add_executable(gtest_study main.cpp)
target_link_libraries(gtest_study PRIVATE gtest_main gmock)
As for 3.: The CMake generator used for building GTest should be independent of the generator of the project using it. The thing that's important is that the compilers used by the build systems are compatible. I cannot go into detail about this, since I've never used CLion and therefore have too little knowlege about the compilers used by it. (Personally I'm working with Visual Studio on Windows.)

CMake : add_executable not generating an executable under windows OS

I am trying to generate an executable with CMake under windows by command line.
This is what I do:
I enter testprog directory then do
cd build
cmake ..
I also tried this:
cd build
cmake -G"Visual Studio 16 2019" ..
same result as earlier attempt.
This builds bunch of files in build directory but no executable is ever created.
It creates files to be opened in visual studio.
This is how my folder look like;
testprog
-build
-src
-main.cpp
-call.h
-include
-main.h
-call.h
-CMakeLists.txt
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_STANDARD 17)
project(testprog)
include_directories(include)
file(GLOB SOURCES "src/*.cpp")
add_executable(testprog ${SOURCES})
This builds bunch of files in build directory but no executable is ever created. It creates files to be opened in visual studio.
That's it.
That's exactly what CMake does; CMake is a meta build system where it generates all necessary files that you can open with, say, Visual Studio on Windows since you've given:
-G "Visual Studio 16 2019"
and build the projects with Visual Studio.
add_executable does not magically build your source files. It only tells the given tool to do so.
It's all same in Unix-like platforms as well; CMake drops Makefile, and then you build with make. (Or other tools like Ninja can be a good candidate instead of make)
EDIT
I understand, but is there no way to build the executable from command line without the need of say Visual studio
Yes, you can! Microsoft provides Build Tools for Visual Studio for those who don't want the whole heavy IDE.
This is quite common when it comes to establishing a build server.
In order to build you have to call cmake --build <dir> [<options>] [-- <build-tool-options>]
Documentation is here

How to build and debug a MSYS2 / MinGW64 / CMake project in Visual Studio 2017?

I have successfully built a C++ project using MSYS2 / MinGW64 / CMake tools. Now I would like to edit it and debug it in Visual Studio, as it is a nice IDE and the default development tool in Windows. Sadly, I am not able to build the project in Visual Studio because it cannot find libraries.
Here is the CMakeLists.txt file I'm using where, among other things, I specify where are the include folders, the link files and link directories:
# src/CMakeLists.txt
cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
# Project name and current version
project(rascam VERSION 0.1 LANGUAGES CXX)
# Enable general warnings
# See http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
# Use 2014 C++ standard.
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Must use GNUInstallDirs to install libraries into correct locations on all platforms:
include(GNUInstallDirs)
# Pkg_config is used to locate header and files for dependency libraries:
find_package(PkgConfig)
# Defines variables GTKMM_INCLUDE_DIRS, GTKMM_LIBRARY_DIRS and GTKMM_LIBRARIES.
pkg_check_modules(GTKMM gtkmm-3.0)
link_directories( ${GTKMM_LIBRARY_DIRS} )
include_directories( ${GTKMM_INCLUDE_DIRS} )
# Compile files:
add_executable(rascapp
cpp/main.cpp
cpp/main-window.cpp
)
# Add folder with all headers:
target_include_directories(rascapp PRIVATE hpp)
# Link files:
target_link_libraries(rascapp
${GTKMM_LIBRARIES}
)
To set up my environment I installed MSYS2 on a Windows platform, and added all the following packages via pacman:
pacman -S base base-devel net-utils git ruby wget man
pacman -S msys/openssh msys/vim msys/bc nano msys/tmux
pacman -S gzip zip unzip msys/p7zip tar msys/tree
pacman -S msys/winpty msys/ed msys/pwgen msys/zsh
pacman -S mingw64/mingw-w64-x86_64-jq
pacman -S msys/screenfetch
pacman -S mingw-w64-x86_64-toolchain
pacman -S mingw64/mingw-w64-x86_64-cmake
My project is dependent on Gtkmm, so I added the following dependency:
pacman -S mingw64/mingw-w64-x86_64-gtkmm3
Then I added the C:\Msys2\MinGW64\bin to the path.
Then, I switched to the MSYS2/MinGW64 terminal, and fetched my project, created a build folder and built it. As I'm in Windows, the CMake produces Visual Studio files by default. I would be fine with that, if only I could make it work. Running out of ideas, I specified the Unix Makefiles option:
cd /c/where/your/root/folder/is
git clone https://github.com/cpp-tutorial/raspberry-cpp-gtk-opencv.git
cd raspberry-cpp-gtk-opencv
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Debug -G"Unix Makefiles" ../src/
make
./racapp.exe
And this does build the project. It produces an executable that I can launch from either MinGW64 or a Window Explorer by double clicking on it. I can also gdb it
After checking that the project looks right, I tried to open it in Visual Studio Community 2017 15.9.3 in two different ways:
Use CMake to build a Visual Studio project: Visual studio opens the project and I can see the different targets, but when I launch a debug session it complains that it cannot found Gtk libraries. Looking in the project properties, I can see the that the libraries are taken from the correct path C:\Msys2\MinGW64\bin. And I verified that the library exists, although with a different name: libgtkmm-3.0.dll.a instead of gtkmm-3.0.dll.
Use Visual Studio's Open File feature: Again, project opens, I can see the targets and the source files, but it complains that it doesn't find the include files gtkmm.h. I haven't managed to reach link phase, but my guess is that it wouldn't find libraries.
My question is, what is the correct and standard way to build and debug a MSYS2 / MinGW64 / CMake project in Visual Studio?
As other users commented (thanks, #DavidGrayson), the gcc.exe and g++.exe compilers that are installed in the MSYS2 configuration do not use the format that Visual Studio requires for debug symbols. In consequence, it is not possible to use Visual Studio for debugging executables built with Mingw.
To be able to debug (and build and edit), use some other IDE, more MinGW friendly, like Code::Blocks.
Still, to answer my own question, I describe here the procedure to configure the project in Visual Studio to edit the source files, build and launch the executable. For this procedure, no need to use CMake for anything:
Launch Visual Studio 2017
File -> Open -> Folder...
Select the folder that contains the top CMakeLists.txt.
It should find automatically that this is a CMake project, and try to load it. Maybe it complains about some errors.
CMake -> Change CMake Settings -> Choose your top CMakeLists.txt.
In the dialog, look for Mingw64-Release (actually, there is a *Mingw64-Debug, but you will not be able to debug anyway).
If everything went well, a CMakeSettings.json has appeared on your project, and Visual Studio rebuilds the project, this time without errors.
Choose an executable target.
Launch.
It should build then execute the application.
This is no longer true, you can build and debug projects using MingW gdb by following the steps mentioned below using the latest Visual Studio IDE:
https://devblogs.microsoft.com/cppblog/using-mingw-and-cygwin-with-visual-cpp-and-open-folder/.
I've tried for a bigger project and it works fine apart from the fact that the debugging is not very clean.

Installation directory in CMakeLists.txt, suitable for Visual Studio and Qt Creator

I have to deal with CMake 3.x, Qt Creator 3.3.0, Qt 4.8.6, Visual Studio 2008 in Windows (and rarely Qt Creator + GCC in Debian).
This instruction
install(TARGETS ${PROJECT} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
is not comfortable because of mixing debug and release *.lib files in the same directory. I'd like to save libs in the corresponding subfolder.
I've tried the following instruction from here:
install(TARGETS ${PROJECT} DESTINATION
${CMAKE_INSTALL_PREFIX}/lib/\${BUILD_TYPE})
It works fine for Visual Studio, as it is a multi-configuration solution and we pass ${BUILD_TYPE}, protected by backslash '\' for further propagation.
But how can I achieve the same output for Qt Creator + MS C++ compiler? Should I assign Debug(for example) to ${CMAKE_BUILD_TYPE} (via command-line interface) and special custom flag, which tells CMake that we deal with nmake/make? I mean conditional install instruction which will work fine in Windows and Linux and require minimal differences in the command-line arguments for CMake. I don't want to reinvent the wheel if there is a standard solution.
You saw that you can use BUILD_TYPE variable set at compile time to configure the target folder of your library at installation. This is specific to Visual Studio.
In other build systems (make, nmake, ninja, etc.) you have to use CMAKE_BUILD_TYPE variable, set at configuration time to retrieve the same information. In such case, as you felt, different configurations (Debug and Release) have to be generated in separated build folders. In these folders, CMake generation step is done with the right value in CMAKE_BUILD_TYPE variable. Example:
cd /home/user/project/xx_project/build_release
cmake -DCMAKE_BUILD_TYPE=Release /home/user/project/xx_project/src
cd /home/user/project/xx_project/build_debug
cmake -DCMAKE_BUILD_TYPE=Debug /home/user/project/xx_project/src
To detect if the user is building from Visual Studio or from command line, "there is a variable for that": The MSVC_IDE Cmake variable
A solution can be something like
if(MSVC_IDE)
install(TARGETS ${PROJECT} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/\${BUILD_TYPE})
else()
install(TARGETS ${PROJECT} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${CMAKE_BUILD_TYPE})
endif()
I am not completely sure of the necessity of the backslash before ${CMAKE_BUILD_TYPE}. You should test that by yourself

How do I use CMake?

I am trying to use CMake in order to compile opencv.
I am reading the tutorial but can't understand what is CMakeLists files and how is it connected to the gui of CMake?
Also couldn't understand what are makefiles, are they the same is CMakeLists?
And which file is it which I in the end open with visual-studio?
I don't know about Windows (never used it), but on a Linux system you just have to create a build directory (in the top source directory)
mkdir build-dir
go inside it
cd build-dir
then run cmake and point to the parent directory
cmake ..
and finally run make
make
Notice that make and cmake are different programs. cmake is a Makefile generator, and the make utility is governed by a Makefile textual file. See cmake & make wikipedia pages.
NB: On Windows, cmake might operate so could need to be used differently. You'll need to read the documentation (like I did for Linux)
CMake takes a CMakeList file, and outputs it to a platform-specific build format, e.g. a Makefile, Visual Studio, etc.
You run CMake on the CMakeList first. If you're on Visual Studio, you can then load the output project/solution.
Yes, cmake and make are different programs. cmake is (on Linux) a Makefile generator (and Makefile-s are the files driving the make utility). There are other Makefile generators (in particular configure and autoconf etc...). And you can find other build automation programs (e.g. ninja).
CMake (Cross platform make) is a build system generator. It doesn't build your source, instead, generates what a build system needs: the build scripts. Doing so you don't need to write or maintain platform specific build files. CMake uses relatively high level CMake language which usually written in CMakeLists.txt files. Your general workflow when consuming third party libraries usually boils down the following commands:
cmake -S thelibrary -B build
cmake --build build
cmake --install build
The first line known as configuration step, this generates the build files on your system. -S(ource) is the library source, and -B(uild) folder. CMake falls back to generate build according to your system. it will be MSBuild on Windows, GNU Makefiles on Linux. You can specify the build using -G(enerator) paramater, like:
cmake -G Ninja -S libSource -B build
end of the this step, generates build scripts, like Makefile, *.sln files etc. on build directory.
The second line invokes the actual build command, it's like invoking make on the build folder.
The third line install the library. If you're on Windows, you can quickly open generated project by, cmake --open build.
Now you can use the installed library on your project with configured by CMake, writing your own CMakeLists.txt file. To do so, you'll need to create a your target and find the package you installed using find_package command, which will export the library target names, and link them against your own target.
Cmake from Windows terminal:
mkdir build
cd build/
cmake ..
cmake --build . --config Release
./Release/main.exe
Regarding CMake 3.13.3, platform Windows, and IDE Visual Studio 2017, I suggest this guide. In brief I suggest:
1. Download cmake > unzip it > execute it.
2. As example download GLFW > unzip it > create inside folder Build.
3. In cmake Browse "Source" > Browse "Build" > Configure and Generate.
4. In Visual Studio 2017 Build your Solution.
5. Get the binaries.
Regards.