Cmake中的条件判断if/elseif/else

一、基本命令解析

  if语句用于判断条件是否成立,条件成立时执行对应的语句。完整的格式如下:

if(<condition>)
<commands>
elseif(<condition>) # 可选,且可重复
<commands>
else() # 可选
<commands>
endif()

  • 如果if括号内的condition为真,则执行if对应的语句块;
  • 如果if括号内的condition为假,则判断elseif语句的condition是否为真,为真则执行elseif对应的语句块,注意:elseif是可选的,并且可以出现多次;
  • 如果elseif括号内的condition为假,则执行else()对应的语句块,注意:else()是可选的,else后面有一对空括号,也可以在括号里面写condition,但是必须与if对应的condition完全一致;
  • 最后以endif()结尾,注意:endif()的括号内也可以写condition,但是必须与if对应的condition完全一致;

二、if语句中条件(condition)的优先级

  if语句中条件(condition)的优先级从高到低如下:

1. 圆括号():括号的优先级最高
2. 一元测试命令:
  • EXIST:判断文件或者目录是否存在,存在时为真。需要提供全路径;如果文件或者目录是符号链接(例如软连接),则只有当链接的目标存在时返回真。格式为:if(EXISTS path-to-file-or-directory)
  • COMMAND:如果给定的名称是命令、宏或者函数这类可被调用的对象,则返回真。格式为:if(COMMAND command-name)
  • DEFINED:如果给定的变量(普通变量、缓存变量、环境变量)存在,则返回真。格式为:if(DEFINED <name>|CACHE{<name>}|ENV{<name>}),注意缓存变量前要加CACHE,环境变量前要加ENV
3. 二元测试命令,二元操作符有的左边和右边需要提供变量:
  • EQUAL:左边两个字符串或者变量相等时为真。格式为:if(<variable|string> EQUAL <variable|string>)
  • LESS:左边小于右边时为真(数值比较)。格式为:if(<variable|string> LESS <variable|string>)
  • LESS_EQUAL:左边小于等于右边时为真(数值比较)。格式为:if(<variable|string> LESS_EQUAL <variable|string>)
  • GREATER:左边大于右边时为真(数值比较)。格式为:if(<variable|string> GREATER <variable|string>)
  • GREATER_EQUAL:左边大于等于右边时为真(数值比较)。格式为:if(<variable|string> GREATER_EQUAL <variable|string>)
  • STREQUAL:左边与右边的字典顺序相等时为真(数值比较)。格式为:if(<variable|string> STREQUAL <variable|string>)
  • STRLESS:左边的字典顺序小于右边的字典序时为真。格式为:if(<variable|string> STRLESS <variable|string>)
  • STRLESS_EQUAL:左边的字典顺序小于等于右边的字典序时为真。格式为:if(<variable|string> STRLESS_EQUAL <variable|string>)
  • STRGREATER:左边的字典顺序大于右边的字典序时为真。格式为:if(<variable|string> STRGREATER <variable|string>)
  • STRGREATER_EQUAL:左边的字典顺序大于等于右边的字典序时为真。格式为:if(<variable|string> STRGREATER_EQUAL <variable|string>)
  • VERSION_EQUAL:左右两边的版本号相等时为真。左右两边的版本号格式为major[.minor[.patch[.tweak]]],每个部分都要求是整数(省略的部分当做0),如果是非整数,从非整数的地方往后会被截断。格式为:if(<variable|string> VERSION_EQUAL <variable|string>)
  • VERSION_LESS:左边版本号小于右边版本号时为真。左右两边的版本号格式为major[.minor[.patch[.tweak]]],每个部分都要求是整数(省略的部分当做0)),如果是非整数,从非整数的地方往后会被截断。格式为:if(<variable|string> VERSION_LESS <variable|string>)
  • VERSION_LESS:左边版本号小于右边版本号时为真。左右两边的版本号格式为major[.minor[.patch[.tweak]]],每个部分都要求是整数(省略的部分当做0),如果是非整数,从非整数的地方往后会被截断。格式为:if(<variable|string> VERSION_LESS <variable|string>)
  • VERSION_LESS_EQUAL:左边版本号小于等于右边版本号时为真。左右两边的版本号格式为major[.minor[.patch[.tweak]]],每个部分都要求是整数(省略的部分当做0),如果是非整数,从非整数的地方往后会被截断。格式为:if(<variable|string> VERSION_LESS_EQUAL <variable|string>)
  • VERSION_GREATER:左边版本号大于右边版本号时为真。左右两边的版本号格式为major[.minor[.patch[.tweak]]],每个部分都要求是整数(省略的部分当做0),如果是非整数,从非整数的地方往后会被截断。格式为:if(<variable|string> VERSION_GREATER <variable|string>)
  • VERSION_GREATER_EQUAL:左边版本号大于等于右边版本号时为真。左右两边的版本号格式为major[.minor[.patch[.tweak]]],每个部分都要求是整数(省略的部分当做0),如果是非整数,从非整数的地方往后会被截断。格式为:if(<variable|string> VERSION_GREATER_EQUAL <variable|string>)
  • MATCHES:按照正则表达式去匹配,左边是待匹配的值,右边是正则表达式,能匹配为时为真。格式为:if(<variable|string> MATCHES regex)
