编译工具 Cmake 教程——翻译自外网

Make Tutorial
hello:
	echo "Hello, World"

image-20240107223207647

Makefile Syntax
targets: prerequisites
	command
	command
	command

目标是文件名,以空格分隔。通常,每条规则只有一个。
这些命令是通常用于创建目标的一系列步骤。这些需要以制表符开头,而不是空格。
先决条件也是文件名,以空格分隔。在运行目标的命令之前,这些文件需要存在。这些也称为依赖项

  • Make选择目标blah,因为第一个目标是默认目标
  • blah 需要 blah.o,因此搜索 blah.o 目标
  • blah.o 需要 blah.c,因此搜索 blah.c 目标
  • blah.c 没有依赖项,因此运行 echo 命令
  • 然后运行 cc -c 命令,因为所有 blah.o 依赖项都已完成
  • 运行top cc命令,因为所有blah依赖都完成了
  • 就是这样:blah 是一个已编译的 C 程序
blah: blah.o
	cc blah.o -o blah # Runs third

blah.o: blah.c
	cc -c blah.c -o blah.o # Runs second

# Typically blah.c would already exist, but I want to limit any additional required files
blah.c:
	echo "int main() { return 0; }" > blah.c # Runs first
// blah.c
int main() { return 0; }

如果删除 blah.c,所有三个目标都将重新运行。如果您对其进行编辑(从而将时间戳更改为比 blah.o 新),则前两个目标将运行。如果您运行 touch blah.o (从而将时间戳更改为比 blah 更新),则只有第一个目标会运行。如果您不进行任何更改,则所有目标都不会运行。试试看!

下一个示例没有做任何新的事情,但仍然是一个很好的附加示例。它将始终运行两个目标,因为 some_file 依赖于 other_file,而 other_file 从未创建。

some_file: other_file
	echo "This will always run, and runs second"
	touch some_file

other_file:
	echo "This will always run, and runs first"
Make clean

它不是首要目标(默认目标),也不是先决条件。这意味着除非您显式调用 make clean,否则它永远不会运行
它并不是一个文件名。如果您碰巧有一个名为 clean 的文件,则该目标将不会运行,这不是我们想要的。

some_file: 
	touch some_file

clean:
	rm -f some_file
Variables

变量只能是字符串。您通常需要使用 :=,但 = 也可以。

files := file1 file2
some_file: $(files)
	echo "Look at this variable: " $(files)
	touch some_file

file1:
	touch file1
file2:
	touch file2

clean:
	rm -f file1 file2 some_file

单引号或双引号对 Make 来说没有任何意义。它们只是分配给变量的字符。不过,引号对于 shell/bash 很有用,并且您在 printf 等命令中需要它们。在此示例中,两个命令的行为相同:

a := one two # a is set to the string "one two"
b := 'one two' # Not recommended. b is set to the string "'one two'"
all:
	printf '$a'
	printf $b
x := dude

all:
	echo $(x)
	echo ${x}

	# Bad practice, but works
	echo $x 
Targets
The all target

Making multiple targets and you want all of them to run? Make an all target. Since this is the first rule listed, it will run by default if make is called without specifying a target.

all: one two three

one:
	touch one
two:
	touch two
three:
	touch three

clean:
	rm -f one two three
Multiple targets

当规则有多个目标时,将为每个目标运行命令。 $@ 是包含目标名称的自动变量。

all: f1.o f2.o

f1.o f2.o:
	echo $@
# Equivalent to:
# f1.o:
#	 echo f1.o
# f2.o:
#	 echo f2.o
Automatic Variables and Wildcards
* Wildcard
  • 和 % 在 Make 中都称为通配符,但它们的含义完全不同。 * 在您的文件系统中搜索匹配的文件名。我建议您始终将其包装在通配符函数中,因为否则您可能会陷入下面描述的常见陷阱。
# Print out file information about every .c file
print: $(wildcard *.c)
	ls -la  $?

‘*’ 可以用在目标、先决条件或通配符函数中。
危险: * 不能直接用在变量定义中
危险:当 * 不匹配任何文件时,保持原样(除非在通配符函数中运行)

thing_wrong := *.o # Don't do this! '*' will not get expanded
thing_right := $(wildcard *.o)

all: one two three four

