Makefile的使用

news/2024/3/29 17:39:01/文章来源:https://www.cnblogs.com/sureZ-learning/p/16622972.html

1 概要

软件的分层使软件的逻辑关系更清晰,但是也带来一个副作用,即Makefile也变得复杂了。道理显而易见:对于一个简单项目,如果所有文件都放在同一个文件夹内,Makefile写起来也会十分简单,但是我们不能一直停留在原始时代,当复杂项目的源文件按类型、功能、模块等分散到不同路径时,需要我们掌握复杂的Makefile写法来编译它们。

Makefile其实就是一套规则(相当于脚本),make按照这一套规则(相当于解释器),生成最后的结果;其次如果只改了某些文件,重新编译时可以只编译那些改变的部分(即增量编译),这样加快了再次编译速度。所以掌握了Makefile可以实现自动化编译可以提高版本构建效率。

2 Makefile的框架

很多人会被Makefile吓到,归结下来,可能是如下几个原因:一是因为Makefile有独自的写法,和平时常用的c、python等语法不同,二是一些IDE屏蔽了工程的构建信息,由于不常使用所以不熟悉,三是Makefile中涉及到编译的几个步骤以及gcc命令、shell脚本等,需要多方面的知识,更令人迷惑的则是Makefile中的隐式规则。但把这些知识点一个个弄明白,分而治之,掌握Makefile也非难事。

Makefile入门网上有许多资料,本文只是梳理我认为的几个Makefile常用知识点。以下分别介绍gcc编译C代码的过程以及复杂Makefile的编写。

2.1 gcc编译C代码过程

对于如下c代码:

#include <stdio.h>int main() 
{printf("hello, world\n");return 0;
}

其编译过程如下4步(编译环境为Ubuntu):

编译过程

step1: 预编译:

gcc -E hello.c -o hello.i

程序中有以#include #define开头的行,称为预处理语句(C语言的编译预处理命令必须用“#”开头),在编译之前必须由编译预处理将它们替换成C编译程序能够接受的正文。分为:

  1. 宏定义, #define 展开宏定义

  2. 条件编译, 如:“#if” “#ifdef” “#else” “#elif” “#endif”等

  3. 文件包含 #include,将被包含的文件插入到该预编译指令的位置

    还有一些删除注释、添加行号和文件名标识等也是在预处理这一步完成的。

step2: 编译:

gcc -S hello.i -o hello.s

编译是指:将高级语言(C语言)翻译为汇编语言的过程,其中包括翻译和查错(词法分析、语法分析、语义分析生成和优化目标代码,出错时,停止编译)。

step3: 汇编:

gcc -c hello.s -o hello.o

汇编过程是将汇编代码转换为机器代码的过程,每一条汇编语句几乎都对应着一条机器指令。

step4: 链接:

gcc -o hello hello.o

示例中hello.c 程序调用了 printf 函数(存在在libc.a中),链接器将libc.a中的print.o与hello.o重新组织以下,形成最终的可执行程序,这属于静态链接过程(static linking)。

2.2 复杂Makefile的组织方式

只有单个文件的Makefile写起来与直接用手敲2.1节的几条命令区别并不大,并不能体现出Makefile的优势;当项目变得复杂(目录结构很多),Makefile才能体现其作为脚本的优势。

1. make与Makefile与gcc的关系:

gcc是编译器;而make是一个命令工具,用来解析makefile脚本。

可以这么简单的比方:

makefile是像一首歌的曲谱,曲谱中写了怎么调用gcc、 GNU binutils、shell命令等对整个项目的各个文件进行分别编译和链接;

make工具就像指挥家,指挥家根据曲谱指挥演奏者怎么样演奏(make工具就根据makefile中的命令进行编译和链接的);

而gcc、 GNU binutils、shell等像演奏者,实际干活的是它们。

2. 构建的核心:

简单认为:构建就是将库、可链接二进制文件(linux上的.o文件)链接成可执行文件的过程。涉及到几个问题:

  1. 库从什么地方找?(-L指令)
  2. 库的名字是什么(-l指令)
  3. 怎么编译库或者可链接二进制文件?源文件怎么收集?(wildcard、foreach、call等系列函数的灵活使用)
  4. 头文件哪里找?(-I指令 汇编的时候才需要头文件,链接时不需要头文件)

