Writing of C dynamic library and C calling dynamic library

Writing of C dynamic library and C calling dynamic library

GCC common compilation options

1. Overall compilation options

option name effect
-c Just compile without linking, generate object file .o
-S Just compile without assembly, generate assembly code
-E Only precompile, no other processing
-g Include standard debugging information in executable programs
-o file output the output file to file
-v Print out the command line information of each process compiled inside the compiler and the version of the compiler
-I dir Add the dir directory to the list of search paths for header files
-L dir Add the dir directory to the list of search paths for library files
-static link static library
-llibrary Link to the library file named library

2. Other common compilation options

option name effect
-ansi Support for ANSI-compliant C programs
-pedantic Allows all warning messages listed in the ANSI C standard to be issued
-pedantic-error Allows all error messages listed in the ANSI C standard to be issued
-Wall Allows all useful warning messages provided by gcc to be issued
-Werror Convert all warning messages to error messages, and terminate the compilation process when a warning occurs
-O Mainly perform two optimizations: Thread Jump and Deferred Stack Pops
-O2 In addition to doing all the "-O1" level optimizations, some additional tuning work is also required, such as processor instruction scheduling, etc.
-O3 Also includes loop unrolling and some other processor-specific optimizations
-static Instructs the linker to build a fully linked executable, i.e. linking static libraries and not dynamic libraries
-fPIC Instructs the linker to create a shared object file, the so file
-shared Generate a dynamic library, generally used with -fPIC above

write DLL

external “c”

The way __stdcall is called will add symbols to the original function name, while extern "c" __cdecl will not add extra symbols.

If the exported function uses extern "C" __cdecl, then there is no need to rename it. At this time, the name in the dll is the original name; if extern "C" __stdcall is used, the function name in the dll is modified at this time. need to be renamed. There are two ways of renaming, either using *.def files, and fixing them outside the file, or using #pragma, aliasing the function in the code.

The role of __declspec(dllexport) and __declspec(dllimport)

__declspec has other uses, only the use related to dll is discussed here. Just like the keywords in parentheses, export and import. __declspec(dllexport) is used on dll to indicate that this is an exported function. And __declspec(dllimport) is used in the program that calls the dll to indicate that this is a function imported from the dll.

__declspec(dllexport) is necessary because the function must be specified in the dll for export. But in another way, you can use the def file to indicate which functions are used for export, and there are function numbers in the def file.

Using __declspec(dllimport) is not required, but recommended. Because if __declspec(dllimport) is not used to indicate that the function is imported from dll, then the compiler does not know where the function is, and there will be an instruction to call XX in the generated exe, this XX is a constant address, XX The address is a jmp dword ptr[XXX] instruction, which jumps to the function body of the function. Obviously, there is an additional intermediate jump for no reason. If __declspec(dllimport) is used to describe, then call dword ptr[XXX] will be generated directly, so that there will be no redundant jumps.

The impact of __stdcall

This is a method of calling conventions for functions, and the method of pushing the stack is different from the method of clearing the stack at the end, __stdcall
是函数自己处理栈, __cdecl是函数调用者清理. By default, VC uses the __cdecl function call method. If the generated dll is only used by C/C++ programs, then there is no need to define the __stdcall call method. If you want to use it for Win32 assembly (or other __stdcall) call method), then you can use __stdcall. This may not be very important, because you can set the rules for function calls when you call the function. Like VC, you can set the calling method of the function, so you can easily use the dll generated by win32 assembly. However, the calling convention of __stdcall will be Name-Mangling, so I think it is easier to use the default calling convention of VC. However, if you want both the __stdcall calling convention and the function name without modification, you can use a *.def file, or provide an alias for the function in the form of #pragma in the code (this method requires you to know that the modified function name is what).

Example:

extern “C” __declspec(dllexport) bool __stdcall cswuyg();

extern “C” __declspec(dllimport) bool __stdcall cswuyg();

#pragma comment(linker,”/export:cswuyg=_cswuyg@0”)

*.def files

Specify the exported function , and tell the compiler not to use the modified function name as the exported function name, but to export the function with the specified function name ( for example, if there is a function func, the function name is still func after the compiler processes it). In this way, you can avoid link errors due to the unique handling of the Microsoft VC++ compiler.

That is to say, if the def file is used, extern "C" is not needed, and __declspec(dllexport) is not needed (however, the dll manufacturer also provides header files in addition to the dll, which needs to be in the Add this extern "C" and calling convention to the header file, because the user needs to follow the same rules as the manufacturer).

Example def file format:

LIBRARY XX (the dll name is not required, but it must be the same as the generated dll name)

EXPORTS