# Fails, because $(thing_wrong) is the string "*.o"
one: $(thing_wrong)

# Stays as *.o if there are no files that match this pattern :(
two: *.o 

# Works as you would expect! In this case, it does nothing.
three: $(thing_right)

# Same as rule three
four: $(wildcard *.o)
% Wildcard
  • % 确实很有用,但由于它可以在多种情况下使用而有点令人困惑。
  • 当用于“匹配”模式时,它匹配字符串中的一个或多个字符。这场比赛被称为“茎”。
  • 当在“替换”模式下使用时,它会采用匹配的词干并替换字符串中的词干。
  • % 最常用于规则定义和一些特定函数中。
Automatic Variables

自动变量有很多,但通常只出现几个:

hey: one two
	# Outputs "hey", since this is the target name
	echo $@

	# Outputs all prerequisites newer than the target
	echo $?

	# Outputs all prerequisites
	echo $^

	touch hey

one:
	touch one

two:
	touch two

clean:
	rm -f hey one two
Fancy Rules
Implicit Rules

Make喜欢c编译。每次它表达爱意时,事情都会变得混乱。也许 Make 最令人困惑的部分是所制定的神奇/自动规则。调用这些“隐式”规则。我个人并不同意这种设计决策,也不建议使用它们,但它们经常被使用,因此了解它们很有用。以下是隐含规则的列表:

  • 编译 C 程序:n.o 是通过 $(CC) -c $(CPPFLAGS) $(CFLAGS) $^ -o $@ 形式的命令从 n.c 自动生成的

  • 编译 C++ 程序:n.o 是通过 $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) $^ -o $@ 形式的命令从 n.cc 或 n.cpp 自动生成的

  • 链接单个目标文件:通过运行命令 $(CC) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ 从 n.o 自动生成 n

    隐式规则使用的重要变量是:

  • CC:编译C程序的程序;默认抄送

  • CXX:编译C++程序的程序;默认g++

  • CFLAGS:提供给 C 编译器的额外标志

  • CXXFLAGS:提供给 C++ 编译器的额外标志

  • CPPFLAGS:提供给 C 预处理器的额外标志

  • LDFLAGS:当编译器应该调用链接器时提供给编译器的额外标志

CC = gcc # Flag for implicit rules
CFLAGS = -g # Flag for implicit rules. Turn on debug info

# Implicit rule #1: blah is built via the C linker implicit rule
# Implicit rule #2: blah.o is built via the C compilation implicit rule, because blah.c exists
blah: blah.o

blah.c:
	echo "int main() { return 0; }" > blah.c

clean:
	rm -f blah*
Static Pattern Rules

静态模式规则是另一种在 Makefile 中减少编写的方法,但我想说它更有用,而且不那么“神奇”。这是他们的语法:

targets...: target-pattern: prereq-patterns ...
   commands

本质是给定的目标与目标模式匹配(通过 % 通配符)。匹配的任何东西都称为茎。然后将主干替换为先决条件模式,以生成目标的先决条件。
一个典型的用例是将 .c 文件编译为 .o 文件。这是手动方式:

objects = foo.o bar.o all.o
all: $(objects)

# These files compile via implicit rules
foo.o: foo.c
bar.o: bar.c
all.o: all.c

all.c:
	echo "int main() { return 0; }" > all.c

%.c:
	touch $@

clean:
	rm -f *.c *.o all

这是更有效的方法,使用静态模式规则:

objects = foo.o bar.o all.o
all: $(objects)

# These files compile via implicit rules
# Syntax - targets ...: target-pattern: prereq-patterns ...
# In the case of the first target, foo.o, the target-pattern matches foo.o and sets the "stem" to be "foo".
# It then replaces the '%' in prereq-patterns with that stem
$(objects): %.o: %.c

all.c:
	echo "int main() { return 0; }" > all.c

%.c:
	touch $@

clean:
	rm -f *.c *.o all
Static Pattern Rules and Filter

当我稍后介绍函数时,我将预示您可以使用它们做什么。过滤功能可以用在静态模式规则中来匹配正确的文件。在此示例中,我编写了 .raw 和 .result 扩展名。

obj_files = foo.result bar.o lose.o
src_files = foo.raw bar.c lose.c

all: $(obj_files)
# Note: PHONY is important here. Without it, implicit rules will try to build the executable "all", since the prereqs are ".o" files.
.PHONY: all 