在编写Makefile时,解决上述几个问题,就可写出正确的Makefile。当然还要注意不少的细节。

3. 复杂Makefile组织的方式:

例如:一个多目录结构,文件夹如树状结构组织,源文件分散在其中。Makefile同样需要树状结构组织(这并不绝对,只要Makefile能找到源文件即可)。

例子:引用的是李老师的B站视频(见参考3),虽然例子比较简单,但是复杂的文件结构也可类似处理。例子已推送到github:

https://github.com/sz-ok/Makefile_learning

下图中手动为Makefile指定了一个标记,方便后面表述。

$ tree
.
├── head
│   └── head.h
├── main
│   ├── main.c
│   └── Makefile --------- mk-main
├── Makefile ------------- mk-top
└── tst├── foo│   ├── foo.c│   └── Makefile ----- mk-foo├── Makefile --------- mk-tst└── tst.c

mk-top:

#作用是制定规则来说明当前目录下生成终极目标文件test
TGT = test
#指定子目录
SUB_DIR = main tst
#指定当前目录
export TOP_PATH = $(shell pwd)
#指定头文件目录
export HEAD_PATH = $(TOP_PATH)/head
#指定子目标
export SUB_TGT = bulit_in.o
#CROSS_COMPILER = arm-linux-
export CC = $(CROSS_COMPILER)gcc
#编译选项,指定编译时的头文件路径
export CFLAGS = -I$(HEAD_PATH) -Wall
#指定链接器
export LD = ld
#指定链接器选项
export LDFLAGS = 
#终极目标 (后面表示包括子目录的所有.o).PHONY: all clean $(SUB_DIR)all:$(TGT)
$(TGT): $(SUB_DIR)$(CC) $(CFLAGS)  $(^:=/$(SUB_TGT)) -o $@#下面规则说明进入到生成test所需要依赖的子目录
#-C选项,可以让make进入到后面指定的目录
$(SUB_DIR): make -C $@ clean:-rm -f $(TGT)for dir in $(SUB_DIR); do \make -C $$dir clean;    \done

mk-main:

SRCS = main.c
SUB_DIR =all:$(SUB_TGT).PHONY: $(SUB_TGT) $(SUB_DIR) clean
#下面的规则说明,如何生成当前目录下的子目标(是由当前目录下的.c生成的.o和当前下的
子目录下的子目标临时打包生成的)
$(SUB_TGT): $(SRCS:.c=.o) $(SUB_DIR)$(LD) $(LDFLAGS)  $(SRCS:.c=.o) $(SUB_DIR:=/$(SUB_TGT)) \-r -o $@%.o: %.c$(CC) $(CFLAGS) $< -c%.d:  %.c$(CC) $(CFLAGS) $< -MM > $@#表明main.o编译会关系到main.d, 而main.d又关联到main.c和common.h,所以只要main.c所引用到的头文件有所修改,都会重新编译main.o和main.d
ifneq ($(MAKECMDGOALS), clean)
sinclude $(SRCS:.c=.d)
endif$(SUB_DIR):make -C $@
clean:-rm -f *.o  *.d  for dir in $(SUB_DIR); do  \make -C $$dir clean;  \done

mk-tst:

SRCS = tst.c
SUB_DIR = fooall:$(SUB_TGT).PHONY: $(SUB_TGT) $(SUB_DIR) clean
#下面的规则说明,如何生成当前目录下的子目标(是由当前目录下的.c生成的.o和当前下的
子目录下的子目标临时打包生成的)
$(SUB_TGT): $(SRCS:.c=.o) $(SUB_DIR)$(LD) $(LDFLAGS)  $(SRCS:.c=.o) $(SUB_DIR:=/$(SUB_TGT)) \-r -o $@%.o: %.c$(CC) $(CFLAGS) $< -c%.d:  %.c$(CC) $(CFLAGS) $< -MM > $@#表明tst.o编译会关系到tst.d, 而tst.d又关联到tst.c和common.h,所以只要tst.c所引用到的头文件有所修改,都会重新编译tst.o和tst.d
ifneq ($(MAKECMDGOALS), clean)
sinclude $(SRCS:.c=.d)
endif$(SUB_DIR):make -C $@clean:-rm -f *.o  *.d  for dir in $(SUB_DIR); do  \make -C $$dir clean;  \done