[function name] @ [function number]

After writing it, you can add it to the VC project.

​ In addition, it should be noted that if you want to use __stdcall, you must use __stdcall in the code, because the *.def file is only responsible for modifying the function name, not the calling convention.

That is, the def file only cares about the function name, regardless of how the function balances the stack.

How to add the *.def file to the project, it is not automatically added when linking. Then do this:

Manually add at the link:

1) Add the properties Configuration Properties Linker Command Line of the project to "Additional options": /def:[full file name].def

2) Add [full file name].def to the properties Configuration Properties Linker Input Module Definition File of the project

DllMain function

Every dynamic link library will have a DllMain function. If the DllMain function is not defined during programming, the compiler will add it to you.

DllMain function format:

BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                       )
{
    switch(ul_reason_for_call)
     {
     case DLL_PROCESS_ATTACH:
            printf("\nprocess attach of dll");
            break;
     case DLL_THREAD_ATTACH:
            printf("\nthread attach of dll");
            break;
     case DLL_THREAD_DETACH:
            printf("\nthread detach of dll");
            break;
     case DLL_PROCESS_DETACH:
            printf("\nprocess detach of dll");
            break;
     }
    return TRUE;
}

Writing a dll can use a .def file to name the exported function name.

Example DLL

C

1. Header filetest.h

#ifndef TEST_H
#define TEST_H

//#define WIN
//#define TEST_EXPORTS
#ifdef WIN
    #ifdef TEST_EXPORTS
    #define EX_FUN __declspec(dllexport)
    #else
    #define EX_FUN __declspec(dllimport)
    #endif
    #define CALL_METHOD __stdcall  //__cdecl
    #define CALLBACK    __stdcall
#else
    #define EX_FUN extern "C"
    #define CALL_METHOD
    #define CALLBACK
#endif //linux

#ifdef __cplusplus
extern "C" {
#endif

EX_FUN void CALL_METHOD test1();
EX_FUN void CALL_METHOD test2();

#ifdef __cplusplus
}
#endif
#endif //TEST_H

2. Implementation filetest.cpp

#include "test.h"
#include <stdio.h>
EX_FUN void CALL_METHOD test1()
{
    printf("test1\n");
}

EX_FUN void CALL_METHOD test2()
{
    printf("test2\n");    
}

3. Call the dllmain.h

#define TEST_EXPORTS
#include "test.h"

void main()
{
    test1();
    test2();
}

C++

1. Header filetestClass.h

#ifndef TESTCLASS_H  
#define TESTCLASS_H

#ifdef TEST_CLASS  
#define EX_CLASS _declspec(dllexport)  
#else  
#define EX_CLASS _declspec(dllimport)  
#endif  
#endif  

class EX_CLASS test  
{  
public:  
    cls(int i,int j);  
    int add();  
private:  
    int m;  
    int n;  
}; 

2. Implementation filetestClass.cpp

#include "testClass.h"  

test::test(int i,int j)  
{  
    m = i;  
    n = j;  
}  

int test::add()  
{  
    return m+n;  
}  

3. Call the dllmain.h

#define TEST_CLASS 
#include "testClass.h"  
#pragma comment(lib,"DLL.lib")  
#include <iostream>  
using namespace std;  

void main()  
{  
    test *clsObj = new test(2,3);  
    int num = clsObj->add();  
    cout<<"result : "<<num<<endl;  
    system("pause");  
}  

Generation of Linux dynamic and static libraries

Reference: http://www.latelee.org/programming-under-linux/library-on-linux.html

1. Sample code

/* lib.h */
#ifndef LIB_H_
#define LIB_H_
void test(int i);
#endif
/*lib.c*/
#include <stdio.h>
void test(int i)
{
    printf(“hell from %s,num:%dn”, __func__, i);
    getchar();
}
/*main.c*/
#include <stdio.h>
#include "lib.h"
int main(void)
{
    printf(“hello from %s:n”, __func__);
    test(250);
    return 0;
}

2. Generate static library

#生成静态库
gcc -c lib.c
ar cr libtest.a lib.o

#查看静态库中的符号
nm libtest.a 
#使用
#测试程序链接到静态库
gcc -o main main.c ./libtest.a
./main 

#还可以这么写
gcc -o main main.c -L. -ltest
./main 

3. Generate dynamic library

#生成动态库
gcc -c lib.c
gcc -fPIC -shared -o libtest.so lib.o
#使用
gcc -o main main.c ./libtest.so
./main 

#还可以这么写
gcc -o main main.c -L. -ltest
./main

4. Configuration of the library environment

Add the path to the library in /etc/profile

export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325438993&siteId=291194637