# Ex 1: .o files depend on .c files. Though we don't actually make the .o file.
$(filter %.o,$(obj_files)): %.o: %.c
	echo "target: $@ prereq: $<"

# Ex 2: .result files depend on .raw files. Though we don't actually make the .result file.
$(filter %.result,$(obj_files)): %.result: %.raw
	echo "target: $@ prereq: $<" 

%.c %.raw:
	touch $@

clean:
	rm -f $(src_files)
Pattern Rules

模式规则经常被使用,但很混乱。您可以通过两种方式来看待它们:

  • 定义您自己的隐式规则的方法
  • 静态模式规则的更简单形式

我们先从一个例子开始:

# Define a pattern rule that compiles every .c file into a .o file
%.o : %.c
		$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

模式规则的目标中包含“%”。这个“%”匹配任何非空字符串,其他字符匹配它们自己。模式规则先决条件中的“%”代表与目标中的“%”匹配的相同词干。

# Define a pattern rule that has no pattern in the prerequisites.
# This just creates empty .c files when needed.
%.c:
   touch $@
Double-Colon Rules

双冒号规则很少使用,但允许为同一目标定义多个规则。如果这些是单冒号,则会打印警告,并且只会运行第二组命令。

all: blah

blah::
	echo "hello"

blah::
	echo "hello again"
Commands and execution
Command Echoing/Silencing

在命令前添加@以阻止其打印
您还可以使用 -s 运行 make 以在每行之前添加 @

all: 
	@echo "This make line will not be printed"
	echo "But this will"
Command Execution

每个命令都在新的 shell 中运行(或者至少效果是这样)

all: 
	cd ..
	# The cd above does not affect this line, because each command is effectively run in a new shell
	echo `pwd`

	# This cd command affects the next because they are on the same line
	cd ..;echo `pwd`

	# Same as above
	cd ..; \
	echo `pwd`
Default Shell

The default shell is /bin/sh. You can change this by changing the variable SHELL:

SHELL=/bin/bash

cool:
	echo "Hello from bash"
Double dollar sign

如果你想要一个字符串有$符号,你可以使用$$。这是在 bash 或 sh 中使用 shell 变量的方法。
请注意下一个示例中 Makefile 变量和 Shell 变量之间的差异。

make_var = I am a make variable
all:
	# Same as running "sh_var='I am a shell variable'; echo $sh_var" in the shell
	sh_var='I am a shell variable'; echo $$sh_var

	# Same as running "echo I am a make variable" in the shell
	echo $(make_var)
Error handling with -k, -i, and -

运行 make 时添加 -k,即使出现错误也可以继续运行。如果您想立即查看 Make 的所有错误,这很有帮助。
在命令前添加 - 以抑制错误
添加 -i 以使每个命令都发生这种情况。

one:
	# This error will be printed but ignored, and make will continue to run
	-false
	touch one
Interrupting or killing make

Note only: If you ctrl+c make, it will delete the newer targets it just made.

Recursive use of make

要递归调用 makefile,请使用特殊的 $(MAKE) 而不是 make,因为它会为您传递 make 标志,并且本身不会受到它们的影响。

new_contents = "hello:\n\ttouch inside_file"
all:
	mkdir -p subdir
	printf $(new_contents) | sed -e 's/^ //' > subdir/makefile
	cd subdir && $(MAKE)

clean:
	rm -rf subdir
Export, environments, and recursive make

当 Make 启动时,它会自动从执行时设置的所有环境变量中创建 Make 变量。

# Run this with "export shell_env_var='I am an environment variable'; make"
all:
	# Print out the Shell variable
	echo $$shell_env_var

	# Print out the Make variable
	echo $(shell_env_var)

export指令采用一个变量并将其设置为所有配方中所有 shell 命令的环境:

shell_env_var=Shell env var, created inside of Make
export shell_env_var
all:
	echo $(shell_env_var)
	echo $$shell_env_var

因此,当您在 make 内部运行 make 命令时,可以使用导出指令使其可供子 make 命令访问。在此示例中,cooly 被导出,以便 subdir 中的 makefile 可以使用它。

new_contents = "hello:\n\techo \$$(cooly)"

