ตั้งค่า LD_LIBRARY_PATH ก่อนนำเข้าใน python

Python ใช้ PYTHONPATH ตัวแปรสภาพแวดล้อมเพื่อกำหนดว่าโฟลเดอร์ใดที่ควรค้นหาโมดูล คุณสามารถเล่นกับมันได้โดยการแก้ไข sys.path ซึ่งทำงานได้ดีกับโมดูล Python ล้วนๆ แต่เมื่อโมดูลใช้ไฟล์อ็อบเจ็กต์ที่ใช้ร่วมกันหรือไลบรารีแบบคงที่ มันจะค้นหาไฟล์เหล่านั้นใน LD_LIBRARY_PATH (บน linux) แต่สิ่งนี้ไม่สามารถเปลี่ยนแปลงได้ง่าย ๆ และขึ้นอยู่กับแพลตฟอร์มเท่าที่ฉันรู้

การแก้ไขด่วนสำหรับปัญหานี้คือการตั้งค่าตัวแปรสภาพแวดล้อมหรือเรียกใช้สคริปต์เช่น LD_LIBRARY_PATH=. ./script.py แต่คุณจะต้องตั้งค่าอีกครั้งสำหรับทุกเชลล์ใหม่ที่คุณเปิด นอกจากนี้ ไฟล์ .so ในกรณีของฉันจะอยู่ในไดเร็กทอรีเดียวกันกับไฟล์ .py เสมอ แต่อาจถูกย้ายไปยังพาธสัมบูรณ์อื่น ดังนั้นฉันต้องการตั้งค่าโดยอัตโนมัติทุกครั้งที่เรียกใช้สคริปต์

ฉันจะแก้ไขเส้นทางที่ล่าม Python ค้นหาแพลตฟอร์มไลบรารีที่ไม่ขึ้นอยู่กับรันไทม์ได้อย่างไร

แก้ไข:

ฉันได้ลอง os.environ['LD_LIBRARY_PATH'] = os.getcwd() แล้ว แต่ก็ไม่มีประโยชน์


person iFreilicht    schedule 23.04.2014    source แหล่งที่มา
comment
สิ่งนี้น่าจะได้รับการจัดการโดยตัวติดตั้งโมดูลโดยการติดตั้งไลบรารีแบบแบ่งใช้ในตำแหน่งมาตรฐาน (แต่อาจเป็นเฉพาะเครื่อง)   -  person chepner    schedule 23.04.2014
comment
... ใช้ virtualenv :) @chepner   -  person Erik Kaplun    schedule 23.04.2014
comment
@chepner หลังจากคิดดูแล้ว การพึ่งพาแพลตฟอร์มเป็นสิ่งที่ต้องพิจารณาเมื่อติดตั้งซอฟต์แวร์ นอกจากนี้ windows ไม่ได้ใช้ .so หรือ .a แต่เป็นไฟล์ .dll และ .lib และไลบรารีของฉันต้องได้รับการคอมไพล์ใหม่ไม่ทางใดก็ทางหนึ่ง ฉันแค่รู้สึกว่าโซลูชันที่รวดเร็วและสกปรกจะช่วยให้การทดสอบและพัฒนาง่ายขึ้น   -  person iFreilicht    schedule 23.04.2014
comment
ฉันลบคำตอบของฉันสำหรับหัวข้อที่เกี่ยวข้องและโพสต์คำถามใหม่: การพยายามนำเข้าโมดูล pypyodbc ทำให้เกิดข้อผิดพลาด 'ไม่พบไลบรารี ODBC' LD_LIBRARY_PATH ตั้งค่าไว้หรือไม่'   -  person fedorqui 'SO stop harming'    schedule 20.07.2017
comment
อาจซ้ำกันของ การเปลี่ยน LD_LIBRARY_PATH ที่รันไทม์สำหรับ ctypes   -  person sdikby    schedule 29.08.2018
comment
ตรวจสอบสิ่งนี้: stackoverflow.com/questions/1178094/   -  person cdarlint    schedule 11.05.2020


คำตอบ (5)


UPDATE: ดูการแก้ไขด้านล่าง

ฉันจะใช้:

import os

os.environ['LD_LIBRARY_PATH'] = os.getcwd()  # or whatever path you want

ซึ่งจะตั้งค่าตัวแปรสภาพแวดล้อม LD_LIBRARY_PATH สำหรับระยะเวลา/อายุการใช้งานของการดำเนินการของกระบวนการปัจจุบันเท่านั้น

แก้ไข: ดูเหมือนว่าจะต้องตั้งค่านี้ก่อนที่จะเริ่ม Python: การเปลี่ยน LD_LIBRARY_PATH ที่รันไทม์สำหรับ ctypes

