Linux 开发环境以及编译链接

再谈编译链接

C++函数重载与编译链接-CSDN博客

        之前我已经写过文章简单介绍了编译链接要做的一些操作。现在为了能更好的理解我们平时的开发环境,我会在Linux系统上完整地走一遍流程。

环境描述

        我们使用普通用户在Linux上进行操作,先写一段测试代码。

[ssddffaa@code code]$ vim test.c#include <stdio.h>int main()
{printf("Hello World!\n");return 0;
}

         接下来我们使用 gcc 编译器编译一下我们的文件。

[ssddffaa@code code]$ gcc test.c 
[ssddffaa@code code]$ ls
a.out  test.c
[ssddffaa@code code]$ ll 
total 16
-rwxrwxr-x. 1 ssddffaa ssddffaa 8360 Mar 28 09:32 a.out
-rw-rw-r--. 1 ssddffaa ssddffaa   75 Mar 28 09:31 test.c
[ssddffaa@code code]$ 

        可以看到默认生成了一个带可执行权限的文件 a.out ,接着我们运行它。

[ssddffaa@code code]$ ./a.out 
Hello World!

        要是不想要默认生成的可执行文件,我们也可以使用 gcc 的 "-o" 参数改变 gcc 的输出。

[ssddffaa@code code]$ gcc test.c -o test.txt
[ssddffaa@code code]$ ll
total 28
-rwxrwxr-x. 1 ssddffaa ssddffaa 8360 Mar 28 09:32 a.out
-rw-rw-r--. 1 ssddffaa ssddffaa   75 Mar 28 09:31 test.c
-rwxrwxr-x. 1 ssddffaa ssddffaa 8360 Mar 28 09:36 test.txt[ssddffaa@code code]$ ./test.txt 
Hello World!

        可以看到我们重新生成了一个可执行文件 test.txt。可能你会疑惑,这个文件的后缀名是 "txt" 怎么还能执行?他不应该是一个记事本嘛?

        在Linux系统中文件是否能被运行有两个条件,一是文件具有可执行权限,二是文件本身具有可执行的功能。以上两个条件我们的 text.txt 都满足了,当然可以正常执行。相对的如果一个文件只有可执行权限,但是文件本身本没有可执行能力,那也是执行不了的。

编译链接

预处理

        下面我们来看一看 test.c 文件经过预处理后会发生什么。通过 gcc 加 "-E" 参数可以使文件编译到预处理阶段完成后就停止,并把结果打印到屏幕上,使用 "-o" 参数可以重定向到指定文件中。

[ssddffaa@code code]$ gcc -E test.c -o test.i
[ssddffaa@code code]$ ll
total 24
-rw-rw-r--. 1 ssddffaa ssddffaa    75 Mar 28 09:31 test.c
-rw-rw-r--. 1 ssddffaa ssddffaa 16872 Mar 28 09:45 test.i[ssddffaa@code code]$ vim test.i
825 extern char *ctermid (char *__s) __attribute__ ((__nothrow__ , __leaf__));
826 # 913 "/usr/include/stdio.h" 3 4
827 extern void flockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
828 
829 
830 
831 extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
832 
833 
834 extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
835 # 943 "/usr/include/stdio.h" 3 4
836 
837 # 2 "test.c" 2
838 
839 int main()
840 {
841 
842  printf("Hello World!\n");
843  return 0;
844 }

        当我们进入 test.i 文件中进行查看时,会发现原本我们只写了几行的代码在 test.i 文件中增加到了800多行。我们多出来的这些代码是什么呢?我想你应该已经猜到了,这是预处理阶段要做的一件事 "头文件展开"。没错,多出来的这几百行代码就是 #include <stdio.h> 的效果,那么这些代码是凭空出现的嘛,显然不是。头文件展开其实就是去把Linux系统中的头文件内容拷贝了一份然后放进了我们的代码。

        我们可以在系统中找一下存放头文件的位置。

