CMake簡要教程

CMake是我非常喜歡且一直使用的工具臼予。它不但能幫助我跨平臺、跨編譯器啃沪,而且最酷的是粘拾,它幫我節(jié)約了太多的存儲空間。特別是與水銀結(jié)合起來使用创千,其友好的體驗缰雇,足以給我們這些苦逼碼農(nóng)一絲慰藉。

以下內(nèi)容翻譯自官網(wǎng)教程

CMake Tutorial

A Basic Starting Point (Step 1)

最基本的就是將一個源代碼文件編譯成一個exe可執(zhí)行程序追驴。對于一個簡單的工程來說械哟,兩行的CMakeLists.txt文件就足夠了。這將是我們教程的開始殿雪。CMakeLists.txt文件看起來會像這樣:

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

注意暇咆,在這個例子中,CMakeLists.txt都是使用的小寫字母丙曙。事實上爸业,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)
    {
    fprintf(stdout,"Usage: %s number\n",argv[0]);
    return 1;
    }
  double inputValue = atof(argv[1]);
  double outputValue = sqrt(inputValue);
  fprintf(stdout,"The square root of %g is %g\n",
          inputValue, outputValue);
  return 0;
}

Adding a Version Number and Configured Header File

我們第一個要加入的特性是,在工程和可執(zhí)行程序上加一個版本號逼肯。雖然你可以直接在源代碼里面這么做耸黑,然而如果用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) 

由于配置文件必須寫到binary tree中崎坊,因此我們必須將這個目錄添加到頭文件搜索目錄中备禀。我們接下來在源碼目錄中創(chuàng)建了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@

當(dāng)CMake配置了這個頭文件奈揍, @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)
    {
    fprintf(stdout,"%s Version %d.%d\n",
            argv[0],
            Tutorial_VERSION_MAJOR,
            Tutorial_VERSION_MINOR);
    fprintf(stdout,"Usage: %s number\n",argv[0]);
    return 1;
    }
  double inputValue = atof(argv[1]);
  double outputValue = sqrt(inputValue);
  fprintf(stdout,"The square root of %g is %g\n",
          inputValue, outputValue);
  return 0;
}

最主要的變更是包含了TutorialConfig.h頭文件,并輸出了版本號纽乱。

Adding a Library (Step 2)

現(xiàn)在我們給工程添加一個庫蛾绎。這個庫會包含我們自己的平方根實現(xiàn)柴我。如此宰睡,應(yīng)用程序就可以使用這個庫而非編譯器提供的庫了。在這個教程中遏片,我們將庫放入一個叫MathFunctions的子文件夾中薯嗤。它會使用如下的一行CMakeLists文件:

add_library(MathFunctions mysqrt.cxx)

原文件mysqrt.cxx有一個叫做mysqrt的函數(shù)可以提供與編譯器的sqrt相似的功能顽爹。為了使用新的庫,我們需要在頂層的CMakeLists 文件中添加add_subdirectory的調(diào)用骆姐。我們也要添加一個另外的頭文件搜索目錄镜粤,使得MathFunctions/mysqrt.h可以被搜索到。最后的改變就是將新的庫加到可執(zhí)行程序中玻褪。頂層的CMakeLists 文件現(xiàn)在看起來是這樣:

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庫成為可選的肉渴。雖然在這個教程當(dāng)中沒有什么理由這么做,然而如果使用更大的庫或者當(dāng)依賴于第三方的庫時带射,你或許希望這么做同规。第一步是要在頂層的CMakeLists文件中加上一個選擇項。

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

