Setel LD_LIBRARY_PATH sebelum mengimpor dengan python

Python menggunakan variabel lingkungan PYTHONPATH untuk menentukan di folder mana ia harus mencari modul. Anda dapat bermain-main dengannya dengan memodifikasi sys.path, yang berfungsi baik untuk Modul Python murni. Tetapi ketika sebuah modul menggunakan file objek bersama atau perpustakaan statis, modul tersebut mencarinya di LD_LIBRARY_PATH (di linux), tetapi ini tidak dapat diubah dengan mudah dan sejauh yang saya tahu bergantung pada platform.

Perbaikan cepat untuk masalah ini tentu saja dengan menyetel variabel lingkungan atau menjalankan skrip seperti LD_LIBRARY_PATH=. ./script.py, tetapi Anda harus menyetelnya lagi untuk setiap shell baru yang Anda buka. Selain itu, file .so dalam kasus saya akan selalu berada di direktori yang sama dengan file .py, tetapi mungkin saja dipindahkan ke jalur absolut lain, jadi saya ingin mengaturnya secara otomatis setiap kali saya menjalankan skrip.

Bagaimana cara mengedit jalur di mana penerjemah Python mencari perpustakaan secara independen pada platform saat runtime?

Sunting:

Saya sudah mencoba os.environ['LD_LIBRARY_PATH'] = os.getcwd(), tetapi tidak berhasil.


person iFreilicht    schedule 23.04.2014    source sumber
comment
Hal ini mungkin harus ditangani oleh penginstal modul dengan menginstal perpustakaan bersama di lokasi standar (meskipun mungkin khusus mesin).   -  person chepner    schedule 23.04.2014
comment
...menggunakan virtualenv :) @chepner   -  person Erik Kaplun    schedule 23.04.2014
comment
@chepner setelah memikirkannya, ketergantungan platform adalah sesuatu yang perlu dipertimbangkan ketika menginstal perangkat lunak. Selain itu, windows tidak menggunakan file .so atau .a tetapi .dll dan .lib, dan perpustakaan saya harus dikompilasi ulang untuk itu dengan satu atau lain cara. Saya hanya merasa solusi cepat dan kotor akan memudahkan pengujian dan pengembangan.   -  person iFreilicht    schedule 23.04.2014
comment
Saya menghapus jawaban saya ke topik terkait dan memposting pertanyaan baru: Mencoba mengimpor modul pypyodbc menghasilkan kesalahan 'Perpustakaan ODBC tidak ditemukan. Apakah LD_LIBRARY_PATH disetel?'.   -  person fedorqui 'SO stop harming'    schedule 20.07.2017
comment
Kemungkinan duplikat dari Mengubah LD_LIBRARY_PATH saat runtime untuk ctypes   -  person sdikby    schedule 29.08.2018
comment
periksa ini: stackoverflow.com/questions/1178094/   -  person cdarlint    schedule 11.05.2020


Jawaban (5)


PEMBARUAN: lihat EDIT di bawah.

Saya akan menggunakan:

import os

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

Ini menetapkan variabel lingkungan LD_LIBRARY_PATH untuk durasi/masa eksekusi proses saat ini saja.

EDIT: sepertinya ini perlu disetel sebelum memulai Python: Mengubah LD_LIBRARY_PATH saat runtime untuk ctypes

Jadi saya sarankan menggunakan skrip pembungkus .sh (atau .py jika Anda bersikeras). Selain itu, seperti yang ditunjukkan oleh @chepner, Anda mungkin ingin mempertimbangkan untuk menginstal file .so Anda di lokasi standar (dalam virtualenv).

Lihat juga Mengatur LD_LIBRARY_PATH dari dalam Python

person Erik Kaplun    schedule 23.04.2014
comment
maaf, saya seharusnya menyebutkan bahwa saya sudah mencobanya dan tidak berhasil, pernyataan import setelah itu masih memunculkan ImportError yang tidak terjadi jika saya menjalankan skrip dengan LD_LIBRARY_PATH=. ./script.py. - person iFreilicht; 23.04.2014
comment
sama sekali tidak jelas bagi saya apa isi skrip pembungkusnya. - person dbliss; 19.03.2016
comment
Saran bagus untuk menginstal perpustakaan ke lokasi standar di dalam virtualenv. - person Ioannis Filippidis; 27.05.2016
comment
Apakah ini berhasil? Saya mencoba ini di __init__.py di pyqt5 kompilasi saya untuk menambahkan jalur LD_LIBRARY_PATH tambahan ke instalasi maya 2017, tetapi ketika saya menjalankan from PyQt5.QtWidgets import QApplication, QWidget dari juru bahasa python, masih tertulis ImportError: libQt5Widgets.so.5: cannot open shared object file: No such file or directory - person Shuman; 26.07.2016
comment
Coba ajukan pertanyaan dengan tag Qt, Python, Maya - person Erik Kaplun; 26.07.2016
comment
Jawaban ini sangat membantu saya! Terima kasih! - person Manav; 27.04.2020
comment
Alternatifnya, Anda dapat mengatur LD_LIBRARY_PATH dan memulai kembali penerjemah Python menggunakan argumen baris perintah yang sama. Lihat stackoverflow.com/a/25457751/603136 untuk detailnya. - person samwyse; 18.06.2020

