LINUX study notes - system environment, environment variables and static dynamic library

Article directory

Course content introduction:

  1. System environment: libraries, environment variables, compilers, system features
  2. Memory management: how the operating system manages memory
  3. File system: file reading and writing, directory reading and writing, file attributes, file management
  4. Process management: Multiple programs run simultaneously to solve complex problems
  5. Signal processing: a communication mechanism between the operating system and the program
  6. Process communication: how multiple processes interact with data, which is the basis for them to work together
  7. Thread management: It is to let a program do several things at the same time
  8. Thread synchronization: Let multiple threads work at the same time without destroying or interfering with each other

​ Our superficial learning task is to learn how to use the API of the operating system, but the core task is to learn the management mechanism of the operating system, understand the management rules of the operating system so that the program can run better under the operating system, and read a lot of API English user manual to improve self-study ability and reading ability of English technical documents.

1. Introduction to UNIX system

​ Born in 1971 at Bell Laboratories of AT&T Corporation in the United States, the main developers are Dennis Rich and Ken Thompson.

​ The main feature of the system is that it supports multi-users, multi-tasking, and supports multiple processor architectures. It also has high security, high reliability, and high stability. It can not only build commercial servers for large-scale key business systems, but also build Embedded applications for mobile terminals, handheld devices, and wearable devices.

Two, Linux system introduction

​ is a UNIX-like system, free and open source. Different distributions use the same kernel. It is generally used in mobile phones, tablets, routers, desktop computers, mainframe computers, and supercomputers. Strictly speaking, Linux only refers to operating systems. The system kernel belongs to the GNU project, and the inventor is Linus Benedict Torvalds.

Logo of the Linux system:

​ It is a penguin, the symbolic animal of Antarctica. At present, Antarctica does not belong to any country and is shared by all mankind. Using it as an operating system in Linux means that this system belongs to all mankind.

Minix operating system:

​ A UNIX-like system developed by Professor Andrew S. Tanenbaum in the Netherlands that does not contain any UNIX source code. Although Linus Torvalds was deeply inspired by Minix, he wrote the first version of the Linux kernel.

GNU Project:

​ Initiated in 1984 and supported by the Free Software Foundation, its basic principle is sharing. The purpose is to develop a free and open source UNIX-like system. The name comes from the recursive abbreviation of GNU's Not UNIX!, because GNU's design is similar to UNIX . But it does not contain copyrighted Unix code. GNU's founder, Richard Matthew Stallman, sees GNU as a "technical means to social ends".

The development of GNU is still incomplete, and the biggest problem is that a fully functional kernel has not yet been developed. GNU's kernel, called the Hurd, has not yet matured. In actual use, most alternatives such as the Linux kernel and FreeBSD are used as the core of the system, and the main operating system is a Linux distribution. The Linux operating system includes the GNU components and software in the Linux kernel and other free software projects, and can be called GNU/Linux.

POSIX standard:

Portable Operating System Interface (POSIX for short) is the general term for a series of interrelated standards defined by IEEE to run software on various UNIX operating systems.

​Linux fully complies with this standard, so the APIs of the two operating systems have the same name, the same parameters, and the same return value. The code written under Linux can be ported to UNIX after slight modification.

GPL General Public License:

GNU General Public License, referred to as GPL for short, is an agreement certificate for computer software issued by the Free Software Foundation, and software using this certificate is called free software. Reuse, modification, and copying of a work and its derivatives are permitted, freely for all, without claiming that the original work was done, or that it was done by others.

3. GNU compilation tools

It is a compilation tool developed by the GNU organization to compile the source code of the Linux kernel. After a long period of development, it has become a compilation platform that can support multiple programming languages ​​and can be used in mainstream operating systems. It is a tool for compiling C code It is called gcc, and the tool for compiling C++ code is called g++.

Commonly used compilation parameters for gcc:

gcc [选项参数] 文件
	-E 			# 预处理
    -S 			# 生成汇编文件
    -c 			# 生成目标文件
    -o 			# 设置编译结果的名字
    -I 			# 设置要导入的头文件的路径
    -l 			# 设置要链接的库名,例如:使用sqrt、pow等数学函数时就需要链接数学库 -lm
    -L 			# 设置要链接的库的路径
    -D 			# 在编译时定义宏
    -g 			# 编译时添加调试信息,这样编译出的程序可以用gdb调试。
    -Wall 		# 显示所有警告,编译器会以更严格的标准检查代码 
    -Werror 	# 把警告当错误处理
    -std 		# 指定编译器要遵循的语法标准,c89,c99,c11,当前系统默认的是c99标准。
    -pedantic 	# 对不符合ANSI/ISO C语言标准的,扩展语法产生警告

gcc related file types:

	xxx.h 		# 头文件
    xxx.c 		# 源文件
    xxx.i 		# 预处理文件
    xxx.s 		# 汇编文件
    xxx.o 		# 目标文件
    xxx.h.gch 	# 头文件的编译结果,用于检查自定义的头文件是否有语法错误,建议立即删除
    libxxx.a 	# 静态库文件,Windows系统下的静态库文件以lib结尾,例:xxx.lib
    libxxx.so 	# 动态库文件,Windows系统下的动态库文件以以dll结尾,例:libxxx.dll

The process of gcc turning C language into an executable program:

# 1、把程序员所编写的代码进行预处理
gcc -E hello.c 				# 把预处理的结果显示到屏幕上
gcc -E hello.c -o hello.i 	# 会生成以.i结尾的预处理文件

# 2、把预处理的结果翻译成汇编代码
gcc -S hello.i 				# 会生成以.s结尾的汇编文件

# 3、把汇编代码翻译成二进制指令
gcc -c hello.s 				# 会生成以.o结尾的目标文件

# 4、把若干个文件目标文件、库文件合并成可执行文件
gcc a.o b.o c.o ... 		# 默认会生成a.out可执行文件,也。
gcc a.o b.o c.o -o hello 	# 可以使用-o指定可执行文件的名字

Preprocessing directives supported by gcc:

#include      // 将指定文件的内容插至此指令处
#include_next // 与#include一样,但从当前目录之后的目录查找,极少用
#define       // 定义宏
#undef        // 删除宏
#if           // 判定
#ifdef        // 判定宏是否已定义
#ifndef       // 判定宏是否未定义
#else         // 与#if、#ifdef、#ifndef结合使用
#elif         // else if多选分支
#endif        // 结束判定
##            // 连接宏内两个连续的字符串
#             // 将宏参数扩展成字符串字面值
#error        // 预处理时产生错误,结束预处理
#warning      // 预处理时产生警告信息
#pragma       // 提供额外信息的标准方法,可用于指定平台
#pragma GCC dependency <文件>     // 若<文件>比此文件新则产生警告
#pragma GCC poison <标识>         // 若出现<标识>则产生错误
#pragma pack(1/2/4/8)             // 按1/2/4/8字节对齐补齐
#line                             // 指定行号

gcc predefined macros:

void printf_macro (void) 
{
    
    
	printf ("__BASE_FILE__     : %s\n", __BASE_FILE__);
	printf ("__FILE__          : %s\n", __FILE__);
	printf ("__LINE__          : %d\n", __LINE__);
	printf ("__FUNCTION__      : %s\n", __FUNCTION__);
	printf ("__func__          : %s\n", __func__);
	printf ("__DATE__          : %s\n", __DATE__);
	printf ("__TIME__          : %s\n", __TIME__);
	printf ("__INCLUDE_LEVEL__ : %d\n", __INCLUDE_LEVEL__);
	printf ("__cplusplus       : %d\n", __cplusplus);
}

4. Environment variables

What are environment variables:

​Environment variables (environment variables) generally refer to some parameters used in the operating system to specify the operating environment of the operating system, such as: temporary folder location, system folder location, etc.

An environment variable is an object with a specific name in the operating system that contains information that one or more applications will use. For example, the path environment variable in the operating system, when the system is required to run a program without telling it the full path where the program is located, the system should not only search for the program under the current directory, but also find it in the path specified in path. Users can better run programs by setting environment variables.

The main role of environment variables:

Set the running parameters of the program:

​Environment variables are equivalent to some parameters set by the system or users for applications. The specific functions are of course related to specific environment variables. For example, what language should a program use by default when it is running, the size of the interface, and log files are stored in Where and where the temporary files are stored can only be determined by querying the environment variables of the operating system.