all:
	mkdir -p subdir
	printf $(new_contents) | sed -e 's/^ //' > subdir/makefile
	@echo "---MAKEFILE CONTENTS---"
	@cd subdir && cat makefile
	@echo "---END MAKEFILE CONTENTS---"
	cd subdir && $(MAKE)

# Note that variables and exports. They are set/affected globally.
cooly = "The subdirectory can see me!"
export cooly
# This would nullify the line above: unexport cooly

clean:
	rm -rf subdir

您需要导出变量才能让它们在 shell 中运行。

one=this will only work locally
export two=we can run subcommands with this

all: 
	@echo $(one)
	@echo $$one
	@echo $(two)
	@echo $$two

.EXPORT_ALL_VARIABLES 为您导出所有变量。

.EXPORT_ALL_VARIABLES:
new_contents = "hello:\n\techo \$$(cooly)"

cooly = "The subdirectory can see me!"
# This would nullify the line above: unexport cooly

all:
	mkdir -p subdir
	printf $(new_contents) | sed -e 's/^ //' > subdir/makefile
	@echo "---MAKEFILE CONTENTS---"
	@cd subdir && cat makefile
	@echo "---END MAKEFILE CONTENTS---"
	cd subdir && $(MAKE)

clean:
	rm -rf subdir
Arguments to make

There’s a nice list of options that can be run from make. Check out --dry-run, --touch, --old-file.

You can have multiple targets to make, i.e. make clean run test runs the clean goal, then run, and then test.

Variables Pt. 2
Flavors and modification

变量有两种类型:
递归(use =) - 仅在使用命令时查找变量,而不是在定义命令时查找变量。
简单扩展(使用 :=) - 就像普通的命令式编程一样 - 只有那些到目前为止定义的才会被扩展

# Recursive variable. This will print "later" below
one = one ${later_variable}
# Simply expanded variable. This will not print "later" below
two := two ${later_variable}

later_variable = later

all: 
	echo $(one)
	echo $(two)

简单地扩展(使用 :=)允许您附加到变量。递归定义将给出无限循环错误。

one = hello
# one gets defined as a simply expanded variable (:=) and thus can handle appending
one := ${one} there

all: 
	echo $(one)

?= 仅设置尚未设置的变量

one = hello
one ?= will not be set
two ?= will be set

all: 
	echo $(one)
	echo $(two)

行尾的空格不会被删除,但行首的空格会被删除。要使用单个空格创建变量,请使用 $(nullstring)

with_spaces = hello   # with_spaces has many spaces after "hello"
after = $(with_spaces)there

nullstring =
space = $(nullstring) # Make a variable with a single space.

all: 
	echo "$(after)"
	echo start"$(space)"end

未定义的变量实际上是一个空字符串!

all: 
	# Undefined variables are just empty strings!
	echo $(nowhere)

Use += to append

foo := start
foo += more

all: 
	echo $(foo)
Command line arguments and override

您可以使用 override 覆盖来自命令行的变量。这里我们用 make option_one=hi 运行 make

# Overrides command line arguments
override option_one = did_override
# Does not override command line arguments
option_two = not_override
all: 
	echo $(option_one)
	echo $(option_two)
List of commands and define

Define 指令不是一个函数,尽管它看起来可能是这样。我发现它很少使用,所以我不会详细介绍,但它主要用于定义罐头食谱,并且与 eval 函数配合得很好。

Define/endef 只是创建一个设置为命令列表的变量。请注意,这与命令之间使用分号有点不同,因为每个命令都在单独的 shell 中运行,正如预期的那样。

one = export blah="I was set!"; echo $$blah

define two
export blah="I was set!"
echo $$blah
endef

all: 
	@echo "This prints 'I was set'"
	@$(one)
	@echo "This does not print 'I was set' because each command runs in a separate shell"
	@$(two)
Target-specific variables

可以为特定目标设置变量

all: one = cool

all: 
	echo one is defined: $(one)

other:
	echo one is nothing: $(one)
Pattern-specific variables

您可以为特定目标模式设置变量

%.c: one = cool

blah.c: 
	echo one is defined: $(one)

other:
	echo one is nothing: $(one)
Conditional part of Makefiles
Conditional if/else
foo = ok

all:
ifeq ($(foo), ok)
	echo "foo equals ok"
else
	echo "nope"
