CMake: Dua perpustakaan, lokasi objek bersama yang sama, satu tidak ditemukan saat runtime

Saya mencoba membangun perpustakaan C libmy yang bergantung pada perpustakaan eksternal libext. Baik libmy dan libext menggunakan CMake. Selanjutnya, libext sebenarnya menghasilkan dua objek bersama, libext1.so dan libext2.so, keduanya dibutuhkan oleh libmy.

Pertama, saya menginstal libext dengan modul CMake khusus, di bawah ${CMAKE_BINARY_DIR}/ext. Prosesnya berhasil dan saya mendapatkan pohon berikut:

${CMAKE_BINARY_DIR}
└── ext
    └── lib
        ├── libext1.so
        └── libext2.so

Untuk menguji libmy, saya membuat beberapa kasus uji di bawah target mytest, yang tertaut ke objek bersama libmy.so, libext1.so dan libext2.so.

Proses pembangunan semua target berakhir dengan sukses. Tetapi ketika saya mencoba menjalankan mytest, saya mendapatkan tidak dapat membuka file objek bersama yang terkenal: Tidak ada file atau direktori tersebut, tetapi hanya untuk libext1.so, sementara libext2.so ditemukan dengan benar. Namun, yang sangat membuat penasaran adalah bahwa libext1.so dan libext2.so terletak di jalur yang sama, dan libext2.so memang berhasil ditautkan pada waktu proses. Inilah yang LD_DEBUG=libs mytest cetak:

10703:  find library=libext2.so [0]; searching
10703:   search path=/usr/local/lib:/home/user/mylib/build/ext/lib:x86_64:      (RUNPATH from file src/test/mytest)
10703:    trying file=/usr/local/lib/libext2.so
10703:    trying file=/home/user/mylib/build/ext/lib/libext2.so
10703:      
10703:  find library=libext1.so [0]; searching
10703:   search cache=/etc/ld.so.cache
10703:    trying file=/usr/local/lib/libext1.so
10703:   search path=/lib/x86_64-linux-gnu/tls/haswell/x86_64:[...truncated long search path (/home/user/mylib/build/ext/lib is not here)...]:/usr/lib      (system search path)
10703:    trying file=/lib/x86_64-linux-gnu/tls/haswell/x86_64/libext1.so
          ...
10703:    trying file=/usr/lib/haswell/libext1.so
10703:    trying file=/usr/lib/x86_64/libext1.so
10703:    trying file=/usr/lib/libext1.so
10703:  
src/test/myest: error while loading shared libraries: libext1.so: cannot open shared object file: No such file or directory

Jadi, entah kenapa, untuk mencari libext1.so digunakan jalur pencarian sistem (yang tidak menyertakan jalur ke perpustakaan eksternal), sedangkan untuk libext2.so digunakan RUNPATH (yang memang memiliki jalur yang benar).

Modul CMake tempat saya membangun perpustakaan eksternal pada dasarnya melakukan ini:

include(ExternalProject)
set(EXTERNAL_INSTALL_LOCATION ${CMAKE_BINARY_DIR}/ext)

ExternalProject_Add(extproject
  GIT_REPOSITORY https://github.com/ext/ext.git
  CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTERNAL_INSTALL_LOCATION})

include_directories(${EXTERNAL_INSTALL_LOCATION}/include)
link_directories(${EXTERNAL_INSTALL_LOCATION}/lib)

set(EXT_INCLUDE_DIR ${EXTERNAL_INSTALL_LOCATION}/include)
set(EXT1_LIBRARY ext1)
set(EXT2_LIBRARY ext2)

Dan file CMakeLists.txt tempat mytest dibuat berisi:

add_executable(mytest mytest.cpp)
target_include_directories (mytest
  PUBLIC
  ${EXT_INCLUDE_DIR})
target_link_libraries(mytest
  my
  ${EXT1_LIBRARY}  
  ${EXT2_LIBRARY})
add_test(NAME mytest COMMAND mytest)

Penafian: Saya memberikan penyederhanaan skenario, karena perpustakaannya agak besar dan proses pembangunannya berisi beberapa komponen lainnya. Tapi semoga ini cukup.


person Ginswich    schedule 14.07.2020    source sumber


Jawaban (1)


Masalahnya agak tidak kentara.

Ternyata libext2.so secara internal juga bergantung pada libext1.so. Informasi ini tidak ditampilkan oleh LD_LEBUG=libs mytest, jadi saya kira ketergantungan pada libext1.so datang langsung dari libmy.so yang memang juga membutuhkannya. Namun, menjalankan LD_DEBUG=all mytest menghasilkan:

11540:  file=libext1.so [0];  needed by /home/user/mylib/build/external/lib/libext2.so [0]

Itu sebabnya pengaturan RPATH atau RUNPATH untuk semua target libmy tidak berpengaruh apa pun, saya kira karena RPATH/RUNPATH untuk libext diatur secara internal oleh CMake proyek itu, dan dengan demikian tidak bergantung pada cara saya membangun libmy.

Karena saya tidak ingin mengubah skrip CMake libext (saya ingin menggunakan skrip default pada proyek itu), yang dapat saya lakukan (afaik) adalah meneruskan argumen tambahan ke perintah ExternalProject_Add. Berikut ini berfungsi:

include(ExternalProject)
set(EXTERNAL_INSTALL_LOCATION ${CMAKE_BINARY_DIR}/ext)

ExternalProject_Add(extproject
  GIT_REPOSITORY https://github.com/ext/ext.git
  CMAKE_ARGS 
  -DCMAKE_INSTALL_PREFIX=${EXTERNAL_INSTALL_LOCATION}
  -DCMAKE_INSTALL_RPATH=${EXTERNAL_INSTALL_LOCATION}/lib)

include_directories(${EXTERNAL_INSTALL_LOCATION}/include)
link_directories(${EXTERNAL_INSTALL_RPATH}/lib)

set(EXT_INCLUDE_DIR ${EXTERNAL_INSTALL_LOCATION}/include)
set(EXT1_LIBRARY ext1)
set(EXT2_LIBRARY ext2)

(Perhatikan argumen -DCMAKE_INSTALL_RPATH=${EXTERNAL_INSTALL_LOCATION}/lib tambahan pada instruksi ExternalProject_Add.)

Itu menetapkan RPATH sehingga libext2.so dapat menemukan libext1.so saat runtime.

person Ginswich    schedule 15.07.2020