foo目录与main目录一样,没有子文件夹,所以mk-foo的Makefile与mk-main一致。

其编译过程大略如下: foo目录编译生成bulit_in.o, 与 tst目录下的tst.o 打包生成 bulit_in.o,与 main目录编译生成的bulit_in.o链接得到最终目标文件test。

  • top Makefile:进入各子目录下执行make命令,将各个子目录下的.o文件链接生成可执行文件
  • 子Makefile:将当前目录下的.c文件编译生成.o文件

3 Makefile中的一些知识点

3.1 常见gcc命令

gcc是GNU compiler collection 的缩写,注意gcc是一个编译器集合,gcc工作时需要binutils配合。

gcc调用binutils工具集:

命令 等价命令 用途
-S cc1 仅编译,不进行汇编、链接 编译
-c as (binutils工具集) 汇编
-o ld (binutils工具集) 链接

gcc常用命令:

选项 用途
-E 只进行预处理,不进行编译、汇编、链接
-D 使用-D name[=definition]预定义名为name的宏
-l(小L) 使用-l libname或者-llibname,使链接器在链接时搜索名为libname.a/libname.so(静态/动态)的库文件
-L 使用-Ldir添加搜索目录,即链接器在搜索-l选项指定的库文件时,除了系统的库目录还会(优先)在-L指定的目录下搜索
-I(大写的i) 使用-I dir,将目录dir添加为头文件搜索目录
-include 使用-include file,等效于在被编译的源文件开头添加#include "file"
-static 指定静态链接(默认是动态链接)
-O0~3 开启编译器优化,-O0为不优化,-O3为最高级别的优化
-Os 优化生成代码的尺寸,使能所有-O2的优化选项,除了那些让代码体积变大的
-Og 优化调试体验,在保留调试信息的同时保持快速的编译,对于生成可调试代码,比-O0更合适,不会禁用调试信息。
-Wall 使编译器输出所有的警告信息
-march 指定目标平台的体系结构,如-march=rv32imafdc,常用于交叉编译
-mtune 指定目标平台的CPU以便GCC优化,如-mtune=nuclei-300-series,常用于交叉编译
-M 生成文件关联的信息。包含目标文件所依赖的所有源代码
-MM 生成文件关联的信息。
-MMD 和-MM相同,但是输出将导入到.d的文件里面

make常用命令:

(通过make -h可查看全部指令,这里仅列出2个常用的)

选项 用途
make -f filename 执行指定的Makefile或其他文件名
make -C DIRECTORY 跳到指定目录执行Makefile

3.2 Makefile中变量

变量的赋值方式:

赋值方式 作用
= 延迟赋值 (变量的值是整个makefile中最后被指定的值)
:= 立即赋值(赋予当前位置的值,不受后面值的影响 )
?= 条件赋值(如果之前有赋值,则不会赋值; 否则采用此条赋值)
+= 追加赋值(拼接,以空格隔开,Makefile中变量类型是字符串类型)

注意:?= 与 +=也是默认延迟赋值。

可以结合实例进行理解,如下:

  • 延迟赋值 =

例如:

# test =
A = 2233
B = ${A}
A = 7788all:@echo "test ="@echo A = $A, B = $B,

结果为:

test =
A = 7788, B = 7788,

“=”是最普通的等号,然而在Makefile中确实最容易搞错的赋值等号,使用”=”进行赋值,变量的值是整个makefile中最后被指定的值。

  • 立即赋值 :=

类似上述例子,将=换为:=

# test :=
A = 2233
B := ${A}
A = 7788all:@echo "test :="@echo A = $A, B = $B,

结果为:

test :=
A = 7788, B = 2233,

”:=”就表示直接赋值,赋予当前位置的值,不受后面值的影响。

  • 条件赋值 ?=

例如:

# test ?=
A = 2233
A ?= 7788all:@echo "test :="@echo A = $A,

结果为:

test :=
A = 2233,

“?=”表示如果该变量没有被赋值,则赋予等号后的值。

怎么理解?= 也是默认延迟赋值呢?

同样例如:

# test ?=
A ?= 7788_${B}
B = 'BBBB'all:@echo "test ?="@echo A = $A,

结果为:

test ?=
A = 7788_BBBB,
  • 追加赋值 += (以空格隔开)