Program sharing:

​ When software A needs to use some functions in software B, but whether it is the operating system or the author of software A or B, no matter where the control software is installed, then you can let software B set the environment variable to tell the operating system that it is installed Where is it, and software A can know where software B is installed by querying the environment variables, so as to call the function of software B.

system running:

​ Users can also tell the operating system some operating parameters by setting environment variables, such as setting the language of the current system, character encoding, and the default size of the terminal.

Common environment variables:

PS1				# 命令提示符
PATH			# 命令的搜索路径
C_INCLUDE_PATH	# 头文件的搜索路径
LIBRARY_PATH	# 库文件的搜索路径
LD_LIBRARY_PATH	# 程序执行时动态库的搜索路径

Set environment variables:

View environment variables:

1. Linux system uses the env command to view environment variables

2. Windows system uses the set command to view environment variables

3. View in the program

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-HoFexW6N-1662083417340) (C:\Users\DELL\Pictures\environment variable table.png)]

#include <stdio.h>
// 程序在运行时父进程都会通过main函数参数传递一份环境变量表的拷贝,是一个以NULL指针结尾的字符指针数组。
int main(int argc,const char* argv[],char* environ[])
{
    
    
    for(int i=0; environ[i]; i++)
    {
    
       
        printf("%s\n",environ[i]);
    }   
}

Exercise 1: Parse out all paths of the PATH environment variable.

By modifying the configuration file settings:
1. How to modify the Linux system
# 打开配置文件:
vi ~/.bashrc			# 只对当前用户用效
vi /etc/environment		# 对所有用户有效

# 在文件末尾添加内容:
export C_INCLUDE_PATH=<环境变量的内容>
C_INCLUDE_PATH=$C_INCLUDE_PATH:<追加新的内容>
	
# 重新加载配置文件:
source ~/.bashrc
2. How to modify the Windows system

How to modify environment variables in Windows 10 system

How to modify environment variables in Windows 11 system

Set environment variables using standard library functions:
环境变量和格式:name=value

// 根据name获得value
char *getenv(const char *name);

// 以name=value的形式设置环境变量,name不存在就添加,存在就覆盖其value
int putenv(char *string);

// 根据name设置value,注意最后一个参数表示,若name已不存在则添加,如果name已经存在是否覆盖其value由overwrite控制
// If name does exist in the  environment, then its value is changed to value if overwrite is nonzero; if overwrite is zero, then the value of name is not changed。
int setenv(const char *name, const char *value, int overwrite);

// 删除环境变量。
int unsetenv(const char *name);

// 清空环境变量,environ==NULL。
int clearenv(void);

注意:由于当前程序获得是环境变量表的拷贝(副本), 因此在当前程序中对环境变量表进行增、删、改不会影响其它程序和操作系统,而修改后环境变量表会传给它的子进程,也就是会对子进程造成影响。

5. Error handling

Errors are indicated by the return value of the function:

// 返回合法值表示成功,返回非法值表示失败
long file_size (const char* path) 
{
    
    
	FILE* fp = fopen (path, "r");
	if (NULL == fp) 
        return -1;

	fseek (fp, 0, SEEK_END);
	long size = ftell (fp);

	fclose (fp);
	return size;
}

// 返回有效指针表示成功, 返回空指针(NULL/0xFFFFFFFF)表示失败
Node* query_list(Node* list,TYPE key)
{
    
    
    for(Node* n=list->head; NULL!=n; n=n->next)
    {
    
    
        if(n->data == key)
            return n;
    }
    return NULL;
}

// 返回0表示成功,非零表示失败,如:main、fseek、access等函数

// 永远成功的函数,如:menu类的函数

Errors are indicated by errno:

errno is the last error code of the logging system. Code is an int value defined in errno.h. Viewing the error code errno is an important method of debugging a program.

​ When an exception occurs when calling a Linux system API function, the errno variable is generally assigned an integer value, and different values ​​indicate different meanings. You can speculate the cause of the error by checking the value, and use this trick to solve the problem in actual programming. Less problems that seemed inexplicable at first.