endif
Check if a variable is empty
nullstring =
foo = $(nullstring) # end of line; there is a space here

all:
ifeq ($(strip $(foo)),)
	echo "foo is empty after being stripped"
endif
ifeq ($(nullstring),)
	echo "nullstring doesn't even have spaces"
endif
Check if a variable is defined

ifdef 不扩展变量引用;它只是查看某些内容是否已定义

bar =
foo = $(bar)

all:
ifdef foo
	echo "foo is defined"
endif
ifndef bar
	echo "but bar is not"
endif
$(MAKEFLAGS)

此示例向您展示如何使用 findstring 和 MAKEFLAGS 测试 make 标志。使用 make -i 运行此示例以查看它打印出 echo 语句。

all:
# Search for the "-i" flag. MAKEFLAGS is just a list of single characters, one per flag. So look for "i" in this case.
ifneq (,$(findstring i, $(MAKEFLAGS)))
	echo "i was passed to MAKEFLAGS"
endif
Functions
First Functions

函数主要用于文本处理。使用 $(fn,arguments) 或 ${fn,arguments} 调用函数。 Make 有相当多的内置函数。

bar := ${subst not,totally, "I am not superman"}
all: 
	@echo $(bar)

如果要替换空格或逗号,请使用变量

comma := ,
empty:=
space := $(empty) $(empty)
foo := a b c
bar := $(subst $(space),$(comma),$(foo))

all: 
	@echo $(bar)

第一个之后的参数中请勿包含空格。这将被视为字符串的一部分。

comma := ,
empty:=
space := $(empty) $(empty)
foo := a b c
bar := $(subst $(space), $(comma) , $(foo))

all: 
	# Output is ", a , b , c". Notice the spaces introduced
	@echo $(bar)
String Substitution

$(patsubst pattern,replacement,text) 执行以下操作:
“在文本中查找与模式匹配的空格分隔的单词,并将其替换为替换。这里模式可能包含一个‘%’,它充当通配符,匹配单词中任意数量的任何字符。如果替换也包含‘%’, ‘%’ 被与模式中 ‘%’ 匹配的文本替换。只有模式和替换中的第一个 ‘%’ 会以这种方式处理;任何后续 ‘%’ 都不会改变。” (GNU 文档)
替换引用 $(text:pattern=replacement) 是对此的简写。
还有另一种仅替换后缀的简写:$(text:suffix=replacement)。这里没有使用%通配符。
注意:不要为此简写添加额外的空格。它将被视为搜索或替换术语。

foo := a.o b.o l.a c.o
one := $(patsubst %.o,%.c,$(foo))
# This is a shorthand for the above
two := $(foo:%.o=%.c)
# This is the suffix-only shorthand, and is also equivalent to the above.
three := $(foo:.o=.c)

all:
	echo $(one)
	echo $(two)
	echo $(three)
The foreach function

foreach 函数如下所示:$(foreach var,list,text)。它将一个单词列表(用空格分隔)转换为另一个单词列表。 var 设置为列表中的每个单词,并且每个单词的文本都会扩展。
这会在每个单词后面添加一个感叹号:

foo := who are you
# For each "word" in foo, output that same word with an exclamation after
bar := $(foreach wrd,$(foo),$(wrd)!)

all:
	# Output is "who! are! you!"
	@echo $(bar)
The if function

if 检查第一个参数是否非空。如果是,则运行第二个参数,否则运行第三个参数。

foo := $(if this-is-not-empty,then!,else!)
empty :=
bar := $(if $(empty),then!,else!)

all:
	@echo $(foo)
	@echo $(bar)
The call function

Make 支持创建基本函数。您只需创建一个变量即可“定义”该函数,但使用参数 ( 0 ) 、 (0)、 (0)(1) 等。然后您可以使用特殊的 call 内置函数来调用该函数。语法为$(调用变量,参数,参数)。 $(0) 是变量,而 ( 1 ) 、 (1)、 (1)(2) 等是参数。

sweet_new_fn = Variable Name: $(0) First: $(1) Second: $(2) Empty Variable: $(3)

all:
	# Outputs "Variable Name: sweet_new_fn First: go Second: tigers Empty Variable:"
	@echo $(call sweet_new_fn, go, tigers)
The shell function

shell - 这调用了 shell,但它用空格替换换行符!