例如:

# test +=
A = 2233
A += 7788_${B}
B = 'BBBB'all:@echo "test +="@echo A = $A,

结果为:

test +=
A = 2233 7788_BBBB,

可见+= 也是默认延迟赋值属性。

但是修改上述例子:

# test +=
A := 2233  # 将A = 2233改为A := 2233, += 好像失去了延迟赋值的属性了
A += 7788_${B}
B = 'BBBB'
all:@echo "test +="@echo A = $A,

结果为:

test +=
A = 2233 7788_,

通过对比,可大概了解这些算符的差别。(PS: 我无力吐槽,为啥设计出这些令人迷惑的东西?)

Makefile中的特殊变量:

特殊变量 作用
$@ 当前规则的目标
$^ 依赖列表(所有依赖)
$< 第一个依赖
$$ 当前执行的进程的进程编号
$* 模式规则中所有%匹配的部分
$? 模式规则中所有比所在规则中的目标更新文件组成的列表

代表命令的变量:

Makefile书写中,有一些书写约定。比如:与编译器相关的一些命令,可以用变量来表示,其好处是:当换编译工具等,可以仅改变变量(相当于C语言的define的作用),约定并不是强制规则,但是按照约定会给他人阅读你的代码带来方便。

常见约定的变量如下表所示:

变量 含义
CC C编译程序。默认是"cc"
CXX C++编译程序。默认是"g++"
CPP C/C++预处理器。默认是"$(CC) -E"
AR 函数库打包程序,可创建静态库.a文档。默认是"ar"。
AS 汇编程序。默认是"as“
CFLAGS C编译程序的命令行参数
CXXFLAGS C++编译程序的命令行参数
CPPFLAGS C/C++预处理器的命令行参数
ARFLAGS 函数库打包程序的命令行参数。默认值是"rv"
ASFLAGS 汇编程序的命令行参数
LDFLAGS 链接器的命令行参数

一些常用shell命令(如cp ls等)可以直接在Makefile中使用。

3.2 Makefile中函数列表

文本处理函数

函数名 作用
$(subst FROM,TO,TEXT) 字符串替换函数:把字串“TEXT”中的“FROM”字符替换为“TO”
$(patsubst PATTERN,REPLACEMENT,TEXT) 支持通配符的字符串替换函数
$(strip STRINT) 去掉字串“STRINT”开头和结尾的空字符,并将其中多个连续空字符合并为一个空字符。
$(findstring FIND,IN) 查找字符串函数,如果在“IN”之中存在“FIND”,则返回“FIND”,否则返回空。
$(filter PATTERN…,TEXT) 过滤函数,空格分割的“TEXT”字串中所有符合模式“PATTERN”的字串
$(filter-out PATTERN...,TEXT) 反过滤函数,和“filter”函数实现的功能相反
$(sort LIST) 排序函数,给字串“LIST”中的单词升序排列,并去掉重复的单词
$(word N,TEXT) 取字串“TEXT”中第“N”个单词(“N”的值从 1 开始)
$(wordlist S,E,TEXT) 从字串“TEXT”中取出从“S”开始到“E”的单词串。“S”和“E” 表示单词在字串中位置的数字
$(words TEXT) 统计单词数目函数
$(firstword NAMES…) 取首单词函数,等效于$(word 1 , NAMES…)

文件名处理函数

函数名 作用
$(dir NAMES…) 取目录函数-从文件名序列“NAMES…”中取出各个文件名的目录部分
$(notdir NAMES…) 取文件名函数-文件名序列“NAMES…”中每一个文件的非目录部分
$(suffix NAMES…) 取后缀函数
$(basename NAMES…) 取前缀函数
$(addsuffix SUFFIX,NAMES…) 加后缀函数
$(addprefix PREFIX,NAMES…) 加前缀函数
$(join LIST1 ,LIST2) 将字串“LIST1”和字串“LIST2”各单词进行对应连接
$(wildcard PATTERN) 获取匹配模式文件名函数,列出当前目录下所有符合模式“PATTERN”格式的文件名。支持通配符

流程相关函数

