Makefile和shell

一 shell中的位置变量

$0:表明脚本的名字,比如执行./test/test.sh 那么$0=./test/test.sh
$#:表示传递到脚本的参数的个数;
$*,$@:两者都是指所有传递到脚本的参数;
$$:这个是脚本运行的pid,跟参数好像没有关系;
$?:命令的退出状态,也就是命令结果码的保存位置;
$n(n=1,2,3…):执行脚本时后面所跟的参数,执行./start.sh arg1 arg2,则$1的值为arg1$2的值为arg2

#!/bin/bash
index=1
for arg in "$@"
    do
        echo "arg $index=$arg"
        let "index+=1"
    done
index=1
for arg in "$*"
    do
        echo "arg $index=$arg"
        let "index+=1"
    done
index=1
for arg in $@
    do
        echo "arg $index=$arg"
        let "index+=1"
    done
index=1
for arg in $*
    do
        echo "arg $index=$arg"
        let "index+=1"
    done

  ./test.sh 1 2 3 4 的运行结果:
在这里插入图片描述
  ./test 1 "2 3" 4 的结果:
在这里插入图片描述

二 shell的条件语句

1 if else

#!/bin/bash
#实现:对100分成绩分等级
echo "input:"
read line
 
if [ "$line" -gt 100 ] || [ "$line" -lt 0 ];then 
    echo "error number"
    exit 0
fi
 
if [ "$line" -gt 80 ];then
    echo "A"
elif [ "$line" -gt 70 ]
then
    echo "B"
elif [ "$line" -gt 60 ]
then
    echo "C"
else
    echo "D"
fi

2 比较

文件比较运算符
-e filename 如果 filename 存在,则为真 [ -e /var/log/syslog ]
-d filename 如果 filename 为目录,则为真 [ -d /tmp/mydir ]
-f filename 如果 filename 为常规文件,则为真 [ -f /usr/bin/grep ]
-L filename 如果 filename 为符号链接,则为真 [ -L /usr/bin/grep ]
-r filename 如果 filename 可读,则为真 [ -r /var/log/syslog ]
-w filename 如果 filename 可写,则为真 [ -w /var/mytmp.txt ]
-x filename 如果 filename 可执行,则为真 [ -L /usr/bin/grep ]
filename1-nt filename2 如果 filename1比 filename2新,则为真 [ /tmp/install/etc/services -nt /etc/services ]
filename1-ot filename2 如果 filename1比 filename2旧,则为真 [ /boot/bzImage -ot arch/i386/boot/bzImage ]
字符串比较运算符 (请注意引号的使用,这是防止空格扰乱代码的好方法)
-z string 如果 string长度为零,则为真 [ -z “ m y v a r " ] − n s t r i n g 如果 s t r i n g 长度非零,则为真 [ − n " myvar" ] -n string 如果 string长度非零,则为真 [ -n " myvar"]nstring如果string长度非零,则为真[n"myvar” ]
string1= string2 如果 string1与 string2相同,则为真 [ “ m y v a r " = " o n e t w o t h r e e " ] s t r i n g 1 ! = s t r i n g 2 如果 s t r i n g 1 与 s t r i n g 2 不同,则为真 [ " myvar" = "one two three" ] string1!= string2 如果 string1与 string2不同,则为真 [ " myvar"="onetwothree"]string1!=string2如果string1string2不同,则为真["myvar” != “one two three” ]
算术比较运算符
num1-eq num2 等于 [ 3 -eq $mynum ]
num1-ne num2 不等于 [ 3 -ne $mynum ]
num1-lt num2 小于 [ 3 -lt $mynum ]
num1-le num2 小于或等于 [ 3 -le $mynum ]
num1-gt num2 大于 [ 3 -gt $mynum ]
num1-ge num2 大于或等于 [ 3 -ge $mynum ]
-eq:等于;(equal)
-ne:不等于;(not equal)
-gt: 大于;(greater than)
-lt: 小于;(less than)
-ge: 大于等于;(greater than or equal to)
-le: 小于等于。(less than or equal to)
  -z:判断变量的值,是否为空; zero = 0。
  在shell中对比字符串和对比数字,要分开两种方式。对比字符串只能使用==<>!=-z-n。对比字符串时,末尾一定要加上x(或者a、b等)一个字符,因为if [ $1x == "ab"x ]时如果没有了x ,并且$1是"“,这个语句会翻译成if [ == "ab" ],左边相当于没有东西了,会报语法错误。或者使用[[ ]],就不需要x了。使用<或者>时,如果是用[ ],需要用转义符”",如>。
  对比数字使用既能使用-eq、-ne、-gt、-ge、-lt、-le,也能使用==、<、>、!=。其中-eq的意思是equal,-ne是unequal,-gt是greater than,-ge是greater than or equal to,-lt是less than,-le是less than or equal to。

