CMake入門

文章翻譯自:CMake Tutorial

第一步 | 第二步 | 第三步 | 第四步 | 第五步 | 第六步 | 第七步

下面會一步一步的來教你如何使用CMake完成軟件的構(gòu)建系統(tǒng)。大部分章節(jié)在Mastering CMake都有專門的介紹倡鲸,但是把他們整理在一起還是非常有用的证薇。本教程可以在CMake的源碼目錄中的Tests/Tutorial目錄找到施禾。每一步都有它自己的子目錄,子目錄有完整的源代碼表制。

<a name="s1" id="s1"></a>

基本使用方法(第一步)

最常見的工程都是從源代碼文件構(gòu)建出可執(zhí)行程序。最簡單的CMakeLists.txt文件只需要兩行,我們就從這個文件開始抑党。CMakeLists 文件是這樣的。

cmake_minimum_required (VERSION 2.6)
project(Tutorial)
add_executable(Tutorial tutorial.cxx)

需要說明一下本例程中CMakeLists文件都使用小寫的命令撵摆。對于大寫底靠,小寫,大小寫混合的命令書寫方法特铝,CMake都支持暑中。tutorial.cxx的源碼用來計算一個數(shù)字的平方根,第一個版本非常簡單鲫剿,如下:

// A simple program that computes the square root of a number
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(int argc, char *argv[])
{
    if (argc < 2) {
        printf("Usage: %s number\n", argv[0]);
        return 1;
    }
    double inputValue = atof(argv[1]);
    double outputValue = sqrt(inputValue);
    printf("The square root of %g is %g\n", inputValue, outputValue);
    return 0;
}

假如CMakeList.txt和tutorial.cxx文件都存放在~/cmake_tutorial目錄鳄逾,使用如下命令就可以構(gòu)建出tutorial執(zhí)行文件:

# mkdir ~/cmake_tutorial/build
# cd ~/cmake_tutorial/build
# cmake -G "Unix Makefiles" ..
# make 
# ./Tutorial 9
The square root of 9 is 3

添加版本號和配置頭文件

我們給工程添加的第一個功能就是版本號。當然了牵素,你也可以專門修改源代碼严衬,但是通過CMakeLists有更大的靈活性。為了增加版本號笆呆,CMakeLists 文件如下:

cmake_minimum_required (VERSION 2.6)
project(Tutorial)

# The version number.
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 0)

# configure a header file to pass some of the CMake settings
# to the source code
configure_file (
    "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
    "${PROJECT_BINARY_DIR}/TutorialConfig.h"
    )

# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
include_directories("${PROJECT_BINARY_DIR}")
     
# add the executable
add_executable(Tutorial tutorial.cxx)

因為我們把配置文件寫入到了二進制目錄中请琳,所有,我們需要把二進制目錄加入到包含目錄中赠幕。在源代碼目錄中俄精,我們新建TutorialConfig.h.in文件,內(nèi)容如下:

// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

CMake 會使用 CMakeLists 文件中的Tutorial_VERSION_MAJORTutorial_VERSION_MINOR 值替換配置文件的@Tutorial_VERSION_MAJOR@@Tutorial_VERSION_MINOR@榕堰。接下來竖慧,我們修改Tutorial.cxx,讓它包含配置頭文件逆屡,使用版本號圾旨。最后的源代碼文件如下:

// A simple program that computes the square root of a number
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "TutorialConfig.h"

int main(int argc, char *argv[])
{
    if (argc < 2) {
        printf("%s Version %d.%d\n",
            argv[0],
            Tutorial_VERSION_MAJOR,
            Tutorial_VERSION_MINOR);
        printf("Usage: %s number\n", argv[0]);
        return 1;
    }
    double inputValue = atof(argv[1]);
    double outputValue = sqrt(inputValue);
    printf("The square root of %g is %g\n", inputValue, outputValue);
    return 0;
}

主要的修改就是包含了TutorialConfig.h頭文件,在使用消息中打印了版本號魏蔗。
執(zhí)行的命令如下:

# cmake .. 
# make
# ./Tutorial
Tutorial Version 1.0
Usage: Tutorial number

<a name="s2" id="s2"></a>

添加一個庫(第二步)

現(xiàn)在我們添加一個庫到工程中砍的。這個庫是我們自己實現(xiàn)的求平方根≥褐危可執(zhí)行文件使用我們自己的庫替換由編譯器提供的求平方根函數(shù)廓鞠。在這個教程中帚稠,我們把庫源文件放到MathFunctions,這個單獨的目錄中床佳。只需要一行的CMakeLists就足夠了:

add_library(MathFunctions mysqrt.cxx)

mysqrt.cxx文件只有一個函數(shù)叫mysqrt滋早,mysqrt和編譯器提供的sqrt提供相同的功能。為了使用新庫砌们,我們在頂層的CMakeLists文件中調(diào)用add_subdirectory杆麸,這樣庫才會被編譯。我們還需要把MathFunctions目錄添加到包含目錄中浪感,這樣才能找到MathFunctions/mysqrt.h文件角溃。最后,還需要把新庫添加到可執(zhí)行文件中篮撑。最終的CMakeLists的最后幾行是這樣的:

include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions")
add_subdirectory (MathFunctions) 
     
# add the executable
add_executable (Tutorial tutorial.cxx)
target_link_libraries (Tutorial MathFunctions)

現(xiàn)在我們考慮使用MathFunctions作為可選項。在本教程中匆瓜,沒有理由需要這么做赢笨,但是,對于更大的庫或依賴第三方代碼的庫驮吱,你可能就原因這么做了茧妒。第一步在頂層CMakeLists文件中添加一個選項:

# should we use our own math functions?
option (USE_MYMATH 
        "Use tutorial provided math implementation" ON) 

這會在CMake GUI中顯示默認值為ON的選項,用戶可以根據(jù)需要修改左冬。這個配置會存儲在緩存中桐筏,在用戶下次CMake工程時,不需要重新配置這個選項拇砰。下一個修改是梅忌,通過配置確定是否需要編譯、鏈接MathFunctions除破。我們把頂層CMakeLists文件的最后幾行修改成這樣:

# add the MathFunctions library?
#
if (USE_MYMATH)
  include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions")
  add_subdirectory (MathFunctions)
  set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)
 
# add the executable
add_executable (Tutorial tutorial.cxx)
target_link_libraries (Tutorial  ${EXTRA_LIBS})

使用USE_MYMATH配置來確定是否需要編譯和使用MathFunctions牧氮。使用變量(本教程中的EXTRA_LIBS)來收集可選庫,然后瑰枫,鏈接進可執(zhí)行文件中踱葛。這是一個通用的方法來保持有很多可選庫的大工程的清晰性。對源代碼的修改已經(jīng)很直截了當了:

// A simple program that computes the square root of a number
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "TutorialConfig.h"
#ifdef USE_MYMATH
#include "MathFunctions.h"
#endif
 
int main (int argc, char *argv[])
{
  if (argc < 2)
    {
    printf("%s Version %d.%d\n", argv[0],
            Tutorial_VERSION_MAJOR,
            Tutorial_VERSION_MINOR);
    printf(stdout,"Usage: %s number\n",argv[0]);
    return 1;
    }
 
  double inputValue = atof(argv[1]);
 
#ifdef USE_MYMATH
  double outputValue = mysqrt(inputValue);
#else
  double outputValue = sqrt(inputValue);
#endif
 
  printf("The square root of %g is %g\n",
          inputValue, outputValue);
  return 0;
}

在源碼中光坝,我們同樣使用了USE_MYMATH尸诽。這是通過在TutorialConfig.h.in配置文件中添加下面的內(nèi)容實現(xiàn)的:

#cmakedefine USE_MYMATH

<a name="s3" id="s3"></a>

安裝和測試(第三步)

