How to support multiple package versions in CMake's user package registry? - cmake

I'm trying to understand how I can use the CMake user package registry to support multiple builds, for example a Debug and a Release build.
I have a package1, which properly calls export(PACKAGE package1) so it registers the build directory with CMake's user package registry. I then proceed to creating 2 separate build directories, one for Debug and one for Release (note that I made the version for the Debug build 3.0.2000000, while the version for the Release build is 3.0.1000000, because I wanted CMake to prefer the Debug build in my use case). As expected, each of these builds registered an item in the registry:
> ls ~/.cmake/packages/package1/
212e973d0f1858e4bdf95b9d105bed5a 78094ed9b729d420c3f782cd8e668e64
Now in a different project, package2, I use find_package(package1 3.0.740) but it only ever finds the one in the Release build. I tried inspecting the package1_CONSIDERED_CONFIGS and package1_CONSIDERED_VERSIONS right after calling find_package but again only the Release build's config and version are there.
The code in package2's CMakeLists.txt file:
SET(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
message("CMAKE_FIND_PACKAGE_SORT_ORDER="
"${CMAKE_FIND_PACKAGE_SORT_ORDER}")
message("CMAKE_FIND_PACKAGE_SORT_DIRECTION="
${CMAKE_FIND_PACKAGE_SORT_DIRECTION}")
find_package(package1 3.0.740)
message("Considered Configs: ${package1_CONSIDERED_CONFIGS}")
message("Considered Versions: ${package1_CONSIDERED_VERSIONS}")
Result of CMake running above code:
cmake ../..
-- Using link pool size - 16 jobs
CMAKE_FIND_PACKAGE_SORT_ORDER=NATURAL
CMAKE_FIND_PACKAGE_SORT_DIRECTION=DEC
Considered Configs: /path/to/package1/Release/package1Config.cmake
Considered Versions: 3.0.1000000
What am I doing wrong? How is the user registry supposed to be used?

Related

Maintaining multiple projects which consume conan packages

Background:
I have a Visual Studio solution(s) with multiple (50+) projects (libraries static/dynamic and final executables). There is internal Visual Studio reference mechanism used to comsume required libraries for particular executables. Of course each project uses external packages, there are "duplicates" like boost, gtest, there are also some "unique" references for only one or few projects.
What's more, libraries are used in other solutions (project sharing) to deploy other executables.
This is my general project structure:
MainDir
|
- DebugDlls (build output)
- Debug64Dlls (build output)
- ReleaseDlls (build output)
- Release64Dlls (build output)
- Libraries
|
- lib1
- lib2
- ...
- Executables
|
- exe1
- exe2
...
I'm about to migrate from NuGet to conan as a dependency manager for external libraries since there are more ready to use conan packages that NuGet one and it's cross-platform. I'd like to do it project by project, dependency by dependency.
One global conan file to rule them all is not an option since each library has to be as standalone as possible so I'm able to simply grab one and use for new executable. What's more it would be impossible to track dependencies of particular library or executable.
My idea is to put a separate conanfile in each project and define dependencies.
Here is the first issue: I need some global/automatic management of common libraries like boost to not mix versions/variants and spare some time on version updates.
this one may be handled by a global file which defines reusable depndencies
is there something ready to use in conan, like template?
Second issue is to copy dlls from dependencies into proper build output so I'm able to execute the binaries.
this one should be fixable also by some global file with proper defines.
Third one is to execute conan install in each project
once again, a hand crafted script will do the job.
I was digging across the conan documentation but it's not very well organized and I was unable to find proper solution in my case. Maybe I missed something?
What would be the best approach here? Is there any build in conan mechanism for that (like CMake add_subdirectory). I would not like to reinvent the well if one already exists :)
I'm about to use conan 1.x

CMake force install after add_subdirectory

We are converting a large Makefile based project to a CMake based system. I have numerous dependencies that I need to build prior to building our code. The first three dependencies are build using the following:
add_subdirectory(dependencies/libexpat/expat)
add_subdirectory(dependencies/libuuid-1.0.3)
add_subdirectory(dependencies/log4c-1.2.4)
expat has it's own CMakeLists.txt file and build with no problems. I would like to force expat to install to the staging directory before continuing. For libuuid I am using a ExternalProject_Add and as part of that process it does install into the staging directory.
Then when I build log4c, which needs expat, I can point it to the location of expat. Otherwise I would need to someone get access to the absolutely path for the temporary build location of expat.
I've tried to add the following after add_subdirectory:
add_subdirectory(dependencies/libexpat/expat)
add_subdirectory(dependencies/libuuid-1.0.3)
install(TARGETS expat LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/usr/lib)
add_subdirectory(dependencies/log4c-1.2.4)
Unfortunately CMake will not run expat's install code. How do I force expat to install after building but before it builds the rest of the project?
This looks like the primary use case for ExternalProject_Add, which is best used as a superbuild setup. This means that your top-level project (the "superbuild") does not build any actual code and instead consists only of ExternalProject_Add calls. Your "real" project is added as one of these "external" projects. This allows you to set up the superbuild with all dependencies, ordering, etc.
The workflow is then as follows:
Generate the superbuild project.
Build the superbuild project. This will build and install all dependencies, and also generate (and build) your real project.
Switch to the buildsystem generated for your real project and start doing further development using that. Your dependencies are already correctly set up and installed by the build of the superbuild project in the previous step.

How to with CPack generate the WIX package?

I used cmake 3.12.0. There are exists one cmake project that creates one console application. I add the ability of package generation to that cmake project:
# ... above cmake code for one console application creation
# below code that I add:
# pack
set (A_PACK_DESCRIPTION_SUMMARY "${PROJECT_NAME} - CMake Assistant Solution")
set (A_INSTALL_PREFIX Consolas)
set(CPACK_WIX_PRODUCT_GUID "F9AAAAE2-D6AF-4EA4-BF46-B3E265400CC8")
set(CPACK_WIX_UPGRADE_GUID "F9AAAAE2-D6AF-4EA4-BF46-B3E265400CC7")
set(CPACK_GENERATOR "WIX")
include(CPack)
With other generators (NSIS, 7Z, ZIP, DEB) all works fine but with WIX appears followed error:
...path\files.wxs(11) : error LGHT0091 : Duplicate symbol 'Component:CM_C_EMPTY_INSTALL_ROOT' found. This typically means that an Id is duplicated. Check to make sure all your identifiers of a given type (File, Component, Feature) are unique.
Why it happens and how to fix it?
This appears to be caused by this bug
Basically you use add_subdirectory(xxx EXCLUDE_FROM_ALL) where the subdirectory has a install(... COMPONENT ...) call. The installed files are excluded from the subdirectory, but still creates COMPONENTs, which are now empty and break wix.
As a workaround, you can add:
set(CPACK_COMPONENTS_ALL Unspecified)
in CMakeLists.txt to exclude all the empty components.
If it helps any, I had this problem and found that I had INSTALL commands that specified only Release Configurations but then tried to build the package using the Debug build configuration. By just switching to building the package specifying the Release configuration all went as expected (Wasted most of an afternoon before I figured this out!)

Problems with CPack building multiple packages at once

I'm facing problems using the packaging with CPack and CMake 3.7.2.
I try to build three different packages, MSI (via WIX), IFW, and ZIP.
According to the documentation I set the following variables in my CMakeLists.txt (and a few more which are required):
set(CPACK_WIX_ROOT "C:/Temp/WiX-3.10/binaries")
set(QTIFWDIR "${GLOBAL}/Qt/Tools/QtInstallerFramework/2.0/bin")
set(CPACK_GENERATOR "WIX;IFW;ZIP")
I'm including CPack at the last possible position before any components are defined.
<all variables have been defined before this point>
include(CPack)
include(CPackWIX)
include(CPackIFW)
cpack_add_component(AppBinaries DISPLAY_NAME "MyAppBinaries" DESCRIPTION "My Application Binaries")
cpack_ifw_configure_component(AppBinaries VERSION ${CPACK_PACKAGE_VERSION} SCRIPT "${CMAKE_SOURCE_DIR}/cpack/installscript.qs")
cpack_add_component(AppDocs DISPLAY_NAME "MyAppDocs" DESCRIPTION "My Application Docs")
cpack_add_component(AppData DISPLAY_NAME "MyAppData" DESCRIPTION "My Application Data")
After creating the build dir and running from there
cmake -G "Visual Studio 14 2015 Win64" ..\TestProject
the files CMakeCache.txt, CPackConfig.cmake, CPackSourceConfig.cmake, and CPackProperties.cmake are generated.
When running cpack -C Release to build all three installers at once, the first one (WIX) is built, but the second one (QtIFW) fails with the messages
CPack Error: Cannot find QtIFW compiler "binarycreator": likely it is
not installed, or not in your PATH CPack Error: Cannot initialize the
generator IFW
I inspected the CMakeCache.txt file but found the following entries properly defined:
//QtIFW binarycreator command line client
CPACK_IFW_BINARYCREATOR_EXECUTABLE:FILEPATH=N:/Global/Qt/Tools/QtInstallerFramework/2.0/bin/binarycreator.exe
//QtIFW devtool command line client
CPACK_IFW_DEVTOOL_EXECUTABLE:FILEPATH=N:/Global/Qt/Tools/QtInstallerFramework/2.0/bin/devtool.exe
//QtIFW installer executable base
CPACK_IFW_INSTALLERBASE_EXECUTABLE:FILEPATH=N:/Global/Qt/Tools/QtInstallerFramework/2.0/bin/installerbase.exe
//QtIFW repogen command line client
CPACK_IFW_REPOGEN_EXECUTABLE:FILEPATH=N:/Global/Qt/Tools/QtInstallerFramework/2.0/bin/repogen.exe
//Enable to build 7-Zip source packages
CPACK_SOURCE_7Z:BOOL=ON
//Enable to build ZIP source packages
CPACK_SOURCE_ZIP:BOOL=ON
//Path to a program.
CPACK_WIX_CANDLE_EXECUTABLE:FILEPATH=C:/Temp/WiX-3.10/binaries/candle.exe
//Path to a program.
CPACK_WIX_LIGHT_EXECUTABLE:FILEPATH=C:/Temp/WiX-3.10/binaries/light.exe
But when I checked the CPack\*Config.cmake files none of the entries above are referenced. After running the cmake -G "Visual Studio 14 2015 Win64" ..\TestProject a second time everything is fine; all those entries are referenced in CPack\*Config.cmake files and all three installers can be built.
So I really get stuck at this point.
Any ideas what could be the issue and how to avoid it?
I finally figured out what didn't work as expected. The setting of the QTIFWDIR variable is not saved to the CPack*Config.cmake files, but the CMAKE_WIX_ROOT variable is. Those variables seem to be evaluated at runtime by CPack. Therefore the WIX build run successfully but the IFW build complained about a the missing binarycreator. Adding the variable with its current setting made everything run as expected.
Follow up:
According to the maintainer QTIFWDIR should be rather an environment variable than a CMake variable. And CPACK_WIX_ROOT is considered to be an internal CPack variable. You need to install WIX (and set the WIX environment variable manually, if it hasn't already been done by the installation).

What is the CMake install time?

A quote from the official documentation:
"Specify rules to run at install time."
What exactly is install time?
The problem for me: I am on Linux, software is installed from packages that are just dependencies and data. There is no CMake that can do anything here. So installation time of software is out of scope from CMake. So what exactly do they mean?
Building a CMake project can roughly be divided into three phases:
Configure time. This includes everything that happens while running cmake itself. This phase is concerned with inspecting certain properties of the host system and generating the specific build files for that platform under the selected configuration.
Build time. This includes everything that happens while actually building your project from the files generated by CMake (like, when running cmake --build or make). This is where all of the actual compilation and linking happens, so at the end of the build phase, you have a usable binary.
Install time. This includes everything that happens when running the INSTALL target generated by CMake (like, when running cmake --build --target install or make install). This takes care of copying the binaries that were generated into the build tree to a different directory. Note that the build tree contains a lot of stuff that is no longer needed once the build is completed if you are only interested in running the binary. Examples include all intermediate build artifacts, like the build files generated during the configure phase or the intermediate object files created during the build phase. Furthermore, the install phase might include additional steps to ensure that the binaries produced during the build are portable. For instance, on Linux systems you might want to remove the build directory from the shared library search path in the binary and replace it with a portable equivalent. So the install phase might do more than just copy all the important files to a new directory. It could also include additional steps that change the binaries to make them more portable.
Note that the last phase is optional. If you do not want to support calling make install but prefer another deployment mechanism, you simply don't use the install command in your CMake script and no INSTALL target will be generated.
I'd like to expand the answer, which ComicSansMS gave you, a little bit.
As he mentioned - CMake generates an extra target called install for the make tool (when you use a Makefile-based generator).
It may look weird for you as a package system is used for Linux. However the install target is still useful or even necessary:
When you develop your application you may need to install (move binaries and possibly some include files) to a certain location so some of your projects may see each other. For example, you may develop a library and a set of non-related applications which use it. Then this library must be installed somewhere to be visible. It doesn't mean you need to put it to the /usr directory; you may use your /home.
The process of Linux package preparation requires an install step. For example, the RPM packaging system does three main steps when the rpm package file is being built: the project is configured, then is compiled and linked and finally is being installed to a certain location. All files from this location are being packed to the rpm file.