​ errno will not be modified when the function is executed successfully, so errno cannot be non-zero as the basis for error judgment. errno is a global variable, and its value may change at any time, so use errno in conjunction with the return value of the function .

#include <stdio.h>
#include <errno.h>

int main () 
{
    
    
	FILE* fp = fopen ("none", "r");
	if (NULL == fp) 
	{
    
    
        // 查看错误编号
		printf ("fopen: %d\n", errno);
        // 根据错误编号查看错误提示
		printf ("fopen: %s\n", strerror (errno));
        // 自动根据错误编号查看错误提示
		printf ("fopen: %m\n");
        // 自动根据错误编号查看错误提示
		perror ("fopen");
		return -1;
	}
	fclose (fp);
	return 0;
}

6. Production and use of library files

What is a library file:

​ A library file is a type of file on the computer that provides users with some out-of-the-box variables, functions, or classes. It is a collection of several object files, and the source code can also be kept secret. Library files are divided into static libraries and dynamic libraries. The difference between static libraries and dynamic libraries is reflected in the linking stage of the program.

The difference between static library and dynamic library:

​ The static library is copied into the program during the linking phase of the program, and the dynamic library is not copied into the program during the linking phase, but is dynamically loaded into the memory by the system for the program to call when the program is running. This is the most essential difference between them .

Production and use of static libraries:

Create a static library:
# 编译出目标文件:
gcc -c xxx1.c
gcc -c xxx2.c
...

# 把目标文件打包成静态库文件
ar -r libxxx.a x1.o x2.o ...

# ar 是一个专门控制静态库的命令
	-r # 把目录文件合并成一个静态库,如果静态库文件已经存在则更新。
	-q # 向静态库中添加目标文件
	-t # 查看静态库中有哪些目标文件
	-d # 从静态库中删除目标文件
	-x # 把静态库展开为目标文件 
Use a static library:
# 方法1、直接调用,把共享库当作目标文件一样,与调用者的目标文件一起合并出可执行文件。
gcc main.c libxxx.a

# 方法2、通过设置LIBRARY_PATH环境变量来指定库的路径,通过-l参数来指定库名
gcc main.c -lxxx

# 方法3、通过gcc -L参数来指定库的路径,通过-l参数来指定库名
gcc main.c -L<PATH> -lxxx

Manufacture and use of dynamic library:

Create a dynamic library:
# 编译出目标文件,-fpic编译出位置无关代码,在代码中使用相对地址,这样共享库就可以加载到内存的任何位置。
gcc -c -fpic xxx1.c
gcc -c -fpic xxx2.c
...

# 把目标文件打包成共享库:
gcc -shared xxx1.o xxx2.o ... -o libxxx.so
Use a dynamic library:
# 方法1、直接调用
gcc main.c libxxx.so

# 方法2、通过设置LIBRARY_PATH环境变量来指定库的路径,需要通过-l来指定库名
gcc main.c -lxxx 
    

# 3、通过gcc -L参数来指定库的路径
gcc main.c -L<PATH> -lxxx

# 注意1:如果执行无法运行,需要检查操作系统是否能加载动态库,检查LD_LIBRARY_PATH环境变量
# 注意2:如果静态库和共享库同时存在,优先使用共享库,通过-static可以指定使用静态库。
Dynamically load shared libraries:
#include <dlfcn.h>
void *dlopen(const char *filename, int flag);
功能:打开共享库
filename:共享库的路径
flag:打开方式
	RTLD_LAZY:延迟加载,使用到共享库时再加载
	RTLD_NOW:立即加载
返回值:成功返回共享库的句柄,失败返回NULL

void *dlsym(void *handle, const char *symbol);
功能:通过函数名在共享库中获取函数指针
handle:共享库的句柄
symbol:函数名
返回值:函数地址,失败返回NULL

char *dlerror(void);
功能:获取错误信息

int dlclose(void *handle);
功能:卸载共享库
注意:编译时添加-ldl参数

Auxiliary tools when using library files:

# 查看目标文件、可执行文件、静态库、共享库文件的符号列表。
nm <flie>

# 删除目标文件、可执行文件、静态库、共享库文件中符号列表、调试信息,可以有效降低文件的大小。
strip <file>