函数名 作用
$(foreach VAR,LIST,TEXT) 类似于 for VAR in LIST:TEXT
$(if CONDITION,THEN-PART[,ELSE-PART]) 类似于 CONDITION?THEN-PART:ELSE-PART
$(call VARIABLE,PARAM1,PARAM2,...) call”函数是唯一一个可以创建定制化参数函数的引用函数,VARIABLE表达式中的$(1),$(2),$(3)等,会被参数< PARAM1>;,;,依次替代
$(value VARIABLE) 不对变量“VARIBLE”进行任何展开操作,直接返回变量“VARIBALE” 的值。
$(eval VARIABLE) 根据其参数的关系、 结构,对它们进行替换展开。经常搭配call函数使用,见参考2
$(origin VARIABLE) 获取此变量(参数)相关的信息,告诉我们这个变量的定义方式
shell函数 函数“shell”的参数(一个 shell 命令)在 shell 环境中的执行结果

3.3 Makefile中模式规则

Makefile中的隐含规则:

如果一个目标文件在Makefile中没有重建它的明确规则,但make时依旧正确运行,有可能时make用到了隐含规则来重建它。

可以使用make -p打印出make的所有隐含规则,调用顺序:显示规则 > 隐含规则 > 否则报错

规则中的模式替换:

格式为:

< targets …>: < target-pattern>: < prereq-patterns …><commands><targets …>:指定一个或多个目标文件,可使用通配符。<target-pattern...>:指定 <targets …>目标文件的模式,如%.o,表示<targets>集合中都是以.o结尾的文件。<prereq-patterns …>:指定<targets …>目标文件依赖的文件的模式,如%.c ,表示 <targets …>集合中的目标文件的依赖文件都是以.c结尾的文件

例子:

TARGET = main.o hello.o test.o
all:$(TARGET)
$(TARGET):%.o:%.cgcc -c $< -o $@

这个模式规则指明了如何由%.c 来创建%.o,属于makefile中的隐含规则。

3.4 Makefile中的变量(字符串)替换

  1. 后缀字符串替换,将字符串中的后缀字符(串)使用指定的字符(串)进行替代。

    格式为 $(var:a=b)

    意思是:将var表达式中以空格分开所有的子串,以a结尾的字符替换为b。

    VAR := acc bcc ccd
    NEW := $(VAR:cc=aa)
    test:@echo "new is $(NEW)"
    

    make test后结果为“new is aaa baa ccd”,通过例子可以看出这种方法只能处理后缀字符串替换。

    NEW := $(VAR:=aa) 
    

    则结果为“new is accaa bccaa ccdaa”,这种方式可以在变量后添加新的字符串。

  2. 变量中的模式替代

    使用%来匹配模式,%匹配的保留字符,其它为替代字符,较第一种方法更为通用。

    格式为$(var:a%b=x%y)

    VAR := a.c b.c c.c
    NEW := $(VAR:%.c=%.o)
    test:@echo "new is $(NEW)"
    

    make test后结果为“new is a.o b.o c.o”

  3. 模式替代函数

    格式为 $(patsubst pattern, replacement, text)

    搜索text中以空格分开的单词,将符合pattern模式替换为replacement,pattern和replacement支持%通配符。

    VAR := a.c b.c c.c
    NEW := $(patsubst %.c, %.o, $(VAR))
    test:@echo "new is $(NEW)"
    

    make test结果同样为“new is a.o b.o c.o”

    这几种方法得到的效果是相同的:

    $(patsubst %.c, %.o, $(VAR))$(VAR:%.c=%.o)$(VAR:.c=.a)
    

3.5 Makefile中的PHONY关键字

Makefile中.PHONY关键字修饰的目标被称之为伪目标。其作用如下:

  1. 避免目标名与文件名重名。用.PHONY修饰后告诉make 目的为了执行执行一些列命令,而不需要创建这个目标。

    如上节例子中的clean,用.PHONY修饰后,无论在当前目录下是否存在“clean”这个文件。我们输入“make clean”之后。“rm”命令都会被执行。而且当一个目标被声明为伪目标后,make 在执行此规则时不会去试图去查找隐含规则来创建它。这样也提高了 make 的执行效率。

  2. 伪目标的另外一种使用场合是在 make 的并行和递归执行过程中。

    并行:

    # 写法1:
    SUBDIRS = foo bar baz
    subdirs:for dir in $(SUBDIRS); do \$(MAKE) -C $$dir; \done# 写法2:这种写法出错更容易定位,且利用了make的并行处理功能。
    SUBDIRS = foo bar baz
    .PHONY: subdirs $(SUBDIRS)
    subdirs: $(SUBDIRS)$(SUBDIRS):$(MAKE) -C $@foo: baz
    

    递归:

    .PHONY: cleanall cleanobj cleandiff
    cleanall : cleanobj cleandiffrm program
    cleanobj :rm *.o
    cleandiff :rm *.diff
    

    当一个伪目标作为另外一个伪目标依赖时,就成了必须执行的部分,如同cleanall调用了cleanobj与cleandiff。

