2013-07-11 3 views
6

पर लिनक्स और मिनीजीडब्ल्यू पर जीसीसी का उपयोग करके साझा लाइब्रेरी का निर्माण करना मुझे एक बिल्ड सेटअप बनाने में परेशानी हो रही है जो क्रमशः जीसीसी और मिनजीडब्ल्यू का उपयोग करके लिनक्स और विंडोज दोनों में साझा पुस्तकालयों को निर्मित करने की अनुमति देता है। लिनक्स में, साझा लाइब्रेरी को संकलन समय पर सभी निर्भरताओं को हल करने की आवश्यकता नहीं होती है; जबकि, यह विंडोज़ में इस मामले में प्रतीत होता है।विंडोज


$ cat foo.h 
#ifndef FOO_H 
#define FOO_H 
void printme(); 
#endif 

$ cat foo.c 
#include "foo.h" 
#include <stdio.h> 
void printme() { 
    printf("Hello World!\n"); 
} 

$ cat bar.h 
#ifndef BAR_H 
#define BAR_H 
void printme2(); 
#endif 

$ cat bar.c 
#include "bar.h" 
#include "foo.h" 
void printme2() { 
    printme(); 
    printme(); 
} 

$ cat main.c 
#include "bar.h" 
int main(){ 
    printme2(); 
} 
: यहाँ समस्या सेटअप है
$ cat Makefile 
.c.o: 
     gcc -fPIC -c $< 

all: foo.o bar.o main.o 
     gcc -shared foo.o -o libfoo.so 
     gcc -shared bar.o -o libbar.so 
     gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main 

अब, लिनक्स में, इस संकलित करता है तथा ठीक चलाता है:

$ make 
gcc -fPIC -c foo.c 
gcc -fPIC -c bar.c 
gcc -fPIC -c main.c 
gcc -shared foo.o -o libfoo.so 
gcc -shared bar.o -o libbar.so 
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main 

$ ./main 
Hello World! 
Hello World! 

विंडोज में, हम dll, जो बहुत ही कम हो ताकि बदलने की जरूरत है और ठीक:

$ cat Makefile 
.c.o: 
     gcc -fPIC -c $< 

all: foo.o bar.o main.o 
     gcc -shared foo.o -o libfoo.dll 
     gcc -shared bar.o -o libbar.dll 
     gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main 

हालांकि, जब हम निर्माण करने का प्रयास करते हैं, तो हमें निम्न त्रुटि मिलती है:

$ make 
gcc -fPIC -c foo.c 
foo.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default] 
gcc -fPIC -c bar.c 
bar.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default] 
gcc -fPIC -c main.c 
main.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default] 
gcc -shared foo.o -o libfoo.dll 
gcc -shared bar.o -o libbar.dll 
bar.o:bar.c:(.text+0x7): undefined reference to `printme' 
bar.o:bar.c:(.text+0xc): undefined reference to `printme' 
collect2.exe: error: ld returned 1 exit status 
make: *** [all] Error 1 

अब, हम बस libbar.dll में foo.o से वस्तुओं को शामिल करके त्रुटि को ठीक कर सकते हैं:

$ cat Makefile 
.c.o: 
     gcc -fPIC -c $< 

all: foo.o bar.o main.o 
     gcc -shared foo.o -o libfoo.dll 
     gcc -shared bar.o foo.o -o libbar.dll 
     gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main 

$ make 
gcc -fPIC -c foo.c 
foo.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default] 
gcc -fPIC -c bar.c 
bar.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default] 
gcc -fPIC -c main.c 
main.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default] 
gcc -shared foo.o -o libfoo.dll 
gcc -shared bar.o foo.o -o libbar.dll 
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main 

$ ./main 
Hello World! 
Hello World! 

हालांकि, मैं इस दृष्टिकोण पसंद नहीं है के बाद से libbar.dll अब प्रतीक शामिल होते हैं दोनों फू और बार के लिए। लिनक्स में, इसमें केवल बार के लिए प्रतीक होते हैं। यह अलगाव उन स्थितियों के लिए महत्वपूर्ण है जहां पुस्तकालय कुछ मानक संख्यात्मक पुस्तकालय जैसे बीएलएएस पर निर्भर करता है। मैं साझा लाइब्रेरी को तैनात करने में सक्षम होना चाहता हूं और यह उपयोगकर्ता की मशीन पर संख्यात्मक लाइब्रेरी के अनुकूलित संस्करण पर निर्भर करता है, न कि स्वयं का।

किसी भी मामले में, साझा लाइब्रेरी बनाने के लिए उचित प्रक्रिया क्या है जहां सभी प्रतीकों संकलन समय पर मौजूद नहीं हैं?