這個選項會顯示在CMake的GUI窟社,并且其默認值為ON捻浦。當(dāng)用戶選擇了之后,這個值會被保存在CACHE中桥爽,這樣就不需要每次CMAKE都進行更改了朱灿。下面一步條件構(gòu)建和鏈接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的使用方法缀去。這是保持一個大的項目看起來比較簡潔的一個方法侣灶。源代碼中相應(yī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)
    {
    fprintf(stdout,"%s Version %d.%d\n", argv[0],
            Tutorial_VERSION_MAJOR,
            Tutorial_VERSION_MINOR);
    fprintf(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
 
  fprintf(stdout,"The square root of %g is %g\n",
          inputValue, outputValue);
  return 0;
} 

在源代碼中我們同樣使用了USE_MYMATH這個宏。它由CMAKE通過配置文件TutorialConfig.h.in來提供給源代碼缕碎。

#cmakedefine USE_MYMATH

Installing and Testing (Step 3)

接下來我們會為我們的工程增加安裝規(guī)則和測試支持褥影。安裝規(guī)則是非常非常簡單的。對于MathFunctions庫我們安裝庫和頭文件只需要添加如下的語句:

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

對于應(yīng)用程序咏雌,我們只需要在頂層CMakeLists 文件中如此配置即可以安裝可執(zhí)行程序和配置了的頭文件:

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

這就是所有需要做的》苍酰現(xiàn)在你就可以編譯這個教程了校焦,然后輸入make install(或者編譯IDE中的INSTALL目標),則頭文件统倒、庫和可執(zhí)行程序等就會被正確地安裝寨典。CMake變量CMAKE_INSTALL_PREFIX被用來決定那些文件會被安裝在哪個根目錄下。添加測試也是一個相當(dāng)簡單的過程房匆。在最頂層的CMakeLists文件的最后我們可以添加一系列的基礎(chǔ)測試來確認這個程序是否在正確工作耸成。

# 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")

第一個測試簡單地確認應(yīng)用是否運行,沒有段錯誤或者其它的崩潰問題浴鸿,并且返回0井氢。這是CTest的最基本的形式。下面的測試都使用了PASS_REGULAR_EXPRESSION測試屬性來確認輸出的結(jié)果中是否含有某個字符串岳链。如果你需要添加大量的測試來判斷不同的輸入值毙沾,則你需要考慮創(chuàng)建一個類似于下面的宏:

#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")

對do_test的任意一次調(diào)用,就有另一個測試被添加到工程中宠页。

Adding System Introspection (Step 4)

接下來左胞,我們來考慮添加一些有些目標平臺可能不支持的代碼。在這個樣例中举户,我們將根據(jù)目標平臺是否有l(wèi)og和exp函數(shù)來添加我們的代碼烤宙。當(dāng)然大多數(shù)平臺都是有這些函數(shù)的,只是本教程假設(shè)這兩個函數(shù)沒有被那么普遍地支持俭嘁。如果平臺有l(wèi)og躺枕,那么在mysqrt中,就用它來計算平方根供填。我們首先使用CheckFunctionExists.cmake來測試這些函數(shù)的是否存在拐云,在頂層的CMakeLists文件中:

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

接下來我們修改TutorialConfig.h.in來定義CMake是否找到這些函數(shù)的宏

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

重要的一點是,對tests和log的測試必須要在配置文件命令前完成近她。配置文件命令會使用CMake中的配置立馬配置文件叉瘩。最后在mysqrt函數(shù)中我們提供了兩種實現(xiàn)方式:

// 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
  . . .

Adding a Generated File and Generator (Step 5)

在這一節(jié)當(dāng)中,我們會告訴你如何將一個生成的源文件加入到應(yīng)用程序的構(gòu)建過程中粘捎。在此例中薇缅,我們會創(chuàng)建一個預(yù)先計算好的平方根的表,并將這個表編譯到應(yīng)用程序中去攒磨。為了達到這個目的泳桦,我們首先需要一個程序來生成這樣的表。在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++代碼產(chǎn)生的灸撰,并且輸出文件的名字是由參數(shù)代入的。下一步就是添加合適的命令到MathFunctions的CMakeLists文件中來構(gòu)建MakeTable這個可執(zhí)行程序,并且作為構(gòu)建過程中的一部分浮毯。完成它需要一些命令完疫,如下:

# 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  )

首先,就像其它可執(zhí)行程序一樣亲轨,MakeTable被添加為可執(zhí)行程序趋惨。然后我們添加了一個自定義命令來詳細描述如何通過運行MakeTable來產(chǎn)生Table.h鸟顺。接下來惦蚊,我們需要讓CMake知道m(xù)ysqrt.cxx依賴于生成的文件Table.h。這是通過往MathFunctions這個庫里面添加生成的Table.h來實現(xiàn)的讯嫂。我們也需要添加當(dāng)前的生成目錄到搜索路徑中蹦锋,從而Table.h可以被mysqrt.cxx找到。

當(dāng)這個工程被構(gòu)建時欧芽,它首先會構(gòu)建MakeTable這個可執(zhí)行程序莉掂。然后運行MakeTable從而生成Table.h。最后千扔,它會編譯mysqrt.cxx來生成MathFunctions library憎妙。

在這一刻,我們添加了所有的特征到最頂層的CMakeLists文件曲楚,它現(xiàn)在看起來是這樣的:

cmake_minimum_required (VERSION 2.6)
project (Tutorial)
 
# 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是這樣的:

// 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文件看起來是這樣的:

# 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)

Building an Installer (Step 6)

最后假設(shè)我們想要把我們的工程發(fā)布給別人從而讓他們?nèi)ナ褂美逋佟N覀兿胍瑫r給他們不同平臺的二進制文件和源代碼。這與步驟3中的install略有不同龙誊,install是安裝我們從源代碼中構(gòu)建的二進制文件抚垃。而在此例中,我們將要構(gòu)建安裝包來支持二進制安裝以及cygwin趟大,debian鹤树,RPMs等的包管理特性。為了達到這個目的逊朽,我們會使用CPack來創(chuàng)建平臺相關(guān)的安裝包罕伯。具體地說,我們需要在頂層CMakeLists.txt文件中的底部添加數(shù)行叽讳。

