Intermixing C and C++ |
This article gives a general idea about the Symbian DEF file. Whenever developers write any DLLs that export a set of APIs to the user, there will be an entry for each exported API in the DEF file created. The developer will use:
After building the application for the first time, it will list all the newly exported APIs. After doing a freeze (for which the abld freeze winscw and abld freeze armv5 commands are used), the DEF files will be created under BWINS and EABI folders within the project directory. These DEF files are used to create .lib files for DLLs. In the DEF file, for each exported API, there will be mapping between its prototype and a number will be present.
Let's assume that directory structure used for implementing a library is as shown below:
If a developer is building the library for the first time, the developer should follow these steps and give the following commands from LibraryName\group:
LibraryName\group>bldmake bldfiles
LibraryName\group>abld build
LibraryName\group>abld freeze
LibraryName\group> abld build
The final step is required since applications that link with this library (LibraryName.DLL) will link with LibraryName.lib during link time. If the developer fails to perform the final step, the application will get a linker error because there is no LibraryName.lib present.
When porting or writing libraries that export C APIs to the user, care should be taken to ensure that extern "C" is used properly if those APIs are implemented in a C++ source file. Otherwise these libraries may either not be built for the target platform (ARMV5) or the user of such library will get a linker error when using exported APIs of such library.
If extern "C" is declared in the header and not defined in the source, then after building the library there will be a similar entry in DEF files. The compiler will not give external linkage to these APIs. This can be observed when trying to use these APIs from some other C source file. To overcome this, extern "C" must be present in both declarations and definitions.
/*File: SampleDLL.h*/ /*extern "C" is not used for declaration!*/ #ifndef SAMPLEDLL_H #define SAMPLEDLL_H typedef int MyInt; typedef int (*MyFunPtr) (); IMPORT_C int MyLibLibFun1(MyInt aParam); IMPORT_C int MyLibLibFun3(MyFunPtr); IMPORT_C int MyLibLibFun2(int (*MyFun1)()); #endif /*SAMPLEDLL_H*/ //File: SampleDLL.cpp #include "SampleDLL.h" // extern "C" is used for definition extern "C" { EXPORT_C int MyLibLibFun1(MyInt aParam) { return aParam + 10; } EXPORT_C int MyLibLibFun2(int (*MyFun1)()) { return MyFun1(); } EXPORT_C int MyLibLibFun3(MyFunPtr aPtr) { return aPtr(); } }
This code will get compiled for WINSCW. The DEF file for WINSCW will have the following entries:
EXPORTS [email protected]@[email protected] @ 1 NONAME ; int MyLibLibFun1(int) [email protected]@[email protected] @ 2 NONAME ; int MyLibLibFun2(int (*)(void)) [email protected]@[email protected] @ 3 NONAME ; int MyLibLibFun3(int (*)(void))
Even if we comment extern "C" from the above SampleDLL.cpp file, we will have the same DEF file entries.
If we try the above code without extern "C" in SampleDLL.cpp, the code will get built and the DEF file entry for ARMv5 will be:
EXPORTS _Z12MyLibLibFun1i @ 1 NONAME _Z12MyLibLibFun2PFivE @ 2 NONAME _Z12MyLibLibFun3PFivE @ 3 NONAME
If we keep the extern "C" in SampleDLL.cpp, this code will not get compiled for ARMv5 and will result in the error given below:
"..\src\Sampledll.cpp", line 7: Error: #337: linkage specification is incompatible with previous "MyLibLibFun1" (declared at line 9 of "..\inc\SampleDLL.h") EXPORT_C int MyLibLibFun1(MyInt aParam) ^ "..\src\Sampledll.cpp", line 17: Error: #337: linkage specification is incompatible with previous "MyLibLibFun3" (declared at line 11 of "..\inc\SampleDLL.h") EXPORT_C int MyLibLibFun3(MyFunPtr aPtr) ^
The reason for the errors is that MyLibLibFun1 and MyLibLibFun3 use typedef datatypes. There is no issue with MyLibLibFun2() since it does not use typedef datatypes. To overcome these errors, we have to keep both the declaration and the definition within extern "C" linkage.
/*File: SampleDLL.h*/ #ifndef SAMPLEDLL_H #define SAMPLEDLL_H /*extern "C" is used for declaration also*/ typedef int MyInt; typedef int (*MyFunPtr) (); #ifdef __cplusplus extern "C" { #endif //__cplusplus IMPORT_C int MyLibLibFun1(MyInt aParam); IMPORT_C int MyLibLibFun3(MyFunPtr); IMPORT_C int MyLibLibFun2(int (*MyFun1)()); #ifdef __cplusplus } #endif //__cplusplus #endif /*SAMPLEDLL_H*/
When everything is within extern "C" (extern "C" in header and implementation), the DEF file for ARMv5 and WINSCW looks as follows:
EXPORTS MyLibLibFun1 @ 1 NONAME MyLibLibFun2 @ 2 NONAME MyLibLibFun3 @ 3 NONAME
So, as one can observe in the above section where different DEF file entries are created with and without extern "C", we should make sure that the rule is followed. extern "C" has to be used in both declaration and definition: otherwise we will either not be able to build it for all the platforms or it will not be possible to use those exported C APIs in other applications.
©Nokia 2007 |