all: 
	@echo $(shell ls -la) # Very ugly because the newlines are gone!
Other Features
Include Makefiles

include 指令告诉 make 读取一个或多个其他 makefile。 makefile 中的一行如下所示:

include filenames...

当您使用像 -M 这样的编译器标志基于源代码创建 Makefile 时,这特别有用。例如,如果某些 c 文件包含标头,则该标头将添加到 gcc 编写的 Makefile 中。我在 Makefile Cookbook 中详细讨论了这一点.

The vpath Directive

使用 vpath 指定某些先决条件集所在的位置。格式为 vpath <目录,空格/冒号分隔> 可以有一个 %,它匹配任何零个或多个字符。您还可以使用变量 VPATH 全局执行此操作

vpath %.h ../headers ../other-directory

# Note: vpath allows blah.h to be found even though blah.h is never in the current directory
some_binary: ../headers blah.h
	touch some_binary

../headers:
	mkdir ../headers

# We call the target blah.h instead of ../headers/blah.h, because that's the prereq that some_binary is looking for
# Typically, blah.h would already exist and you wouldn't need this.
blah.h:
	touch ../headers/blah.h

clean:
	rm -rf ../headers
	rm -f some_binary
Multiline

当命令太长时,反斜杠(“\”)字符使我们能够使用多行

some_file: 
	echo This line is too long, so \
		it is broken up into multiple lines
.phony

将 .PHONY 添加到目标将防止 Make 将虚假目标与文件名混淆。在此示例中,如果创建了 clean 文件,make clean 仍将运行。从技术上讲,我应该在每个示例中使用 all 或 clean,但我没有保持示例干净。此外,“虚假”目标的名称通常很少是文件名,实际上许多人会跳过这一点。

some_file:
	touch some_file
	touch clean

.PHONY: clean
clean:
	rm -f some_file
	rm -f clean
.delete_on_error

如果命令返回非零退出状态,make 工具将停止运行规则(并将传播回先决条件)。
如果规则以这种方式失败,DELETE_ON_ERROR 将删除规则的目标。所有目标都会发生这种情况,而不仅仅是之前的 PHONY 目标。始终使用它是一个好主意,即使 make 由于历史原因而没有这样做。

.DELETE_ON_ERROR:
all: one two

one:
	touch one
	false

two:
	touch two
	false
Makefile Cookbook

让我们看一个非常有趣的 Make 示例,它非常适合中型项目。
这个 makefile 的巧妙之处在于它会自动为您确定依赖项。您所要做的就是将 C/C++ 文件放入 src/ 文件夹中。

# Thanks to Job Vranish (https://spin.atomicobject.com/2016/08/26/makefile-c-projects/)
TARGET_EXEC := final_program

BUILD_DIR := ./build
SRC_DIRS := ./src

# Find all the C and C++ files we want to compile
# Note the single quotes around the * expressions. The shell will incorrectly expand these otherwise, but we want to send the * directly to the find command.
SRCS := $(shell find $(SRC_DIRS) -name '*.cpp' -or -name '*.c' -or -name '*.s')

# Prepends BUILD_DIR and appends .o to every src file
# As an example, ./your_dir/hello.cpp turns into ./build/./your_dir/hello.cpp.o
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)

# String substitution (suffix version without %).
# As an example, ./build/hello.cpp.o turns into ./build/hello.cpp.d
DEPS := $(OBJS:.o=.d)

# Every folder in ./src will need to be passed to GCC so that it can find header files
INC_DIRS := $(shell find $(SRC_DIRS) -type d)
# Add a prefix to INC_DIRS. So moduleA would become -ImoduleA. GCC understands this -I flag
INC_FLAGS := $(addprefix -I,$(INC_DIRS))

# The -MMD and -MP flags together generate Makefiles for us!
# These files will have .d instead of .o as the output.
CPPFLAGS := $(INC_FLAGS) -MMD -MP

# The final build step.
$(BUILD_DIR)/$(TARGET_EXEC): $(OBJS)
	$(CXX) $(OBJS) -o $@ $(LDFLAGS)

# Build step for C source
$(BUILD_DIR)/%.c.o: %.c
	mkdir -p $(dir $@)
	$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@