ดังนั้นฉันขอแนะนำให้ใช้สคริปต์ wrapper .sh (หรือ .py หากคุณยืนยัน) นอกจากนี้ ตามที่ @chepner ชี้ให้เห็น คุณอาจต้องการพิจารณาติดตั้ง .so ไฟล์ของคุณในตำแหน่งมาตรฐาน (ภายใน virtualenv)

ดูเพิ่มเติมที่การตั้งค่า LD_LIBRARY_PATH จากภายใน Python

person Erik Kaplun    schedule 23.04.2014
comment
ขออภัย ฉันควรจะบอกว่าฉันได้ลองแล้ว แต่มันใช้งานไม่ได้ คำสั่งนำเข้าหลังจากนั้นยังคงส่ง ImportError ซึ่งจะไม่เกิดขึ้นถ้าฉันเรียกใช้สคริปต์ด้วย LD_LIBRARY_PATH=. ./script.py - person iFreilicht; 23.04.2014
comment
ฉันไม่ชัดเจนเลยสำหรับฉันว่าสคริปต์ wrapper ควรมีอะไรบ้าง - person dbliss; 19.03.2016
comment
คำแนะนำที่ดีสำหรับการติดตั้งไลบรารีไปยังตำแหน่งมาตรฐาน ภายใน virtualenv - person Ioannis Filippidis; 27.05.2016
comment
มันใช้ได้ไหม? ฉันลองสิ่งนี้ใน __init__.py ใน pyqt5 ที่คอมไพล์แล้วของฉันเพื่อเพิ่มเส้นทาง LD_LIBRARY_PATH เพิ่มเติมให้กับการติดตั้ง Maya 2017 แต่เมื่อฉันเรียกใช้ from PyQt5.QtWidgets import QApplication, QWidget จากล่าม python มันยังคงบอกว่า ImportError: libQt5Widgets.so.5: cannot open shared object file: No such file or directory - person Shuman; 26.07.2016
comment
ลองถามคำถามด้วยแท็ก Qt, Python, Maya - person Erik Kaplun; 26.07.2016
comment
คำตอบนี้ช่วยฉันได้มากจริงๆ! ขอบคุณ! - person Manav; 27.04.2020
comment
หรือคุณสามารถตั้งค่า LD_LIBRARY_PATH และรีสตาร์ทล่าม Python อีกครั้งโดยใช้อาร์กิวเมนต์บรรทัดคำสั่งเดียวกัน ดูstackoverflow.com/a/25457751/603136สำหรับรายละเอียด - person samwyse; 18.06.2020

วิธีแก้ไขปัญหาของฉันคือให้นี่เป็นบรรทัดแรกของสคริปต์ Python (แทนที่จะเป็น shebang ปกติ):

exec env LD_LIBRARY_PATH=/some/path/to/lib /path/to/specific/python -x "$0" "$@"

และนี่คือวิธีการทำงาน:

  • หากไม่มี shebang เชลล์ปัจจุบันจะถือว่าไฟล์เป็นเชลล์สคริปต์
  • "exec" ทำให้แน่ใจว่าบรรทัดแรกนี้จะเป็นคำสั่งสุดท้ายจากไฟล์นี้ที่ดำเนินการโดยเชลล์
  • "env" ถูกใช้ที่นี่เพื่อตั้งค่าตัวแปรสภาพแวดล้อม เช่น LD_LIBRARY_PATH,
  • สามารถระบุเส้นทางที่แน่นอนไปยังล่ามของ Python หรือ "env" สามารถค้นหาเส้นทางใน PATH
  • "-x" เป็นตัวเลือกของ Python ซึ่งทำให้บรรทัดแรกถูกละเว้นโดยล่าม Python
  • "$0" คือชื่อสคริปต์ "$@" ถูกแทนที่ด้วยพารามิเตอร์ตำแหน่ง
person Jarek    schedule 20.04.2018

Python เมื่อได้รับค่าของตัวแปรสภาพแวดล้อมเช่นเดียวกับใน os.environ[‘LD_LIBRARY_PATH’] หรือ os.environ[‘PATH’] มันจะคัดลอกค่าลงในพจนานุกรมจากสภาพแวดล้อมของกระบวนการพาเรนต์ โดยทั่วไปแล้ว bash (สภาพแวดล้อมของกระบวนการ bash จะถูกส่งต่อไปยังกระบวนการลูก ซึ่งเป็นอินสแตนซ์ที่รัน python)

คุณสามารถดูส่วนตัวแปรสภาพแวดล้อมนี้ได้ด้วยเอาต์พุตคำสั่ง env จาก bash