if [ -z $os_mem_size ]

三 case

  case 语句的语法如下:

case $变量名 in
“值 1”)
;;
如果变量的值等于值1,则执行程序1
“值2”)
如果变量的值等于值2,则执行程序2
;;
……
;;
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac

四 循环语句 for while until

#!/bin/bash
#循环  for
 
for i in 1 2 3 4 5
do 
    echo "i = $i"
done
 
# $(ls)执行命令ls
for i in $(ls)  
do
    echo "i = $i"
    sleep 1
done

在这里插入图片描述

#!/bin/bash
#输入密码,只有三次机会输入
i=1
while [ : ]
do
    echo "input password:"
    read pass
    if [ "$pass" = "123456" ]
    then 
	echo "success"
	break
    fi
    
    if [ "$i" -eq 3 ]
    then
	echo "falied"
	exit 0
    fi 
    let "i++"
done
#循环4次,每打印i的值睡一秒,i++
i=1
while [ "$i" -lt 5 ]
do
    echo "i = $i"
    sleep 1
    let "i++"
done

五 set -e

  你写的每个脚本都应该在文件开头加上set -e,这句语句告诉bash如果任何语句的执行结果不是true则应该退出。
  这样的好处是防止错误像滚雪球般变大导致一个致命的错误,而这些错误本应该在之前就被处理掉。如果要增加可读性,可以使用set -o errexit,它的作用与 set -e 相同。


六 Makefile 的规则

target ... : prerequisites ...
[tab]command #命令前面为tab键
...

  target是一个目标文件,可以是 Object File,执行文件,还可以是一个标签(Label)。prerequisites是生成 target 所需要的文件或是目标。command是执行的命令。例如:

edit : main.o kbd.o command.o
    cc -o edit main.o kbd.o command.o
main.o : main.c defs.h
    cc -c main.c
clean :
    rm edit main.o kbd.o command.o

  Makefile 里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释。
  1、显式规则。说明了如何生成一个或多的的目标文件。这是由 Makefile 的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。
  2、隐晦规则。由于我们的 make 有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写 Makefile,这是由 make 所支持的。
  3、变量的定义。在 Makefile 中我们要定义一系列的变量,变量一般都是字符串,这个有点你 C 语言中的宏,当 Makefile 被执行时,其中的变量都会被扩展到相应的引用位置上。
  4、文件指示。其包括了三个部分,一个是在一个 Makefile 中引用另一个 Makefile,就像 C语言中的 include 一样;另一个是指根据某些情 况指定 Makefile 中的有效部分,就像 C 语言中的预编译#if 一样;还有就是定义一个多行的命令。
  5、注释。 Makefile 中只有行注释,和 UNIX 的 Shell 脚本一样,其注释是用#字符。如果你要在你的 Makefile 中使用#字符,可以用反斜框进行转义,如: \#。 最后,还值得一提的是,在 Makefile 中的命令,必须要以[Tab]键开始。

七 自动推导

1 使用变量(减少.o)

objects = main.o kbd.o command.o
edit : $(objects)
    cc -o edit $(objects)
main.o : main.c defs.h
    cc -c main.c
kbd.o : kbd.c defs.h command.h
    cc -c kbd.c
command.o : command.c defs.h command.h
    cc -c command.c

  用变量 object 代替 .o 文件。

2 C文件的推导

objects = main.o kbd.o command.o
edit : $(objects)
    cc -o edit $(objects)
main.o : defs.h
kbd.o : defs.h command.h
command.o : defs.h command.h
.PHONY : clean
clean :
    rm edit $(objects)

  这种方法,也就是 make 的“隐晦规则”。上面文件内容中,.PHONY意思表示clean是一个“伪目标”。

