一文带你从零到实战,学会gcc和Makefile,多文件编译神器的使用与编写

目录: 

目录: 

一、什么是Makefile

1.1 makefile的作用:

1.2 makefile的基本组成:

二、Linux编译过程:

2.1 linux编译过程:

2.1.1 预处理(Preprocessing)

2.1.2 编译(Compilation)

2.1.3 汇编(Assembly)

2.1.4 链接(Linking)

2.1.5 过程总结

2.2 脚本语言: Makefile

2.2.1 第一层显式规则:

2.2.2 第二层变量:

2.2.3 第三层隐含规则:

2.2.4 第四层通配符:

2.2.5 第五层函数:

1. $(foreach var,list,text)

2.  $(wildcard pattern)

3. $(wildcard pattern)

 4. $(patsubst pattern,replacement,$(files2))

 三、Makefile实操:

3.1 支持头文件依赖

3.2 添加CFLAGS

四、通用Makefile的使用:

4.1 本程序的Makefile分为3类:

4.2 各级子目录的Makefile:

4.3 顶层目录的Makefile:

4.4 顶层目录的Makefile.build:

4.5 怎么使用这套Makefile:

4.6 顶层目录

4.7 Makefile.build

4.8 子目录 

五、通用 Makefile 的解析:

5.1 通用 Makefile 的设计思想

5.2 顶层 Makefile 中把顶层目录的 built-in.o 链接成 APP:


一、什么是Makefile

Makefile 是一个用来管理自动化构建过程的文件,主要用于编译和构建项目。在软件开发中,尤其是在编译大型项目时,手动编译每个源文件并将它们链接成一个可执行文件或库可能会非常繁琐。Makefile 提供了一种自动化和高效的方式来管理这些任务。

1.1 makefile的作用:

1. 自动化构建Makefile 允许开发者定义一组规则来说明如何编译和链接程序。这些规则可以通过简单的命令自动执行,从而避免了手动执行每个步骤。

2. 依赖管理Makefile 可以跟踪文件之间的依赖关系。例如,如果一个源文件被修改,Makefile 会只重新编译受影响的文件,而不是重新编译整个项目。这大大提高了编译效率。

3. 可重用性Makefile 通常用于跨多个项目的通用构建规则,开发者可以在不同的项目中重用这些规则。

1.2 makefile的基本组成:

一个简单的 Makefile 通常包含以下部分:

1. 目标(Target):要生成的文件(如可执行文件)。

2. 依赖(Dependencies):生成目标所依赖的文件或其他目标。

3. 命令(Commands):生成目标所需要执行的命令。这些命令通常是 Unix/Linux 的 shell 命令。

二、Linux编译过程:

2.1 linux编译过程:

微观的C/C++编译执行过程。

在 C 语言中,源代码文件(.c 文件)到最终的可执行文件(.exe 文件)的生成过程,通常包括以下几个步骤:预处理汇编编译、和链接

2.1.1 预处理(Preprocessing)