在這一步中,我們給工程添加安裝規(guī)則和測試支持盯另。安裝規(guī)則已經(jīng)很明顯了性含。對于MathFunctions庫,我們需要安裝庫文件和頭文件土铺,在MathFunctions/CMakeLists中間添加下面兩行:

install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)

對于程序文件胶滋,我們在頂層CMakeLists文件中添加下面幾行來安裝可以執(zhí)行文件和配置文件:

# add the install targets
install (TARGETS Tutorial DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"        
         DESTINATION include)

到此已經(jīng)全部做完了“鬻蓿現(xiàn)在,你可以構(gòu)建本教程究恤,執(zhí)行make install(或在IDE中構(gòu)建INSTALL目標)俭令,將會安裝合適的頭文件、庫文件部宿、可執(zhí)行文件抄腔。CMake變量CMAKE_INSTALL_PREFIX用來確定文件安裝的根目錄。添加測試也已經(jīng)很明顯了理张。在頂層CMakeLists文件的最后赫蛇,我們使用一些計算好的數(shù)字來驗證程序是否正確運行:

# does the application run
add_test (TutorialRuns Tutorial 25)
 
# does it sqrt of 25
add_test (TutorialComp25 Tutorial 25)
 
set_tests_properties (TutorialComp25 
  PROPERTIES PASS_REGULAR_EXPRESSION "25 is 5")
 
# does it handle negative numbers
add_test (TutorialNegative Tutorial -25)
set_tests_properties (TutorialNegative
  PROPERTIES PASS_REGULAR_EXPRESSION "-25 is 0")
 
# does it handle small numbers
add_test (TutorialSmall Tutorial 0.0001)
set_tests_properties (TutorialSmall
  PROPERTIES PASS_REGULAR_EXPRESSION "0.0001 is 0.01")
 
# does the usage message work?
add_test (TutorialUsage Tutorial)
set_tests_properties (TutorialUsage
  PROPERTIES 
  PASS_REGULAR_EXPRESSION "Usage:.*number")

第一個測試簡單的驗證程序是否可以執(zhí)行,有沒有段錯誤或其他原因?qū)е碌谋罎⑽戆龋⑶曳祷刂禐椋拔蛟拧_@個是最基本的CTest測試。接下來幾個測試都使用PASS_REGULAR_EXPRESSION測試屬性來驗證程序的輸出是否滿足特定的規(guī)則织狐。這些測試案例都是用來驗證程序計算出的平方根是否是正確的和在錯誤參數(shù)時暂幼,是否打印出使用方法。如果移迫,你需要驗證更多的數(shù)字旺嬉,你可以考慮使用下面的宏:

#define a macro to simplify adding tests, then use it
macro (do_test arg result)
  add_test (TutorialComp${arg} Tutorial ${arg})
  set_tests_properties (TutorialComp${arg}
    PROPERTIES PASS_REGULAR_EXPRESSION ${result})
endmacro (do_test)
 
# do a bunch of result based tests
do_test (25 "25 is 5")
do_test (-25 "-25 is 0")

每次調(diào)用do_test都會添加名稱、輸入厨埋、結(jié)果基于參數(shù)的測試案例邪媳。

<a name="s4" id="s4"></a>

添加系統(tǒng)內(nèi)省(第四步)

接下來,讓我們根據(jù)目標平臺是否支持某些特性荡陷,來增加一些代碼到我們的工程雨效。比如這個例子,我們通過判斷目標平臺是否支持logexp函數(shù)废赞,來確定是否啟用代碼设易。當然了,幾乎所有的平臺都支持這些函數(shù)蛹头,但對于本教授假設(shè)它們是不太常見的顿肺。如果平臺有log函數(shù),我們在mysqrt中用于記錄平方根渣蜗。我們首先在最上層的CMakeLists.txt里面屠尊,使用CheckFunctionExists.cmake宏來檢測是否有這些行數(shù)。

# does this system provide the log and exp functions?
include (CheckFunctionExists)
check_function_exists (log HAVE_LOG)
check_function_exists (exp HAVE_EXP)