यदि यह महत्वपूर्ण है, तो मैंने इन उदाहरणों को लिनक्स पर जीसीसी 4.6.3 और विंडोज़ पर जीसीसी 4.7.2 के साथ mingw-get-inst-20120426.exe के साथ संकलित किया।

+0

आप 'f__.h' और 'bar.h' दोनों में आवश्यक' __declspec (dllimport) 'और' __declspec (dllexport) 'खो रहे हैं। की तरह कुछ: '#if __ELF__ #define एपीआई __attribute ((दृश्यता (" डिफ़ॉल्ट "))) परिभाषित परिभाषित निर्यात #define एपीआई __declspec (dllexport) #else #define एपीआई __declspec (dllimport) #endif #elif ' फिर' foo.c' और 'bar.c' में '# परिभाषित करें'। – bit2shift

+0

कुछ ऐसा [https://]] (https://github.com/bit2shift/r3dVoxel/blob/master/inc/r3dVoxel/r3vABI.hpp#L7-L13) लेकिन बिना 'बाहरी "सी" 'के बिना, जो एक सी ++ निर्माण है। – bit2shift

उत्तर

8

विंडोज़ पर, आपको DLL के लिए आयात लाइब्रेरी बनाने की आवश्यकता है। एक आयात पुस्तकालय स्थिर पुस्तकालय की तरह दिखता है, जिसमें यह सभी आवश्यक प्रतीकों को परिभाषित करता है, लेकिन इसमें वास्तविक कार्य कार्यान्वयन नहीं होते हैं, इसमें केवल स्टब्स हैं। स्थाई लिंकिंग से बचते समय आयात लाइब्रेरी "अपरिभाषित संदर्भ" त्रुटियों को हल करेगी।

मिनजीडब्ल्यू के साथ एक आयात पुस्तकालय बनाने के लिए, here निर्देशों का पालन करें। कुंजी यह है कि जब डीएलएल का निर्माण होता है, तो आपको आयात पुस्तकालय libexample_dll.a उत्पन्न करने के लिए लिंकर को -Wl,--out-implib,libexample_dll.a विकल्प को पास करना होगा।

फिर, जब आप अपना मुख्य निष्पादन योग्य संकलित करते हैं, तो आप आयात पुस्तकालय के विरुद्ध लिंक करने के लिए -lexample_dll विकल्प (-L. के साथ) का उपयोग करते हैं।अपने कोड के साथ तो, मुझे लगता है कि यह काम करना चाहिए:

all: foo.o bar.o main.o 
    gcc -shared foo.o -o libfoo.dll -Wl,--out-implib,libfoo.a 
    gcc -shared bar.o foo.o -o libbar.dll -Wl,--out-implib,libbar.a 
    gcc main.o -Wl,-rpath=. -L. -lbar -lfoo -o main 

इसके अलावा, जो Windows पर ध्यान दें, DLL में निर्यात कार्यों के लिए बुला सम्मेलन लगभग हमेशा __stdcall नहीं डिफ़ॉल्ट __cdecl है, इसलिए यदि आप करने के लिए अपने DLLs चाहते अन्य सॉफ़्टवेयर द्वारा प्रयोग योग्य होने के लिए, मैं उन्हें __cdecl बनाने की सलाह दूंगा। लेकिन इसकी कड़ाई से आवश्यकता नहीं है, जब तक कि डीएलएल और हेडर फाइलों में दोनों कोड कॉलिंग सम्मेलन के बारे में सहमत हों।

+2

यह बहुत अच्छा काम किया। एक मामूली टिप्पणी के रूप में, मैंने उपयोग किया: आयात पुस्तकालय का उपयोग करने के लिए "gcc -shared bar.o -L। -lfoo -o libbar.dll -Wl, - out-implib, libbar.a"। – wyer33

+0

आपको कॉलिंग सम्मेलन का हिस्सा सभी गलत मिला है। Win32 API सम्मेलन '__stdcall' है, ** लेकिन यह सबसे अधिक उपयोग नहीं किया जाने वाला सम्मेलन ** है, '__cdecl' है। आपको सर्वोत्तम परिणामों को प्राप्त करने के लिए 'बाहरी "सी" 'के साथ जोड़ा गया एक खाली कॉलिंग कन्वेंशन (उर्फ निहित' __cdecl') का उपयोग करना चाहिए: कोई मैंगलिंग और .def फ़ाइलों की आवश्यकता नहीं है (जिसे आप इन दिनों अप्रचलित मानते हैं बुरा सामान)। – bit2shift

+0

'__stdcall' मुख्य रूप से 'कोडबैक' मैक्रो का उपयोग करते हुए Win32 विंडो सबसिस्टम में संदेश हैंडलिंग के लिए कॉलबैक को परिभाषित करते समय उपयोगकर्ता कोड में स्पष्ट रूप से उपयोग किया जाता है। – bit2shift