Search code examples
clinkerruntime-errorstatic-librarieslibraries

Cannot statically use an installed library


I am trying to statically link and use a library that I installed in my system, but even when at compile/link time I do not get errors. At runtime I get them.

Getting the library

I downloaded and installed libpfm4. I ran make sudo make install:

And got this:

installing in /usr/local
make[1]: Entering directory '/home/username/libpfm4/lib'
building: libpfm.a libpfm.so.4.11.1
mkdir -p /usr/local/lib
install -m 644 libpfm.a /usr/local/lib
install libpfm.so.4.11.1 /usr/local/lib
cd /usr/local/lib; ln -sf libpfm.so.4.11.1 libpfm.so.4
cd /usr/local/lib; ln -sf libpfm.so.4.11.1 libpfm.so
ldconfig
make[1]: Leaving directory '/home/username/libpfm4/lib'
make[1]: Entering directory '/home/username/libpfm4/tests'
make[1]: Nothing to be done for 'install'.
make[1]: Leaving directory '/home/username/libpfm4/tests'
make[1]: Entering directory '/home/username/libpfm4/examples'
make[1]: Nothing to be done for 'install'.
make[1]: Leaving directory '/home/username/libpfm4/examples'
make[1]: Entering directory '/home/username/libpfm4/perf_examples'
make[1]: Nothing to be done for 'install'.
make[1]: Leaving directory '/home/username/libpfm4/perf_examples'
make[1]: Entering directory '/home/username/libpfm4/include'
mkdir -p /usr/local/include/perfmon
install -m 644 perfmon/pfmlib.h perfmon/perf_event.h perfmon/pfmlib_perf_event.h /usr/local/include/perfmon
make[1]: Leaving directory '/home/username/libpfm4/include'
make[1]: Entering directory '/home/username/libpfm4/docs'
mkdir -p /usr/local/share/man/man3
( cd man3; install -m 644 libpfm.3 pfm_find_event.3 pfm_get_event_attr_info.3 pfm_get_event_info.3 pfm_get_event_encoding.3 pfm_get_event_next.3 pfm_get_pmu_info.3 pfm_get_os_event_encoding.3 pfm_get_version.3 pfm_initialize.3 pfm_terminate.3 pfm_strerror.3 libpfm_intel_core.3 libpfm_intel_x86_arch.3 libpfm_amd64.3 libpfm_amd64_k7.3 libpfm_amd64_k8.3 libpfm_amd64_fam10h.3 libpfm_amd64_fam15h.3 libpfm_amd64_fam16h.3 libpfm_amd64_fam17h.3 libpfm_amd64_fam17h_zen2.3 libpfm_amd64_fam19h_zen3.3 libpfm_amd64_fam19h_zen3_l3.3 libpfm_intel_atom.3 libpfm_intel_nhm.3 libpfm_intel_nhm_unc.3 libpfm_intel_wsm.3 libpfm_intel_wsm_unc.3 libpfm_intel_snb.3 libpfm_intel_snb_unc.3 libpfm_intel_ivb.3 libpfm_intel_ivb_unc.3 libpfm_intel_hsw.3 libpfm_intel_bdw.3 libpfm_intel_rapl.3 libpfm_intel_slm.3 libpfm_intel_tmt.3 libpfm_intel_skl.3 libpfm_intel_icl.3 libpfm_intel_glm.3 libpfm_intel_knl.3 libpfm_intel_knm.3 libpfm_intel_snbep_unc_cbo.3 libpfm_intel_snbep_unc_ha.3 libpfm_intel_snbep_unc_imc.3 libpfm_intel_snbep_unc_pcu.3 libpfm_intel_snbep_unc_qpi.3 libpfm_intel_snbep_unc_ubo.3 libpfm_intel_snbep_unc_r2pcie.3 libpfm_intel_snbep_unc_r3qpi.3 libpfm_intel_ivbep_unc_cbo.3 libpfm_intel_ivbep_unc_ha.3 libpfm_intel_ivbep_unc_imc.3 libpfm_intel_ivbep_unc_pcu.3 libpfm_intel_ivbep_unc_qpi.3 libpfm_intel_ivbep_unc_ubo.3 libpfm_intel_ivbep_unc_r2pcie.3 libpfm_intel_ivbep_unc_r3qpi.3 libpfm_intel_ivbep_unc_irp.3 libpfm_intel_knc.3 libpfm_intel_hswep_unc_cbo.3 libpfm_intel_hswep_unc_ha.3 libpfm_intel_hswep_unc_imc.3 libpfm_intel_hswep_unc_irp.3 libpfm_intel_hswep_unc_pcu.3 libpfm_intel_hswep_unc_qpi.3 libpfm_intel_hswep_unc_r2pcie.3 libpfm_intel_hswep_unc_r3qpi.3 libpfm_intel_hswep_unc_sbo.3 libpfm_intel_hswep_unc_ubo.3 libpfm_intel_bdx_unc_cbo.3 libpfm_intel_bdx_unc_ha.3 libpfm_intel_bdx_unc_imc.3 libpfm_intel_bdx_unc_irp.3 libpfm_intel_bdx_unc_pcu.3 libpfm_intel_bdx_unc_qpi.3 libpfm_intel_bdx_unc_r2pcie.3 libpfm_intel_bdx_unc_r3qpi.3 libpfm_intel_bdx_unc_sbo.3 libpfm_intel_bdx_unc_ubo.3 libpfm_intel_skx_unc_cha.3 libpfm_intel_skx_unc_imc.3 libpfm_intel_skx_unc_irp.3 libpfm_intel_skx_unc_m2m.3 libpfm_intel_skx_unc_m3upi.3 libpfm_intel_skx_unc_pcu.3 libpfm_intel_skx_unc_ubo.3 libpfm_intel_skx_unc_upi.3 pfm_get_perf_event_encoding.3 libpfm_perf_event_raw.3 /usr/local/share/man/man3 )
make[1]: Leaving directory '/home/username/libpfm4/docs'