接著我們在TutorialConfig.h.in定義以下變量

// does the platform provide exp and log functions?
#cmakedefine HAVE_LOG
#cmakedefine HAVE_EXP

一定要在logexp檢測完成后耕拷,才能使用configure_file命令讼昆。configure_file命令使用當前的設(shè)置生成配置文件。最后骚烧,我們根據(jù)平臺是否存在logexp函數(shù)浸赫,來完成不同的mysqrt函數(shù)

// if we have both log and exp then use them
#if defined (HAVE_LOG) && defined (HAVE_EXP)
  result = exp(log(x)*0.5);
#else // otherwise use an iterative approach
  . . .

<a name="s5" id="s5"></a>

添加一個生成的文件和文件生成器(第五步)

在本章節(jié)中闰围,我們將向你展示如何在軟件的構(gòu)建過程中添加一個生成的源文件。在這個例子中既峡,我們將把預(yù)先計算好平方根的表格添加到構(gòu)建過程中魔招,并且把表格編譯進軟件中作谚。為了完成這個例子,我們首先需要一個程序來生成表格。在MathFunctions的子目錄尚洽,新建文件MakeTable.cxx來生成表格刨沦。

// A simple program that builds a sqrt table 
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
 
int main (int argc, char *argv[])
{
  int i;
  double result;
 
  // make sure we have enough arguments
  if (argc < 2)
    {
    return 1;
    }
  
  // open the output file
  FILE *fout = fopen(argv[1],"w");
  if (!fout)
    {
    return 1;
    }
  
  // create a source file with a table of square roots
  fprintf(fout,"double sqrtTable[] = {\n");
  for (i = 0; i < 10; ++i)
    {
    result = sqrt(static_cast<double>(i));
    fprintf(fout,"%g,\n",result);
    }
 
  // close the table with a zero
  fprintf(fout,"0};\n");
  fclose(fout);
  return 0;
}

另外记盒,這個表格是有效的C++代碼体啰,表格保存的文件名通過命令行參數(shù)傳遞。接著我們在MathFunctions的CMakeLists.txt文件中添加合適的命令來生成MakeTable可執(zhí)行文件卦方,并且在構(gòu)建過程中執(zhí)行它羊瘩。需要幾個命令來實現(xiàn)這個目的,如下所示:

# first we add the executable that generates the table
add_executable(MakeTable MakeTable.cxx)
 
# add the command to generate the source code
add_custom_command (
  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
  COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
  DEPENDS MakeTable
  )
 
# add the binary tree directory to the search path for 
# include files
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )
 
# add the main library
add_library(MathFunctions mysqrt.cxx ${CMAKE_CURRENT_BINARY_DIR}/Table.h  )

首先添加命令生成MakeTable的可執(zhí)行文件盼砍。然后添加自定義命令指定如何使用MakeTable生成Table.h文件困后。接著,通過把生成的文件Table.h添加到MathFunctions庫的源文件列表衬廷,我們讓CMake知道m(xù)ysqrt.cxx依賴生成的文件Table.h。我們還需要把當前二進制目錄添加到包含目錄列表中汽绢,所以mysqrt.cxx才能包含Table.h吗跋,并且在包含目錄中發(fā)現(xiàn)Table.h。當工程被構(gòu)建時宁昭,首先構(gòu)建MakeTable可執(zhí)行文件跌宛,接著運行MakeTable生成Table.h。最后积仗,編譯包含Table.h的mysqrt.cxx文件生成MathFunctions庫疆拘。這時,所有功能已完成的最上層的CMakeList.txt文件看起來是這樣的:

cmake_minimum_required (VERSION 2.6)
project (Tutorial)
include(CTest)
 
# The version number.
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 0)
 
# does this system provide the log and exp functions?
include (${CMAKE_ROOT}/Modules/CheckFunctionExists.cmake)
 
check_function_exists (log HAVE_LOG)
check_function_exists (exp HAVE_EXP)
 
# should we use our own math functions
option(USE_MYMATH 
  "Use tutorial provided math implementation" ON)
 