3 头文件的推导

objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o
edit : $(objects)
    cc -o edit $(objects)
$(objects) : defs.h
kbd.o command.o files.o : command.h
display.o insert.o search.o files.o : buffer.h
.PHONY : clean
clean :
    rm edit $(objects)

八 变量和运算符

1 变量

$@:目标文件,$^:所有的依赖文件,$<:第一个依赖文件,$()表示引用括号内变量的值。

main:main.o mytool1.o mytool2.o
    gcc -o $@ $^
main.o:main.c mytool1.h mytool2.h
    gcc -c $<

  在makefile的规则命令行中使用$var就是在命令中引用makefile的变量,这里仅仅是读取makefile的变量然后扩展开,将其值作为参数传给了一个shell命令;而$$var是在访问一个shell命令内定义的变量,而非makefile的变量。

2 运算符

  1. =:最基本的赋值,make会将整个makefile展开后,再决定变量的值。例如:y的值是 xyz bar,而不是 foo bar。
x = foo
y = $(x) bar
x = xyz
  1. :=:覆盖之前的值,变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值。例如:y的值将会是 foo bar,而不是 xyz bar。
x := foo
y := $(x) bar
x := xyz
  1. ?=:是如果没有被赋值过就赋予等号后面的值。
  2. +=:是添加等号后面的值。
  3. @$():中的 @ 的含义是:在终端不输出该命令行。

3 wildcard

九 指定目标

1 all的作用

  make默认的执行第一个目标,由于makefile是根据最后的关联来执行命令的,所以不会执行无关的第二个目标命令,但是有的时候,比如只需要编译,而不需要连接,就不会形成关联。这中情况下,就需要all,如下会将所有的目标都执行了。

all : hello another
 
hello : hello.cpp
    g++ -o $@ $<
 
another : another.cpp
    g++ -o $@ $<

2 指定目标

  可以指示make,让其完成你所指定的目标。要达到这一目的很简单,需在make命令后直接跟目标的名字就可以完成,任何在makefile中的目标都可以被指定成终极目标,但是除了以-打头,或是包含了=的目标,因为有这些字符的目标,会被解析成命令行参数或是变量。甚至没有被我们明确写出来的目标也可以成为make的终极目标,也就是说,只要make可以找到其隐含规则推导规则,那么这个隐含目标同样可以被指定成终极目标。

3 MAKECMDGOALS

  有一个 make 的环境变量叫MAKECMDGOALS,存放指定的终极目标的列表,如果命令行没有指定目标,那么变量是空值。这个变量可以使用在一些比较特殊的情形下。例如:

sources = foo.c bar.c  
ifneq ( $(MAKECMDGOALS),clean)  
include $(sources:.c=.d)  
endif 

  如果输入的命令不是make clean,那么 makefile 会自动包含foo.dbar.d这两个文件。

4 clean

  清空目标文件的规则:每个 Makefile 中都应该写一个清空目标文件(.o 和执行文件)的规则,这不仅便于重编译,也很利于保持文件的清洁。

clean:
    rm edit $(objects)

更为稳健的做法是:

.PHONY : clean
clean :
    -rm edit $(objects)

  而在rm命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。当然, clean 的规则不要放在文件的开头,不然,这就会变成 make 的默认目标。不成文的规则是——clean 从来都是放在文件的最后。

十 Makefile 的文件名

  默认的情况下, make 命令会在当前目录下按顺序找寻文件名为GNUmakefilemakefileMakefile的文件,找到了解释这个文件。在这三个文件名中,最好使用Makefile这个文件名,因为,这个文件名第一个字符为大写,这样有一种显目的感觉。最好不要用GNUmakefile,这个文件是 GNU 的 make 识别的。有另外一些 make 只对全小写的makefile文件名敏感,但是基本上来说,大多数的 make 都支持makefileMakefile。如果自定义名称,可以使用 make 的参数- f--file指定文件。

十一 shell

  Makefile本质上来讲也是shell脚本,即每条command都是shell进程,运行完shell进程都会退出。

十二 引用其它的 Makefile

  在 Makefile 使用 include 关键字可以把别的 Makefile 包含进来,被包含的文件会原模原样的放在当前文件的包含位置。 include 的语法是:
include <filename>:filename 可以是当前操作系统 Shell 的文件模式(可以保含路径和通配符)在 include 前面可以有一些空字符,但是绝不能是[Tab]键开始。 include 和;可以用一个或多个空格隔开。 举个例子,你有这样几个 Makefile: a.mk、 b.mk、 c.mk,还有一个文件叫 foo.make,以及一个变量$(bar),其包含了 e.mk 和 f.mk,那么,下面的语句:

include foo.make *.mk $(bar)

等价于:

include foo.make a.mk b.mk c.mk e.mk f.mk

  make 命令开始时,会把找寻 include 所指出的其它 Makefile,并把其内容安置在当前的位置。就好像 C/C++的#include 指令一样。 如果文件都没有指定绝对路径或是相对路径的话, make会在当前目录下首先寻找,如果当前目录下没有找到,那么, make 还会在下面的几个目录下找:
  1、如果 make 执行时,有-I--include-dir参数,那么 make 就会在这个参数所指定的目录下去寻找。
  2、如果目录;/include(一般是: /usr/local/bin 或/usr/include)存在的话, make 也会去找。如果有文件没有找到的话, make 会生成一条警告信息,但不会马上出现致命错误。它会继续载入其它的文件,一旦完成 makefile 的读取, make 会再 重试这些没有找到,或是不能读取的文件,如果还是不行, make 才会出现一条致命信息。如果你想让 make 不理那些无法读取的文件,而继续执行,你可以在 include 前加一个减号-。如:-include ;其表示,无论 include 过程中出现什么错误,都不要报错继续执行。和其它版本 make 兼容的相关命令是 sinclude,其作用和这一个是一样的。

十三 make参数

  不需要 makefile 中的规则执行起来,只想检查一下命令,或是执行的序列,可以使用 make 命令的下述参数:-n–just-print–dry-run–recon
  不执行参数,这些参数只是打印命令,不管目标是否更新,把规则和连带规则下的命令打印出来,但不执行,这些参数对于我们调试makefile很有用处:-t–touch
  -q–question:把目标文件的时间更新,但不更改目标文件。也就是说,make假装编译目标,但不是真正的编译目标,只是把目标变成已编译过的状态。
  这个参数的行为是找目标的意思,也就是说,如果目标存在,那么其什么也不会输出,当然也不会执行编译,如果目标不存在,其会打印出一条出错信息。-W <file>–what-if=<file>–assume-new=<file>–new-file=<file>
  这个参数需要指定一个文件。一般是是源文件(或依赖文件),Make会根据规则推导来运行依赖于这个文件的命令,一般来说,可以和-n参数一同使用,来查看这个依赖文件所发生的规则命令。结合-p-v来输出makefile被执行时的信息。

十四 Scons

  make 这个工具自上个世纪 70 年代 Stuart Feldman 在贝尔实验室开发出以来,就一直是类 UNIX 程序员的最爱之一。
  通过检查文件的修改时间,make 工具可以知道编译目标文件所要依赖的其他文件。在复杂的项目中,如果只有少数几个文件修改过,make 工具知道仅仅需要对哪些文件重新编译就可以确保目标程序被正确的编译链接。这样做的好处就是在编译中,不仅可以节省大量的重复输入,还可以确保程序可以被正确的链接,缩短编译的时间。
  虽然如此,但是为 make 工具编写建造规则却不是一件容易的事。它复杂的配置规则,即使是有经验的开发者也望而生畏。
  那么,今天介绍一个它的同类产品,也可以说是升级产品:Scons,它做的事情跟make一样,但更简单,更容易。
  Scons是一个开放源码、以Python语言编码的自动化构建工具,可用来替代make编写复杂的makefile。并且scons是跨平台的,只要scons脚本写的好,可以在Linux和Windows下随意编译。
  SCons 的设计目标就是让开发人员更容易、更可靠和更快速的建造软件。
  与传统的 make 工具比较,SCons 具有以下优点:
  使用 Python 脚本做为配置文件,对于 C,C++ 和 Fortran, 内建支持可靠自动依赖分析 . 不用像 make 工具那样需要 执行"make depends"和"make clean"就可以获得所有的依赖关系。
