devernay / cminpack

A C/C++ rewrite of the MINPACK software (originally in FORTRAN) for solving nonlinear equations and nonlinear least squares problems
http://devernay.free.fr/hacks/cminpack/
145 stars 63 forks source link

Fixing multiarch installation directories for libraries on Debian-based distributions #58

Closed luau-project closed 8 months ago

luau-project commented 8 months ago

What?

I have improved cminpack installation with CMake to properly handle multiarch differences on Debian-based distributions. In the proposed pull request, employing CMake's module GNUInstallDirs, libraries get installed in a location suitable to the system without further setup operations.

Why?

On Debian-based distributions (tested on Ubuntu Server 22.04, and Debian 12), the default location chosen by cminpack to install its static and shared library files on 64-bit systems is /usr/local/lib64. However, on a normal setup without further tweaks, such operating systems do not look on /usr/local/lib64 for libraries. Thus, at runtime, the system is not able to find the shared libraries required by apps which were dynamically linked to cminpack.

How?

Testing?

  1. I have tested the proposed changes on two fresh-installed Debian-based distros: Ubuntu Server 22.04 and Debian 12. On both systems, after the installation of cminpack shared libraries with the applied changes, the user just need to issue a sudo ldconfig to reload the cache and everything works as expected, as can be seen on Ubuntu and Debian screenshots.

  2. I have also tested the changes on a fresh Fedora 38 Server instance. On 64-bit systems, Fedora uses /usr/local/lib64 as default system location. Therefore, the new behavior is identical to the old behavior on Fedora.

Test Reproduction?

[!NOTE] Below, I am sharing a compressed file test-assets.tar.gz, which will be used to aid in the process to reproduce tests. Feel free to extract and examine the content safely on a VM.

The following steps were tested exhaustively on a fresh Ubuntu Server 22.04 installed on Multipass (Multipass is a canonical app to easily deploy Ubuntu VM instances). You are free to reproduce it on any virtualization software of choice, but I'll describe the process used in terms of Multipass:

  1. Optional: Install Multipass, and just click Open Shell in the tray icon. Multipass will download the image and spin up a fresh Ubuntu VM in the latest edition.

  2. Once a shell is open in the VM, type the following commands to update the system and install common build-tools:

    sudo apt update && sudo apt upgrade -y && sudo apt autoremove -y
    sudo apt install build-essential git cmake -y
  3. Optional: Launch a terminal on your host machine, change directory to the location of test-assets.tar.gz, and transfer the file to the user home directory (/home/<user> or ~) on VM, which primary below stands for the name of your VM instance:

    multipass transfer test-assets.tar.gz primary:.
  4. In the VM, change directory to tmp and extract the file:

    cd /tmp
    tar -xf ~/test-assets.tar.gz
  5. Execute sh official-cminpack.sh to git-clone cminpack from the official github, build the shared library with CMake, and install them in the default location. After that, the shell script builds a minimal app to evaluate a vector's enorm in the test directory, and links it dynamically to cminpack shared libraries. Then, the app is run:

    sh official-cminpack.sh
  6. At the end of execution, it is expected to face an issue saying that the system is not able to find cminpack shared libraries:

    Screenshot from 2024-01-02 15-51-11

  7. Uninstall cminpack from the last steps:

    sh revert-cminpack-install.sh
  8. Now, it is time to install cminpack in the VM, but this time grabbing cminpack from my forked repo branch. The following shell script will download cminpack from my forked github repo branch, build the shared library with CMake, and install them in the default location with the changes applied. After that, the shell script builds an identical app in the test-fork directory, and links it dynamically to cminpack shared libraries. Then, the app is run:

    sh fork-cminpack.sh
  9. The app now runs perfectly fine, because cminpack is now installed on /usr/local/lib determined by GNUInstallDirs, with the system being able to find cminpack shared libraries.

Screenshot from 2024-01-02 16-32-40

Screenshots?

Ubuntu

Comparison between old and new behavior on Ubuntu Server 22.04 running on Multipass

ubuntu-comparison

Debian

Comparison between old and new behavior on Debian 12 running on VirtualBox

debian-comparison