Eşdeğer adlara sahip işlevler sağlayan iki kitaplığım varsa ne yapmalıyım?
vorbis_...
, sf_...
, sdl_...
). Bu aslında C ++ 'nın isim alanlı fonksiyonlar için sembol isimlerine yaptığı şeydir.
Eşdeğer adlara sahip işlevler sağlayan iki kitaplığım varsa ne yapmalıyım?
vorbis_...
, sf_...
, sdl_...
). Bu aslında C ++ 'nın isim alanlı fonksiyonlar için sembol isimlerine yaptığı şeydir.
Yanıtlar:
Yorumlara göre: "Dışa aktar" derken, kitaplığa bağlanan modülleri görünür kılmayı kastediyorum - extern
dosya kapsamındaki anahtar kelimeye eşdeğer . Bunun nasıl kontrol edildiği işletim sistemine ve bağlayıcıya bağlıdır. Ve her zaman yukarı bakmam gereken bir şey .
Bir nesne dosyasındaki sembolleri yeniden adlandırmak mümkündür objcopy --redefine-sym old=new file
(bkz. Man objcopy).
Ardından yeni adlarını kullanarak işlevleri çağırın ve yeni nesne dosyasıyla bağlantı kurun.
Windows altında , bu kitaplıklardan birini belleğe yüklemek için LoadLibrary () işlevini kullanabilir ve ardından işlevleri bir işlev işaretçisi aracılığıyla çağırmak ve çağırmak için ihtiyaç duyduğunuz her işlevin adresini almak için GetProcAddress () öğesini kullanabilirsiniz .
Örneğin
HMODULE lib = LoadLibrary("foo.dll");
void *p = GetProcAddress(lib, "bar");
// cast p to the approriate function pointer type (fp) and call it
(*fp)(arg1, arg2...);
FreeLibrary(lib);
foo.dll'de bar adlı bir işlevin adresini alır ve onu çağırırdı.
Unix sistemlerinin benzer işlevleri desteklediğini biliyorum ama isimlerini düşünemiyorum.
dlopen
dlsym
ve dlclose
. Ancak, Unix'teki kapsülleme, Windows'taki kadar etkili olmayabilir.
İşte bir düşünce. Sorunlu kitaplıklardan birini onaltılık düzenleyicide açın ve sorun teşkil eden dizelerin tüm oluşumlarını başka bir şeye değiştirin. Daha sonra yeni isimleri gelecekteki tüm aramalarda kullanabilmeniz gerekir.
GÜNCELLEME: Bu tarafta yeni yaptım ve işe yarıyor gibi görünüyor. Tabii ki, bunu tam olarak test etmedim - bacağınızı bir hexedit av tüfeğiyle uçurmanın gerçekten iyi bir yolundan başka bir şey olmayabilir.
Orada .o dosyalarınız varsa, burada iyi bir cevap: https://stackoverflow.com/a/6940389/4705766
Özet:
objcopy --prefix-symbols=pre_string test.o
.o dosyasındaki sembolleri yeniden adlandırmak için veya
objcopy --redefine-sym old_str=new_str test.o
.o dosyasındaki belirli sembolü yeniden adlandırmak için.Linux kullandığınızı varsayarsak, önce eklemeniz gerekir
#include <dlfcn.h>
İşlev işaretçisi değişkenini uygun bağlamda bildirin, örneğin,
int (*alternative_server_init)(int, char **, char **);
Ferruccio'nun https://stackoverflow.com/a/678453/1635364 adresinde belirtildiği gibi , kullanmak istediğiniz kitaplığı çalıştırarak açıkça yükleyin (favori bayraklarınızı seçin)
void* dlhandle;
void* sym;
dlhandle = dlopen("/home/jdoe/src/libwhatnot.so.10", RTLD_NOW|RTLD_LOCAL);
Daha sonra aramak istediğiniz fonksiyonun adresini okuyun
sym = dlsym(dlhandle, "conflicting_server_init");
aşağıdaki gibi atayın ve yayınlayın
alternative_server_init = (int (*)(int, char**, char**))sym;
Orijinaline benzer şekilde arayın. Son olarak, çalıştırarak boşaltın
dlclose(dlhandle);
Onları birlikte kullanmamalısın. Doğru hatırlarsam, bağlayıcı böyle bir durumda bir hata verir.
Ben denemek yoktu, ama bir çözüm ile olabilir dlopen()
, dlsym()
ve dlclose()
hangi programlı dinamik kütüphaneleri işlemek için izin verir. İki işleve aynı anda ihtiyacınız yoksa, ikinci kitaplığı / işlevi kullanmadan önce ilk kitaplığı açabilir, ilk işlevi kullanabilir ve ilk kitaplığı kapatabilirsiniz.
Bu sorun, c ++ 'ın ad alanlarına sahip olmasının nedenidir. Aynı ada sahip 2 üçüncü taraf kitap için c'de gerçekten harika bir çözüm yok.
Dinamik bir nesne ise, paylaşılan nesneleri (LoadLibrary / dlopen / etc) açıkça yükleyebilir ve bu şekilde çağırabilirsiniz. Alternatif olarak, aynı kodda aynı anda her iki kütüphaneye de ihtiyacınız yoksa, statik bağlantı ile bir şeyler yapabilirsiniz (.lib / .a dosyalarınız varsa).
Elbette bu çözümlerin hiçbiri tüm projeler için geçerli değildir.
Yemin etmek? Bildiğim kadarıyla, aynı ada sahip bağlantı noktalarını gösteren iki kitaplığınız varsa ve her ikisine de bağlantı kurmanız gerekiyorsa yapabileceğiniz pek bir şey yok.
Bunlardan birinin etrafına bir sarmalayıcı kitaplığı yazmalısınız. Sarıcı kitaplığınız, benzersiz adlara sahip sembolleri ortaya çıkarmalı ve benzersiz olmayan adların sembollerini açığa çıkarmamalıdır.
Diğer seçeneğiniz, başlık dosyasındaki işlev adını ve kütüphane nesnesi arşivindeki sembolü yeniden adlandırmaktır.
Her iki durumda da, ikisini de kullanmak bir hack işi olacak.
Soru on yıllık bir geçmişe yaklaşıyor, ancak her zaman yeni arayışlar var ...
Daha önce yanıtlandığı gibi, --redefine-sym bayrağına sahip objcopy, Linux'ta iyi bir seçimdir. Tüm belgeler için örneğin https://linux.die.net/man/1/objcopy adresine bakın. Biraz hantal çünkü değişiklik yaparken aslında tüm kitaplığı kopyalıyorsunuz ve her güncelleme bu çalışmanın tekrarlanmasını gerektiriyor. Ama en azından işe yaramalı.
Windows için, kütüphaneyi dinamik olarak yüklemek bir çözümdür ve Linux'taki dlopen alternatifi gibi kalıcı bir çözümdür. Bununla birlikte, hem dlopen () hem de LoadLibrary (), tek sorunun yinelenen adlar olması durumunda önlenebilecek fazladan kod ekler. Burada Windows çözümü objcopy yaklaşımından daha zariftir: Bağlayıcıya bir kitaplıktaki sembollerin başka bir adla bilindiğini söyleyin ve bu adı kullanın. Bunu yapmak için birkaç adım var. Bir def dosyası oluşturmanız ve İHRACAT bölümünde isim çevirisini sağlamanız gerekmektedir. Bkz. Https://msdn.microsoft.com/en-us/library/hyx1zcd3.aspx (VS2015, sonunda daha yeni sürümlerle değiştirilecektir) veya http://www.digitalmars.com/ctg/ctgDefFiles.html(muhtemelen daha kalıcı) bir def dosyasının tam söz dizimi ayrıntıları için Süreç, kitaplıklardan biri için bir def dosyası oluşturmak ve ardından bu def dosyasını bir kitaplık dosyası oluşturmak için kullanmak ve ardından bu kitaplık dosyasıyla bağlantı kurmak olacaktır. (Windows DLL'ler için, lib dosyaları kod yürütme için değil, yalnızca bağlama için kullanılır.) Bir .dll dosyası ve lib dosyası oluşturma işlemi için bir başlık dosyası varken .lib dosyası nasıl yapılır konusuna bakın . Burada tek fark, takma adların eklenmesidir.
Hem Linux hem de Windows için, adları takma adı verilen kitaplığın üstbilgilerindeki işlevleri yeniden adlandırın. Çalışması gereken başka bir seçenek de, yeni adlara atıfta bulunan dosyalarda, # eski_adı yeni_adı tanımlamak, dışa aktarılacak kitaplığın başlıklarını # dahil etmek ve ardından arayanda #undef eski_adı olmak olacaktır. Kitaplığı kullanan çok sayıda dosya varsa, daha kolay bir alternatif tanımları, içerenleri ve tanımları saran bir başlık veya başlıklar yapmak ve ardından bu başlığı kullanmaktır.
Umarım bu bilgi yardımcı olmuştur!
Hiç dlsym, dlopen, dlerror, dlclose, dlvsym, vb. Kullanmadım, ancak man sayfasına bakıyorum ve bu, libm.so'yu açma ve cos işlevini çıkarma konusunda bir örnek veriyor. Dlopen çarpışmaları arama sürecinden geçer mi? Aksi takdirde, OP her iki kitaplığı da manuel olarak yükleyebilir ve kitaplıklarının sağladığı tüm işlevlere yeni adlar atayabilir.