4. 一元逻辑操作符号:
  • NOT:条件不满足时为真。格式为:if(NOT <condition>)
5. 二元逻辑操作符:
  • AND:左右两边条件均成立时为真。格式为:if(<cond1> AND <cond2>)
  • OR:左右两边条件任一个成立时为真。格式为:if(<cond1> OR <cond2>)

三、示例说明

  if语句分为基本表达式、逻辑操作、存在性判断、文件操作、变量比较、版本号比较、变量展开几大类判定,下面依次以示例来介绍:

3.1 基本表达式

  • if(<constant>)
    如果constant1, ON, YES, TRUE, Y非0值时为真;
    如果constant0, OFF, NO, FALSE, N, IGNORE, NOTFOUND, 空字符串, 以NOTFOUND为后缀时为假;
    注意constant是大小写不敏感的,如果constant不是上述值,则会被当成变量或者字符串。
# CMakeLists.txt
if(YES)
    message("YES")
endif()

if(NOTFOUND)
else()
    message("Not found")
endif()
# 命令行中执行cmake .后的输出
YES
Not found
  • if(<variable>)
    如果给定的变量有定义,且值不是0, OFF, NO, FALSE, N, IGNORE, NOTFOUND, 空字符串, 以NOTFOUND为后缀时为真;
    其他情况该判断为假;
    注意:宏参数和环境变量不能这样判断,例如if(ENV{var})肯定为假;
# CMakeLists.txt
if(test)
else()
    message("var test not exists")
endif()

set(test 100)
if(test)
    message("var test exists and it's value is ${test}")
endif()
# 命令行中执行cmake .后的输出
var test not exists
var test exists and it's value is 100
  • if(<string>)
    string为双引号括起来的字符串,除了以下两种情况外,其他情况均为假:
    string的值为1, ON, YES, TRUE, Y非0值时为真
    CMP0054策略设置为OLD,则双引号括起来的字符串会当成变量解引用为变量的值(字符串对应的变量已经定义的情况下),之后再判定表达式的真假;当CMP0054策略设置为NEW,双引号括起来的字符串仅仅是作为字符串。
# CMakeLists.txt
set(test "YES")
set(stest "test")
cmake_policy(SET CMP0054 NEW) # 设置策略CMP0054为NEW
if("Y")
    message("TRUE")
endif()

if("test") # test被当成字符串,非constant的真值,因此判定为假
else()
    message("string 'test' result false")
endif()
if("${stest}") # stest变量值为test,test被当成字符串,非constant的真值,因此判定为假
else()
    message("string $stest dereference value ${stest} result false")
endif()

cmake_policy(SET CMP0054 OLD) # 设置策略CMP0054为OLD
if("test") # test被当成变量,解引用后值为YES,为constant真值
    message("var test dereference value ${test}, result true")
endif()
if("${stest}") # stest先解析为test,test被当成变量,解引用后值为YES,为constant真值
    message("string $stest dereference value ${stest} then $test dereference value ${test} result true")
endif()
# 命令行中执行cmake .后的输出
string 'test' result false
string $stest dereference value test result false
string test dereference value YES, result true
string $stest dereference value test then $test dereference value YES result true

3.2 逻辑操作

  • if(NOT <condition>):逻辑非操作