# configure a header file to pass some of the CMake settings
# to the source code
configure_file (
  "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
  "${PROJECT_BINARY_DIR}/TutorialConfig.h"
  )
 
# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
include_directories ("${PROJECT_BINARY_DIR}")
 
# add the MathFunctions library?
if (USE_MYMATH)
  include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions")
  add_subdirectory (MathFunctions)
  set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)
 
# add the executable
add_executable (Tutorial tutorial.cxx)
target_link_libraries (Tutorial  ${EXTRA_LIBS})
 
# add the install targets
install (TARGETS Tutorial DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"        
         DESTINATION include)
 
# does the application run
add_test (TutorialRuns Tutorial 25)
 
# does the usage message work?
add_test (TutorialUsage Tutorial)
set_tests_properties (TutorialUsage
  PROPERTIES 
  PASS_REGULAR_EXPRESSION "Usage:.*number"
  )
 
 
#define a macro to simplify adding tests
macro (do_test arg result)
  add_test (TutorialComp${arg} Tutorial ${arg})
  set_tests_properties (TutorialComp${arg}
    PROPERTIES PASS_REGULAR_EXPRESSION ${result}
    )
endmacro (do_test)
 
# do a bunch of result based tests
do_test (4 "4 is 2")
do_test (9 "9 is 3")
do_test (5 "5 is 2.236")
do_test (7 "7 is 2.645")
do_test (25 "25 is 5")
do_test (-25 "-25 is 0")
do_test (0.0001 "0.0001 is 0.01")

TutorialConfig.h.in是這樣的:

// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
#cmakedefine USE_MYMATH
 
// does the platform provide exp and log functions?
#cmakedefine HAVE_LOG
#cmakedefine HAVE_EXP

MathFunctions的CMakeLists.txt如下:

# first we add the executable that generates the table
add_executable(MakeTable MakeTable.cxx)
# add the command to generate the source code
add_custom_command (
  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
  DEPENDS MakeTable
  COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
  )
# add the binary tree directory to the search path 
# for include files
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )
 
# add the main library
add_library(MathFunctions mysqrt.cxx ${CMAKE_CURRENT_BINARY_DIR}/Table.h)
 
install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)

<a name="s6" id="s6"></a>

構(gòu)建安裝包(第六步)

接下來寂曹,假設(shè)我們想要把我們的工程分發(fā)給其他人哎迄,以便他們可以使用它。我們想要在不同的平臺分發(fā)二進制和源碼隆圆。這里的安裝和我們在之前的章節(jié)安裝和測試(第三步)中的是有些區(qū)別的漱挚,在第三步我們編譯源代碼后,直接安裝二進制文件渺氧。在本例子中旨涝,我們將要構(gòu)建二進制安裝包,可以在包管理系統(tǒng)中使用侣背,例如:cygwin白华,debian慨默,RPMs等等。我們使用CPack來創(chuàng)建平臺相關(guān)的安裝包弧腥。我們需要在最上層的CMakeLists.txt的尾部添加一些代碼:

# build a CPack driven installer package
include (InstallRequiredSystemLibraries)
set (CPACK_RESOURCE_FILE_LICENSE  
     "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
set (CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
set (CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
include (CPack)

做起來很簡單厦取。我們從包含InstallRequiredSystemLibraries開始。這個模塊會包含當前平臺需要使用的運行時庫鸟赫。接下來我們設(shè)置一些CPack變量蒜胖,比如:版權(quán)許可文件目錄,軟件版本信息抛蚤。在本教程的開始部分台谢,我們已經(jīng)設(shè)置好了版本信息。最后我們包含CPack模塊岁经,它會使用這些變量和其他的系統(tǒng)屬性去生成安裝包朋沮。
  下一步,正常的構(gòu)建工程缀壤,然后運行CPack樊拓。建立一個二進制分發(fā),你可以運行:

cpack --config CPackConfig.cmake

建立一個源碼分發(fā)塘慕,你可以運行:

cpack --config CPackSourceConfig.cmake

<a name="s7" id="s7"></a>

添加儀表盤(Dashboard)支持(第七步)

把我們的測試結(jié)果提交到儀表盤是非常簡單的筋夏。在本教程前面的步驟中,我們已經(jīng)定義了一些測試用例图呢。我們只需要運行這些測試用例条篷,并且提交結(jié)果到儀表盤。為了支持儀表盤蛤织,我們需要在最上層的CMakeLists.txt中包含CTest模塊赴叹。

# enable dashboard scripting
include (CTest)

我們需要新建CTestConfig.cmake,在文件中定義本項目在儀表盤中的名稱指蚜。

set (CTEST_PROJECT_NAME "Tutorial")

CTest在執(zhí)行時會讀取這個文件乞巧。你可以使用CMake為你的項目創(chuàng)建一個簡單的儀表盤,把目錄切換到二進制目錄摊鸡,然后運行ctest -D Experimental绽媒。你的儀表盤的結(jié)果會提交到Kitware的公共儀表盤這里

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市免猾,隨后出現(xiàn)的幾起案子些椒,更是在濱河造成了極大的恐慌,老刑警劉巖掸刊,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件免糕,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機石窑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門牌芋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人松逊,你說我怎么就攤上這事躺屁。” “怎么了经宏?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵犀暑,是天一觀的道長。 經(jīng)常有香客問我烁兰,道長耐亏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任沪斟,我火速辦了婚禮广辰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘主之。我一直安慰自己择吊,他們只是感情好,可當我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布槽奕。 她就那樣靜靜地躺著几睛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪粤攒。 梳的紋絲不亂的頭發(fā)上所森,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天,我揣著相機與錄音琼讽,去河邊找鬼。 笑死洪唐,一個胖子當著我的面吹牛钻蹬,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播凭需,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼问欠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了粒蜈?” 一聲冷哼從身側(cè)響起顺献,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎枯怖,沒想到半個月后注整,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年肿轨,在試婚紗的時候發(fā)現(xiàn)自己被綠了寿冕。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡椒袍,死狀恐怖驼唱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情驹暑,我是刑警寧澤玫恳,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站优俘,受9級特大地震影響京办,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜兼吓,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一臂港、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧视搏,春花似錦审孽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至筋遭,卻和暖如春打颤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背漓滔。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工编饺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人响驴。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓透且,卻偏偏與公主長得像,于是被迫代替她去往敵國和親豁鲤。 傳聞我的和親對象是個殘疾皇子秽誊,可洞房花燭夜當晚...
    茶點故事閱讀 44,689評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Cmake 入門 前言 CMake是一個比make更高級的編譯配置工具,它可以根據(jù)不同平臺琳骡、不同的編譯器锅论,生成相應(yīng)...
    渝潼不肖生閱讀 2,074評論 1 5
  • CMake學(xué)習(xí) 本篇分享一下有關(guān)CMake的一些學(xué)習(xí)心得以及相關(guān)使用。 本文目錄如下: [1楣号、CMake介紹] [...
    AlphaGL閱讀 12,246評論 11 79
  • 注:首發(fā)地址 1. 前言 當在做 Android NDK 開發(fā)時最易,如果不熟悉用 CMake 來構(gòu)建怒坯,讀不懂 CMa...
    cfanr閱讀 24,374評論 1 53
  • 老來平平過,無病無災(zāi)禍耘纱。 兒孫個個賢敬肚,錢財算什么! 老來先賦閑束析,莫等退休后艳馒。 素食主三餐,難得老來瘦员寇。 起床迎日出...
    葉祿青閱讀 1,078評論 0 0
  • 兔子先生和兔子小姐她們不是情侶弄慰,是最好的閨蜜,互相關(guān)心蝶锋,互相照顧陆爽。一個性格開朗,一個內(nèi)斂扳缕,互相填補著彼此的不足慌闭。 ...
    兔子先生和兔子小姐閱讀 2,693評論 1 1