I can now see the library in /usr/local/libpfm.{a,so,so.4,so.4.11.1}.

Compiling the program

#include <stdio.h>
#include <perfmon/pfmlib.h>

int main(int argc, char **argv){
    int idx;
    pfm_os_t os;
    pfm_event_info_t info;

    idx = 239075328;
    os = PFM_OS_NONE;
    pfm_initialize();
    pfm_get_event_info(idx, os, &info);

    printf("Name:  %s\n"
           "Desc:  %s\n"
           "Equiv: %s\n"
           "Code:  %lu\n"
           "IDX:   %d\n"
           "Attr:  %d\n",
           info.name,
           info.desc,
           info.equiv,
           info.code,
           info.idx,
           info.nattrs);

    return 0;
}

I use this to compile:

gcc -lpfm -Wall -Werror -std=gnu11 -pthread -g -o0 -fno-omit-frame-pointer -I include -o out.bin code.c

I get a clean output.

Running the program

$ ./out.bin
./out.bin: error while loading shared libraries: libpfm.so.4: cannot open shared object file: No such file or directory

If I use ldd, I get this:

$ ldd out.bin
    linux-vdso.so.1 (0x00007ffc8f9fe000)
    libpfm.so.4 => not found
    libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fdcdcf0b000)
    libc.so.6 => /lib64/libc.so.6 (0x00007fdcdcd40000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fdcdcf44000)

What may I be missing?


Solution

  • There's a difference between the link-time path to a library and the run-time path.

    Since the library is in a location that (apparently) isn't handled by the run-time loader you must add a flag when linking to tell the linker to add information about it in the executable for the run-time loader to check.

    This is done with the -rpath linker specific flag.

    You can pass it using gcc with the -Wl option:

    gcc ... -Wl,-rpath=/usr/local/lib -L/usr/local/lib -lpfm