QEMU运行第一章代码

切换分支

  1. git checkout ch1

detail

git checkout ch1 命令是用来切换到名为 ch1 的分支或者恢复工作目录中的文件到 ch1 提交的状态

运行代码

  1. cd os
  2. LOG=TRACE make run

detail

LOG=TRACE 是指定 LOG 的级别为 TRACE,可以查看重要程度不低于 TRACE 的输出日志。目前 TRACE 的重要程度最低,因此这样能够看到全部日志

学习Lib-OS的宗旨

引言 - rCore-Tutorial-Book-v3 3.6.0-alpha.1 文档 (rcore-os.cn)

要仔细看最后一段.

创建一个Rust工程

使用Cargo创建Rust工程

  1. cargo new os --bin

detail

os/Cargo.toml 里的内容,记录着这个项目的信息.

  1. [package]
  2. name = "os"
  3. version = "0.1.0"
  4. edition = "2021"
  5. [dependencies]

运行Rust工程

  1. cd os
  2. cargo run

用strace观察应用程序层是怎么调用标准库的

  1. strace target/debug/os

log

所有的log

  1. execve("target/debug/os", ["target/debug/os"], 0x7ffc9e2f62e0 /* 46 vars */) = 0
  2. brk(NULL) = 0x653c719dd000
  3. arch_prctl(0x3001 /* ARCH_??? */, 0x7ffed7691920) = -1 EINVAL (Invalid argument)
  4. mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7913b1fc9000
  5. access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
  6. openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
  7. newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=63807, ...}, AT_EMPTY_PATH) = 0
  8. mmap(NULL, 63807, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7913b1fb9000
  9. close(3) = 0
  10. openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
  11. read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
  12. newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=125488, ...}, AT_EMPTY_PATH) = 0
  13. mmap(NULL, 127720, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7913b1f99000
  14. mmap(0x7913b1f9c000, 94208, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x3000) = 0x7913b1f9c000
  15. mmap(0x7913b1fb3000, 16384, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1a000) = 0x7913b1fb3000
  16. mmap(0x7913b1fb7000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1d000) = 0x7913b1fb7000
  17. close(3) = 0
  18. openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
  19. read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832
  20. pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
  21. pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48
  22. pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0I\17\357\204\3$\f\221\2039x\324\224\323\236S"..., 68, 896) = 68
  23. newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=2220400, ...}, AT_EMPTY_PATH) = 0
  24. pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
  25. mmap(NULL, 2264656, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7913b1c00000
  26. mprotect(0x7913b1c28000, 2023424, PROT_NONE) = 0
  27. mmap(0x7913b1c28000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x7913b1c28000
  28. mmap(0x7913b1dbd000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7913b1dbd000
  29. mmap(0x7913b1e16000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x215000) = 0x7913b1e16000
  30. mmap(0x7913b1e1c000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7913b1e1c000
  31. close(3) = 0
  32. mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7913b1f96000
  33. arch_prctl(ARCH_SET_FS, 0x7913b1f96780) = 0
  34. set_tid_address(0x7913b1f96a50) = 4628
  35. set_robust_list(0x7913b1f96a60, 24) = 0
  36. rseq(0x7913b1f97120, 0x20, 0, 0x53053053) = 0
  37. mprotect(0x7913b1e16000, 16384, PROT_READ) = 0
  38. mprotect(0x7913b1fb7000, 4096, PROT_READ) = 0
  39. mprotect(0x653c70293000, 12288, PROT_READ) = 0
  40. mprotect(0x7913b2003000, 8192, PROT_READ) = 0
  41. prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
  42. munmap(0x7913b1fb9000, 63807) = 0
  43. poll([{fd=0, events=0}, {fd=1, events=0}, {fd=2, events=0}], 3, 0) = 0 (Timeout)
  44. rt_sigaction(SIGPIPE, {sa_handler=SIG_IGN, sa_mask=[PIPE], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7913b1c42520}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
  45. getrandom("\xbd\x19\x85\x71\xcb\xc5\x6b\x55", 8, GRND_NONBLOCK) = 8
  46. brk(NULL) = 0x653c719dd000
  47. brk(0x653c719fe000) = 0x653c719fe000
  48. openat(AT_FDCWD, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 3
  49. prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
  50. newfstatat(3, "", {st_mode=S_IFREG|0444, st_size=0, ...}, AT_EMPTY_PATH) = 0
  51. read(3, "653c70241000-653c70247000 r--p 0"..., 1024) = 1024
  52. read(3, "--p 00215000 08:03 133853 "..., 1024) = 1024
  53. read(3, "-7913b1fcd000 r--p 00000000 08:0"..., 1024) = 913
  54. close(3) = 0
  55. sched_getaffinity(4628, 32, [0, 1]) = 16
  56. rt_sigaction(SIGSEGV, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
  57. rt_sigaction(SIGSEGV, {sa_handler=0x653c70265f30, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_SIGINFO, sa_restorer=0x7913b1c42520}, NULL, 8) = 0
  58. rt_sigaction(SIGBUS, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
  59. rt_sigaction(SIGBUS, {sa_handler=0x653c70265f30, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_SIGINFO, sa_restorer=0x7913b1c42520}, NULL, 8) = 0
  60. sigaltstack(NULL, {ss_sp=NULL, ss_flags=SS_DISABLE, ss_size=0}) = 0
  61. mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7913b1fc6000
  62. mprotect(0x7913b1fc6000, 4096, PROT_NONE) = 0
  63. sigaltstack({ss_sp=0x7913b1fc7000, ss_flags=0, ss_size=8192}, NULL) = 0
  64. write(1, "Hello, world!\n", 14Hello, world!
  65. ) = 14
  66. sigaltstack({ss_sp=NULL, ss_flags=SS_DISABLE, ss_size=8192}, NULL) = 0
  67. munmap(0x7913b1fc6000, 12288) = 0
  68. exit_group(0) = ?
  69. +++ exited with 0 +++

这段输出是Linux系统中通过strace命令跟踪一个程序执行时的系统调用序列。strace是一个强大的诊断、调试和故障排查工具,能够展示一个程序及其子进程所执行的系统调用,以及这些调用的返回值。下面是对输出中一些关键步骤的简要解析:

  1. execve: 程序启动,执行target/debug/os可执行文件,并传递["target/debug/os"]作为命令行参数,以及环境变量。
  2. 内存管理: 包括brk, mmap, mprotect等调用,用于分配、映射和调整进程的内存布局。例如,mmap用于映射匿名内存、加载共享库如libgcc_s.so.1libc.so.6到进程地址空间。
  3. 动态链接: 通过打开和读取/etc/ld.so.cache和相关共享库文件(如libgcc_s.so.1libc.so.6),进行动态链接库的加载准备。
  4. 权限与安全: 如arch_prctl调用用来设置进程的架构特定寄存器,可能涉及到栈保护或其他安全措施。
  5. 文件访问: 例如尝试访问/etc/ld.so.preload来检查是否有额外的动态链接库需要预先加载,以及读取映射共享库内容。
  6. 信号处理: 如rt_sigaction调用,用于设置对特定信号(如SIGPIPE, SIGSEGV, SIGBUS)的处理方式,确保程序能响应这些信号并采取适当行动。
  7. 资源限制与管理: 通过prlimit64调用来获取或设置进程资源限制,比如堆栈大小。
  8. I/O操作: 如openat, read, write等,涉及到文件或标准输入输出的读写操作。此处包括读取自身内存映射信息和最终向标准输出写入"Hello, world!\n"。
  9. 进程终止: 最后,通过exit_group(0)调用,程序正常结束,退出状态码为0,表示成功执行。

    这段跟踪记录详细展示了程序从启动到执行完毕的底层系统活动,对于理解程序运行时的行为、性能分析或问题排查非常有用。

detail

与 Hello, world! 应用实际执行相关的只有两个系统调用

  1. # 输出字符串
  2. write(1, "Hello, world!\n", 14) = 14
  3. # 程序退出执行
  4. exit_group(0)

观察"被隐藏"的操作系统

strace一个空的程序

  1. mkdir ./empty_c_project
  2. cd ./empty_c_project
  3. gcc -o empty empty.c
  4. strace ./empty

程序内容

  1. int main()
  2. {
  3.     return 0;
  4. }

log

  1. execve("./empty", ["./empty"], 0x7ffc5012dd30 /* 46 vars */) = 0
  2. brk(NULL) = 0x57b5ec70b000
  3. arch_prctl(0x3001 /* ARCH_??? */, 0x7ffe40adc1c0) = -1 EINVAL (Invalid argument)
  4. mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7009833a7000
  5. access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
  6. openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
  7. newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=63807, ...}, AT_EMPTY_PATH) = 0
  8. mmap(NULL, 63807, PROT_READ, MAP_PRIVATE, 3, 0) = 0x700983397000
  9. close(3) = 0
  10. openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
  11. read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832
  12. pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
  13. pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48
  14. pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0I\17\357\204\3$\f\221\2039x\324\224\323\236S"..., 68, 896) = 68
  15. newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=2220400, ...}, AT_EMPTY_PATH) = 0
  16. pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
  17. mmap(NULL, 2264656, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x700983000000
  18. mprotect(0x700983028000, 2023424, PROT_NONE) = 0
  19. mmap(0x700983028000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x700983028000
  20. mmap(0x7009831bd000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7009831bd000
  21. mmap(0x700983216000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x215000) = 0x700983216000
  22. mmap(0x70098321c000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x70098321c000
  23. close(3) = 0
  24. mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x700983394000
  25. arch_prctl(ARCH_SET_FS, 0x700983394740) = 0
  26. set_tid_address(0x700983394a10) = 5271
  27. set_robust_list(0x700983394a20, 24) = 0
  28. rseq(0x7009833950e0, 0x20, 0, 0x53053053) = 0
  29. mprotect(0x700983216000, 16384, PROT_READ) = 0
  30. mprotect(0x57b5ec153000, 4096, PROT_READ) = 0
  31. mprotect(0x7009833e1000, 8192, PROT_READ) = 0
  32. prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
  33. munmap(0x700983397000, 63807) = 0
  34. exit_group(0) = ?
  35. +++ exited with 0 +++

查看rustc的运默认配置信息

  1. rustc --version --verbose

从其中的 host 一项可以看出默认的目标平台是 x86_64-unknown-linux-gnu,其中 CPU 架构是 x86_64,CPU 厂商是 unknown,操作系统是 linux,运行时库是 GNU libc(封装了 Linux 系统调用,并提供 POSIX 接口为主的函数库)。

  1. rustc 1.79.0 (129f3b996 2024-06-10)
  2. binary: rustc
  3. commit-hash: 129f3b9964af4d4a709d1383930ade12dfe7c081
  4. commit-date: 2024-06-10
  5. host: x86_64-unknown-linux-gnu
  6. release: 1.79.0
  7. LLVM version: 18.1.7

在另一个平台上运行rust

查看rustc支持的平台

  1. rustc --print target-list | grep riscv

可以看到程序列出来的平台:

  1. riscv32gc-unknown-linux-gnu
  2. riscv32gc-unknown-linux-musl
  3. riscv32i-unknown-none-elf
  4. riscv32im-risc0-zkvm-elf
  5. riscv32im-unknown-none-elf
  6. riscv32ima-unknown-none-elf
  7. riscv32imac-esp-espidf
  8. riscv32imac-unknown-none-elf
  9. riscv32imac-unknown-xous-elf
  10. riscv32imafc-esp-espidf
  11. riscv32imafc-unknown-none-elf
  12. riscv32imc-esp-espidf
  13. riscv32imc-unknown-none-elf
  14. riscv64-linux-android
  15. riscv64gc-unknown-freebsd
  16. riscv64gc-unknown-fuchsia
  17. riscv64gc-unknown-hermit
  18. riscv64gc-unknown-linux-gnu
  19. riscv64gc-unknown-linux-musl
  20. riscv64gc-unknown-netbsd
  21. riscv64gc-unknown-none-elf
  22. riscv64gc-unknown-openbsd
  23. riscv64imac-unknown-none-elf

这里我们选择 riscv64gc-unknown-none-elf 目标平台。这其中的 CPU 架构是 riscv64gc ,CPU厂商是 unknown ,操作系统是 none , elf 表示没有标准的运行时库(表明没有任何系统调用的封装支持),但可以生成 ELF 格式的执行程序。

detail

  1. rustc: 这是Rust编程语言的编译器命令行工具。它用于编译Rust源代码到各种不同的目标平台上,包括但不限于各种CPU架构和操作系统。
  2. --print target-list: 这是一个rustc的命令行选项,用来打印出rustc支持的所有编译目标(target triples)。Target triple是一种描述编译目标平台的字符串格式,通常包含架构、操作系统和环境信息,比如x86_64-unknown-linux-gnu表示64位x86架构、未知操作系统、GNU库环境。
  3. |(管道符号): 这是一个Unix/Linux shell命令,用于将前一个命令的输出作为后一个命令的输入。在这里,它把rustc --print target-list的输出作为下一个命令(grep riscv)的输入。
  4. grep riscv: grep是一个文本搜索工具,用于在输入数据中查找包含指定模式的行。这里使用grep riscv来过滤出那些包含“riscv”字符串的行。由于前面的命令列出了所有支持的编译目标,这一步就是从这些目标中筛选出与RISC-V架构相关的所有目标。

去掉操作系统支持,编译rust

  1. cargo run --target riscv64gc-unknown-none-elf

log

这里重点关注关于 error[E0463]的表述,是编译器找不到rust的std库,

  1. warning: `/home/winddevil/.cargo/config` is deprecated in favor of `config.toml`
  2. note: if you need to support cargo 1.38 or earlier, you can symlink `config` to `config.toml`
  3. warning: `/home/winddevil/.cargo/config` is deprecated in favor of `config.toml`
  4. note: if you need to support cargo 1.38 or earlier, you can symlink `config` to `config.toml`
  5. Compiling os v0.1.0 (/home/winddevil/workspace/os)
  6. error[E0463]: can't find crate for `std`
  7. |
  8. = note: the `riscv64gc-unknown-none-elf` target may not support the standard library
  9. = note: `std` is required by `os` because it does not declare `#![no_std]`
  10. error: cannot find macro `println` in this scope
  11. --> src/main.rs:2:5
  12. |
  13. 2 | println!("Hello, world!");
  14. | ^^^^^^^
  15. error: `#[panic_handler]` function required, but not found
  16. error: requires `sized` lang_item
  17. For more information about this error, try `rustc --explain E0463`.
  18. error: could not compile `os` (bin "os") due to 4 previous errors

detail

当你运行 cargo run --target riscv64gc-unknown-none-elf 命令时,你是在使用Rust的包管理器Cargo来构建并运行一个Rust项目,但目标平台设定为了RISC-V 64位架构、具有GC(General Purpose,通用)扩展、面向一个未知且没有操作系统的环境(通常指嵌入式系统或微控制器)。下面是这个命令的几个关键点解析:

  • cargo run: 这个命令告诉Cargo构建当前包(默认是项目的根crate)并随后运行生成的可执行文件。它相当于先执行cargo build,然后执行生成的二进制文件。

    • --target: 这是一个选项,用于指定构建的目标架构和平台。这对于交叉编译特别重要,即在一种架构上编译代码,使其能在另一种架构上运行。
  • riscv64gc-unknown-none-elf: 这个目标三元组定义了编译的目标平台特征:
    • riscv64gc: 指定目标架构为RISC-V 64位版本,带GC(General Purpose)扩展,这通常意味着启用了像乘法和除法这样的基本指令集扩展。
    • unknown: 表示供应商或制造商未知,这在嵌入式开发中很常见,因为目标硬件可能不是由知名的商业公司生产。
    • none: 表明目标系统没有操作系统。这对于裸机编程(bare metal programming)、微控制器编程或自定义OS开发非常重要。
    • elf: 表明输出格式为ELF(Executable and Linkable Format),这是一种常用的可执行文件、目标文件和核心转储格式,适用于多种操作系统和体系结构。

使用rust core来代替std

Rust 有一个对 Rust 语言标准库–std 裁剪过后的 Rust 语言核心库 core。core库是不需要任何操作系统支持的,它的功能也比较受限,但是也包含了 Rust 语言相当一部分的核心机制,可以满足我们的大部分功能需求.

[rCore学习笔记 06]运行Lib-OS的更多相关文章

  1. iOS学习笔记06—Category和Extension

    iOS学习笔记06—Category和Extension 一.概述 类别是一种为现有的类添加新方法的方式. 利用Objective-C的动态运行时分配机制,Category提供了一种比继承(inher ...

  2. 机器学习实战(Machine Learning in Action)学习笔记————06.k-均值聚类算法(kMeans)学习笔记

    机器学习实战(Machine Learning in Action)学习笔记————06.k-均值聚类算法(kMeans)学习笔记 关键字:k-均值.kMeans.聚类.非监督学习作者:米仓山下时间: ...

  3. Linux进程线程学习笔记:运行新程序

    Linux进程线程学习笔记:运行新程序                                         周银辉 在上一篇中我们说到,当启动一个新进程以后,新进程会复制父进程的大部份上下 ...

  4. [Golang学习笔记] 06 程序实体3 类型断言和类型转换

    类型断言: 语法:<目标类型的值>,<布尔参数> := <表达式>.( 目标类型 ) // 安全类型断言<目标类型的值> := <表达式>. ...

  5. Python学习笔记(15)- os\os.path 操作文件

    程序1 编写一个程序,统计当前目录下每个文件类型的文件数,程序实现如图: import os def countfile(path): dict1 = {} # 定义一个字典 all_files = ...

  6. stm32寄存器版学习笔记06 输入捕获(ETR脉冲计数)

    STM32外部脉冲ETR引脚:TIM1-->PA12;TIMER2-->PA0:TIMER3-->PD2;TIMER4-->PE0… 1.TIM2 PA0计数 配置步骤 ①开启 ...

  7. [原创]java WEB学习笔记06:ServletContext接口

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  8. Bash脚本编程学习笔记06:条件结构体

    简介 在bash脚本编程中,条件结构体使用if语句和case语句两种句式. if语句 单分支if语句 if TEST; then CMD fi TEST:条件判断,多数情况下可使用test命令来实现, ...

  9. OpenCV 学习笔记 06 图像检索以及基于图像描述符的搜索

    OpenCV 可以检测图像的主要特征,然后提取这些特征,使其成为图像描述符,这些图像特征可作为图像搜索的数据库:此外可以利用关键点将图像拼接 stitch 起来,组成一个更大的图像.如将各照片组成一个 ...

  10. angularjs学习笔记2—运行phonecat项目

    如果你去angularjs中文网看它的教程,你会发现一开始它提供了一个phonecat的引导项目,这个项目是angular官方给出的一个类似于demo的教程项目,并配有相应文档,按照这个项目并配合文档 ...

随机推荐

  1. 构建自定义镜像并优化dockerfile文件

    目录 一.系统环境 二.前言 三.镜像构建步骤 四.dockerfile文件常用指令 4.1 dockerfile文件常用指令 4.2 RUN.CMD.ENTRYPOINT的区别 五.构建centos ...

  2. Pandas学习之路【1】

    安装pandas: pip install pandas pandas读取数据: 数据类型 读取方式 csv, tsv, txt pd.read_csv Excel pd.read_excel mys ...

  3. Native如何使用Tunnel Mode

    mAudioSessionId = AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION); mHwSync = AudioSystem: ...

  4. 005. gitlab安装

    1. gitlab介绍 官方网站: www.gitlab.com gitlab是一款使用ruby编写的代码版本管理系统,他可以通过web界面来管理代码. 2. gitlab安装 官方安装文档: htt ...

  5. Qt-FFmpeg开发-视频播放【硬解码】(2)

    Qt-FFmpeg开发-视频播放[硬解码] 目录 Qt-FFmpeg开发-视频播放[硬解码] 1.概述 2.实现效果 3.FFmpeg硬解码流程 4.主要代码 6.完整源代码 更多精彩内容 个人内容分 ...

  6. 分享5款.NET开源免费的Redis客户端组件库

    前言 今天大姚给大家分享5款.NET开源.免费的Redis客户端组件库,希望可以帮助到有需要的同学. StackExchange.Redis StackExchange.Redis是一个基于.NET的 ...

  7. c/c++复习 2.0 ProMax

    main函数执行前后做了什么 初始化.data数据段,包括静态变量和全局变量 初始化.bss字段,包括int 0; bool false: 指针 NULL 设置栈指针.main函数的参数传递.全局对象 ...

  8. react表单处理 非受控组件

    没有和state数据源进行关联的表单项,而是借助ref,使用元素DOM方式获取表单元素值 使用步骤 调用 React.createRef() 方法创建ref对象 将创建好的 ref 对象添加到文本框中 ...

  9. mysql case when使用

    ## mysql case when使用 SELECT order_no,case is_test when 0 then '否'when 1 then '是'end as '是否测试' from ` ...

  10. 从Purge机制说起,详解GaussDB(for MySQL)的优化策略

    本文分享自华为云社区<[华为云MySQL技术专栏]GaussDB(for MySQL) Purge优化>,作者:GaussDB 数据库. 在MySQL中,尤其是在使用InnoDB引擎时,P ...