The UseRPMTools CMake module simplifies the RPM package generation using both CPack and CMake. It has been done because CPack does not have an RPM generator. This CMake macro is only useful for Linux systems using RPM packages (RedHat/Fedora, Mandriva, ...)
A CPack RPM generator is now built-in CMake 2.6.x CMake:CPackPackageGenerators#RPM_.28Unix_Only.29
The usage is simple:
- put the macro file "UseRPMTools.cmake" in your CMAKE_MODULE_PATH
- Then add something like this to your CMakeLists.txt
INCLUDE(CPack) INCLUDE(UseRPMTools) IF(RPMTools_FOUND) RPMTools_ADD_RPM_TARGETS(packagename) ENDIF(RPMTools_FOUND)
then if the necessary RPM building tools are found you inherit 2 new top-level (custom) targets named
you may call them to build binary or source RPM.
The macro generates a MINIMAL spec file, but if you want to tailor your handcrafted spec file you may provide one to the macro as a second argument:
You will get the same targets but using your custom spec files.
If your custom spec file need to be CONFIGUREd then name it with .in extension and the macro will process the file accordingly.
CPack Built-in RPM support design issues
The builtin support of RPM generator has been added to CMake/CPack cvs during the end of August 2007. As stated CMake:CPackPackageGenerators#RPM the builtin support is not as powerful as the macro module. Beside the lack of time to do it I'll give here some ideas concerning the current limitation of the built-in support. I put it here in order to enable future work on this for anybody wanting to volunteer (including me if I have more time).
Macro-based CPack generator
Heres comes some ideas and question regarding a possibly 100% CMake Macro cpack generator.
I think it would be nice if we could implement most (if not all) CPack generators as almost "pure" CMake scripts. This is what I wanted to do when writing the CPack RPM generator, and this may be seen in the
CMake/Source/CPack/cmCPackRPMGenerator.cxx::cmCPackRPMGenerator::CompressFiles which mostly does: this->ReadListFile("CPackRPM.cmake");
The fact is I did face some design issues in the CPack generic generator which prevents me for doing what I wanted to.
The main issue are the implicit functional hypothesis built-in the CMake/Sources/CPack/cmCPackGenericGenerator.cxx from which all generator are derived from.
The way Generic Generator is implemented enforces a particular SEQUENTIAL definition and usage of CPACK_xxx var names.
Typically when a Generator is run you end-up in:
- -->conditionnaly remove the directory defined by CPACK_TOPLEVEL_DIRECTORY
- -->Set up some more names
const char* tempPackageFileName = this->GetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME"); const char* packageFileName = this->GetOption("CPACK_OUTPUT_FILE_PATH"); const char* tempDirectory = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
- -->Collect files in the package tree in order to build the file list to be passed to compressFiles
- -->Eventually remove old (previously generated) package file
- -->cmCPackGenericGenerator::compressFiles(const char* outFileName, const char* toplevel,const std::vector<std::string>& files)
HERE cmCPackGenericGenerator fixes the name to be used by the specialized generator this is tempPackageFileName the value of tempPackageFileName comes from step 5.
- --> copy the tempPackageFileName to packageFileName packageFileName comes from step 5.
I think almost all of this is OK but:
- The compressFile step should be given a chance to overload some of the CPACK_xxxx variables previously defined because for example the naming scheme indicated by: CPACK_OUTPUT_FILE_NAME may not be followed by ALL generators.
- cmake-2.5.0-Linux-i686.tar.gz is OK for TGZ generator
- cmake-2.5.0-Linux-i686.rpm is not because it does not follow standard RPM naming scheme which should be something like cmake-<version>-<rpmrelease>.<arch>.rpm e.g. cmake-2.5.0-2fc6.i686.rpm
I think the naming scheme problem comes from the fact that we are trying to share the cpack config files generated by CPack.cmake which may not be suitable for all generators.
The overloading scheme should be done by simply avoiding to use
const char* packageFileName = this->GetOption("CPACK_OUTPUT_FILE_PATH");
before calling compressFile but just after. That way inside the derived-class compress file we may:
this->SetOption("CPACK_OUTPUT_FILE_NAME",rpmFileName); (see commented code in cmCPackRPMGenerator.cxx)
may simply do it.
Moreover in order to achieve a "true" user-extensible 100% macros CPack Generator I think we may split the current CPackRPM.cmake into at least 3 files.
- CPackRPM.cmake which contains RPM specific var definitions this may be this->ReadListFile before calling compressFile (ideally this may be done by CPackGenericGenerator if "Macro" generator case is detected)
- CPackRPM_BinaryRun.cmake this will be this->ReadListFile in case we require a Binary package
- CPackRPM_SourceRun.cmake this will be this->ReadListFile in case we require a Source package
Using this scheme the CPackGenericGenerator may look for CPack<GenName>*.cmake files in the CMAKE_MODULE_PATH and we may write a single CPackMacroGenerator class which will be more or less like CPackRPMGenerator + the source vs binary handling and authorized varname overload.
I don't know how/if CPack is told to build a SOURCE or a BINARY package? Is it known to cpack or cpack only knows the name of its config file?