预处理是 C 语言编译的第一个阶段,它的任务是处理以 # 开头的预处理指令,比如 #include#define 等。预处理的结果仍然是 C 语言代码。

  • 宏替换:将代码中的宏(如 #define)替换为定义的内容。例如,#define STR "Jiuxia is a teacher\n" 会把代码中的 STR 替换成 "Jiuxia is a teacher\n"
  • 头文件包含:将头文件中的内容插入到 #include 指令的地方。例如,#include <stdio.h> 会被替换为 stdio.h 中的所有代码。
  • 条件编译:处理诸如 #ifdef#ifndef 这些条件编译指令,确定哪些代码需要保留,哪些需要移除。

预处理后的代码通常是一个扩展的 .i 文件。

2.1.2 编译(Compilation)

编译阶段将经过预处理的 C 代码转换为汇编代码。在这个过程中,编译器会检查代码的语法是否正确,并将高层次的 C 代码翻译成低级的汇编语言代码。

  • 编译器将把每个 C 语句转换成对应的汇编语言指令。
  • 输出的文件通常是 .s 文件(汇编代码文件)。

2.1.3 汇编(Assembly)

汇编阶段将汇编语言代码转换为机器代码。这个阶段的输出是目标文件(Object File),目标文件包含机器代码和一些二进制数据,但它仍然不是一个完整的可执行文件。

  • 汇编器将 .s 文件(汇编代码)转换成二进制的机器代码。
  • 生成的文件通常是 .o(在 Linux 下)或 .obj(在 Windows 下)文件。

2.1.4 链接(Linking)

链接是整个编译过程的最后一个阶段,它的作用是将所有目标文件(以及可能依赖的库)链接成一个可执行文件。

  • 符号解析:确定每个函数和变量的内存地址,确保所有的引用都能正确找到定义。
  • 库链接:如果你的程序使用了外部库(比如标准 C 库 libc),链接器会将这些库链接进来。
  • 生成可执行文件:链接器将所有目标文件和库组合起来,生成最终的可执行文件(.exe 或 .out)。

链接完成后,输出的就是一个可以运行的可执行文件。

2.1.5 过程总结

预处理:处理 #define#include 等预处理指令,输出扩展后的源代码文件(.i 文件)。

编译:将 C 语言代码转换为汇编代码(.s 文件)。

汇编:将汇编代码转换为目标文件(.o 或 .obj 文件)。

链接:将目标文件与外部库链接在一起,生成最终的可执行文件(.exe 或 .out 文件)。

2.2 脚本语言: Makefile

Linux C/C++ 必须要使用的一个编译脚本。

2.2.1 第一层显式规则:

目标文件:依赖文件

[TAB] 指令

第一个目标文件是我的最终目标!!!(递归)

最简单的C语言编程:

hello: hello.ogcc hello.o -o hellohello.o: hello.Sgcc -c hello.S -o hello.ohello.S: hello.igcc -S hello.i -o hello.Shello.i: hello.cgcc -E hello.c -o hello.i

使用rm -rf hello.o hello.S hello.i hello对这些编译文件进行删除处理。这种没有目标文件的操作我们可以叫做伪目标。

伪目标:.PHONY:

hello: hello.ogcc hello.o -o hellohello.o: hello.Sgcc -c hello.S -o hello.ohello.S: hello.igcc -S hello.i -o hello.Shello.i: hello.cgcc -E hello.c -o hello.i.PHONY:
clear:rm -rf hello.o hello.S hello.i

circle.c circle.h cube.c cube.h main.c main.h

得到可执行文件test省去预编译汇编

test: circle.o cube.o main.ogcc circle.o cube.o main.o -o testcircle.o: circle.cgcc -c circle.c -o circle.ocube.o: cube.cgcc -c cube.c -o cube.omain.o: main.cgcc -c main.c -o main.o.PHONY: clearall clear
cleanall:rm -rf circle.o cube.o main.o testclean:rm -rf circle.o cube.o main.o

2.2.2 第二层变量:

=(替换)                +=(追加)                :=(恒等于,常量)

$(变量名)(使用变量进行替换)

TAR = test
OBJ = circle.o cube.o main.o
CC := gcc$(TAR): $(OBJ)$(CC)  $(OBJ) -o $(TAR)circle.o: circle.c$(CC) -c circle.c -o circle.ocube.o: cube.c$(CC) -c cube.c -o cube.omain.o: main.c$(CC) -c main.c -o main.o.PHONY: clearall clearcleanall:rm -rf circle.o cube.o main.o testclean:rm -rf circle.o cube.o main.o

即时变量、延时变量,export:

A := xxx           #    A的值即刻确定,在定义时即确定

B = xxx           #    B的值使用到时才确定

:=        #即时变量

=         #延时变量

?=       #延时变量,如果是第1次定义才起效,如果在前面该变量已定义则忽略这句

+=        #附加,它是即时变量还是延时变量取决于前面的定义

A := $(C)
B = $(C)
C = abc#D = 100ask
D ?= weidongshanall:@echo A = $(A)@echo B = $(B)@echo D = $(D)C += 123

2.2.3 第三层隐含规则:

%.c(任意的.c文件)        %.o(任意的.o文件)         

*.c (所有的.c文件)          *.o(所有的.o文件)

TAR = test
OBJ = circle.o cube.o main.o
CC := gcc$(TAR): $(OBJ)$(CC)  $(OBJ) -o $(TAR)%.o: %.c$(CC) -c %.c -o %.o    .PHONY: clearall clearcleanall:rm -rf $(OBJ) $(TAR)clean:rm -rf $(OBJ)

2.2.4 第四层通配符:

$^  (所有的依赖文件)

$@(所有的目标文件)

$<  (所有依赖文件的第一个文件)

$*   (不包含扩展名的目标文件名称)

$? (所有时间戳比目标文件晚的依赖文件,并以空格分开)

TAR = test
OBJ = circle.o cube.o main.o
CC := gcc
RMRF := rm -rf$(TAR): $(OBJ)$(CC) $^ -o $@%.o: %.c$(CC) -c $^ -o $@  .PHONY: clearall clearcleanall:$(RMRF) $(OBJ) $(TAR)clean:$(RMRF) $(OBJ)

2.2.5 第五层函数:

1. $(foreach var,list,text)

简单地说,就是 for each var in list, change it to text。

对 list 中的每一个元素,取出来赋给 var,然后把 var 改为 text 所描述 的形式。

A = a b c
B = $(foreach f, $(A), $(f).o)all:@echo B = $(B)

2.  $(wildcard pattern)

pattern 所列出的文件是否存在,把存在的文件都列出来。

$(filter pattern. ..,text)                    #在text中取出符合patten格式的值

$(filter-out pattern.. . ,text)            #在text中取出不符合patten格式的值

C = a b c d/D = $(filter %/, $(C))
E = $(filter-out %/, $(C))all:@echo D = $(D)@echo E = $(E)

3. $(wildcard pattern)

pattern定义了文件名的格式,wildcard取出其中存在的文件。

files = $(wildcard *.c)    #列出符合后缀是.c的文件都有哪些all:@echo files = $(files)

files2 = a.c b.c c.c d.c e.c
files3 = $(wildcard $(files2))all:@echo files = $(files)@echo files3 = $(files3)

 4. $(patsubst pattern,replacement,$(files2))

从列表中取出每—个值,如果符合pattern,则替换为replacement

files2 = a.c b.c c.c d.c e.c
files3 = $(wildcard $(files2))dep_files = $(patsubst %.c,%.d,$(files2))    #将files2中.c后缀文件替换为.d后缀文件all:@echo dep_files = $(dep_files)

 三、Makefile实操:

3.1 支持头文件依赖

a.c

 #include <stdio.h>void func_b();
void func_c();int main()
{func_b();func_c();return 0;
}

b.c

#include <stdio.h>void func_b()
{printf("This is B\n");
}

c.c 

#include <stdio.h>
#include "c.h"void func_c()
{printf("This is C = %d\n", C);
}

c.h

 #define C 4

gcc -M c.c                                       //打印出依赖
gcc -M -MF c.d c.c                         //把依赖写入文件c.d
gcc -c -o c.o c.c -MD -MF c.d        //编译c.o,把依赖写入文件c.d

Makefile 

objs = a.o b.o c.odep_files := $(patsubst %,.%.d, $(objs))
dep_files := $(wildcard $(dep_files))test: $(objs)gcc -o test $^ifneq ($(dep_files),)                              #将依赖文件添加进去
include $(dep_files)
endif%.o : %.cgcc -c -o $@ $< -MD -MF .$@.d        #自动生成依赖文件clean:rm *.o testdistclean:rm $(dep_files).PHONY: clean	

3.2 添加CFLAGS

c.c

#include <stdio.h>
#include <c.h>void func_c()
{printf("This is C = %d\n", C);
}

CFLAGS = -Werror -I.include         #-Werror将所有的警告变为错误
                                                       #-I.include执行当前目录下的include文件

%.o : %.c
        gcc $(CFLAGS) -c -o $@ $< -MD -MF .$@.d       #自动生成依赖文件

Makefile 

objs = a.o b.o c.odep_files := $(patsubst %,.%.d, $(objs))
dep_files := $(wildcard $(dep_files))CFLAGS = -Werror -I.include                           #-Werror将所有的警告变为错误#-I.include执行当前目录下的include文件test: $(objs)gcc -o test $^ifneq ($(dep_files),)                                 #将依赖文件添加进去
include $(dep_files)
endif%.o : %.cgcc $(CFLAGS) -c -o $@ $< -MD -MF .$@.d       #自动生成依赖文件clean:rm *.o testdistclean:rm $(dep_files).PHONY: clean

四、通用Makefile的使用:

参考 Linux 内核的 Makefile 编写了一个通用的 Makefile,它可以用来 编译应用程序:

1.支持多个目录、多层目录、多个文件;

2.支持给所有文件设置编译选项;

3.支持给某个目录设置编译选项;

4.支持给某个文件单独设置编译选项;

5.简单、好用。

4.1 本程序的Makefile分为3类:

1. 顶层目录的Makefile

2. 顶层目录的Makefile.build

3. 各级子目录的Makefile

4.2 各级子目录的Makefile:

 它最简单,形式如下:

EXTRA_CFLAGS  := 
CFLAGS_file.o := obj-y += file.o
obj-y += subdir/

"obj-y += file.o"  表示把当前目录下的file.c编进程序里。

"obj-y += subdir/" 表示要进入subdir这个子目录下去寻找文件来编进程序里,是哪些文件由subdir目录下的Makefile决定。

"EXTRA_CFLAGS",    它给当前目录下的所有文件(不含其下的子目录)设置额外的编译选项, 可以不设置

  "CFLAGS_xxx.o",    它给当前目录下的xxx.c设置它自己的编译选项, 可以不设置

注意: 

1. "subdir/"中的斜杠"/"不可省略

2. 顶层Makefile中的CFLAGS在编译任意一个.c文件时都会使用

3. CFLAGS  EXTRA_CFLAGS  CFLAGS_xxx.o 三者组成xxx.c的编译选项

4.3 顶层目录的Makefile:

它除了定义obj-y来指定根目录下要编进程序去的文件、子目录外,

主要是定义工具链前缀CROSS_COMPILE,

定义编译参数CFLAGS,

定义链接参数LDFLAGS,

这些参数就是文件中用export导出的各变量。

4.4 顶层目录的Makefile.build:

这是最复杂的部分,它的功能就是把某个目录及它的所有子目录中、需要编进程序去的文件都编译出来,打包为built-in.o

4.5 怎么使用这套Makefile:

1.把顶层Makefile, Makefile.build放入程序的顶层目录

      在各自子目录创建一个空白的Makefile

2.确定编译哪些源文件

修改顶层目录和各自子目录Makefile的obj-y : 

obj-y += xxx.o
obj-y += yyy/

上一句表示要编译当前目录下的xxx.c文件, 下一句表示要编译当前目录下的yyy子目录    

3. 确定编译选项、链接选项

CFLAGS := -Wall -O2 -g
CFLAGS += -I $(shell pwd)/includeLDFLAGS := export CFLAGS LDFLAGS

修改顶层目录Makefile的CFLAGS,这是编译所有.c文件时都要用的编译选项;

修改顶层目录Makefile的LDFLAGS,这是链接最后的应用程序时的链接选项;


4. 修改各自子目录下的Makefile:

EXTRA_CFLAGS := -D DEBUG
CFLAGS_sub3.o := -D DEBUG_SUB3

"EXTRA_CFLAGS",    它给当前目录下的所有文件(不含其下的子目录)设置额外的编译选项, 可以不设置

"CFLAGS_xxx.o",    它给当前目录下的xxx.c设置它自己的编译选项, 可以不设置
   
5. 使用哪个编译器?

CROSS_COMPILE =

修改顶层目录Makefile的CROSS_COMPILE, 用来指定工具链的前缀(比如arm-linux-)
   
6. 确定应用程序的名字:

TARGET := test

修改顶层目录Makefile的TARGET, 这是用来指定编译出来的程序的名字

7. 执行"make"来编译,执行"make clean"来清除,执行"make distclean"来彻底清除。

clean:rm -f $(shell find -name "*.o")rm -f $(TARGET)

4.6 顶层目录

 Makefile

 
CROSS_COMPILE = 
AS		= $(CROSS_COMPILE)as
LD		= $(CROSS_COMPILE)ld
CC		= $(CROSS_COMPILE)gcc
CPP		= $(CC) -E
AR		= $(CROSS_COMPILE)ar
NM		= $(CROSS_COMPILE)nmSTRIP		= $(CROSS_COMPILE)strip
OBJCOPY		= $(CROSS_COMPILE)objcopy
OBJDUMP		= $(CROSS_COMPILE)objdumpexport AS LD CC CPP AR NM
export STRIP OBJCOPY OBJDUMPCFLAGS := -Wall -O2 -g
CFLAGS += -I $(shell pwd)/includeLDFLAGS := export CFLAGS LDFLAGSTOPDIR := $(shell pwd)
export TOPDIRTARGET := testobj-y += main.o
obj-y += sub.o
obj-y += a/all : start_recursive_build $(TARGET)@echo $(TARGET) has been built!start_recursive_build:make -C ./ -f $(TOPDIR)/Makefile.build$(TARGET) : start_recursive_build$(CC) -o $(TARGET) built-in.o $(LDFLAGS)clean:rm -f $(shell find -name "*.o")rm -f $(TARGET)distclean:rm -f $(shell find -name "*.o")rm -f $(shell find -name "*.d")rm -f $(TARGET)

4.7 Makefile.build

PHONY := __build
__build:obj-y :=
subdir-y :=
EXTRA_CFLAGS :=include Makefile# obj-y := a.o b.o c/ d/
# $(filter %/, $(obj-y))   : c/ d/
# __subdir-y  : c d
# subdir-y    : c d
__subdir-y	:= $(patsubst %/,%,$(filter %/, $(obj-y)))
subdir-y	+= $(__subdir-y)# c/built-in.o d/built-in.o
subdir_objs := $(foreach f,$(subdir-y),$(f)/built-in.o)# a.o b.o
cur_objs := $(filter-out %/, $(obj-y))
dep_files := $(foreach f,$(cur_objs),.$(f).d)
dep_files := $(wildcard $(dep_files))ifneq ($(dep_files),)include $(dep_files)
endifPHONY += $(subdir-y)__build : $(subdir-y) built-in.o$(subdir-y):make -C $@ -f $(TOPDIR)/Makefile.buildbuilt-in.o : $(subdir-y) $(cur_objs)$(LD) -r -o $@ $(cur_objs) $(subdir_objs)dep_file = .$@.d%.o : %.c$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -Wp,-MD,$(dep_file) -c -o $@ $<.PHONY : $(PHONY)

4.8 子目录 

 
EXTRA_CFLAGS := -D DEBUG
CFLAGS_sub3.o := -D DEBUG_SUB3obj-y += sub2.o 
obj-y += sub3.o 

五、通用 Makefile 的解析:

5.1 通用 Makefile 的设计思想

在 Makefile 文件中确定要编译的文件、目录,比如:

obj-y += main.o
obj-y += a/

Makefile”文件总是被“Makefile.build”包含的。

在 Makefile.build 中设置编译规则,有 3 条编译规则:

怎么编译子目录? 进入子目录编译:

$(subdir-y):
make -C $@ -f $(TOPDIR)/Makefile.build
  1. $(subdir-y) 被展开为所有子目录的列表。
  2. 对于列表中的每个子目录,make 命令都会被调用。
  3. -C $@ 将Make的工作目录切换到当前子目录。
  4. -f $(TOPDIR)/Makefile.build 指定使用位于顶层目录下的 Makefile.build 文件来构建当前子目录。

顶层Makefile会递归地构建所有子目录,每个子目录都会使用自己的Makefile来构建其目标文件。 

怎么编译当前目录中的文件?

        规则部分:%.o : %.c

  • %.o:这是一个模式规则的模式部分,表示所有以.o结尾的目标文件。%是一个占位符,代表目标文件名中除扩展名以外的部分。
  • : %.c:这是模式规则的结果部分,表示所有以.c结尾的源文件都会生成对应的目标文件。同样,%.c中的%是一个占位符,代表源文件名中除扩展名以外的部分。
  • 这条规则的意思是,对于任何以.c结尾的源文件,都会生成一个与之对应且以.o结尾的目标文件。

    命令部分:

  • $(CC):这是一个变量,代表编译器的名称。通常,这个变量被设置为gccclang等。
  • $(CFLAGS):这是一个变量,包含了编译器的基本编译选项。
  • $(EXTRA_CFLAGS):这是一个变量,包含了额外的编译器选项,可能由项目配置或特定文件指定。
  • $(CFLAGS_$@):这是一个变量,其中$@是当前目标文件的名称。它允许为不同的目标文件指定不同的编译器选项。
  • -Wp,-MD,$(dep_file):这是一个用于生成依赖文件的选项。-MD告诉编译器生成依赖文件,而$(dep_file)是依赖文件的名称。
  • -c:这是一个编译选项,指示编译器只进行编译,不进行链接。
  • -o $@:这个选项告诉编译器将输出文件(目标文件)命名为当前目标文件的名称,即$@
  • $<:这是一个自动变量,代表当前规则中第一个依赖文件的名称,即源文件。

使用指定的编译器($(CC))和一系列编译选项($(CFLAGS)$(EXTRA_CFLAGS)$(CFLAGS_$@)),编译名为$<的源文件(.c),生成一个名为$@的目标文件(.o),并且同时生成一个依赖文件($(dep_file)),其中包含了源文件和目标文件之间的依赖关系。 

当前目录下的.o 和子目录下的 built-in.o 要打包起来:

built-in.o : $(cur_objs) $(subdir_objs)
$(LD) -r -o $@ $^

        规则部分:built-in.o : $(cur_objs) $(subdir_objs)

  • built-in.o:这是目标文件,表示最终生成的文件名。
  • : $(cur_objs) $(subdir_objs):冒号后面的部分是依赖列表,表示生成built-in.o所需的依赖项。这里,$(cur_objs)$(subdir_objs)是变量,它们分别包含当前目录和子目录中所有对象文件的列表。

这条规则的意思是,built-in.o这个目标文件依赖于$(cur_objs)$(subdir_objs)中列出的所有对象文件。

        命令部分:$(LD) -r -o $@ $^

  • $(LD):这是一个变量,代表链接器的名称。通常,这个变量被设置为gccld等。
  • -r:这是一个链接器选项,指示链接器生成可重定位的输出文件。这意味着生成的文件可以在不同的程序中使用,而不是一个独立的可执行文件。
  • -o $@:这个选项告诉链接器将输出文件命名为当前目标文件的名称,即$@
  • $^:这是一个自动变量,代表当前规则中所有依赖项的列表,即$(cur_objs)$(subdir_objs)中列出的所有对象文件。

使用指定的链接器($(LD))和选项(-r),将所有依赖的对象文件($^,即$(cur_objs)$(subdir_objs)中的所有.o文件)链接成一个可重定位的输出文件($@,即built-in.o)。 

5.2 顶层 Makefile 中把顶层目录的 built-in.o 链接成 APP:

$(TARGET) : built-in.o$(CC) $(LDFLAGS) -o $(TARGET) built-in.o

5.3 情景演绎

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

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

相关文章

Android Studio 自定义字体大小

常用编程软件自定义字体大全首页 文章目录 前言具体操作1. 打开设置对话框2. 选择外观字体 前言 Android Studio 自定义字体大小&#xff0c;统一设置为 JetBrains Mono &#xff0c;大小为 14 具体操作 【File】>【Settings...】>【Appearance & Behavior】>【…

二、设置地图配置表

一、导入一个背景图 由于背景图比较大&#xff0c;需要缩小至0.73 二、写配置文件&#xff08;SO&#xff09; 使用List需要一个命名空间 写一个类&#xff0c;声明房间的出现数量和种类&#xff1b;将它实例化出来 三、枚举变量的多选 在枚举变量中标记命名空间&#xff…

docker 多线成服务,比如gunicorn服务启动报错解决办法

docker执行的时候报错&#xff0c;排查是线程创建权限不足导致的&#xff0c;报错如下。 解决办法 docker run -e OPENBLAS_NUM_THREADS1 your_image

Unity XR Interaction Toolkit 踩坑记录

1&#xff1a;按下 grap/select 键 物品直接飞到手上 2 按下 grap/select 键 物品一点点的想自己移动

OpenCV杂项图像变换(2)线性混合函数blendLinear()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 执行两个图像的线性混合&#xff1a; dst ( i , j ) weights1 ( i , j ) ∗ src1 ( i , j ) weights2 ( i , j ) ∗ src2 ( i , j ) \texttt{…

关于多线程你了解多少?

或许是执念太重&#xff0c;又或许是性格缺陷&#xff0c;我对java中一些知识的坚持&#xff0c;已经到了让人无法接受的地步。有些人甚至因此在背后骂我神经病、傻瓜。但我依旧我行我素&#xff0c;即使中间懈怠了很长时间&#xff0c;重新开始时我依旧会以这些知识为起点。不…

Ubuntu上搭建Nginx环境

1. 软件包下载 nginx下载地址 下载linux版本的nginx&#xff0c;如图圈示 2. 将下载好的软件包上传至Linux服务器 假设上传到 /opt/nginx 目录,进入目录 cd /opt/nginx解压&#xff0c;根据版本自行修改版本号 tar zxvf nginx-1.16.0.tar.gz3.安装 安装编译所需的依赖&a…

前端算法 === 力扣 111 二叉树的最小深度

目录 问题描述 DFS&#xff08;深度优先搜索&#xff09;方案 BFS&#xff08;广度优先搜索&#xff09;方案 总结 力扣&#xff08;LeetCode&#xff09;上的题目111是关于二叉树的最小深度问题。这个问题可以通过深度优先搜索&#xff08;DFS&#xff09;和广度优先搜索&…

QJson的写入和解析基本操作

一、QJson简介 QJson 是一个用于处理 JSON&#xff08;JavaScript Object Notation&#xff09;数据的 C 库 JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式 JSON 的语法简洁明了&#xff0c;使用人类可读的文本格式来表示数据 它由键值…

分块矩阵的转置

证明 则 证明&#xff1a;令&#xff0c;有&#xff0c;对它做一个分块使得和后面的分块矩阵中的是同型矩阵&#xff0c;要证明&#xff08;任意的&#xff09;&#xff0c;需要证明1&#xff09;是一个的矩阵 2&#xff09;任意的 首先证明1&#xff09;我们先定义两个函…

Getting RateLimitError while implementing openai GPT with Python

题意&#xff1a;“在使用 Python 实现 OpenAI GPT 时遇到 RateLimitError 错误。” 问题背景&#xff1a; I have started to implement openai gpt model in python. I have to send a single request in which I am getting RateLimitError. “我开始在 Python 中实现 Ope…

SSH弱口令爆破服务器

一、实验背景 1、概述 使用kali的hydra进行ssh弱口令爆破&#xff0c;获得服务器的用户名和口令&#xff0c;通过 ssh远程登录服务器。 2、实验环境 kali攻击机&#xff1a;192.168.1.107 centos服务器&#xff1a;192.168.1.105 二、前置知识 1、centos设置用户并设置弱…

HR招聘,如何解决面试流程繁琐的问题

要解决面试流程繁琐的问题&#xff0c;就必须要精简和优化招聘流程。比如精简面试环节&#xff0c;制定标准化流程&#xff0c;完善信息管理&#xff0c;对面试环节进行细致梳理之后&#xff0c;尽快识别并去除那些不必要的步骤&#xff0c;这样就能够减少求职者的等待时间&…

IAR软件配置笔记

Project->Optiions->配置Device Debug中配置 C/C Compiler中配置 优化等级 C语法标准选择 回到主界面&#xff0c;Tools->Options 字体调整 Editor更改缩进数 Project->Make编译 调试模式和编辑模式的View菜单栏不一样http://t.csdnimg.cn/JsWjy Disa…

Python | Linux | 解析Himawari-8/9 | Standard Data

写作前面 之前一个相关的工作需要解析Himawari-8/9 Standard Data文件&#xff0c;因为他是二进制的&#xff0c;之前没有处理过&#xff0c;导致完全摸不着头脑。在网上找了中英文搜索找了好久&#xff0c;虽然也找到了公开的解析代码&#xff0c;但是放在自己的数据这感觉总是…

Golang | Leetcode Golang题解之第375题猜数字大小II

题目&#xff1a; 题解&#xff1a; func getMoneyAmount(n int) int {f : make([][]int, n1)for i : range f {f[i] make([]int, n1)}for i : n - 1; i > 1; i-- {for j : i 1; j < n; j {f[i][j] j f[i][j-1]for k : i; k < j; k {cost : k max(f[i][k-1], f[…

字节跳动-生活服务-java后端-一面

基础题 计算机网络 1.tcp三次握手和四次挥手&#xff1f;tcp的第三次握手可以传输应用层数据嘛&#xff1f; 4.1 TCP 三次握手与四次挥手面试题 | 小林coding (xiaolincoding.com) 2.描述一下打开百度首页后发生的网络过程&#xff1f; 计算机网络面试题 | 小林coding (xi…

无损放大图片,盘点5款最新无损放大图片软件

我们常常遇到需要放大图片却又不希望损失画质的尴尬境地。无论是为了打印大幅海报、在线展示高清细节&#xff0c;还是想要修复珍贵的老照片&#xff0c;无损放大图片成为了许多人的迫切需求。下面给大家分享5款最新无损放大图片软件&#xff0c;高效且实用&#xff0c;一起来学…

C++基础练习

1》提示并输入一个字符串&#xff0c;统计该字符串中字母个数、数字个数、空格个数、其他字符的个数 1 #include<iostream>2 using namespace std;3 4 int main()5 {6 string str1; //定义字符串数据7 cout << "请输入一个字符串>>>" ;8…

好出创新点的方向:SAM做医学图像分割!轻松登Nature!

继MedSAM登上Nature后&#xff0c;牛津大学也最新提出了MedSAM-2&#xff0c;不但分割一切医学图像&#xff0c;还能分割视频&#xff01;准确度提升一个level&#xff0c;直接刷新医学图像分割SOTA榜&#xff01; 这种惊人的医学图像分割效果都得益于SAM模型&#xff08;尤其是…