Installation (“Deployment”)

“Prefix”: Where Everything Comes Together

  • Multiple projects usually are installed at one prefix/usr

  • Subdirectories

    • bin/: executables

    • lib/ (or lib64): libraries

    • include/: header files (usually comes with -dev or -devel distro packages, as do static libraries)

    • share/: data files

    • (more)

  • Build parameter: CMAKE_INSTALL_PREFIX (default: /usr/local)

$ cmake -DCMAKE_INSTALL_PREFIX=/tmp/install /home/jfasch/work/jfasch-home/trainings/material/soup/cmake/07-install-basic

Installing Targets

INSTALL(TARGETS hello DESTINATION lib)                 # <--- lands in <prefix>/lib/
INSTALL(TARGETS hello-first DESTINATION bin)           # <--- lands in <prefix>/bin/
INSTALL(TARGETS hello-second DESTINATION bin)          # <--- lands in <prefix>/bin/

Doing The Installation (make install)

$ cmake -DCMAKE_INSTALL_PREFIX=/tmp/install /home/jfasch/work/jfasch-home/trainings/material/soup/cmake/07-install-basic
$ make
$ make install
...
Install the project...
-- Install configuration: ""
-- Installing: /tmp/install/lib/libhello.a
-- Installing: /tmp/install/bin/hello-first
-- Installing: /tmp/install/bin/hello-second
$ tree /tmp/install/
/tmp/install/
├── bin
│   ├── hello-first
│   └── hello-second
└── lib
    └── libhello.a

And Shared Libraries?

$ cmake -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=/tmp/install /home/jfasch/work/jfasch-home/trainings/material/soup/cmake/07-install-basic
$ make
$ make install
...
-- Set runtime path of "/tmp/install/bin/hello-first" to ""    # <--- RUNPATH?
-- Set runtime path of "/tmp/install/bin/hello-second" to ""   # <--- RUNPATH?
...
$ tree /tmp/install/
/tmp/install/
├── bin
│   ├── hello-first
│   └── hello-second
└── lib
    └── libhello.so

Shared Libraries: Installed Vs. Local (RUNPATH)

  • NEEDED

    $ readelf  --dynamic ./hello-first
     ...
     0x0000000000000001 (NEEDED)             Shared library: [libhello.so]
     ...
    

    ⟶ Executable hello-first depends on hello (CMakeLists.txt: TARGET_LINK_LIBRARIES())

  • Question: where is that external dependency found when program is started?

  • Answer 1: local (uninstalled) case

    $ readelf  --dynamic ./hello-first
     ...
     0x000000000000001d (RUNPATH)            Library runpath: [/home/jfasch/tmp/cmake-demo:]
     ...
    
    Which libraries would be loaded if I ran ./hello-first?
    $ ldd ./hello-first
            ...
            libhello.so => /home/jfasch/tmp/cmake-demo/libhello.so (0x00007f773aefe000)
            ...
    

    ⟶ uninstalled executable runs from the build directory

    $ ./hello-first
    Hello World
    
  • Answer 2: installed case

    $ readelf  --dynamic /tmp/install/bin/hello-first
    ... no RUNPATH ...
    
    $ ldd /tmp/install/bin/hello-first
            ...
            libhello.so.1 => not found
            ...
    

    ⟶ installed executable does not run

    $ /tmp/install/bin/hello-first
    /tmp/install/bin/hello-first: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory
    

    Fix: set loader path, e.g.

    $ LD_LIBRARY_PATH=/tmp/install/lib /tmp/install/bin/hello-first
    Hello World
    

Shared Libraries: ABI Versions

  • Set ABI version (SONAME), and make install

    SET_PROPERTY(TARGET hello PROPERTY VERSION "1")
    
  • SONAME ELF attribute

    $ readelf  --dynamic /tmp/install/bin/hello-first
    0x0000000000000001 (NEEDED)             Shared library: [libhello.so.1]
    
  • SONAME link (done by ldconfig on a live system, after package installation)

    $ tree /tmp/install/
    /tmp/install/
    ├── bin
    │   ├── hello-first
    │   └── hello-second
    └── lib
        ├── libhello.so -> libhello.so.1
        └── libhello.so.1