คุณยังสามารถดู/อ่านข้อมูล env นี้ได้จาก /proc/<pid>/environ โดยแนะนำการวนซ้ำไม่สิ้นสุด (while 1: pass) หลังจากแก้ไขตัวแปรสภาพแวดล้อมใด ๆ

หากคุณเห็น/อ่านค่าตัวแปร/ข้อมูลจาก /proc/<pid>/environ หลังจากแก้ไขภายในสคริปต์ python คุณจะเห็นว่าข้อมูลของตัวแปรจริงไม่ได้รับการแก้ไข แม้ว่าสคริปต์ python จะแสดงค่าคีย์พจนานุกรมที่แก้ไขและอัปเดตแล้วก็ตาม

สิ่งที่เกิดขึ้นจริงเมื่อคุณแก้ไขตัวแปร env ภายในสคริปต์ python เช่นเดียวกับใน os.environ['LD_LIBRARY_PATH']='/<new_location>' คือมันแค่อัปเดตค่าในพจนานุกรมท้องถิ่น ซึ่งไม่ได้แมปกับส่วนตัวแปร env ของกระบวนการ ดังนั้นมันจะไม่เผยแพร่ย้อนกลับไปทั้งหมดเพื่อสะท้อนถึงสภาพแวดล้อมของกระบวนการปัจจุบัน เนื่องจาก มีเพียงพจนานุกรมท้องถิ่นเท่านั้น ได้รับการแก้ไข/อัปเดต/เติมข้อมูล

ดังนั้นหากเราต้องการให้สะท้อนตัวแปรสภาพแวดล้อมใหม่ เราควรเขียนทับอิมเมจหน่วยความจำของกระบวนการด้วยข้อมูลตัวแปรสภาพแวดล้อมใหม่ โดยใช้ execv

ตัวอย่าง:

new_lib = '/<new_location>'
if not new_lib in os.environ['LD_LIBRARY_PATH']:
    os.environ['LD_LIBRARY_PATH'] += ':'+new_lib
    try:
        os.execv(sys.argv[0], sys.argv)
    except Exception as e:
        sys.exit('EXCEPTION: Failed to Execute under modified environment, '+e)

import xyz
#do something else

ข้อจำกัด: ตามหลักการแล้ว python ไม่ควรอนุญาตให้แก้ไขตัวแปร os.environ ดังกล่าว แต่เนื่องจากไม่มีประเภทข้อมูลพจนานุกรมคงที่ จึงอนุญาตให้แก้ไขตัวแปรข้อมูลได้ ไม่มีประโยชน์ใดๆ ในการแก้ไขค่า เนื่องจากจะไม่มีประโยชน์ใดๆ ในการสะท้อนถึงสภาพแวดล้อมที่แท้จริงของกระบวนการที่กำลังทำงานอยู่ เว้นแต่ว่าจะใช้ execv

person Sundeep471    schedule 23.03.2018
comment
เกี่ยวกับเรื่องนี้: But because there is no constant dictionary data type ‹ ฉันแน่ใจว่าหากพวกเขาพยายามแล้วพวกเขาสามารถวางรายการแบบอ่านอย่างเดียวใน mappingproxy (type(type.__dict__)) ในโมดูล nt/posix var ที่นำเข้าไปยัง os สำหรับ vars env แบบคงที่ โดยที่ os.environ อาจเป็นอินสแตนซ์ envdict ที่รวมทั้งสองแบบคงที่ และชื่อที่ไม่คงที่บน __getitem__() แต่ก็ไม่ใช่เรื่องใหญ่อะไร ดังนั้นพวกเขาจึงไม่สนใจ ;) - person Tcll; 29.02.2020
comment
อาจต้องค้นหา command line จริงที่ใช้ในการรันโปรแกรม... - person Antti Haapala; 08.05.2020

วิธีแก้ปัญหาทำงานได้ดีหาก env ถูกเริ่มต้นใหม่

import os

os.environ['LD_LIBRARY_PATH'] = os.getcwd()  # or whatever path you want 

ต้องใช้รหัสแทน....

os.execv(sys.argv[0], sys.argv)
person Michele Belotti    schedule 11.08.2020

เนื่องจาก coreutils 8.30 จึงเป็นไปได้ที่จะใช้ env -S เพื่อแยกบรรทัด shebang เพื่อแยกอาร์กิวเมนต์:

#!/usr/bin/env -S LD_LIBRARY_PATH=/path/to/lib python options

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

#!/bin/sh
"export" "LD_LIBRARY_PATH=/path/to/lib:$LD_LIBRARY_PATH"
"exec" "python3" "$0" "$@"
# Further python program
import somemodule
person sercxjo    schedule 06.11.2020