[ssddffaa@code code]$ sudo find / -name stdio.h
[sudo] password for ssddffaa: 
/usr/include/c++/4.8.2/tr1/stdio.h
/usr/include/bits/stdio.h
/usr/include/stdio.h

        出现了3个路径不过只有最下面那个才是我们使用的头文件,这一点可以通过查看 gcc 的默认include路径了解。

[ssddffaa@code include]$ `gcc -print-prog-name=cc1plus` -v
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../x86_64-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/x86_64-redhat-linux/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/backward/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include/usr/local/include/usr/include
End of search list.

        可以看到,我们包含的头文件确确实实是存在在我们的计算机上的。平时我们使用的 printf 等函数,并没有我们自己实现但是我们就在使用了,这是因为我们包含了头文件,然后在预处理时编译器会把我们包含的头文件内容拷贝到我们写的代码里,然后在之后的编译阶段编译器才能识别到 printf 等库函数接着进行下一步操作。

        预处理阶段不仅仅只是展开头文件还有以下内容。

#1 将#define删除,并且展开所有的宏定义
#2 处理条件编译,#if #ifdef #elif #endif等
#3 头文件展开
#4 删除注释
#5 添加行号和文件标识,以便编译时产生调试试用的行号以及编译错误警告号
#6 保留所有的#pragma编译器指令,因为编译器需要使用它们

编译

        预处理完成后会进入编译阶段,在这个阶段我们之前处理过的 test.i 文件会进一步进行处理。编译阶段在整个编译链接中是最复杂的一个。

        编译过程可以分为6步:

#1 词法分析:扫描器(Scanner)将源代的字符序列分割成一系列的记号(Token)
#2 语法分析:语法分析器将记号(Token)产生语法树(Syntax Tree)
#3 语义分析:静态语义(编译器可以确定的语义),动态语义(只能在运行期才能确定的语义)
#4 源代码优化:源代码优化器,将整个语法树转换为中间代码(中间代码是与目标机器和运行环境无关的)中间使得编译器被分为前端和后端,编译器前端负责产生机器无关的中间代码编译器后端将中间代码转化为目标机器代码
#5 目标代码生成:代码生成器(Code Generator)
#6 目标代码优化:目标代码优化器(Target Code Optimizer)

        我们代码语法的检查,代码的优化等都是在编译阶段完成的。在编译阶段还会生成符号表,它用于链接阶段。 

        使用 gcc 加 "-S" 参数可以让文件编译执行到编译阶段完成后终止。

[ssddffaa@code code]$ gcc -S test.c -o test.s
[ssddffaa@code code]$ ll
total 28
-rw-rw-r--. 1 ssddffaa ssddffaa    75 Mar 28 09:31 test.c
-rw-rw-r--. 1 ssddffaa ssddffaa 16872 Mar 28 09:45 test.i
-rw-rw-r--. 1 ssddffaa ssddffaa   448 Mar 28 20:23 test.s[ssddffaa@code code]$ vim test.s1         .file   "test.c"2         .section        .rodata3 .LC0:4         .string "Hello World!"5         .text6         .globl  main7         .type   main, @function8 main:9 .LFB0:10         .cfi_startproc11         pushq   %rbp12         .cfi_def_cfa_offset 1613         .cfi_offset 6, -1614         movq    %rsp, %rbp15         .cfi_def_cfa_register 616         movl    $.LC0, %edi17         call    puts18         movl    $0, %eax19         popq    %rbp20         .cfi_def_cfa 7, 821         ret22         .cfi_endproc23 .LFE0:24         .size   main, .-main25         .ident  "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)"26         .section        .note.GNU-stack,"",@progbits

        可以看到 test.s 文件里是汇编代码。

汇编阶段

        在汇编阶段,汇编器将 test.s 文件翻译成机器语言指令,把这些指令打包成一种叫做可重定位二进制目标程序的格式,并将结果保存在目标文件 test.o 中,test.o 是一个二进制文件。

        使用 gcc 加 "-c" 参数可以让文件编译执行到汇编阶段完成后终止。