3.6 Makefile 中 echo 和@echo的区别

echo: 会在shell中显示echo这条命令和后面要输出的内容
@echo: 不会显示echo这条命令,只会显示后面要输出的内容

例如:

echo “hello world”  输出为:
echo "hello world"
hello world@echo "hello world" 输出为:
hello world

3.7 在Makefile打印错误或警告信息

# 在makefile中打印警告或者错误消息的方法:
$(warning xxxxx) 
# 或者
$(error xxxxx) 
# 输出变量方式为:
$(warning $(XXX)) 

参考:

  1. Makefile中文手册

  2. makefile eval函数详解

  3. Makefile视频教程

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

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

相关文章

Codeforces Round #772 (Div. 2)

Codeforces Round #772 (Div. 2) VPA B C3min 12min 52min+4排名:rk3893 基准分:\(\color{ForestGreen}{1362}\) 从天选到天崩 A \(\color{Gray}{800}\)CF1635A Min Or Sum简要分析可知,其实答案就是对于所有数取或运算和(具体懒得管) 时间复杂度:\(O(n)\) int n,x; void w…

SMB登录事件排查经验分享

1. 概述1.1 案例先来看两张图: 看到这两张图的第一印象应该是这是一个成功的登陆,其类型为3,代表网络登陆,4624表示成功登陆,可能大部分人都是如此认为。 那么实际上呢?这里面是存在一定歧义的,今天给大家同步一下这里面的详细细节。1.2 原理当用户使用SMB 协议连接时,…

GET 和 POST详解

https://blog.csdn.net/qq_44204058/article/details/113984363 一、HTTP请求方法Http协议定义了很多与服务器交互的方法,最基本的有4种,分别是GET,POST,PUT,DELETE. 一个URL地址用于描述一个网络上的资源,而HTTP中的GET, POST, PUT, DELETE就对应着对这个资源的查,改,增,…

leetcode 594. Longest Harmonious Subsequence 最长和谐子序列(简单).md

题目给我们一个数组,让我们找出最长的和谐子序列,和谐子序列就是序列中数组的最大最小差值均为1,这里只让我们求长度,而不需要返回具体的子序列。所以我们可以对数组进行排序,实际上只要找出来相差为1的两个数的总共出现个数就是一个和谐子序列长度了。一、题目大意 https…

2022DASCTF X SU 三月春季挑战赛 web

