CMake: สองไลบรารีซึ่งมีตำแหน่งเดียวกันของวัตถุที่ใช้ร่วมกัน ไม่พบหนึ่งไลบรารีในขณะรันไทม์

ฉันกำลังพยายามสร้างไลบรารี C libmy ที่ขึ้นอยู่กับไลบรารีภายนอก libext ทั้ง libmy และ libext ใช้ CMake นอกจากนี้ libext ยังสร้างอ็อบเจ็กต์ที่ใช้ร่วมกันสองรายการ คือ libext1.so และ libext2.so ซึ่งทั้งสองอ็อบเจ็กต์จำเป็นสำหรับ libmy

ก่อนอื่น ฉันติดตั้ง libext ด้วยโมดูล CMake ที่กำหนดเอง ซึ่งต่ำกว่า ${CMAKE_BINARY_DIR}/ext กระบวนการนี้สำเร็จและฉันได้ผลลัพธ์ดังนี้:

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

เพื่อทดสอบ libmy ฉันสร้างกรณีทดสอบบางส่วนภายใต้เป้าหมาย mytest ซึ่งเชื่อมโยงไปยังวัตถุที่ใช้ร่วมกัน libmy.so, libext1.so และ libext2.so

กระบวนการสร้างเป้าหมายทั้งหมดสิ้นสุดลงเรียบร้อยแล้ว แต่เมื่อฉันพยายามเรียกใช้ mytest ฉันพบปัญหา ไม่สามารถเปิดไฟล์อ็อบเจ็กต์ที่แชร์ได้: ไม่มีไฟล์หรือไดเร็กทอรีดังกล่าว แต่สำหรับ libext1.so เท่านั้น ในขณะที่พบ libext2.so อย่างถูกต้อง อย่างไรก็ตาม สิ่งที่มากน่าสงสัยก็คือ ทั้ง libext1.so และ libext2.so อยู่ในเส้นทางเดียวกัน และ libext2.so ก็เชื่อมโยงได้สำเร็จจริง ๆ ขณะรันไทม์ นี่คือสิ่งที่ LD_DEBUG=libs mytest พิมพ์:

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

ดังนั้น ด้วยเหตุผลบางประการ ในการค้นหา libext1.so ระบบจะใช้พาธการค้นหาของระบบ (ซึ่งไม่รวมพาธไปยังไลบรารีภายนอก) ในขณะที่ libext2.so จะใช้ RUNPATH (ซึ่งมีพาธที่ถูกต้อง)

โดยพื้นฐานแล้วโมดูล CMake ที่ฉันสร้างไลบรารีภายนอกจะทำสิ่งนี้:

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)

และไฟล์ CMakeLists.txt ที่ mytest ถูกสร้างขึ้นประกอบด้วย:

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)

ข้อจำกัดความรับผิดชอบ: ฉันทำให้สถานการณ์ง่ายขึ้น เนื่องจากไลบรารีมีขนาดค่อนข้างใหญ่และกระบวนการสร้างประกอบด้วยองค์ประกอบอื่นๆ หลายประการ แต่หวังว่านี่จะเพียงพอแล้ว


person Ginswich    schedule 14.07.2020    source แหล่งที่มา


คำตอบ (1)


ประเด็นนี้ค่อนข้างละเอียดอ่อน

ปรากฎว่า libext2.so ภายในนั้นขึ้นอยู่กับ libext1.so ด้วย ข้อมูลนี้ไม่แสดงโดย LD_LEBUG=libs mytest ดังนั้นฉันคิดว่าการขึ้นต่อกันของ libext1.so มาจาก libmy.so โดยตรง ซึ่งก็ต้องการมันเช่นกัน อย่างไรก็ตาม การรันเอาต์พุต LD_DEBUG=all mytest:

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

นั่นคือสาเหตุที่การตั้งค่า RPATH หรือ RUNPATH สำหรับเป้าหมายทั้งหมดของ libmy ไม่มีผลกระทบใดๆ ฉันเดาว่าเพราะ RPATH/RUNPATH สำหรับ libext ได้รับการตั้งค่าภายในโดย CMake ของโปรเจ็กต์นั้น และดังนั้นจึงเป็นอิสระจากวิธีที่ฉันสร้าง libmy

เนื่องจากฉันไม่ต้องการแก้ไขสคริปต์ CMake ของ libext (ฉันต้องการใช้สคริปต์เริ่มต้นของโปรเจ็กต์นั้น) สิ่งที่ฉันทำได้ (afaik) คือส่งอาร์กิวเมนต์เพิ่มเติมไปยังคำสั่ง ExternalProject_Add ผลงานดังต่อไปนี้:

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)

(สังเกตอาร์กิวเมนต์ -DCMAKE_INSTALL_RPATH=${EXTERNAL_INSTALL_LOCATION}/lib เพิ่มเติมจากคำสั่ง ExternalProject_Add)

นั่นตั้งค่า RPATH เพื่อให้ libext2.so สามารถค้นหา libext1.so ได้ที่รันไทม์

person Ginswich    schedule 15.07.2020