[ssddffaa@code code]$ gcc -c test.c -o test.o
[ssddffaa@code code]$ ll
total 32
-rw-rw-r--. 1 ssddffaa ssddffaa    75 Mar 28 09:31 test.c
-rw-rw-r--. 1 ssddffaa ssddffaa 16872 Mar 28 09:45 test.i
-rw-rw-r--. 1 ssddffaa ssddffaa  1496 Mar 28 20:40 test.o
-rw-rw-r--. 1 ssddffaa ssddffaa   448 Mar 28 20:33 test.s[ssddffaa@code code]$ vim test.o

        使用 vim 文本编辑器进入 test.o 查看会全是乱码,这是因为 test.o 中是二进制数据,而 vim 只能识别文本,所以我们换一个工具进行查看。

[ssddffaa@code code]$ hexdump test.o

        可以看到文件由二进制转为16进制的内容。我们的计算机能识别二进制,而我们的 test.o 文件就是一个二进制文件那我们可以不可以运行它呢?我们来试一下。

[ssddffaa@code code]$ ll
total 32
-rw-rw-r--. 1 ssddffaa ssddffaa    75 Mar 28 09:31 test.c
-rw-rw-r--. 1 ssddffaa ssddffaa 16872 Mar 28 09:45 test.i
-rw-rw-r--. 1 ssddffaa ssddffaa  1496 Mar 28 20:40 test.o
-rw-rw-r--. 1 ssddffaa ssddffaa   448 Mar 28 20:33 test.s
[ssddffaa@code code]$ chmod +x test.o
[ssddffaa@code code]$ ll
total 32
-rw-rw-r--. 1 ssddffaa ssddffaa    75 Mar 28 09:31 test.c
-rw-rw-r--. 1 ssddffaa ssddffaa 16872 Mar 28 09:45 test.i
-rwxrwxr-x. 1 ssddffaa ssddffaa  1496 Mar 28 20:40 test.o
-rw-rw-r--. 1 ssddffaa ssddffaa   448 Mar 28 20:33 test.s
[ssddffaa@code code]$ ./test.o 
-bash: ./test.o: cannot execute binary file

        可以看到报了错误 "无法执行的二进制文件"。汇编生成的二进制文件还不具有可执行的能力,这是因为缺少了库文件。我们在预处理阶段包含的头文件只是声明,声明和定义是分离的,定义是存储在库文件中的,同时库中还包含了许多方法。

链接

        汇编过后生成的目标文件(*.o)并不是最终的可执行二进制文件,而是一种中间文件(或临时文件),目标文件任然需要经过链接才能变成可执行文件。

        在链接阶段,链接器会把我们写的所有目标文件(*.o)与系统组件(标准库,动态链接库等)结合起来生成一个可执行程序。(链接程序运行需要的一大堆目标文件,以及所依赖的其它库文件,最后生成可执行文件)。 

[ssddffaa@code code]$ gcc test.c -o test
[ssddffaa@code code]$ ll
total 44
-rwxrwxr-x. 1 ssddffaa ssddffaa  8360 Mar 28 21:47 test
-rw-rw-r--. 1 ssddffaa ssddffaa    75 Mar 28 09:31 test.c
-rw-rw-r--. 1 ssddffaa ssddffaa 16872 Mar 28 09:45 test.i
-rw-rw-r--. 1 ssddffaa ssddffaa  1496 Mar 28 20:40 test.o
-rw-rw-r--. 1 ssddffaa ssddffaa   448 Mar 28 20:33 test.s
[ssddffaa@code code]$ ./test 
Hello World!

         Linux下的C语言的标准库文件在 "/usr/lib64/" 下本质就是一个文件。

[ssddffaa@code code]$ ll /usr/lib64/libc.so*
-rw-r--r--. 1 root root 253 May 18  2022 /usr/lib64/libc.so
lrwxrwxrwx. 1 root root  12 Mar 27 08:53 /usr/lib64/libc.so.6 -> libc-2.17.so

        Linux和Windows下的库文件。 

