QEMU运行第一章代码

切换分支

git checkout ch1

detail

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

运行代码

cd os
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工程

cargo new os --bin

detail

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

[package]
name = "os"
version = "0.1.0"
edition = "2021" [dependencies]

运行Rust工程

cd os
cargo run

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

strace target/debug/os

log

所有的log

execve("target/debug/os", ["target/debug/os"], 0x7ffc9e2f62e0 /* 46 vars */) = 0
brk(NULL) = 0x653c719dd000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffed7691920) = -1 EINVAL (Invalid argument)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7913b1fc9000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=63807, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 63807, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7913b1fb9000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
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
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=125488, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 127720, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7913b1f99000
mmap(0x7913b1f9c000, 94208, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x3000) = 0x7913b1f9c000
mmap(0x7913b1fb3000, 16384, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1a000) = 0x7913b1fb3000
mmap(0x7913b1fb7000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1d000) = 0x7913b1fb7000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
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
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
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
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
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=2220400, ...}, AT_EMPTY_PATH) = 0
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
mmap(NULL, 2264656, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7913b1c00000
mprotect(0x7913b1c28000, 2023424, PROT_NONE) = 0
mmap(0x7913b1c28000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x7913b1c28000
mmap(0x7913b1dbd000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7913b1dbd000
mmap(0x7913b1e16000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x215000) = 0x7913b1e16000
mmap(0x7913b1e1c000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7913b1e1c000
close(3) = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7913b1f96000
arch_prctl(ARCH_SET_FS, 0x7913b1f96780) = 0
set_tid_address(0x7913b1f96a50) = 4628
set_robust_list(0x7913b1f96a60, 24) = 0
rseq(0x7913b1f97120, 0x20, 0, 0x53053053) = 0
mprotect(0x7913b1e16000, 16384, PROT_READ) = 0
mprotect(0x7913b1fb7000, 4096, PROT_READ) = 0
mprotect(0x653c70293000, 12288, PROT_READ) = 0
mprotect(0x7913b2003000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
munmap(0x7913b1fb9000, 63807) = 0
poll([{fd=0, events=0}, {fd=1, events=0}, {fd=2, events=0}], 3, 0) = 0 (Timeout)
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
getrandom("\xbd\x19\x85\x71\xcb\xc5\x6b\x55", 8, GRND_NONBLOCK) = 8
brk(NULL) = 0x653c719dd000
brk(0x653c719fe000) = 0x653c719fe000
openat(AT_FDCWD, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 3
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
newfstatat(3, "", {st_mode=S_IFREG|0444, st_size=0, ...}, AT_EMPTY_PATH) = 0
read(3, "653c70241000-653c70247000 r--p 0"..., 1024) = 1024
read(3, "--p 00215000 08:03 133853 "..., 1024) = 1024
read(3, "-7913b1fcd000 r--p 00000000 08:0"..., 1024) = 913
close(3) = 0
sched_getaffinity(4628, 32, [0, 1]) = 16
rt_sigaction(SIGSEGV, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGSEGV, {sa_handler=0x653c70265f30, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_SIGINFO, sa_restorer=0x7913b1c42520}, NULL, 8) = 0
rt_sigaction(SIGBUS, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGBUS, {sa_handler=0x653c70265f30, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_SIGINFO, sa_restorer=0x7913b1c42520}, NULL, 8) = 0
sigaltstack(NULL, {ss_sp=NULL, ss_flags=SS_DISABLE, ss_size=0}) = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7913b1fc6000
mprotect(0x7913b1fc6000, 4096, PROT_NONE) = 0
sigaltstack({ss_sp=0x7913b1fc7000, ss_flags=0, ss_size=8192}, NULL) = 0
write(1, "Hello, world!\n", 14Hello, world!
) = 14
sigaltstack({ss_sp=NULL, ss_flags=SS_DISABLE, ss_size=8192}, NULL) = 0
munmap(0x7913b1fc6000, 12288) = 0
exit_group(0) = ?
+++ 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! 应用实际执行相关的只有两个系统调用

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

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

strace一个空的程序

mkdir ./empty_c_project
cd ./empty_c_project
gcc -o empty empty.c
strace ./empty

程序内容

int main()
{
    return 0;
}

log

execve("./empty", ["./empty"], 0x7ffc5012dd30 /* 46 vars */) = 0
brk(NULL) = 0x57b5ec70b000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffe40adc1c0) = -1 EINVAL (Invalid argument)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7009833a7000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=63807, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 63807, PROT_READ, MAP_PRIVATE, 3, 0) = 0x700983397000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
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
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
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
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
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=2220400, ...}, AT_EMPTY_PATH) = 0
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
mmap(NULL, 2264656, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x700983000000
mprotect(0x700983028000, 2023424, PROT_NONE) = 0
mmap(0x700983028000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x700983028000
mmap(0x7009831bd000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7009831bd000
mmap(0x700983216000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x215000) = 0x700983216000
mmap(0x70098321c000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x70098321c000
close(3) = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x700983394000
arch_prctl(ARCH_SET_FS, 0x700983394740) = 0
set_tid_address(0x700983394a10) = 5271
set_robust_list(0x700983394a20, 24) = 0
rseq(0x7009833950e0, 0x20, 0, 0x53053053) = 0
mprotect(0x700983216000, 16384, PROT_READ) = 0
mprotect(0x57b5ec153000, 4096, PROT_READ) = 0
mprotect(0x7009833e1000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
munmap(0x700983397000, 63807) = 0
exit_group(0) = ?
+++ exited with 0 +++

查看rustc的运默认配置信息

rustc --version --verbose

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

rustc 1.79.0 (129f3b996 2024-06-10)
binary: rustc
commit-hash: 129f3b9964af4d4a709d1383930ade12dfe7c081
commit-date: 2024-06-10
host: x86_64-unknown-linux-gnu
release: 1.79.0
LLVM version: 18.1.7

在另一个平台上运行rust

查看rustc支持的平台

rustc --print target-list | grep riscv

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

riscv32gc-unknown-linux-gnu
riscv32gc-unknown-linux-musl
riscv32i-unknown-none-elf
riscv32im-risc0-zkvm-elf
riscv32im-unknown-none-elf
riscv32ima-unknown-none-elf
riscv32imac-esp-espidf
riscv32imac-unknown-none-elf
riscv32imac-unknown-xous-elf
riscv32imafc-esp-espidf
riscv32imafc-unknown-none-elf
riscv32imc-esp-espidf
riscv32imc-unknown-none-elf
riscv64-linux-android
riscv64gc-unknown-freebsd
riscv64gc-unknown-fuchsia
riscv64gc-unknown-hermit
riscv64gc-unknown-linux-gnu
riscv64gc-unknown-linux-musl
riscv64gc-unknown-netbsd
riscv64gc-unknown-none-elf
riscv64gc-unknown-openbsd
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

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

log

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

warning: `/home/winddevil/.cargo/config` is deprecated in favor of `config.toml`
note: if you need to support cargo 1.38 or earlier, you can symlink `config` to `config.toml`
warning: `/home/winddevil/.cargo/config` is deprecated in favor of `config.toml`
note: if you need to support cargo 1.38 or earlier, you can symlink `config` to `config.toml`
Compiling os v0.1.0 (/home/winddevil/workspace/os)
error[E0463]: can't find crate for `std`
|
= note: the `riscv64gc-unknown-none-elf` target may not support the standard library
= note: `std` is required by `os` because it does not declare `#![no_std]` error: cannot find macro `println` in this scope
--> src/main.rs:2:5
|
2 | println!("Hello, world!");
| ^^^^^^^ error: `#[panic_handler]` function required, but not found error: requires `sized` lang_item For more information about this error, try `rustc --explain E0463`.
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. C# 记一次对chm帮助文档的信息提取

    事情时这样,有用友u8的字典数据的帮助文档一份,同事需要把里面的很多张表的字典信息给提取出来,然后构成sql语句,插入数据库.字典就是一张对表里的字段的一个说明,长这样 同事一开始是手动复制到exce ...

  2. 基于WebSocket的modbus通信(一)- 客户端

    上一篇已经实现了ModbusTcp服务器和8个主要的功能码,只是还没有实现错误处理功能. 但是在测试客户端时却发现了上一篇的一个错误,那就是写数据成功,服务器不需要响应. 接下来要做的就是实现Modb ...

  3. Cygwin安装及简单说明

    1 简介 官方说明:Cygwin is a Linux-like environment for Windows. It consists of a DLL (cygwin1.dll), which ...

  4. windows 开发者注册后写代码,这个给钱吗?

  5. Mysql性能优化(详解)

    引言 今天,数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显.关于数据库的性能,这并不只是DBA才需要担心的事,而这更是我们程序员需要去关注的事情.当我们去设计数据库表结构,对操 ...

  6. Flarum 安装和使用教程

    随着开源社区的日益繁荣,人们对社区品质的要求也越来越高.传统的 BBS 论坛模式已经难以满足现代用户对美观.便捷.互动性的需求.搭建一个现代化的高品质社区,成为许多网站管理者的迫切需求和共同挑战. 今 ...

  7. java8 Optional使用 stream filter多级过滤

    java8 Optional使用 stream filter多级过滤 package com.example.core.mydemo.java8; public class MyModel { pri ...

  8. Python中的属性

    Python中的属性主要分为类属性,对象属性. 1.类属性 类属性:类所有,所有的实例对象都能够共享,类定义时就直接指定的属性,能通过类名和实力对象名访问,当当前的类属性被实例对象通过对象名.属性名的 ...

  9. CLR via C# 笔记 -- 特性(18)

    1. 特性继承自System.Attribute,能作用于TypeDef(类.结构.枚举.接口和委托),MethodDef(含构造器),ParamDef,FieldDef,PropertyDef,Ev ...

  10. Android 各层架构

    Android应用框架层和硬件抽象层以及底层之间的关系 1. JNI技术: (1).JNI技术简单的说就是在本地Java语言声明本地方法和加载动态链接库(.so文件) (2).动态链接库(.so文件) ...