Solusi saya untuk masalah ini adalah dengan menempatkan ini sebagai baris pertama skrip Python (bukan shebang biasa):

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

Dan inilah cara kerjanya:

  • tanpa shebang shell saat ini memperlakukan file tersebut sebagai skrip shell,
  • "exec" memastikan bahwa baris pertama ini juga merupakan perintah terakhir dari file ini yang dijalankan oleh shell,
  • "env" digunakan di sini untuk mengatur variabel lingkungan apa pun, mis. LD_LIBRARY_PATH,
  • jalur yang tepat ke juru bahasa Python dapat ditentukan atau "env" dapat menemukannya di PATH,
  • "-x" adalah opsi Python yang menyebabkan baris pertama diabaikan oleh juru bahasa Python,
  • "$0" adalah nama skrip, "$@" diganti dengan parameter posisi.
person Jarek    schedule 20.04.2018

Python, ketika mendapatkan nilai variabel lingkungan seperti pada os.environ[‘LD_LIBRARY_PATH’] atau os.environ[‘PATH’], ia menyalin nilai tersebut, ke dalam kamus, dari lingkungan proses induknya, umumnya bash (lingkungan proses bash dibawa ke proses anak, contoh berjalan python).

Anda dapat melihat bagian variabel lingkungan ini dengan keluaran perintah env dari bash.

Anda juga dapat melihat/membaca data env ini dari /proc/<pid>/environ, dengan memperkenalkan loop tak terbatas (while 1: pass) setelah memodifikasi variabel lingkungan apa pun.

Jika Anda melihat/membaca nilai/data variabel ini dari /proc/<pid>/environ setelah memodifikasinya di dalam skrip python, Anda akan melihat bahwa data variabel sebenarnya tidak diubah, meskipun skrip python menunjukkan nilai kunci kamus yang dimodifikasi, diperbarui.

Apa yang sebenarnya terjadi ketika Anda memodifikasi variabel env di dalam skrip python, seperti pada os.environ['LD_LIBRARY_PATH']='/<new_location>', adalah ia hanya memperbarui nilai dalam kamus lokal, yang tidak dipetakan ke bagian variabel env proses. Oleh karena itu, ini tidak akan disebarkan kembali untuk mencerminkan lingkungan proses saat ini, karena HANYA kamus lokal yang dimodifikasi/diperbarui/diisi.

Oleh karena itu, jika kita ingin variabel lingkungan baru direfleksikan, kita harus menimpa gambar memori proses dengan data variabel lingkungan baru, menggunakan execv.

Contoh:

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

Batasan: Idealnya, python tidak mengizinkan modifikasi variabel os.environ seperti itu. Namun karena tidak ada tipe data kamus konstan, maka memungkinkan modifikasi variabel data. Sama sekali tidak ada gunanya mengubah nilai, karena tidak ada gunanya mencerminkan lingkungan nyata proses yang sedang berjalan, kecuali execv digunakan.

person Sundeep471    schedule 23.03.2018
comment
mengenai ini: But because there is no constant dictionary data type ‹ Saya yakin jika mereka mencobanya, mereka dapat menempatkan item read-only di proxy pemetaan (type(type.__dict__)) dalam nt/posix modul var yang diimpor ke os untuk var env statis, di mana os.environ bisa menjadi instance envdict yang menggabungkan keduanya statis dan nama non-statis di __getitem__(), tapi itu bukan masalah besar, jadi mereka tidak peduli. ;) - person Tcll; 29.02.2020
comment
mungkin perlu mencari tahu baris perintah sebenarnya yang digunakan untuk menjalankan program... - person Antti Haapala; 08.05.2020

Solusinya berfungsi dengan baik jika env diaktifkan kembali

import os

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

Kode harus diambil pada tempatnya....

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

Sejak coreutils 8.30 dimungkinkan untuk menggunakan env -S untuk membagi baris shebang untuk memisahkan argumen:

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

Untuk kompatibilitas dengan sistem lama, Anda dapat menggunakan fakta bahwa shell mengizinkan semua perintah diapit tanda kutip, sedangkan di python hanya berupa string:

#!/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