# Linux: .so(动态库)    .a(静态库)
# Windows .dll(动态库)    .lib(静态库)库的命名规则
# libname.so.XXX
# 其中lib是库前缀名,name则是库的名称,so是库后缀,XXX是版本号

        编译型语言,安装开发包,必定是下载安装对应的头文件和库文件。

        库其实就是把源文件(.c),经过一定的翻译,然后打包形成一个文件。不用给你提供太多的源文件,也可以达到隐藏源文件的目的。

        头文件提供声明,库文件提供实现 + 你的代码 = 你的软件。

动态链接与静态链接

        库有动态库和静态库,链接也有动态链接和静态链接。

动态链接

        动态库是一个共享的库文件,当程序开始执行时编译器便会告诉程序动态库在哪个位置,有哪些方法。当程序执行到需要库里的文件时便会跑到库里去执行,执行完又继续执行下一步操作。像这样编译器告诉程序动态库的位置,然后程序需要时跑去执行的方式叫动态链接。

        动态库不能缺失,一旦对应的动态库缺失,影响的不止一个程序,可能导致很多程序都无法正常运行。

静态链接

        静态链接就相当于直接把静态库中要用到的内容直接和我们的目标文件链接在一起生成可执行程序。完成后,就算静态库没了程序也能正常运行。

比较

        动态链接和静态链接各有各的优势,当一个库文件有许多程序都需要使用时,用动态链接可以让程序不用去每个都拷贝一份库文件。而且更新库文件时方便,你只需要改库文件就可以完成库的更新。

        静态链接可以让程序不依赖之前的静态库文件,减少重定向链接到动态库的开销提高了程序效率。但是这个效率只提高了5%左右。更新库时麻烦,需要重新修改静态库文件,然后再编译链接一次生成新的可执行文件。

验证

        使用 "ldd" 可以查看程序的动态链接情况

[ssddffaa@code code]$ ldd testlinux-vdso.so.1 =>  (0x00007ffc36b9c000)libc.so.6 => /lib64/libc.so.6 (0x00007f4ff73f3000)/lib64/ld-linux-x86-64.so.2 (0x00007f4ff77c1000)

        可以看到,在Linux下 gcc 默认使用的是动态链接。 在编译时加上 "-static" 参数可以让 gcc 使用静态链接。

[ssddffaa@code code]$ gcc test.c -o test-static -static
/usr/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status

         报错了,这个报错的原因呢是因为我们的Linux系统上默认是没有静态库的,需要我们手动去安装一下。

[ssddffaa@code code]$ sudo yum install -y glibc-static
[ssddffaa@code code]$ sudo yum install -y libstdc++-static

        安装完成后我们再去试一下。

[ssddffaa@code code]$ gcc test.c -o test-static -static
[ssddffaa@code code]$ ll -h
total 888K
-rwxrwxr-x. 1 ssddffaa ssddffaa 8.2K Mar 28 21:47 test
-rw-rw-r--. 1 ssddffaa ssddffaa   75 Mar 28 09:31 test.c
-rw-rw-r--. 1 ssddffaa ssddffaa  17K Mar 28 09:45 test.i
-rw-rw-r--. 1 ssddffaa ssddffaa 1.5K Mar 28 20:40 test.o
-rw-rw-r--. 1 ssddffaa ssddffaa  448 Mar 28 20:33 test.s
-rwxrwxr-x. 1 ssddffaa ssddffaa 842K Mar 29 01:41 test-static
[ssddffaa@code code]$ ldd test-static not a dynamic executable

         可以看到成功生成了一个可执行程序 test-static,并且它没有使用任何动态库。但是 test-static 和 test 的大小起来大了80K左右。

#1 如果我们没有静态库,但是我们就要-static,是不行的
#2 如果我们没有动态库,只有静态库,而且gcc能找到不使用-staticgcc还是会链接成功,并且使用静态库这是因为gcc默认使用动态链接,使用-static只是增加了静态链接的优先级
#3 不一定是纯的全部动态链接或静态链接,是混合的

         查看可执行程序使用的库情况。