# CMakeLists.txt
if(NOT IGNORE)
    message("not ignore is true")
endif()
if(NOT YES)
else()
    message("not YES is false")
endif()
# 命令行中执行cmake .后的输出
not ignore is true
not YES is false
  • if(<cond1> AND <cond2>):逻辑与操作
# CMakeLists.txt
if(ON AND Y)
    message("ON AND Y is true")
endif()
if(TRUE AND FALSE)
else()
    message("TRUE AND FALSE is false")
endif()
# 命令行中执行cmake .后的输出
ON AND Y is true
TRUE AND FALSE is false
  • if(<cond1> AND <cond2>):逻辑或操作
# CMakeLists.txt
if(IGNORE OR NOTFOUND)
else()
    message("IGNORE OR NOTFOUND is false")
endif()
if(TRUE OR FALSE)
    message("TRUE OR FALSE is true")
endif()
if(TRUE AND (IGNORE OR YES)) # 注意括号的优先级最高,会先计算括号内的OR逻辑的值
    message("TRUE AND (IGNORE OR YES) is true")
endif()
# 命令行中执行cmake .后的输出
IGNORE OR NOTFOUND is false
TRUE OR FALSE is true
TRUE AND (IGNORE OR YES) is true

3.3 存在性检查

  • if(COMMAND command-name):判断是否为命令
# CMakeLists.txt
function(f)
endfunction()

if(COMMAND f)
    message("f is function")
endif()
if(COMMAND message)
    message("message is a command")
endif()
if(COMMAND test)
else()
    message("test is not a command")
endif()
# 命令行中执行cmake .后的输出
f is function
message is a command
test is not a command
  • if(POLICY policy-id):判断是否为策略,策略的格式为CMP<NNNN>
# CMakeLists.txt
if(POLICY CMP0054)
    message("CMP0054 is a policy")
endif()
set(cmp CMP0001)
if(POLICY ${cmp})
    message("${cmp} is a policy")
endif()
set(cmp CMP_TEST)
if(POLICY ${cmp})
else()
    message("${cmp} is not a policy")
endif()
# 命令行中执行cmake .后的输出
CMP0054 is a policy
CMP0001 is a policy
CMP_TEST is not a policy
  • if(TARGET target-name):判断是否为通过调用add_executable()、add_library()、add_custom_target()创建的构建目标
# CMakeLists.txt
add_executable(runTest test.cpp)
add_library(libTest test.cpp)
if(TARGET runTest)
    message("runTest is a target")
endif()
if(TARGET libTest)
    message("libTest is a target")
endif()
if(TARGET test)
else()
    message("test is not a target")
endif()
# 命令行中执行cmake .后的输出
runTest is a target
libTest is a target
test is not a target
  • if(TEST test-name):判断是否为通过调用add_test()创建的测试对象
# CMakeLists.txt
add_executable(runTest test.cpp)
add_test(NAME mytest COMMAND runTest)
if(TEST mytest)
    message("mytest is a test")
endif()
# 命令行中执行cmake .后的输出
mytest is a test
  • if(DEFINED <name>|CACHE{<name>}|ENV{<name>}):判断变量、缓存变量、环境变量是否存在,DEFINED不关注变量具体的值。有两点需要注意:一是宏参数不是变量;二是无法直接判断一个变量是不是非缓存变量,因为不论是缓存变量还是非缓存变量,只要变量存在,if(DEFINED someName)都会返回true,但是可以通过if(DEFINED CACHE{someName})判断出一个缓存变量是否存在,因此判断一个非缓存变量是否存在,可以通过if(DEFINED someName AND NOT DEFINED CACHE{someName})实现。
# CMakeLists.txt
if(DEFINED var1)
else()
    message("var1 not defined")
endif()

set(var2 "NOTFOUND")
if(DEFINED var2)
    message("var2 defined and it's value is ${var2}")
endif()
if(var2) # 会按照if(constant)基本表达式来判断
else()
    message("var2 return false, value is ${var2}")
endif()

if(DEFINED ENV{MY_TEST_ENV_VAR})
    message("ENV MY_TEST_ENV_VAR defined: $ENV{MY_TEST_ENV_VAR}")
else()
    message("ENV MY_TEST_ENV_VAR not defined")
endif()