# 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}")
set (CPACK_PACKAGE_VERSION_PATCH "${Tutorial_VERSION_PATCH}")
include (CPack)

這就是所有要做的捣炬。我們首先包含了InstallRequiredSystemLibraries。這個模塊將會包含當(dāng)前平臺所需要的所有運行時庫绽榛。接下來湿酸,我們設(shè)置了一些CPack的變量來保存license以及工程的版本信息。版本信息利用了我們在早前的教程中使用到的變量灭美。最后我們包含了CPack這個模塊來使用這些變量和你所使用的系統(tǒng)的其它特性來設(shè)置安裝包推溃。

接下來一步是用通常的方式構(gòu)建工程,然后在CPack上運行它届腐。如果要構(gòu)建一個二進制包你需要運行:

cpack --config CPackConfig.cmake

如果要創(chuàng)建一個關(guān)代碼包你需要輸入

cpack --config CPackSourceConfig.cmake

Adding Support for a Dashboard (Step 7)

將測試結(jié)果上傳到dashboard上是非常簡單的铁坎。我們在早前的步驟中已經(jīng)定義了一些測試蜂奸。我們僅需要運行這些例程然后提交到dashboard上。為了包含對dashboards的支持硬萍,我們需要在頂層的CMakeLists文件中包含CTest模塊扩所。

# enable dashboard scripting
include (CTest)

我們也創(chuàng)建了一個CTestConfig.cmake文件來指定這個工程在dashobard上的的名字。

set (CTEST_PROJECT_NAME "Tutorial")

CTest會讀這個文件并且運行它朴乖。如果要創(chuàng)建一個簡單的dashboard祖屏,你可以在你的工程上運行CMake,改變生成路徑的目錄买羞,然后運行ctest -D Experimental袁勺。你的dashboard的結(jié)果會被上傳到Kitware的公共dashboard中。