[ssddffaa@code code]$ file test
test: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=9fc19efe5a60448b3a2d19e1e150f7b77d65993a, not stripped
[ssddffaa@code code]$ file test-static
test-static: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=7cd92dd71613a6bad6eea55cc7d520b28e98e9d7, not stripped

Debug && Release

        Debug 模式相比 Release 模式增加了调试信息,可以方便开发人员对代码进行调试。gcc 默认使用的是 Release 模式,要使用 Debug 模式需要加上参数 "-g"。

[ssddffaa@code code]$ gcc test.c -o test_debug -g
[ssddffaa@code code]$ gcc test.c -o test-static_debug -static -g
[ssddffaa@code code]$ ll
total 1716
-rwxrwxr-x. 1 ssddffaa ssddffaa   8360 Mar 28 21:47 test
-rw-rw-r--. 1 ssddffaa ssddffaa     75 Mar 28 09:31 test.c
-rwxrwxr-x. 1 ssddffaa ssddffaa   9360 Mar 29 02:09 test_debug
-rwxrwxr-x. 1 ssddffaa ssddffaa 861288 Mar 29 01:41 test-static
-rwxrwxr-x. 1 ssddffaa ssddffaa 862296 Mar 29 02:10 test-static_debug

        可以看到 Debug 模式生成的可执行程序都比 Release 模式下生成的可执行程序大,这是因为 Debug 模式增加了调试信息。 

[ssddffaa@code code]$ readelf -S test_debug | grep debug[27] .debug_aranges    PROGBITS         0000000000000000  00001061[28] .debug_info       PROGBITS         0000000000000000  00001091[29] .debug_abbrev     PROGBITS         0000000000000000  00001122[30] .debug_line       PROGBITS         0000000000000000  00001164[31] .debug_str        PROGBITS         0000000000000000  0000119f

make/Makefile

         一个工程中的源文件不计其数,按类型、功能、模块分别放在若干个目录中,Makefile 定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。

        make是一条指令,Makefile是一个当前目录下的文件。

[ssddffaa@code code]$ touch Makefile
[ssddffaa@code code]$ vim Makefile1 test.exe:test.c                #编写 Makefile 第一行是依赖关系2         gcc -o test.exe test.c #第二行是以TAB开始然后输入依赖方法。3 .PHONY:clean                   #加上PHONY参数修饰clean4 clean:                         #清理5         rm -f test.exe         #清理方法

        通过 make 指令来执行 Makefile 文件内容。

[ssddffaa@code code]$ make
gcc -o test.exe test.c
[ssddffaa@code code]$ ll
total 20
-rw-rw-r--. 1 ssddffaa ssddffaa   40 Mar 29 02:41 Makefile
-rw-rw-r--. 1 ssddffaa ssddffaa   75 Mar 28 09:31 test.c
-rwxrwxr-x. 1 ssddffaa ssddffaa 8360 Mar 29 02:41 test.exe
[ssddffaa@code code]$ ./test.exe
Hello World!
[ssddffaa@code code]$ make clean
rm -f test.exe
[ssddffaa@code code]$ ll
total 8
-rw-rw-r--. 1 ssddffaa ssddffaa 76 Mar 29 02:50 Makefile
-rw-rw-r--. 1 ssddffaa ssddffaa 75 Mar 28 09:31 test.c

        可以看出 make/Makefile 能把我们从冗余的 gcc 命令中解脱出来,只需 make 和 make clean 就可以构建和删除项目。

参考文章

程序详细编译过程(预处理、编译、汇编、链接) - 知乎 (zhihu.com)

详解C/C++代码的预处理、编译、汇编、链接全过程 - 知乎 (zhihu.com)

深入浅出静态链接和动态链接-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/780117.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue中使用图片url直接下载图片

vue中使用图片url直接下载图片 // 下载图片downloadByBlob(url, name) {let image new Image()image.setAttribute(crossOrigin, anonymous)image.src urlimage.onload () > {let canvas document.createElement(canvas)canvas.width image.widthcanvas.height image…