# 查看可执行文件依赖了哪些共享库
ldd <file>
   
# 把二进制文件的内容转换成汇编代码,就是传说中的反汇编,但如果二进行文件进行加密机制则无法成功转换
objdump <file>

Advantages of static libraries:

Easy to use:

​ When linking the object file to generate the program, you only need to compile the static library and the object file together, and the compiler will copy the static content used in the object file to the program, and the program does not need the static library when it is running.

Runs fast:

​ The content of the static library file is copied to the program, so when the program is running, when using the functions and variables in the static library, it will only jump inside the program, so the program using the static library is better than the program using the dynamic library Runs fast.

Disadvantages of static libraries:

Trouble updating:

​ If the content in the static library changes, such as: version upgrade, bug modification, then the program that uses the relevant static library needs to be recompiled, and if it is an application program, the user needs to download it again.

Waste memory:

​ If there is a static library called libxxx.a, and a.out, b.out, and c.out programs all use it, then the contents of libxxx.a will be copied to a.out, b.out, and c.out, when these three programs are running, three copies of the content in the libxxx.a static library file exist in the memory, so there is redundancy and waste of memory.

Disadvantages of dynamic libraries:

​ When linking the object file, although the dynamic library needs to be compiled together with the object file that uses it, the compiler only records the location of the called content (function, variable) in the dynamic library, and only jumps to the dynamic library in the generated program. The relevant instructions of the library, when the program is running, the dynamic library needs to be loaded into the memory together, and when the relevant content of the dynamic library is executed, it will jump to the memory where the dynamic library is located for execution, and then return after completion, which will cause two question.

Runs slowly:

​ Using a dynamic library program requires jumping back and forth between the program and the dynamic library, so it runs slower than a program using a static library.

The program could not be executed:

​ If the program uses a dynamic library, when it runs, the system needs to load the dynamic library it uses into the memory together. If the system cannot find the corresponding dynamic library, the program cannot run (xxx.dll often prompted by the Windows system The file is missing, the program cannot run), there are many reasons for this error, such as: environment variable configuration error, dynamic library file storage location error, executable file is copied to other computers and the dynamic library file is not copied together.

Summarize:

​ When a module will not change again, and there are some requirements for execution speed, it is suitable to encapsulate it into a static library.

Advantages of dynamic libraries:

Save memory:

The dynamic library used only needs to be loaded once by the system, and different programs can use the dynamic library in the memory, thus saving a lot of memory. Since multiple programs can share a dynamic library, the dynamic library is also called a shared library.

Easy to update:

​ If the function format in the dynamic library does not change (return value, function name, parameter list), but only the business logic code in the function changes, then only the dynamic library needs to be recompiled, and no relevant executables need to be recompiled files, which is why some apps can update automatically.

Summarize:

​ With the continuous improvement of computer performance, it makes up for the shortcomings of the slow running speed of the dynamic library. In addition, it can save memory and facilitate updates. The most important thing is that the computer hardware has been upgraded, so most codes need to be continuously upgraded. , so we package modules into dynamic libraries in most cases.

Operation:

​ Encapsulate commonly used data structures and algorithms into a dynamic library:

1. General chained queue

2. Universal chain stack

3. General binary search tree

4. General two-way circular linked list

5. General sequential search and binary search algorithms

6. General general bubble sort, insertion sort, selection sort

Advantages of dynamic libraries:

Save memory:

The dynamic library used only needs to be loaded once by the system, and different programs can use the dynamic library in the memory, thus saving a lot of memory. Since multiple programs can share a dynamic library, the dynamic library is also called a shared library.

Easy to update:

​ If the function format in the dynamic library does not change (return value, function name, parameter list), but only the business logic code in the function changes, then only the dynamic library needs to be recompiled, and no relevant executables need to be recompiled files, which is why some apps can update automatically.

Summarize:

​ With the continuous improvement of computer performance, it makes up for the shortcomings of the slow running speed of the dynamic library. In addition, it can save memory and facilitate updates. The most important thing is that the computer hardware has been upgraded, so most codes need to be continuously upgraded. , so we package modules into dynamic libraries in most cases.

Guess you like

Origin blog.csdn.net/m0_62480610/article/details/126656451