内建支持 C, C++, D, Java, Fortran, Yacc, Lex, Qt,SWIG 以及 Tex/Latex。 用户还可以根据自己的需要进行扩展以获得对需要编程语言的支持。
  支持 make -j 风格的并行建造。相比 make -j,SCons 可以同时运行 N 个工作,而 不用担心代码的层次结构。使用 Autoconf 风格查找头文件,函数库,函数和类型定义。良好的夸平台性。SCons 可以运行在 Linux, AIX, BSD, HP/UX, IRIX, Solaris, Windows, Mac OS X 和 OS/2 上。

project

https://cmake.org/cmake/help/latest/command/project.html
project 主要用于提供项目的名称、版本、使用编译语言等信息
https://www.cnblogs.com/gaox97329498/p/10957786.html
注意:

  • 在当前系统版本下面,实际上 Project 并不支持 document 提供的 DESCRIPTION 、HOMEPAGE_URL
  • project 必须放在最上面, 且不能通过 include来包含

macro

https://www.h3399.cn/201802/546661.html
cmake 中有两个相似的关键字, macro 和 function 这两个都是创建一段有名字的代码稍后可以调用, 还可以传参数

macro 宏定义与 function 函数的相同点

macro 形式如下:

macro( [arg1 [arg2 [arg3 …]]])
COMMAND1(ARGS …)
COMMAND2(ARGS …)

endmacro()
function 形式如下:

function( [arg1 [arg2 [arg3 …]]])
COMMAND1(ARGS …)
COMMAND2(ARGS …)

function()
定义一个名称为 name 的宏 (函数),arg1… 是传入的参数我们除了可以用 ${arg1} 来引用变量以外, 系统为我们提供了一些特殊的变量:

变量 说明
ARGV# # 是一个下标,0 指向第一个参数,累加
ARGV 所有的定义时要求传入的参数
ARGN 定义时要求传入的参数以外的参数,比如定义宏(函数)时,要求输入 1 个,书记输入了 3 个,则剩下的两个会以数组形式存储在 ARGN 中
ARGC 传入的实际参数的个数,也就是调用函数是传入的参数个数
macro 宏定义与 function 函数的不同点

宏的 ARGNARGV 等参数不是通常 CMake 意义上的变量 它们是字符串替换, 很像 C 预处理器对宏的处理 因此, 如下命令是错误的:

if(ARGV1) # ARGV1 is not a variable
if(DEFINED ARGV2) # ARGV2 is not a variable
if(ARGC GREATER 2) # ARGC is not a variable
foreach(loop_var IN LISTS ARGN) # ARGN is not a variable
正确写法如下:

if(${ARGV1})
if(DEFINED A R G V 2 ) i f ( {ARGV2}) if( ARGV2)if({ARGC} GREATER 2)
foreach(loop_var IN LISTS A R G N ) o r s e t ( l i s t v a r " {ARGN}) or set(list_var " ARGN)orset(listvar"{ARGN}")
foreach(loop_var IN LISTS list_var)
一个简单的例子