Django屏蔽Server响应头信息

一、背景 最近我们被安全部门的漏洞扫描工具扫出了一个服务端口的漏洞。这个服务本身是一个Django启动的web服务&#xff0c;并且除了登录页面&#xff0c;其它页面或者接口都需要进行登录授权才能进行访问。 漏洞扫描信息和提示修复信息如下: 自然这些漏洞如何修复&#xff0c…

npm包发布

一、npm npm&#xff08;Node Package Manager&#xff09;是 Node.js 的包管理工具&#xff0c;用于安装、分享和管理 JavaScript 包和项目依赖。npm 是 Node.js 的默认包管理器&#xff0c;随同 Node.js 一起安装。 二、npm主要功能特点 包管理&#xff1a;npm 允许开发者…

美国裸机云多IP服务器:独享IP,多C段,高速稳定,站群优选!

美国裸机云多IP服务器&#xff0c;近年来在站群运营、网络架构优化等领域逐渐崭露头角&#xff0c;成为许多企业和个人用户的优选方案。那么&#xff0c;这种服务器究竟有何特别之处呢?下面&#xff0c;我们就来详细科普一下。 首先&#xff0c;我们来了解一下什么是裸机云多I…

太阳能发电园区3D可视化:揭秘绿色能源新纪元

在科技飞速发展的今天&#xff0c;绿色能源已成为推动社会进步的重要力量。太阳能发电作为绿色能源的重要代表&#xff0c;正在全球范围内掀起一股清洁能源的革命浪潮。 太阳能发电园区作为集中展示太阳能发电技术和应用的场所&#xff0c;其规模之大、设备之复杂&#xff0c;常…

Linux部分命令

目录 1.文件介绍 2.ls命令 3.目录命令 4.相对路径以及绝对路径 5.命令创建目录&#xff08;文件夹&#xff09; 6.which命令 7.find命令 8.grep命令 9.wc命令 10.echo、tail、重定向符 1.文件介绍 和window不同&#xff0c;Linux没有盘路径&#xff0c;所有的文件都存…

VSCode在文件生成添加作者,创建时间、最后编辑人和最后编辑时间等信息

一、安装插件 我使用的是 korofileheader 二、配置文件 左下角点击设置图标—设置—输入"ext:obkoro1.korofileheader"—点击"在setting.json中编辑" 进入后会自动定位到你添加信息的地方 "Author": "tom", "Date": "…

一些在 Spring Boot 单元测试中常用的框架

JUnit&#xff1a;基于 Java 语言的单元测试框架&#xff0c;主要用作基础测试框架。JSON Path&#xff1a;类似于 XPath 在 XML文档中的定位&#xff0c;JSON Path 表达式通常用来检索路径或设置 JSON 文件中的数据。AssertJ&#xff1a;强大的流式断言工具&#xff0c;它需要…

Netty核心原理剖析与RPC实践16-20

Netty核心原理剖析与RPC实践16-20 16 IO 加速&#xff1a;与众不同的 Netty 零拷贝技术 今天的课程我们继续讨论 Netty 实现高性能的另一个高阶特性——零拷贝。零拷贝是一个耳熟能详的词语&#xff0c;在 Linux、Kafka、RocketMQ 等知名的产品中都有使用&#xff0c;通常用于…

了解HTTP安全标头(HTTP Security Headers)

了解HTTP安全标头&#xff08;HTTP Security Headers&#xff09; 安全标头是指定网络客户端&#xff08;通常是浏览器&#xff09;和应用程序服务器之间 HTTP 通信行为和安全相关细节的 HTTP 响应标头&#xff0c;其目的是促进深度防御。一旦设置了这些 HTTP 响应头&#xff…

uniapp开发App——登陆流程 判断是否登陆,是,进入首页,否,跳转到登录页

一、登陆流程 文字描述&#xff1a;用户进入App&#xff0c;之后就是判断该App是否有用户登陆过&#xff0c;如果有&#xff0c;直接进入首页&#xff0c;否则跳转到登陆页&#xff0c;登陆成功后&#xff0c;进入首页。 流程图如下&#xff1a; 二、在uniapp项目中代码实现 实…

