由于windows在动态链接的时候,必须从dll文件对应的lib文件里面寻找可链接程序的标志符,因此当你编译生成一个动态库的时候,必须生成相应的lib文件。
有两种方法,一种是
1、在命令行执行:dumpbin /exports yourdll.dll > yourdll.def
2、编辑 yourdll.def 文件,使之格式与.def文件格式一致。比如:
EXPORTS;
fn1;
fn2;
3、在命令行执行:
lib /def:yourdll.def /machine:i386 /out:yourdll.lib
下面是sqlite3的def文件,其实就是你要导出的函数的名字。
EXPORTS sqlite3_aggregate_context sqlite3_aggregate_count sqlite3_auto_extension sqlite3_backup_finish sqlite3_backup_init sqlite3_backup_pagecount sqlite3_backup_remaining sqlite3_backup_step sqlite3_bind_blob sqlite3_bind_double sqlite3_bind_int sqlite3_bind_int64 sqlite3_bind_null sqlite3_bind_parameter_count sqlite3_bind_parameter_index sqlite3_bind_parameter_name sqlite3_bind_text sqlite3_bind_text16 sqlite3_bind_value sqlite3_bind_zeroblob sqlite3_blob_bytes sqlite3_blob_close sqlite3_blob_open sqlite3_blob_read sqlite3_blob_reopen sqlite3_blob_write sqlite3_busy_handler sqlite3_busy_timeout sqlite3_changes sqlite3_clear_bindings sqlite3_close sqlite3_collation_needed sqlite3_collation_needed16 sqlite3_column_blob sqlite3_column_bytes sqlite3_column_bytes16 sqlite3_column_count sqlite3_column_database_name sqlite3_column_database_name16 sqlite3_column_decltype sqlite3_column_decltype16 sqlite3_column_double sqlite3_column_int sqlite3_column_int64 sqlite3_column_name sqlite3_column_name16 sqlite3_column_origin_name sqlite3_column_origin_name16 sqlite3_column_table_name sqlite3_column_table_name16 sqlite3_column_text sqlite3_column_text16 sqlite3_column_type sqlite3_column_value sqlite3_commit_hook sqlite3_compileoption_get sqlite3_compileoption_used sqlite3_complete sqlite3_complete16 sqlite3_config sqlite3_context_db_handle sqlite3_create_collation sqlite3_create_collation16 sqlite3_create_collation_v2 sqlite3_create_function sqlite3_create_function16 sqlite3_create_function_v2 sqlite3_create_module sqlite3_create_module_v2 sqlite3_data_count sqlite3_db_config sqlite3_db_handle sqlite3_db_mutex sqlite3_db_status sqlite3_declare_vtab sqlite3_enable_load_extension sqlite3_enable_shared_cache sqlite3_errcode sqlite3_errmsg sqlite3_errmsg16 sqlite3_exec sqlite3_expired sqlite3_extended_errcode sqlite3_extended_result_codes sqlite3_file_control sqlite3_finalize sqlite3_free sqlite3_free_table sqlite3_get_autocommit sqlite3_get_auxdata sqlite3_get_table sqlite3_global_recover sqlite3_initialize sqlite3_interrupt sqlite3_last_insert_rowid sqlite3_libversion sqlite3_libversion_number sqlite3_limit sqlite3_load_extension sqlite3_log sqlite3_malloc sqlite3_memory_alarm sqlite3_memory_highwater sqlite3_memory_used sqlite3_mprintf sqlite3_mutex_alloc sqlite3_mutex_enter sqlite3_mutex_free sqlite3_mutex_leave sqlite3_mutex_try sqlite3_next_stmt sqlite3_open sqlite3_open16 sqlite3_open_v2 sqlite3_os_end sqlite3_os_init sqlite3_overload_function sqlite3_prepare sqlite3_prepare16 sqlite3_prepare16_v2 sqlite3_prepare_v2 sqlite3_profile sqlite3_progress_handler sqlite3_randomness sqlite3_realloc sqlite3_release_memory sqlite3_reset sqlite3_reset_auto_extension sqlite3_result_blob sqlite3_result_double sqlite3_result_error sqlite3_result_error16 sqlite3_result_error_code sqlite3_result_error_nomem sqlite3_result_error_toobig sqlite3_result_int sqlite3_result_int64 sqlite3_result_null sqlite3_result_text sqlite3_result_text16 sqlite3_result_text16be sqlite3_result_text16le sqlite3_result_value sqlite3_result_zeroblob sqlite3_rollback_hook sqlite3_rtree_geometry_callback sqlite3_set_authorizer sqlite3_set_auxdata sqlite3_shutdown sqlite3_sleep sqlite3_snprintf sqlite3_soft_heap_limit sqlite3_soft_heap_limit64 sqlite3_sourceid sqlite3_sql sqlite3_status sqlite3_step sqlite3_stmt_readonly sqlite3_stmt_status sqlite3_strnicmp sqlite3_table_column_Metadata sqlite3_test_control sqlite3_thread_cleanup sqlite3_threadsafe sqlite3_total_changes sqlite3_trace sqlite3_transfer_bindings sqlite3_update_hook sqlite3_uri_parameter sqlite3_user_data sqlite3_value_blob sqlite3_value_bytes sqlite3_value_bytes16 sqlite3_value_double sqlite3_value_int sqlite3_value_int64 sqlite3_value_numeric_type sqlite3_value_text sqlite3_value_text16 sqlite3_value_text16be sqlite3_value_text16le sqlite3_value_type sqlite3_vfs_find sqlite3_vfs_register sqlite3_vfs_unregister sqlite3_vmprintf sqlite3_vsnprintf sqlite3_vtab_config sqlite3_vtab_on_conflict sqlite3_wal_autocheckpoint sqlite3_wal_checkpoint sqlite3_wal_checkpoint_v2 sqlite3_wal_hook sqlite3_win32_mbcs_to_utf8 sqlite3_win32_utf8_to_mbcs
第二种就是在你要到处的函数的前面加
extern "c" void
__declspec
(
dllexport
) CallC(
char
* szText){
std::cout << szText << std::endl;
}
void
__declspec
(
dllexport
) CallC(
char
* szText){
std::cout << szText << std::endl;
}
void
__declspec
(
dllexport
) __stdcall CallStd(
char
* szText){
std::cout << szText << std::endl;
}
具体好像他们又有区别,希望知道的朋友能给解释下,我也不是很清楚了,我当时就这么用,然后我的问题搞定了,看了一些资料,也没搞得很明白,具体有一段英文的好像写的还比较明白了 一起贴下面了。
Stdcall and DLL tools of MSVC and MinGW
The __stdcall calling convention has been there for a very longtime. While older calling conventions like __pascal fell intooblivion,__stdcall became the standard calling convention of Win32API functions. Unlike __cdecl (the native calling conventionof C/C++),it is supported in C/C++,Visual Basic,Java,and other languagesalike,which makes it the first choice when building a DLL for cross-languageuse.
The internal representations of both __cdecl and __stdcallfunctions have decorations. In MSVC (Microsoft Visual C++) and MinGW(Minimalistic GNU for Windows) GCC,__cdecl function will be prefixedan underscore,and __stdcall functions will have the beginning underscoreas well as be appended by the at-sign (@) followed by the numberof bytes in the argument list. So,double __cdecl sin(double)will be decorated as _sin,and double __stdcall sin(double)will be decorated as _sin@8.
But things are not that simple. The decorations could change when theyappear in DLLs or when they are produced by different compilers. The followingtable lists the names as are produced by MSVC,MinGW,Digital Mars C/C++Compiler (DMC),Borland C++ Compiler/C++ Builder (BCC):
Calling Convention | Internal* | MSVC DLL (w/ DEF) | MSVC DLL (dllexport) | DMC DLL | MinGW DLL | BCC DLL |
__stdcall | _Function@n | Function | _Function@n | _Function@n | Function@n | Function |
__cdecl | _Function | Function | Function | Function | Function | _Function |
* For all but BCC,which has the same namingconvention for symbols in code and exported name in DLL.
What a mess (especially when you notice that,for MSVC,whether aname is exported by a DEF file or by the
Tools working with DEF files
First,I will talk about the DEF file format and the relevant tools usedwith MSVC and MinGW. Many intricacies lie here.DEF file format
We care about only two sections of the DEF file: the LIBRARY section andthe EXPORTS section. The LIBRARY section specifies the internal name ofthe DLL; and the EXPORTS section specifies the function or data items toexport. A short example follows:This DEF file defines three exports for a testdll.dll:the first one is a __cdecl function,the second one a __stdcallfunction,and the third one an alias of the first function (the leftside of the "=" sign is an exported name and the right side the internalname). The three functions are also assigned ordinals. A functioncan be called by its name or its ordinal.LIBRARY testdll.dll EXPORTS cdeclFunction @1 _stdcallFunction@8 @2 aliasName = cdeclFunction @3
CL
CL can accept a DEF file on the command line,and it simply passesthe file name to LINK. E.g.,will becomecl /LD testdll.obj testdll.def
link /out:testdll.dll /dll /implib:testdll.lib /def:testdll.def testdll.obj
LINK
LINK is our most important tool when treating DLL and DEF fileswith MSVC. The command line mentioned in CL already shows the optionscommonly used when creating a DLL with a DEF file. The main point is: ifwe do not use a DEF file when creating a DLL,the exported name of a __stdcallfunction will be _Function@n; but if we use a DEFfile,the exported name could be either Function or _Function@n;if both names appear,only the undecorated form is used. However,wecan force both forms of exports with the following lines in the EXPORTSsection:TestFunction = _TestFunction@4 _TestFunction@4 = _TestFunction@4
LIB
If we have the DLL from somebody else (no source available),and we havethe DEF file,the easiest way to create an import library is to use the LIBtool. The following Syntax is often enough (check MSDNfor more details):Nota bene: 1) it seems LIB does not accept aliased forms(it will simply ignore the part after the equal-sign); 2) it assumes allfunctions in the DEF file __cdecl. The second point lies in thefact that the import library it produces will map each symbol in the DLLto an internal name with an underscore prefixed,i.e.,the linker usingthe import library will try to resolve an undefined symbol _Functionto the symbol Function in the DLL. It takes no special care ofthe __stdcall calling convention. With some techniques we coulduse LIB to produce import libraries for __stdcall functions,but the caller could only call them by ordinal,not by name. The detailsare left as an exerciselib /def:DEF_file
gcc
Here we use gcc to call ld. The reason why we do not use lddirectly is that using gcc is generally more convenient. Theld
GNU ld has many options regarding DLLs,but we shall only focuson four (help information follows):Either gcc or ld can accept a DEF file directly on the commandline. When a function (say,TestFunction@4) is marked as __declspec(dllexport),and we have the following line in theEXPORTS section,--add-stdcall-alias Export symbols with and without @nn --kill-at Remove @nn from exported symbols --out-implib <file> Generate import library --output-def <file> Generate a .DEF file for the built DLL
both symbols will be exported to the DLL ( LINK has similarbehavIoUr too). This behavIoUr is different from dllwrap,whichwe shall talk of immediately.TestFunction = TestFunction@4
dllwrap
GNU dllwrap could produce a DLL by a DEF file. We generally use dllwrapin the following Syntax,and dllwrap will transparently call gcc, ld,and dlltoolto fulfil its task. If dllwrap is asked to produce an import librarydllwrap --def DEF_file -o DLL_file OBJ_files [--output-lib LIB_file]
dlltool
GNU dlltool may be used to create the files needed to build anduse dynamic link libraries (DLLs). The following options are of interestto us currently:dlltool works like LIB,and similarly it will ignore the part after the equal-sign in a DEF file,but ithas its special features that somehow compensate for this shortcoming:-l --output-lib <outname> Generate an interface library. -D --dllname <name> Name of input dll to put into interface lib. -d --input-def <deffile> Name of .def file to be read in. -U --add-underscore Add underscores to symbols in interface library. -k --kill-at Kill @<n> from exported names.
- the
-U optionmakes the items in the DEF file map to symbols prefixed with anunderscore in the DLL,and - the
-k option makes theitems in the DEF file map to symbols stripped of @n inthe DLL.
pexports
This is a stand-alone open-source tool to produce a DEF file from a givenDLL. It is not distributed with MSVC or MinGW,and you may choose to download hereif you do not find it elsewhere.The __stdcall DLL and the import library
Having learnt so much about the tools,now we are ready to do what we wanted.We still need sed (search on the Internet if you do not alreadyhave this useful tool),and a knowledge of regular expression is requiredto understand thoroughly how it works.Microsoft Visual C++
The simplest way to produce a DLL is to use the /LD command-lineoption of CL:The resulting DLL will have exported names like _MyFunction@8,as is shown in the `MSVC DLL (dllexport)' columnabove. To create symbols with no decoration,we must use a DEF file. Thefollowing is an automatic way to create a DEF file from the DLL if __declspec(dllexport) is used to indicate which functions toexport:cl /LD OBJ_files
At this step,you may also want to generate a DEF file to make the DLLusable with MinGW source.link /out:DLL_file /dll OBJ_files pexports DLL_file | sed "s/^_\([[:alnum:]_]\+\)@[[:digit:]]\+/\1/" > DEF_file
Once you have the object files and the DEF file,creating the DLL and theimport library can be done in one step:pexports DLL_file | sed "s/^_\([[:alnum:]_]\+\)\(@[[:digit:]]\+\)/\1\2/" > DEF_for_gcc
And you are free to use the DLL and the import library now as you wish.link /out:DLL_file /dll /def:DEF_file /implib:LIB_file OBJ_files
MinGW GCC
If we do not need to control which functions to export except by __declspec(dllexport),we can type:If we want to use a DEF file to control which functions to export,we canstart by (assuming __declspec(dllexport) is used to indicate whichfunctions to export)gcc -shared -o DLL_file OBJ_files -Wl,--output-def,DEF_file gcc -shared -o DLL_file OBJ_files -Wl,--kill-at dlltool -d DEF_file --dllname DLL_file --output-lib LIB_file --kill-at
to produce a DEF file with exports like " Function =Function@n@Ordinal". After editing it to our will,the following commandswill finish the job:gcc -shared -o DLL_file OBJ_files -Wl,--kill-at,DEF_file
And the import library is now at your hand to use.dllwrap --def DEF_file -o DLL_file OBJ_files sed "s/[[:alnum:]_]\+ *= *//" DEF_file > New_DEF_file dlltool -d New_DEF_file --dllname DLL_file --output-lib LIB_file --kill-at
I am not sure whether I have stated clearly,but I have listed all myfindings when I struggled to find out how to use the DLL tools properlyand how to deal with __stdcall functions in DLLs. Hope you findit useful.
ACKNOWLEDGEMENT: The MinGW mailing list provided much usefulinformation; Luke Dunstan provided important suggestions and corrections.