# Build step for C++ source
$(BUILD_DIR)/%.cpp.o: %.cpp
	mkdir -p $(dir $@)
	$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@


.PHONY: clean
clean:
	rm -r $(BUILD_DIR)

# Include the .d makefiles. The - at the front suppresses the errors of missing
# Makefiles. Initially, all the .d files will be missing, and we don't want those
# errors to show up.
-include $(DEPS)

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

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

相关文章

RLHF与LLM训练的碰撞:寻找最佳实践之路!

了解更多公众号&#xff1a;芝士AI吃鱼 在讨论大型语言模型&#xff08;LLM&#xff09;时&#xff0c;无论是在研究新闻还是教程中&#xff0c;经常提到一个称为“带有人类反馈的强化学习”&#xff08;RLHF&#xff09;的过程。由于RLHF能够将人类偏好纳入优化过程&#xff0…

K8s Pod详解

1.Pod结构 每个Pod中都可以包含一个或者多个容器&#xff0c;这些容器可以分为两类&#xff1a; 用户程序所在的容器&#xff0c;数量可多可少 Pause容器&#xff0c;这是每个Pod都会有的一个根容器&#xff0c;它的作用有两个&#xff1a; 可以以它为依据&#xff0c;评估整个…

Redis 发布订阅

目录 1.Redis Unsubscribe 命令 - 指退订给定的频道。简介语法可用版本: > 2.0.0返回值: 这个命令在不同的客户端中有不同的表现。 示例 2.Redis Subscribe 命令 - 订阅给定的一个或多个频道的信息。简介语法可用版本: > 2.0.0返回值: 接收到的信息 示例 3.Redis Pubsub …

功能自动化测试流程

1概述 本流程是描述软件功能自动化测试过程中的步骤、内容与方法&#xff0c;明确各阶段的职责、活动与产出物。 2流程活动图 3活动说明 3.1测试计划&#xff08;可选&#xff09; 与以前的测试计划过程一致&#xff0c;只是在原来的测试计划中&#xff0c;添加对项目实施自动…

Vue+element-china-area-data实现省市区三级联动

安装依赖 npm install element-china-area-data -S cnpm install element-china-area-data -S 引用 import { provinceAndCityData, regionData, provinceAndCityDataPlus, regionDataPlus, CodeToText, TextToCode } from element-china-area-data&#xff1b; provinceAnd…

父类,父类的分类、子类 同时重写方法,调用问题

做一个猜想&#xff0c;当父类、父类的分类、子类 都写了同一个方法&#xff0c;那么在调用的时候会优先调用哪个方法呢&#xff1f;我们可以先写一个简单的demo implementation Person (void)test {NSLog("%",self.class); }end然后是Person的分类 #import "…

springBoot容器功能

一、添加组件 1、Configuration 1.1基本使用 新建一个MyConfig类 , 演示Configuration Bean的作用 &#xff0c; 即相当于spring中的beanx.xml&#xff0c; Bean 就是bean标签 此方法&#xff0c;默认是单实例&#xff0c; 即获取多少次都是同一个对象 自定义名字&#xff0…

核酸汇·2024第三届中国核酸药物与新型疫苗产业大会将于5月上海召开

近年来&#xff0c;全球上市的核酸药物数量逐年递增&#xff0c;核酸药物也逐渐成为生物医药投资的重点以及医药企业研发的热点。作为一种具有颠覆性技术的药物&#xff0c;小核酸药物具备多种优势&#xff0c;在抗击传染病、治疗罕见病和慢性病等领域具有巨大的发展潜力, 目前…

安防视频监控系统EasyCVR设备分组中在线/离线数量统计的开发与实现

安防视频监控EasyCVR系统具备较强的兼容性&#xff0c;它可以支持国标GB28181、RTSP/Onvif、RTMP&#xff0c;以及厂家的私有协议与SDK&#xff0c;如&#xff1a;海康ehome、海康sdk、大华sdk、宇视sdk、华为sdk、萤石云sdk、乐橙sdk等。EasyCVR平台可覆盖多类型的设备接入&am…

数据加工:从原始数据到有价值的信息

在当今数字化的时代&#xff0c;数据已经成为了企业和组织最宝贵的资产之一。然而&#xff0c;原始数据往往需要经过加工和处理&#xff0c;才能转化为有价值的信息和知识。数据加工是指将原始数据进行处理和分析&#xff0c;以提取有用的信息和知识的过程。数据加工的重要性不…