代码随想录算法训练营第二十四天(回溯1)|77. 组合(JAVA)

文章目录 回溯理论基础概念类型回溯模板 77. 组合解题思路源码 回溯理论基础 概念 回溯是递归的副产品&#xff0c;本质上是一种穷举 回溯解决的问题可以抽象为一种树形结构 类型 回溯主要用来解决以下问题 组合问题&#xff1a;N个数里面按一定规则找出k个数的集合切割问…

如何使用Docker打包构建Java项目然后部署发布?

前言 今天我们来讲下如何使用Docker打包构建Java项目并且完成部署发布。 前期准备&#xff0c;需要安装好docker。 以及一个需要安装好Maven的镜像&#xff0c;可以参考下面的文章。 构建一个包含mvn命令的Java 17基础镜像-CSDN博客 一、打包构建Java项目镜像 1、创建Jav…

【力扣】300. 最长递增子序列(DFS+DP两种方法实现)

目录 题目传送最长递增子序列[DFS 方法]DFS方法思路图思路简述代码大家可以自行考虑有没有优化的方法 最长递增子序列[DP]方法DP方法思路图思路简述代码方案 题目传送 原题目链接 最长递增子序列[DFS 方法] DFS方法思路图 思路简述 对于序列中的每一个数字只有选择和不选择两…

电脑开机慢怎么办,电脑开机慢解决方法

新电脑呢&#xff0c;开机速度特别快。有很多人会感觉到电脑拿回家以后&#xff0c;一按开机键&#xff0c;六秒七秒&#xff0c;这个电脑就启动起来了&#xff0c;但是用一段时间以后呢&#xff0c;他会明显感觉到这个开机的速度呢&#xff0c;会特别慢&#xff0c;可能从六秒…

OSX-02-Mac OS应用开发系列课程大纲和章节内容设计

本节笔者会详细介绍下本系统专题的大纲&#xff0c;以及每个专题章节的组织结构。这样读者会有一个全局的概念。 在开始前还是在再介绍一下下面这个框架图&#xff0c;因为比较重要&#xff0c;在这里再冗余介绍一下。开发Apple公司相关产品的软件时&#xff0c;主要有两个框架…

kubernetes(K8S)学习(六):K8S之Dashboard图形界面

K8S之Dashboard图形界面 一、Dashboard简介二、k8s安装Dashboard(1)下载Dashboard镜像&#xff08;可选&#xff09;(2)根据yaml文件创建资源(3)查看资源(4)生成登录需要的token(5)使用火狐 / 搜狗浏览器访问&#xff08;个人用的搜狗&#xff09; 一、Dashboard简介 官网&…

【最新版RabbitMQ3.13】Linux安装基于源码构建的RabbitMQ教程

前言 linux环境 安装方式有三种&#xff0c;我们这里使用源码安装 Linux下rpm、yum和源码三种安装方式简介 个人语雀首发教程&#xff1a;https://www.yuque.com/wzzz/java/kl2zn22b42svsc6b csdn地址: https://blog.csdn.net/u013625306/article/details/137151862 安装版本…

Netty核心原理剖析与RPC实践6-10

Netty核心原理剖析与RPC实践6-10 06-粘包拆包问题&#xff1a;如何获取一个完整的网络包 本节课开始我们将学习 Netty 通信过程中的编解码技术。编解码技术这是实现网络通信的基础&#xff0c;让我们可以定义任何满足业务需求的应用层协议。在网络编程中&#xff0c;我们经常…

java 视频使用FFmpeg添加水印以及头部尾部

在Java中&#xff0c;你可以使用FFmpeg库来给视频添加水印和头部尾部。FFmpeg是一个开源的跨平台音视频处理工具&#xff0c;提供了丰富的命令行选项&#xff0c;可以满足各种视频处理的需求。 添加水印 以下是一个使用FFmpeg添加水印的简单示例: import com.github.kokorin…