İki kitaplık aynı adı taşıyan ve bir çakışma oluşturan bir işlev sağlıyorsa ne yapmalıyım?


98

Eşdeğer adlara sahip işlevler sağlayan iki kitaplığım varsa ne yapmalıyım?


2
bu statik kitaplıklar mı yoksa dinamik olarak bağlantılı mı?
Alnitak

daha fazla ayrıntıya ihtiyacımız var ... bu isimler ihraç mı ediliyor? yoksa sadece dahili olarak mı kullanılıyorlar? İsimleri değiştirebilir misin?
Johannes Schaub - litb

İkisi de dinamik olarak bağlantılıdır. Kütüphanelerin sahibi olmadığım için isimleri değiştiremem.
qeek

Harika soru. Tabii ki tüm semboller benzersiz bir kimlikle öneki olsaydı bu iki kütüphaneleri ile ilgili bir sorun olmaz (örn vorbis_..., sf_..., sdl_...). Bu aslında C ++ 'nın isim alanlı fonksiyonlar için sembol isimlerine yaptığı şeydir.
Vortico

Bu çok ilginç bir soru ama maalesef çok kesin değil ve çok fazla geniş cevap almanın nedeni bu.
yugr

Yanıtlar:


53
  • Eğer birini veya her ikisini kontrol edin: düzenlemek bir isim ve recompile değiştirmek Veya eşdeğer görmek Ben ve bilinmeyeni 'ın çalışacak cevapları olmadan kaynak koduna erişim.
  • İkisini de kontrol etmezseniz, birini paketleyebilirsiniz. Bu, başka bir ada sahip bir sarmalayıcı aracılığıyla ulaşılan rahatsız edici olan dışındaki orijinalin tüm sembollerini yeniden dışa aktarmak dışında hiçbir şey yapmayan başka bir ( statik olarak bağlantılı !) Kitaplık derlemektir . Ne güçlük.
  • Daha sonra eklendi: qeek dinamik kitaplıklardan bahsettiğini söylediğinden, Ferruccio ve mouviciel'in önerdiği çözümler muhtemelen en iyisidir. (Uzun zaman önce statik bağlantının varsayılan olduğu günlerde yaşıyor gibiyim. Düşüncelerimi renklendiriyor.)

Yorumlara göre: "Dışa aktar" derken, kitaplığa bağlanan modülleri görünür kılmayı kastediyorum - externdosya 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 .


Bu benim de ilk düşüncemdi, ama aynı çarpışma problemiyle karşılaşmayacak mısın? Sonunda, tüm proje - derleme / bağlantı zamanında veya çalışma zamanında - birbirine bağlanmalıdır; bu sırada her iki rahatsız edici kitaplık olduğu gibi yüklenmelidir.
Sniggerfardimungus

@unknown: sarıcı gerekir statik bağlantı ile derlenmiş ve kusurlu sembol ihracat olmamalıdır. Ardından sarmalayıcıyı dinamik olarak bağlayabilirsiniz. Daha fazla netlik için düzenlendi, Teşekkürler.
dmckee --- eski moderatör yavru kedi

Qeek'in problemi ddl'lerdeyse ve statik kitaplıklarla ilgili değilse, bir sarmalayıcı ile yeni bir kitaplık oluşturmak nasıl mümkün olabilir? Çünkü, sarmalayıcı kitaplığı, kitaplıktaki bağlantı kurmak istemediğiniz bir işlevin çevresini dinamik olarak sarmalamak zorunda kalacaktır.
jeffD

@dmckee - "ihracat" derken neyi kastediyorsunuz?

5
belki birisi bu tekniğin basit bir örneğini verebilir? Bir exe, her biri aynı ada sahip bir işlev içeren iki kitaplık.

54

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.


2
Güzel. Makefile'a eklemek önemsiz olacaktır. Kütüphaneler hiç güncellenirse, bir objcopy büyüsünün güncellenmesi diğer çözümlerden bazılarına göre çok daha kolay olacaktır.
sigjuice

9
Başlık dosyalarındaki sembolleri de yeniden adlandırmayı unutmayın.
mouviciel

^ sed / awk / perl, başlıktaki sembollerin yeniden adlandırılmasını otomatikleştirmek için de yararlı olacaktır
Alex Reinking

16

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 dlsymve dlclose. Ancak, Unix'teki kapsülleme, Windows'taki kadar etkili olmayabilir.
user877329


8

İş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.


aslında korkunç bir çözüm değil. Biraz hile, ama tek yapmanız gereken sembol tablosundaki dizeleri değiştirmek. Bunda gerçek bir işlevsel zarar yok.
Evan Teran

Muhtemelen kitaplığı da yeniden adlandırmak istersiniz - başka biri gelip onu tekrar yüklemeye çalışmasın diye. Bir çatışmadan düzinelerce veya yüzlercesine geçersiniz. =] Stackoverflow ile ilgili bunu seviyorum: bir soruya test edilmiş bir cevabımız var ve 3 oy var. İlk (eksik) cevap: 17. =]
Sniggerfardimungus

1
Yalnızca adları kısaltabileceğiniz için yeniden adlandırma fırsatları sınırlıdır . Ayrıca Linux'ta ELF hash tablolarını güncellemekte zorlanacaksınız.
yugr

8

Orada .o dosyalarınız varsa, burada iyi bir cevap: https://stackoverflow.com/a/6940389/4705766

Özet:

  1. objcopy --prefix-symbols=pre_string test.o .o dosyasındaki sembolleri yeniden adlandırmak için

veya

  1. objcopy --redefine-sym old_str=new_str test.o .o dosyasındaki belirli sembolü yeniden adlandırmak için.

7

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);


6

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.


Teşekkürler. Bunu düşünmedim. Yine de ikisine de aynı anda sahip olmak isterim.
qeek

Ya ikisini aynı anda kullanmak istersem?
QZHua

@QZHua: Diğer cevaplayıcılar (örneğin, sembol yeniden adlandırmayı içeren) probleminizi çözmelidir.
mouviciel

4

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.


2
Oh evet. Bu genel soru için bu iyi bir cevap gibi görünüyor. Bununla birlikte, her şeyi aynı derleyicide derlerseniz ad alanları harikadır. Yaşasın, isim çatışması yok. Ancak ikili biçimde bir kitaplık alırsanız ve onu başka bir derleyiciyle bütünleştirmek istiyorsanız, o zaman - iyi şanslar. Nesne dosyalarındaki ad karıştırma kuralları yalnızca ilk engeldir (ad alanlarının etkisini ortadan kaldıran harici "C" yardımcı olabilir).
Tomasz Gandor

3

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.


12
Yemin etmek kesinlikle ilk adımdır. Hiç şüphe yok.
dmckee --- eski moderatör yavru kedi

1
"yapabileceğin pek bir şey yok" - bu hala geçerli mi? Diğer yanıtlar çok sayıda farklı çözüm sağlar.
yugr

2

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.



1

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!


0

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.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.