set(cacheVar "YES" CACHE INTERNAL "internal var")
if(DEFINED CACHE{cacheVar})
    message("cache cacheVar defined: ${cacheVar}")
endif()
if(DEFINED cacheVar) # 无法区分普通变量或缓存变量
    message("cacheVar defined: ${cacheVar}")
endif()

if(DEFINED var2 AND (NOT DEFINED CACHE{var2})) # 判断一个变量是否为普通变量
    message("var2 defined and is not a cache variable")
endif()
# 在命令行中定义一个环境变量
export MY_TEST_ENV_VAR="env var"

# 命令行中执行cmake .后的输出
var1 not defined
var2 defined and it's value is NOTFOUND
var2 return false, value is NOTFOUND
ENV MY_TEST_ENV_VAR defined: env var
cache cacheVar defined: YES
cacheVar defined: YES
var2 defined and is not a cache variable
  • if(<variable|string> IN_LIST <variable>):判断变量是否存在列表中。
# CMakeLists.txt
set(listVar test1 test2 test3)  # define list : test1;test2;test3
if(test1 IN_LIST listVar)
    message("test1 in listVar")
endif()
if(test4 IN_LIST listVar)
else()
    message("test4 not in listVar")
endif()
# 命令行中执行cmake .后的输出
test1 in listVar
test4 not in listVar

3.4 文件操作

  文件的操作,CMake官方文档中都要求使用全路径,if判断的结果才是有明确定义的,相对路径可能无法识别(例如~不会解析成home目录)。

  • if(EXISTS path-to-file-or-directory):判断文件或目录是否存在。
# CMakeLists.txt
set(myfile "/tmp/testfile")
set(mydir "/tmp/testdir")
if(EXISTS ${myfile})
    message("file ${myfile} exist")
endif()
if(EXISTS ${mydir})
    message("directory ${mydir} exist")
endif()

if(EXISTS "/tmp/link")
    message("link to target exists")
endif()
if(EXISTS "/tmp/link2")
else()
    message("link2 to target2 not exists")
endif()
# 先来创建一些文件和软连接
touch /tmp/testfile
mkdir /tmp/testdir
ln -s /tmp/target /tmp/link
touch /tmp/target # link链接到target
ln -s /tmp/target2 /tmp/link2 # link2链接的文件实际不存在

# 命令行中执行cmake .后的输出
file /tmp/testfile exist
directory /tmp/testdir exist
link to target exists
link2 to target2 not exists
  • if(file1 IS_NEWER_THAN file2):判断文件1是否比文件2要新。注意:当有文件不存在的时候,该判断返回true
# CMakeLists.txt
if("/tmp/newfile" IS_NEWER_THAN "/tmp/oldfile")
    message("/tmp/newfile is newer than /tmp/oldfile")
endif()
# 创建测试文件,按顺序
touch /tmp/oldfile
touch /tmp/newfile

# 命令行中执行cmake .后的输出
/tmp/newfile is newer than /tmp/oldfile
  • if(IS_DIRECTORY path-to-directory):判断是否为目录;
# CMakeLists.txt
if(IS_DIRECTORY "/tmp")
    message("/tmp is directory")
endif()
if(IS_DIRECTORY "/tmp/no-exist-dir")
else()
    message("/tmp/no-exist-dir not a directory")
endif()
if(IS_DIRECTORY "/tmp/testfile")
else()
    message("/tmp/testfile not a directory")
endif()
# 先来创建文件
touch /tmp/testfile

# 命令行中执行cmake .后的输出
/tmp is directory
/tmp/no-exist-dir not a directory
/tmp/testfile not a directory
  • if(IS_SYMLINK file-name):判断是否为链接文件;
# CMakeLists.txt
if(IS_SYMLINK "/tmp/link")
    message("/tmp/link is symbol link")
endif()
if(IS_SYMLINK "/tmp/testfile")
else()
    message("/tmp/testfile not symbol link")
endif()
# 命令行中执行cmake .后的输出
/tmp/link is symbol link
/tmp/testfile not symbol link
  • if(IS_ABSOLUTE path):判断是否为绝对路径;注意有几个特殊的处理:1)空路径判定为false;2)Windows下,以盘符和冒号开头(例如C:),或以正斜线/反斜线开头的都将判定为true,因此C:no\base\dirtrue,尽管盘符后的no\base\dir是一个相对路径;3)非Windows,例如LinuxmacOS下,~开头的也会判定为true,即使路径并不存在。