2022DASCTF——web1.ezpop 2.calc 3.upgdstoreezpop 给出了源码: <?phpclass crow {public $v1;public $v2;function eval() {echo new $this->v1($this->v2);}public function __invoke(){$this->v1->world();} }class fin {public $f1;public function __de…

SAAS市场不是“出身之争”,客户需求主导一切

“Salesforce中国区宣布解散”的消息,市场已经给出诸多分析和猜测。有意思的是,每当有外企中国业务受阻,市场就会有一波声音出来,认为这是外企在中国水土不服。这次也不例外,有一种观点认为外国软件不适合中国国情,未来将是中国SAAS厂商的机遇。 抛开现象看本质,抛开推测…

使用time.Time数据类型获取时间报错

报错类型:Error 1292: Incorrect datetime value: 0000-00-00 for column created_at at row 1 在添加用户到数据库时,使用的字段created_at,类型为time.Time ,无法正确的获取到当前数据点的报错记录,如下图所示: 解决方法与解决过程: 因为我这是学习别人的项目,所以拥…

今日内容之 CSS盒子模型和JS基础知识数据类型

CSS盒子模型所有的标签都可以看成是一个快递盒 1.margin(外边距):标签之间的距离 两个快递盒之间的距离 2.border(边框):标签的边框 快递盒的厚度 3.padding(内边距):内部文本与边框的距离 盒子内物…

由浇花工具开始物联网平台之开始前言篇【1】

在2020年时,突然有个想法,就是做个浇花工具,因为平时喜欢养花,有时忘记浇花,有时感觉手动浇花太麻烦,所以做个这个小玩意,是用.NET 开发的WinForm小程序,来控制单片机,带动水泵浇花,还可以测量干燥度自动浇花。现在突然又想起这事,那就由这个浇花工具开始我的物联网…

LTI系统正弦函数输入的稳态响应(Problem3.12)

这几天南方好几个省市高温大旱持续,长江流域水位下降,而北方多雨,这算是极端气候吗。一、稳态响应,涉及到的课后作业题是P3.12线性时不变系统(LTI)的稳态响应。 二、书中正文第75页三、解答过程 牢记: 1、如果你决定做某事,那就动手去做;不要受任何人、任何事的干…

[转]经典-python串口读取gps可视化 - MKT-porter - 博客园

(转载请删除括号里的内容) GPS模块设置 1使用ucenter设置gps输出 默认gps 9600 或者115200 选择串口链接 2 设置波特率 send之后重新连接gps模块,波特率修改成115200,send只是当前有效,断电恢复原来的. 3 修改GPS输出频率断电生效,保存在gps的内存里 4修改gps输出帧 默认输出…

易基因|作物育种:MdMTA介导的RNA甲基化(m6A修饰)在苹果抗逆品种选育中的作用研究

大家好,这里是专注表观组学十余年,领跑多组学科研服务的易基因。 m6A是RNA上最丰富的一种修饰,平均每条转录本有1~3个m6A修饰。植物也有相应的m6A writers、readers、erasers系统。近年来,m6A修饰在植物育种领域的研究进展极为迅速。本期我们对m6A RNA甲基化在抗逆苹果品种…

VMware扩展磁盘

以下操作不会破坏原有的数据,但还是有风险的,建议先备份数据。1.关闭虚拟机,扩展磁盘2.查看当前分区大小和分配情况 df -h lsblk fdisk -l 3.扩展sda3 fdisk /dev/sda 进入fdisk模式 m 查看帮助 p 查看分区情况,记录一下sda3的start值 d 删除sda3分区,还要输入分区数(分…

[网鼎杯 2018]Comment-1|SQL注入|二次注入

1、打开之后只有一个留言页面,很自然的就想到了二次注入得问题,顺带查看了下源代码信息,并没有什么提示,显示界面如下:2、那先扫描一下目录,同时随便留言一个测试以下,但是显示需要登录,账户、密码给出了部分提示,但是最后三位密码需要爆破,结果如下:3、扫描到了.gi…

MySQL学习(3)---MySQL常用命令

ps:此随笔基于mysql 5.7.*版本。 已知root账户密码进行登录 格式:mysql [-h地址] [-p端口] -u用户名 -p密码 省略不写地址或端口则自动使用默认。(地址:localhost;端口:3306) 两种方式进行登录。方式1:方式2:忘记root账户密码进行登录(修改root密码)以管理员身份打开一个…

爬虫进阶-python爬虫爬取百度图片

爬虫进阶-python爬取百度图片​今天来和大家分享下,如何通过爬虫,爬取百度图片,并下载保存到本地。 一、开发环境 开发环境:python 3.9和sublime_text ps:pycharm今天第一次用,随着将越来越多开发环境集成到vscode上,感觉太复杂了,配置又不太懂,总是有问题,虽然很喜欢…

前端Day06

HTML5新特性 语义化: 多媒体标签: 新增input类型: 新增表单属性:

一、对象与类

已经工作几年了,java,vue,python,C++各种项目都随叫随到,但除了C++其他都没有系统的学习过。这里仅记录下从头学习java基础的过程,和我认为值得记录的一些点,权当做一个备份和文档。 学习参考书:java核心技术 卷1 第九版。家里正好有这本书很多年了,也就看这个了,不是…

Python自学教程4-数据类型学什么

Hi,我是九柄,全网同号,今天我们说说Python的数据类型。 python数据类型有什么特点 每一门编程语言都要学数据类型的,每种类型的操作会稍微有一点区别。Python是一门非常灵活的编程语言,数据类型的指定和其他编程语言会稍微有一点区别。 首先,Python 不需要显性声明数据的…