macro(FOO arg1 arg2 arg3)
message(STATUS “this is arg1: a r g 1 , A R G V 0 = {arg1},ARGV0= arg1,ARGV0={ARGV0}”)
message(STATUS “this is arg2: a r g 2 , A R G V 1 = {arg2},ARGV1= arg2,ARGV1={ARGV1}”)
message(STATUS “this is arg3: a r g 3 , A R G V 2 = {arg3},ARGV2= arg3,ARGV2={ARGV2}”)
message(STATUS “this is argc: A R G C " ) m e s s a g e ( S T A T U S " t h i s i s a r g s : {ARGC}") message(STATUS "this is args: ARGC")message(STATUS"thisisargs:{ARGV},ARGN= A R G N " ) i f ( a r g 1 S T R E Q U A L o n e ) m e s s a g e ( S T A T U S " t h i s i s a r g 1 " ) e n d i f ( ) i f ( A R G V 2 S T R E Q U A L " t w o " ) m e s s a g e ( S T A T U S " t h i s i s a r g 2 " ) e n d i f ( ) s e t ( {ARGN}") if(arg1 STREQUAL one) message(STATUS "this is arg1") endif() if(ARGV2 STREQUAL "two") message(STATUS "this is arg2") endif() set( ARGN")if(arg1STREQUALone)message(STATUS"thisisarg1")endif()if(ARGV2STREQUAL"two")message(STATUS"thisisarg2")endif()set({arg1} nine)
message(STATUS “after set arg1=KaTeX parse error: Expected '}', got 'EOF' at end of input: {{arg1}}”)
endmacro(FOO)
function(BAR arg1)
message(STATUS “this is arg1: a r g 1 , A R G V 0 = {arg1},ARGV0= arg1,ARGV0={ARGV0}”)
message(STATUS “this is argn: A R G N " ) i f ( a r g 1 S T R E Q U A L f i r s t ) m e s s a g e ( S T A T U S " t h i s i s f i r s t " ) e n d i f ( ) s e t ( a r g 1 t e n ) m e s s a g e ( S T A T U S " a f t e r s e t a r g 1 = {ARGN}") if(arg1 STREQUAL first) message(STATUS "this is first") endif() set(arg1 ten) message(STATUS "after set arg1= ARGN")if(arg1STREQUALfirst)message(STATUS"thisisfirst")endif()set(arg1ten)message(STATUS"aftersetarg1={arg1}”)
endfunction(BAR arg1)
set(p1 one)
set(p2 two)
set(p3 three)
set(p4 four)
set(p5 five)
set(p6 first)
set(p7 second)
FOO(${p1} ${p2} ${p3} ${p4} p 5 ) B A R ( {p5}) BAR( p5)BAR({p6} p 7 ) m e s s a g e ( S T A T U S " a f t e r b a r p 6 = {p7}) message(STATUS "after bar p6= p7)message(STATUS"afterbarp6={p6}”)
输出结果如下:

– this is arg1:one,ARGV0=one
– this is arg2:two,ARGV1=two
– this is arg3:three,ARGV2=three
– this is argc:5
– this is args:one;two;three;four;five,ARGN=four;five
– after set arg1=nine
– this is arg1:first,ARGV0=first
– this is argn:second
– this is first
– after set arg1=ten
– after bar p6=first
接下来看一个让我们蛋都能疼碎了的例子, 简直不想用 cmake:

macro(_bar)
foreach(arg IN LISTS ARGN)
message(STATUS “this is in macro ${arg}”)
endforeach()
endmacro()
function(_foo)
foreach(arg IN LISTS ARGN)
message(STATUS “this in function is ${arg}”)
endforeach()
_bar(x y z)
endfunction()
_foo(a b c)
看一下输出:

– this in function is a
– this in function is b
– this in function is c
– this is in macro a
– this is in macro b
– this is in macro c
就是这么蛋疼, 我们传给了_bar(x y z), 结果打印出来的是 a b c, 那我们把第二行的 foreach 改成

foreach(arg IN LISTS ${ARGN})

, 看一下结果:

– this in function is a
– this in function is b
– this in function is c
没有输出_bar 中的信息为啥? 因为这个 ARGN 的作用域是在 function 中的, 也就是_foo 函数中的那个 ARGN 有兴趣的话可以试试在 macro 中调用 function

add_definitions

添加编译参数,比如add_definitions(-DDEBUG)将在gcc命令行添加DEBUG宏定义

link_directories

该指令的作用主要是指定要链接的库文件的路径,该指令有时候不一定需要。因为find_package和find_library指令可以得到库文件的绝对路径。不过你自己写的动态库文件放在自己新建的目录下时,可以用该指令指定该目录的路径以便工程能够找到。
例子如下:
link_directories(
lib
)

aux_source_directory

https://blog.csdn.net/u012564117/article/details/95085360
查找在某个路径下的所有源文件。

aux_source_directory(< dir > < variable >)
搜集所有在指定路径下的源文件的文件名,将输出结果列表储存在指定的变量中。该命令主要用在那些使用显式模板实例化的工程上。模板实例化文件可以存储在Templates子目录下,然后可以使用这条命令自动收集起来;这样可以避免手工罗列所有的实例。
使用该命令来避免为一个库或可执行目标写源文件的清单,是非常具有吸引力的。

add_executable:

https://cmake.org/cmake/help/latest/command/add_executable.html
使用给定的源文件,为工程引入一个可执行文件。
https://www.jianshu.com/p/19765d4932a4

CMAKE_COMMAND

https://cmake.org/cmake/help/latest/variable/CMAKE_COMMAND.html

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值