# CMakeLists.txt
if(IS_ABSOLUTE "/tmp/testfile")
    message("/tmp/testfile is full path")
endif()
if(IS_ABSOLUTE "~/no-file")
    message("~ regard as full path")
endif()
if(IS_ABSOLUTE "./CMakeLists.txt")
else()
    message("./CMakeLists.txt is not full path")
endif()
# 命令行中执行cmake .后的输出
/tmp/testfile is full path
~ regard as full path
./CMakeLists.txt is not full path

3.5 变量比较操作

  比较操作可以分为三大类:1)正则表达式匹配;2)按数值大小;3)按字典序。

3.5.1 正则表达式比较
  • if(<variable|string> MATCHES regex):正则表达式regex的格式可以参考这里
# CMakeLists.txt
if("test" MATCHES .*)
    message("match any")
endif()
if("t" MATCHES .)
    message("match sigle char")
endif()
# 命令行中执行cmake .后的输出
match any
match sigle char
3.5.2 数值比较

  数值比较有小于(LESS)、大于(GREATER)、等于(EQUAL)、大于等于(GREATER_EQUAL)、小于等于(LESS_EQUAL)五种。需要注意:比较的两个变量是有效的数值,例如100、200这些是有效数值,"100"、"200"也是有效数值,但是"a100"、"200c"就不是有效数值。如果任意一个不是有效数值,会返回false

# CMakeLists.txt
if("a100" GREATER 50)
else()
    message("unvalid number a100")
endif()

if("100" GREATER "50")
    message("GREATER")
endif()

if("2" LESS "3")
    message("LESS")
endif()

if(5 EQUAL 5)
    message("EQUAL")
endif()

if(5 LESS_EQUAL 5)
    message("LESS_EQUAL - actual equal")
endif()
if(5 LESS_EQUAL 6)
    message("LESS_EQUAL")
endif()


if(5 GREATER_EQUAL 5)
    message("GREATER_EQUAL - actual equal")
endif()
if("7" GREATER_EQUAL 6)
    message("GREATER_EQUAL")
endif()
# 命令行中执行cmake .后的输出
unvalid number a100
GREATER
LESS
EQUAL
LESS_EQUAL - actual equal
LESS_EQUAL
GREATER_EQUAL - actual equal
GREATER_EQUAL
3.5.3 字典序比较

  数值比较有小于(STRLESS)、大于(STRGREATER)、等于(STREQUAL)、大于等于(STRGREATER_EQUAL)、小于等于(STRLESS_EQUAL)五种,注意不管是数还是字符串,都是按照字典序进行比较

# CMakeLists.txt
if(21 STRLESS 3)
    message("STRLESS - number")
endif()
if("21" STRLESS "3")
    message("STRLESS - string")
endif()

if("abc" STREQUAL "abc")
    message("STREQUAL")
endif()

if(5 STRGREATER 200000)
    message("STRGREATER - number")
endif()
if("5" STRGREATER "200000")
    message("STRGREATER - string")
endif()

if("abc" STRLESS_EQUAL "abc")
    message("STRLESS_EQUAL - actual equal")
endif()
if("abc" STRLESS_EQUAL "b")
    message("STRLESS_EQUAL")
endif()

if("abc" STRGREATER_EQUAL "abc")
    message("STRGREATER_EQUAL - actual equal")
endif()
if("abc" STRGREATER_EQUAL "abb")
    message("STRGREATER_EQUAL")
endif()
# 命令行中执行cmake .后的输出
STRLESS - number
STRLESS - string
STREQUAL
STRGREATER - number
STRGREATER - string
STRLESS_EQUAL - actual equal
STRLESS_EQUAL
STRGREATER_EQUAL - actual equal
STRGREATER_EQUAL

3.6 版本号比较

  版本号比较也有VERSION_LESSVERSION_GREATERVERSION_EQUALVERSION_LESS_EQUALVERSION_GREATER_EQUAL五种,需要注意两点:

  • 版本号的格式为major[.minor[.patch[.tweak]]]的四段点分格式,每部分都是一个整数值;
  • 如果版本号不是一个有效的整数,那么会从非数字的地方到尾部全部截断。例如1.2a22.3.4会截断成1.2a后的部分全部被丢弃。如果最开始就是非数字,那么版本号被当成0
