cmakempirpmbuildrpm-spec

How to get rpm-mpi-hooks to append correct version information to rpm built with cmake?


I have been facing problems generating an RPM for a C++ project using MPI (openmpi in my case) , build with cmake on a Rocky9 (virtual) machine. Since RHEL8, MPI distributions are expected to include an extra identifier for MPI to the Requires and Provides sections of a .spec file to mark their specific version.

This is supposed to be done by the rpm-mpi-hooks package. however I can not find any information on how this is supposed to actually run. The RPMs I currently generated give me this error when I try to install

 Problem 1: conflicting requests
  - nothing provides libmpi.so.40()(64bit) needed by myrpm

as the expected packages have the form of libmpi.so.40()(64bit)(openmpi-x86_64) but mine requires libmpi.so.40()(64bit).

I have found some resources of people facing the same problems here, here, here, and here, which generally point towards the Fedora guidelines towards packaging MPI. I have tried quite a few things, including using the macro's as they are provided in many spots of the .spec file, I have tried renaming the binary to have a -mpi marker at the end, or moving them to a specific MPI directory without success.

Using the guidelines to making a spec-file, I constructed a very simple setup, where the actual code is a tiny HelloWorld C++ code. With a CMakeLists.txt:

cmake_minimum_required(VERSION 3.0)

project(HelloWorld)
add_executable(HWorld main.cxx)

set(CMAKE_INSTALL_PREFIX "/usr")

find_package(MPI REQUIRED)
include_directories(SYSTEM ${MPI_INCLUDE_PATH})
target_link_libraries(HWorld ${MPI_C_LIBRARIES} ${MPI_CXX_LIBRARIES})

install(TARGETS HWorld DESTINATION bin)

and a very general .spec file:

Name:           HWorld
Version:        1
Release:        1%{?dist}
Summary:        Test script with MPI

License:        Test

Source0:        https://www.example.com/%{name}/releases/%{name}-%{version}.tar.gz

%define debug_package %{nil}

BuildRequires:  gcc
BuildRequires:  make

%description

%prep
%setup -q

%build
%cmake
%cmake_build

%install
%cmake_install

%files
%{_bindir}/%{name}

%post

%changelog
* ...

This gives me an rpm with the bad mpi requires tag:

$ rpmbuild -bb HWorld.spec
$ rpm -qp --requires HWorld-1-1.el9.x86_64.rpm
...
libmpi.so.40()(64bit)

Solution

  • It is generally best to look for inspiration from something that already exists.

    For example, the vtk package provided by EPEL is built via cmake and depends on MPI.

    Here is a sample CMakeLists.txt

    cmake_minimum_required(VERSION 3.0)
    project(helloworld)
    add_executable(helloworld main.c)
    find_package(MPI REQUIRED)
    include_directories(SYSTEM ${MPI_INCLUDE_PATH})
    target_link_libraries(helloworld ${MPI_C_LIBRARIES})
    install(TARGETS helloworld DESTINATION bin)
    

    and the spec file (openmpi is hardcoded, you generally want to build a specfile that works for both mpich and openmpi

    Name:           helloworld  
    Version:        1.0  
    Release:        1%{?dist}  
    Summary:        Test script with MPI  
      
    License:        Test  
      
    Source0:        https://www.example.com/%{name}/releases/helloworld-%{version}.tar.gz  
      
    %define debug_package %{nil}  
      
    BuildRequires:  gcc  
    BuildRequires:  cmake  
      
    %description  
      
    %prep  
    %setup -q  
      
    %build  
    %global _vpath_builddir build-openmpi  
    %_openmpi_load  
    %cmake  
    %cmake \
     -DCMAKE_PREFIX_PATH:PATH=$MPI_HOME \
     -DCMAKE_INSTALL_PREFIX:PATH=$MPI_HOME  
      
    %cmake_build  
      
    %install  
    %cmake_install  
      
    %package openmpi  
    BuildRequires: openmpi-devel  
    Summary: binaries built with openmpi  
      
    %description openmpi  
      
    %files openmpi  
    %{_libdir}/openmpi/bin/%{name}
    

    and here are the requirements of the helloworld-openmpi package:

    
    $ rpm -qpR RPMS/aarch64/helloworld-openmpi-1.0-1.el9.aarch64.rpm 
    libc.so.6()(64bit)
    libc.so.6(GLIBC_2.17)(64bit)
    libc.so.6(GLIBC_2.34)(64bit)
    libmpi.so.40()(64bit)(openmpi-aarch64)
    rpmlib(CompressedFileNames) <= 3.0.4-1
    rpmlib(FileDigests) <= 4.6.0-1
    rpmlib(PayloadFilesHavePrefix) <= 4.0-1
    rpmlib(PayloadIsZstd) <= 5.4.18-1
    rtld(GNU_HASH)