YOLOv8-Seg改进:轻量化改进 | MobileNetV3,轻量级骨架首选

🚀🚀🚀本文改进:MobileNetV3的创新点包括:使用自适应瓶颈宽度、借鉴SENet中的Squeeze-and-Excitation机制、引入h-swish激活函数等。 🚀🚀🚀YOLOv8-seg创新专栏:http://t.csdnimg.cn/KLSdv 学姐带你学习YOLOv8,从入门到创新,轻轻松松搞定科研; 1)手把手教…

base64与BytesIO图片进行编码、解码;api调用

base64与BytesIO简单介绍 io.BytesIO 和 Base64 编码都是用于在内存中处理二进制数据的方法&#xff0c;但它们的目的和使用场景有所不同。 1&#xff09; io.BytesIO io.BytesIO 是 Python io 库中的一个类&#xff0c;它提供了一个在内存中处理二进制数据的接口&#xff0…

使用srs_librtmp实现RTMP推流

1、背景 由于项目有需求在一个现有的产品上增加RTMP推流的功能&#xff0c;目前只推视频流。 2、方案选择 由于是在现有的产品上新增功能&#xff0c;那么为了减少总的成本&#xff0c;故选择只动应用软件的来实现需求。 现有的产品中的第三方库比较有限&#xff0c;连个ffmp…

PPT模板,免费下载

找PPT模板、素材&#xff0c;就上这几个网站&#xff0c;免费下载。 1、菜鸟图库 https://www.sucai999.com/search/ppt/0_0_0_1.html?vNTYxMjky 菜鸟图库素材非常齐全&#xff0c;设计、办公、图片、视频等素材这里都能找到&#xff0c;PPT模板数量很可观&#xff0c;模板样…

《AI基本原理和python实现》栏目介绍

一、说明 栏目《AI基本原理和python实现》的设计目的是为了实现相关算法的python编程。因为用python实现AI需对相关的python库进行全方位了解&#xff0c;本栏目基本包含了【机器学习】相关的经典算法&#xff0c;除此之外还包括了数据分析、时间序列等一些概念和相关python代码…

斯坦福Mobile ALOHA提到的ACT之外的另两项技术:Diffusion Policy、VINN

前言 本文接上一篇文章《斯坦福机器人Mobile ALOHA的关键技术&#xff1a;动作分块ACT的算法原理与代码剖析》而来&#xff0c;当然最开始本文是作为上一篇文章的第二、第三部分的 但因为ACT太过关键&#xff0c;除了在上一篇文章中写清楚其算法原理之外&#xff0c;还得再剖…

借助文档控件Aspose.Words,使用 Java 在 Word 文档中创建表格

Microsoft Word 是一种流行的文字处理应用程序&#xff0c;用于创建各种类型的文档。这些文档可能包含多种类型的元素&#xff0c;包括文本、图像、表格和图表。当涉及到用 Java 自动创建和操作文档时&#xff0c;您可能需要一个轻松的解决方案来在 Word 文档中创建表格。因此&…

操作系统课程设计:常用页面置换算法(OPT、FIFO、LRU)的实现及缺页率的计算(C语言)

名人说&#xff1a;莫听穿林打叶声&#xff0c;何妨吟啸且徐行。—— 苏轼《定风波莫听穿林打叶声》 Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#xff09; 目录 一、效果图二、代码&#xff08;带注释&#xff09;三、说明 一、效果图 二、代码&#xff08;带…

@RequestParam

在我们写接口的时候&#xff0c;经常会用到这个注解来标记参数&#xff0c;通过这个注解我们可以把请求的url中的参数名和值映射到被标记的参数上。 比如下方&#xff0c;这个接口是通过传入的参数来查询相关信息的 我们定义这样一个接口&#xff0c;设置了8个参数&#xff0c;…

接口测试工具:Postman的高级用法

Postman 是一款功能强大的 API 开发和测试工具&#xff0c;以下是一些高级用法的详细介绍和操作步骤。【文末有配套视频教程和免费的资料文档领取】 一、环境和全局变量 环境变量允许你设置特定于环境&#xff08;如开发、测试、生产&#xff09;的变量&#xff0c;全局变量则…