# CMakeLists.txt
if(1.2.3.4 VERSION_GREATER 1.2a.3.5)
    message("VERSION_GREATER - truncate")
endif()

if(1.2.3.4 VERSION_LESS 1.2.3.5)
    message("VERSION_LESS")
endif()

if(1.2.3.4 VERSION_GREATER 1.1)
    message("VERSION_GREATER")
endif()

if(1.2.3.4 VERSION_EQUAL 1.2.3.4)
    message("VERSION_EQUAL")
endif()

if(1.2.3.4 VERSION_LESS_EQUAL 1.2.3.4)
    message("VERSION_LESS_EQUAL - actual equal")
endif()
if(1.2.3.4 VERSION_LESS_EQUAL 1.2.3.5)
    message("VERSION_LESS_EQUAL")
endif()

if(1.2.3.4 VERSION_GREATER_EQUAL 1.2.3.4)
    message("VERSION_GREATER_EQUAL - actual equal")
endif()
if(1.2.3.4 VERSION_GREATER_EQUAL 1.2.3.2)
    message("VERSION_GREATER_EQUAL")
endif()
VERSION_GREATER - truncate
VERSION_LESS
VERSION_GREATER
VERSION_EQUAL
VERSION_LESS_EQUAL - actual equal
VERSION_LESS_EQUAL
VERSION_GREATER_EQUAL - actual equal
VERSION_GREATER_EQUAL

3.7 变量展开

  对于if(${var})这种形式,很容易理解是要将变量var的值放到if中进行判断。但是由于在CMake中,if表达式出现的比${}要早,因此早期对于if(var)这种形式,var到底是按照变量还是值/字符串来解析?CMake的做法是:首先看var是否是一个已经定义的变量,如果是,则需要将他的值替换到if中,否则就直把var当成一个字符串/值。
  来看一个例子:

set(var "NO")
if(var)
    message("true for ${var}")
else()
    message("false for ${var}")
endif()

  此处的var是一个已经定义好的变量,因此if判断转化为if("NO"),它会按照if(<constant>)最终的判定结果是false,因此上面的执行结果输出false for NO。如果没有set(var "NO")这句定义,那么if判断转为if(<variable>),因为变量不存在而判定为false

  来看一个稍微复杂一点的例子:

set(var "NO")
set(var2 "var")
if(${var2}) # 首先会解析${var2},因此等价于if(var),进而等价于if("NO")
    message("true for ${var2}")
else()
    message("false for ${var2}")
endif()

  在if命令执行之前,${var2}首先会执行,会替换成变量var2的值,因此变成if(var),然后仍然会先去判断var是否是一个已经定义好的变量。因此后续的执行过程与上个例子一样。if判断转化为if("NO"),它会按照if(<constant>)最终的判定结果是false,输出false for NO。如果没有set(var "NO")这句赋值,那么if判断转为if(<variable>),因为变量不存在而判定为false。当然,如果把if(${var2})替换成if(var2),会转化成if("var"),那么if判断转为if(<string>),字符串结果判定为true.

set(var "NO")
set(var2 "var")
if(var2) # var2是变量,因此等价于if("var"),此时"var"会当成字符串而不是变量
    message("true for ${var2}")
else()
    message("false for ${var2}")
endif()

附录:参考文档

  1. https://cmake.org/cmake/help/latest/command/if.html
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • 1. Directory 当CMake处理一个项目时,入口点是一个名为CMakeLists.txt的源文件,这个一...
    Tony__Ren阅读 8,121评论 0 3
  • linux资料总章2.1 1.0写的不好抱歉 但是2.0已经改了很多 但是错误还是无法避免 以后资料会慢慢更新 大...
    数据革命阅读 12,018评论 2 34
  • 搬运自本人 CSDN 博客:https://blog.csdn.net/ajianyingxiaoqinghan/...
    琦小虾阅读 14,939评论 0 11
  • CMake 全称“cross platform make”,是开源、跨平台的自动化构建系统。CMake 由 Kit...
    神齐阅读 3,909评论 0 6