最后畜普,可以在這里下載到整個教程的源代碼期丰。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市吃挑,隨后出現(xiàn)的幾起案子钝荡,更是在濱河造成了極大的恐慌,老刑警劉巖舶衬,帶你破解...
    沈念sama閱讀 221,406評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件埠通,死亡現(xiàn)場離奇詭異,居然都是意外死亡约炎,警方通過查閱死者的電腦和手機植阴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來圾浅,“玉大人掠手,你說我怎么就攤上這事±瓴叮” “怎么了喷鸽?”我有些...
    開封第一講書人閱讀 167,815評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長灸拍。 經(jīng)常有香客問我做祝,道長,這世上最難降的妖魔是什么鸡岗? 我笑而不...
    開封第一講書人閱讀 59,537評論 1 296
  • 正文 為了忘掉前任混槐,我火速辦了婚禮,結(jié)果婚禮上轩性,老公的妹妹穿的比我還像新娘声登。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,536評論 6 397
  • 文/花漫 我一把揭開白布悯嗓。 她就那樣靜靜地躺著件舵,像睡著了一般。 火紅的嫁衣襯著肌膚如雪脯厨。 梳的紋絲不亂的頭發(fā)上铅祸,一...
    開封第一講書人閱讀 52,184評論 1 308
  • 那天,我揣著相機與錄音合武,去河邊找鬼临梗。 笑死,一個胖子當(dāng)著我的面吹牛眯杏,可吹牛的內(nèi)容都是我干的夜焦。 我是一名探鬼主播壳澳,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼岂贩,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了巷波?” 一聲冷哼從身側(cè)響起萎津,我...
    開封第一講書人閱讀 39,668評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎抹镊,沒想到半個月后锉屈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,212評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡垮耳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,299評論 3 340
  • 正文 我和宋清朗相戀三年颈渊,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片终佛。...
    茶點故事閱讀 40,438評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡俊嗽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出铃彰,到底是詐尸還是另有隱情绍豁,我是刑警寧澤,帶...
    沈念sama閱讀 36,128評論 5 349
  • 正文 年R本政府宣布牙捉,位于F島的核電站竹揍,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏邪铲。R本人自食惡果不足惜芬位,卻給世界環(huán)境...
    茶點故事閱讀 41,807評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望带到。 院中可真熱鬧昧碉,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至锹漱,卻和暖如春箭养,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背哥牍。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評論 1 272
  • 我被黑心中介騙來泰國打工毕泌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人嗅辣。 一個月前我還...
    沈念sama閱讀 48,827評論 3 376
  • 正文 我出身青樓撼泛,卻偏偏與公主長得像,于是被迫代替她去往敵國和親澡谭。 傳聞我的和親對象是個殘疾皇子愿题,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,446評論 2 359

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

  • CMake學(xué)習(xí) 本篇分享一下有關(guān)CMake的一些學(xué)習(xí)心得以及相關(guān)使用。 本文目錄如下: [1蛙奖、CMake介紹] [...
    AlphaGL閱讀 12,252評論 11 79
  • 文章翻譯自:CMake Tutorial 第一步 | 第二步 | 第三步 | 第四步 | 第五步 | 第六步 | ...
    汪坤閱讀 14,102評論 1 23
  • 注:首發(fā)地址 1. 前言 當(dāng)在做 Android NDK 開發(fā)時潘酗,如果不熟悉用 CMake 來構(gòu)建,讀不懂 CMa...
    cfanr閱讀 24,425評論 1 53
  • 人生路上有很多畫過妝的禮物雁仲,他們常常藏在丑陋的外表之下仔夺,上天給過的痛苦體驗有時只是想召喚人們停下匆忙的腳步,用心面...
    向陽花開開開閱讀 1,758評論 0 0
  • 兩個窮屌絲,兩張辦公桌吹艇,兩臺電腦加上N個兼職惰蜜。不說創(chuàng)造多少盈利吧,好歹勉強維持生活掐暮,這公司在外人看來恐怕都是很不值...
    佰聞客_劉宣閱讀 371評論 0 1