<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          關(guān)于CMake,這篇真的很到位!!

          共 24017字,需瀏覽 49分鐘

           ·

          2020-09-19 04:18


          關(guān)注、星標(biāo)公眾號,直達精彩內(nèi)容

          來源:txp玩Linux

          作者 : txp

          整理 :?李肖遙

          最近很多讀者在群里問道CMake的問題,與Makefile的差別等等,今天給大家整理了一篇文章,字?jǐn)?shù)較多,希望對大家有幫助。

          今天給大家分享的是工程管理工具cmake,沒有先介紹makefile工程管理工具(坦白來說,這兩者都差不多,cmake最終還是會生成Makefile的,只是說cmake語法稍微比較簡單一些,沒有Makefile那么復(fù)雜!)。

          就自己個人經(jīng)歷,現(xiàn)在一般公司去寫Makefile和cmake的比較少(當(dāng)然去招聘網(wǎng)站上,有的時候還是可以看到有這個技能要求會寫的,所以說能夠自己寫出來是最為完美的!),一般都是直接使用廠家的Makefile或者Cmake;

          但作為學(xué)習(xí),還是要認(rèn)真學(xué)習(xí)里面的原理,比如出現(xiàn)了錯誤,你要能夠定位到錯誤并把它解決掉,因為可能錯誤就出現(xiàn)在配置好的Makefile或者Cmake里面,所以你要看的懂里面代碼的意思(也就是說,你知道這個工具是這樣用,但是也要明白它的原理機制,做到之知其然,知其所以個然來!),這樣才能把問題解決掉。

          而且就個人見解,在傳統(tǒng)的linux工程管理用Makefile的比較多(Uboot里面也是大量使用Makefile來進行管理工程);在新型領(lǐng)域,比如物聯(lián)網(wǎng)開發(fā)(特別是一些開源項目等),用Cmake的比較多(當(dāng)然也有可能是例外哈!);好了,廢話就不多說了,開始來學(xué)習(xí)了:

          一、Cmake學(xué)習(xí)使用:

          1、安裝Cmake管理工具:

          一般實際嵌入式linux開發(fā),幾乎都是用Ubuntu來開發(fā)的,因為那啥,安裝啥應(yīng)用程序的非常方便,只需一個命令“apt install + 應(yīng)用程序名稱” 大部分都直接搞定,不用再去配置(特殊的,就例外,還要一些其他相關(guān)配置!),安裝Cmake就是一條命令直接搞定:

          root@txp-virtual-machine:/home/txp#?apt?install?cmake
          Reading?package?lists...?Done
          Building?dependency?tree????

          2、先從一個簡單示例,來得出一般書寫步驟規(guī)律:

          這里先寫一個簡單的代碼工程main.c,然后再使用我們的cmake來管理代碼工程:

          #include?

          int?main(void)
          {
          ????printf("TXP嵌入式\n");
          ????return?0;

          }

          然后開始寫cmake工程管理文件,我在當(dāng)前目錄建立一個CMakeLists.txt文件,然后再往里面開始工程管理代碼

          root@txp-virtual-machine:/home/txp/test#?pwd
          /home/txp/test
          root@txp-virtual-machine:/home/txp/test#?touch?CMakeLists.txt
          root@txp-virtual-machine:/home/txp/test#?ls
          CMakeLists.txt??main.c


          CMakeLists.txt文件里面的內(nèi)容如下:

          cmake_minimum_required?(VERSION?2.8)

          project?(main)

          add_executable(main?main.c)

          解釋一下這三條語句分別代表什么意思:

          1、表示cmake最低執(zhí)行版本是2.8才有效來管理我們的工程項目。

          2、表示整個工程名為main

          3、表示最終要生成的elf文件的名字叫main,使用的源文件是main.c

          現(xiàn)在我們來實現(xiàn)cmake的功能,在當(dāng)前目錄下,使用命令"cmake ."(.表示當(dāng)前目錄,而..表示上一級目錄),生成makefile等相關(guān)文件;然后再執(zhí)行一下make命令進行編譯工程,就能生成可執(zhí)行文件main了,同時也會生成makefile文件,最后就可以執(zhí)行可執(zhí)行main文件,就能得到我們所要的結(jié)果:

          root@txp-virtual-machine:/home/txp/test#?cmake?.
          --?The?C?compiler?identification?is?GNU?4.8.4
          --?The?CXX?compiler?identification?is?GNU?4.8.4
          --?Check?for?working?C?compiler:?/usr/bin/cc
          --?Check?for?working?C?compiler:?/usr/bin/cc?--?works
          --?Detecting?C?compiler?ABI?info
          --?Detecting?C?compiler?ABI?info?-?done
          --?Check?for?working?CXX?compiler:?/usr/bin/c++
          --?Check?for?working?CXX?compiler:?/usr/bin/c++?--?works
          --?Detecting?CXX?compiler?ABI?info
          --?Detecting?CXX?compiler?ABI?info?-?done
          --?Configuring?done
          --?Generating?done
          --?Build?files?have?been?written?to:?/home/txp/test


          root@txp-virtual-machine:/home/txp/test#?ls
          CMakeCache.txt??CMakeFiles??cmake_install.cmake??CMakeLists.txt??main??main.c??Makefile


          root@txp-virtual-machine:/home/txp/test#?make
          Scanning?dependencies?of?target?main
          [100%]?Building?C?object?CMakeFiles/main.dir/main.c.o
          Linking?C?executable?main
          [100%]?Built?target?main





          root@txp-virtual-machine:/home/txp/test#?./main
          TXP嵌入式

          如果你再好奇一下的話,可以打開看看Makefile里面的內(nèi)容是啥,很容易想到是用makefile的方式來實現(xiàn)對工程main的管理,這里我就不畫蛇添足把源代碼貼出來了。cmake_install.cmake 是一些相關(guān)配置選項:

          #?Install?script?for?directory:?/home/txp/test

          #?Set?the?install?prefix
          IF(NOT?DEFINED?CMAKE_INSTALL_PREFIX)
          ??SET(CMAKE_INSTALL_PREFIX?"/usr/local")
          ENDIF(NOT?DEFINED?CMAKE_INSTALL_PREFIX)
          STRING(REGEX?REPLACE?"/$"?""?CMAKE_INSTALL_PREFIX?"${CMAKE_INSTALL_PREFIX}")

          #?Set?the?install?configuration?name.
          IF(NOT?DEFINED?CMAKE_INSTALL_CONFIG_NAME)
          ??IF(BUILD_TYPE)
          ????STRING(REGEX?REPLACE?"^[^A-Za-z0-9_]+"?""
          ???????????CMAKE_INSTALL_CONFIG_NAME?"${BUILD_TYPE}")
          ??ELSE(BUILD_TYPE)
          ????SET(CMAKE_INSTALL_CONFIG_NAME?"")
          ??ENDIF(BUILD_TYPE)
          ??MESSAGE(STATUS?"Install?configuration:?\"${CMAKE_INSTALL_CONFIG_NAME}\"")
          ENDIF(NOT?DEFINED?CMAKE_INSTALL_CONFIG_NAME)

          #?Set?the?component?getting?installed.
          IF(NOT?CMAKE_INSTALL_COMPONENT)
          ??IF(COMPONENT)
          ????MESSAGE(STATUS?"Install?component:?\"${COMPONENT}\"")
          ????SET(CMAKE_INSTALL_COMPONENT?"${COMPONENT}")
          ??ELSE(COMPONENT)
          ????SET(CMAKE_INSTALL_COMPONENT)
          ??ENDIF(COMPONENT)
          ENDIF(NOT?CMAKE_INSTALL_COMPONENT)

          #?Install?shared?libraries?without?execute?permission?
          IF(NOT?DEFINED?CMAKE_INSTALL_SO_NO_EXE)
          ??SET(CMAKE_INSTALL_SO_NO_EXE?"1")
          ENDIF(NOT?DEFINED?CMAKE_INSTALL_SO_NO_EXE)

          IF(CMAKE_INSTALL_COMPONENT)
          ??SET(CMAKE_INSTALL_MANIFEST?"install_manifest_${CMAKE_INSTALL_COMPONENT}.txt")
          ELSE(CMAKE_INSTALL_COMPONENT)
          ??SET(CMAKE_INSTALL_MANIFEST?"install_manifest.txt")
          ENDIF(CMAKE_INSTALL_COMPONENT)

          FILE(WRITE?"/home/txp/test/${CMAKE_INSTALL_MANIFEST}"?"")
          FOREACH(file?${CMAKE_INSTALL_MANIFEST_FILES})
          ??FILE(APPEND?"/home/txp/test/${CMAKE_INSTALL_MANIFEST}"?"${file}\n")
          ENDFOREACH(file)
          ~?????????????????

          而CMakeFiles是一個文件夾,里面文件內(nèi)容如下:

          root@txp-virtual-machine:/home/txp/test/CMakeFiles#?ls
          2.8.12.2??cmake.check_cache??CMakeDirectoryInformation.cmake??
          CMakeOutput.log??CMakeTmp??main.dir??Makefile2?
          Makefile.cmake??progress.marks??TargetDirectories.txt

          小結(jié):
          從上面簡單的示例我們可以看出,Cmake所有的語句都是寫在一個名為"CMakeLists.txt"的文本文件里面,所以完成一個工程用cmake管理的完整步驟如下:

          1、先建立CMakeLists.txt(這跟我們用makefile來管理工程一樣,都有一個特殊的文件來專門書寫工程管理代碼的,cmake也不例外,使用CMakeLists.txt文本文件來專門書寫代碼管理工程項目)。

          2、然后進行往CMakeLists.txt寫配置,具體簡單配置參考上面的形式寫,復(fù)雜的配置,我們會在下面進行演示講解的。

          3、接著使用命令"cmake .",這里必須是CMakeLists.txt同級目錄下執(zhí)行這個命令哈,生成makefile等文件

          4、最后使用make命令進行工程編譯,進而生成可執(zhí)行文件。

          3、同一個目錄有多個源文件:

          這里我們在當(dāng)前目錄再添加兩個文件:test1.c和test1.h。test1.c文件內(nèi)容如下:

          #include?
          #include?"test1.h"

          void?func(int?a)
          {
          ????printf("a=%d\n",a);
          }

          test1.h里面的內(nèi)容如下:

          #ifndef?_TEST1_H
          #define?_TEST1_H

          void?func(int?a);

          #endif?/*?_TEST1_H?*/

          然后在main。c里面進行調(diào)用func()這個函數(shù):

          #include?
          #include?"test1.h"
          int?main(void)
          {
          ????func(6);
          ????printf("TXP嵌入式\n");
          ????return?0;

          }

          然后這個時候我們的CMakeLists.txt里面書寫形式肯定要改了:

          cmake_minimum_required?(VERSION?2.8)

          project?(main)

          add_executable(main?main.c?test1.c)

          最終結(jié)果如下:

          root@txp-virtual-machine:/home/txp/test#?cmake?.
          --?Configuring?done
          --?Generating?done
          --?Build?files?have?been?written?to:?/home/txp/test
          root@txp-virtual-machine:/home/txp/test#?make
          Scanning?dependencies?of?target?main
          [?50%]?Building?C?object?CMakeFiles/main.dir/main.c.o
          [100%]?Building?C?object?CMakeFiles/main.dir/test1.c.o
          Linking?C?executable?main
          [100%]?Built?target?main
          root@txp-virtual-machine:/home/txp/test#?ls
          1??CMakeCache.txt??CMakeFiles??cmake_install.cmake??CMakeLists.txt??main??main.c??Makefile??test1.c??test1.h
          root@txp-virtual-machine:/home/txp/test#?./main
          a=6
          TXP嵌入式

          小結(jié):

          上面的CMakeLists.txt的寫法,你會注意到add_executable(main main.c test1.c)多了一個源文件(你可以把源碼看作成加工的原材料,在makefile里面也是這樣來理解目標(biāo)文件的生成!),所以如果你還要往當(dāng)前目錄下添加源文件的話,在書寫CMakeLists.txt文本文件時,直接在第三個語句里面添加源文件;不過這種方式有缺陷,比如說,如果當(dāng)前文件下有幾百個源文件,這個時候你不可能一個個去手寫敲吧,不然這樣就又回到了原始社會,就不能體現(xiàn)cmake的優(yōu)越性出來了!更多用法,且聽下回細解!


          二、用好 Cmake,高興一整天(甚至...):

          1、多個源文件,使用命令 aux_source_directory(dir var):

          在上一篇文章最后結(jié)尾的時候,有一個問題,就是在同一目錄下面,有多個源文件的時候,這個時候你不能都往下面第三條命令里面一直手動添加源文件,那工作效率多低啊:

          cmake_minimum_required(VERSION?2.8)

          project(main)

          add_executable(main?main.c?test1.c)

          于是乎為了解決這種低效率的操作,在 cmake 里面有一條指令可以完全搞定這個問題;不過為了說明問題,在這之前我又添加了兩個文件:test2.c 和 test2.h:

          root@txp-virtual-machine:/home/txp/test#?ls
          1???????????????cmake_install.cmake??main.c????test1.h??touch1.c
          CMakeCache.txt??CMakeLists.txt???????Makefile??test2.c??touch1.h
          CMakeFiles??????main?????????????????test1.c???test2.h

          test2.c內(nèi)容如下:

          #include?
          #include?"test2.h"

          void?func1()
          {
          ??printf("i?like?the?cmake\n");
          }

          test2.h內(nèi)容如下:

          #ifndef?_TEST2_H_
          #define?_TEST2_H_

          void?func1();

          #endif

          最后main.c里面調(diào)用了func1函數(shù):

          #include?
          #include?"test1.h"
          #include?"test2.h"
          int?main(void)
          {
          ????func1();
          ????func(8);
          ????printf("TXP嵌入式\n");
          ????return?0;

          }

          接下來我們的重點就來了,在cmake里面可以使用aux_source_directory(dir var)就可以搞定上面效率低的問題,接下來我們在CMakeLists.txt這樣操作:

          cmake_minimum_required(VERSION?2.8)

          project(main)

          aux_source_directory(.?SRC_LIST)

          add_executable(main?${SRC_LIST})


          然后再進行編譯:

          root@txp-virtual-machine:/home/txp/test#?cmake?.
          --?Configuring?done
          --?Generating?done
          --?Build?files?have?been?written?to:?/home/txp/test


          root@txp-virtual-machine:/home/txp/test#?make
          Scanning?dependencies?of?target?main
          [?25%]?Building?C?object?CMakeFiles/main.dir/main.c.o
          [?50%]?Linking?C?executable?main


          root@txp-virtual-machine:/home/txp/test#?./main
          i?like?the?cmake
          the?b?is?8
          TXP嵌入式


          說明:

          aux_source_directory(. SRC_LIST):表示是把當(dāng)當(dāng)前目錄下的所有源文件都添加到源列表變量里面去,最后用add_executable(main ${SRC_LIST})把所有有用的源文件加工成目標(biāo)文件main。不過這方法也有他的缺點,就是把當(dāng)前目錄下的源文件都添加到變量SRC_LIST,如果我們不需要一些沒有用的文件(只要拿到所需的源文件就行),可以進行這樣操作:

          cmake_minimum_required(VERSION?2.8)

          project(main)

          set(SRC_LIST
          ????????./main.c
          ????????./test1.c
          ????????./test2.c
          ?????????)

          add_executable(main?${SRC_LIST})

          這樣是能夠通過編譯的:

          root@txp-virtual-machine:/home/txp/test#?cmake?.
          --?Configuring?done
          --?Generating?done
          --?Build?files?have?been?written?to:?/home/txp/test
          root@txp-virtual-machine:/home/txp/test#?make
          [100%]?Built?target?main

          2、在上面的例子中,我們會發(fā)現(xiàn)同一目錄下源文件比較亂,所以在cmake里面有這樣的規(guī)則,可以把相同類型以及相關(guān)的源文件放到同一個目錄,比如說,現(xiàn)在我在test目錄下創(chuàng)建test1和test2兩個目錄文件,并同時把test1.c、test1.h、test2.c、test2.h分別放到這兩個目錄下去:

          root@txp-virtual-machine:/home/txp/test#?mkdir?-p?test1?test2
          root@txp-virtual-machine:/home/txp/test#?ls
          @???????????????CMakeFiles???????????main??????test1????test2
          1???????????????cmake_install.cmake??main.c????test1.c??test2.c
          CMakeCache.txt??CMakeLists.txt???????Makefile??test1.h??test2.h

          然后把相關(guān)文件一到這兩個目錄文件下去:

          root@txp-virtual-machine:/home/txp/test#?mv?test1.c?test1.h?test1

          root@txp-virtual-machine:/home/txp/test#?mv?test2.c?test2.h?test2
          root@txp-virtual-machine:/home/txp/test#?ls
          @??CMakeCache.txt??cmake_install.cmake??main????Makefile??test2
          1??CMakeFiles??????CMakeLists.txt???????main.c??test1

          root@txp-virtual-machine:/home/txp/test#?tree

          ├──?cmake_install.cmake
          ├──?CMakeLists.txt
          ├──?main
          ├──?main.c
          ├──?Makefile
          ├──?test1
          │???├──?test1.c
          │???└──?test1.h
          └──?test2
          ????├──?test2.c
          ????└──?test2.h


          然后這個時候要修改CMakeLists.txt里面的規(guī)則屬性了:

          cmake_minimum_required(VERSION?2.8)

          project(main)

          include_directories(test1?test2)
          aux_source_directory(test1?SRC_LIST)
          aux_source_directory(test2?SRC_LIST1)

          add_executable(main?main.c??${SRC_LIST}?${SRC_LIST1})

          然后編譯輸出,也是能夠通過的:

          root@txp-virtual-machine:/home/txp/test#?cmake?.
          --?Configuring?done
          --?Generating?done
          --?Build?files?have?been?written?to:?/home/txp/test
          root@txp-virtual-machine:/home/txp/test#?make
          Scanning?dependencies?of?target?main
          [?25%]?Building?C?object?CMakeFiles/main.dir/main.c.o
          [?50%]?Building?C?object?CMakeFiles/main.dir/test1/test1.c.o
          [?75%]?Building?C?object?CMakeFiles/main.dir/test2/test2.c.o
          [100%]?Linking?C?executable?main
          [100%]?Built?target?main
          root@txp-virtual-machine:/home/txp/test#?ls
          @??CMakeCache.txt??cmake_install.cmake??main????Makefile??test2
          1??CMakeFiles??????CMakeLists.txt???????main.c??test1
          root@txp-virtual-machine:/home/txp/test#?./main
          i?like?the?cmake
          the?b?is?8
          TXP嵌入式

          說明:

          這里出現(xiàn)了一個新的命令:include_directories。該命令是用來向工程添加多個指定頭文件的搜索路徑,路徑之間用空格分隔。

          其實在實際開發(fā)工程中,一般會把源文件放到src目錄下,把頭文件放入到include文件下,生成的對象文件放入到build目錄下,最終輸出的elf文件會放到bin目錄下,這樣讓人看起來一目了然


          、Cmake中添加鏈接庫文件:

          在上一篇文Cmake文章里面,我們同樣在文章的最后面留了一個問題實現(xiàn),就是把源文件放到src目錄下,把頭文件放到include目錄下去,這樣也比較符合別人和自己日后去配置工程(一看到這兩個目就能知道啥意思了,清晰明了),同時在linux環(huán)境下生成的elf文件放到bin目錄下;不過在文章發(fā)出去了幾天,后面有網(wǎng)友又有提出了一些新的需求:


          (如果網(wǎng)友有啥實際需要,可以私聊我,只要在我自身能力之內(nèi),我都可以寫成文章出來分享給大家)熟悉我的網(wǎng)友都知道,我也是小白,會從很基礎(chǔ)的東西開始分享開始,雖然都是比較理論化的東西,但是都是點滴的積累(有的時候,其實你真正在有些項目開發(fā)過程中,學(xué)到的東西不是很多,更多的是依靠平時的基礎(chǔ)積累加以擴展,所以總的來說,平時的折騰還是非常值得!);同時有啥比較實際一點的需求咋也慢慢深入,一步步來,穩(wěn)扎穩(wěn)打,知識性的東西來不得半點虛假和馬虎。好了,開始進入主題分享了:

          一、src、include、bin目錄的使用(更加正規(guī)化):

          1、先開始創(chuàng)建這三個目錄結(jié)構(gòu),并把相應(yīng)的文件放入進去:

          root@txp-virtual-machine:/home/txp/testmy#?mkdir?bin?build?src?include
          root@txp-virtual-machine:/home/txp/testmy#?ls
          bin??build??include??src

          include目錄下文件放入(這里test1.h和test2.h的內(nèi)容是接續(xù)前面的文章里面的內(nèi)容,這里我就不再造輪子了):

          root@txp-virtual-machine:/home/txp/testmy/include#?ls
          test1.h??test2.h

          src目錄下文件放入(這里test1.c和test2.c的內(nèi)容是接續(xù)前面的文章里面的內(nèi)容,這里我就不再造輪子了):

          root@txp-virtual-machine:/home/txp/testmy/src#?ls
          main.c??test1.c??test2.c


          最終我們還要在testmy目錄和src目錄下都創(chuàng)建一個CMakeLists.txt:

          /*testmy目錄下的CMakeLists.txt內(nèi)容:*/


          cmake_minimum_required(VERSION?2.8)

          project(main)

          add_subdirectory(src)


          /*src目下CMakeLists.txt內(nèi)容:*/

          aux_source_directory(.?SRC_LIST)

          include_directories(../include)

          add_executable(main?${SRC_LIST})

          set?(EXECUTABLE_OUTPUT_PATH?${PROJECT_SOURCE_DIR}/bin)


          上面第一個CMakeLists.txt里面陌生的語句解釋:

          • add_subdirectory(src)意思是可以向當(dāng)前工程添加存放源文件的子目錄,并可以指定中間二進制和目標(biāo)二進制的存放位置(subdirectory字母就是子目錄的意思,所以意思是:這里指定src目錄下存放了源文件,當(dāng)執(zhí)行cmake時,就會進入src目錄下去找src目錄下的CMakeLists.txt,所以在src目錄下也建立一個CMakeLists.txt),官方用法是這樣的(不過這里暫時沒去深究):

          add_subdirectory
          ----------------

          Add?a?subdirectory?to?the?build.

          ::

          ??add_subdirectory(source_dir?[binary_dir]
          ???????????????????[EXCLUDE_FROM_ALL])

          Add?a?subdirectory?to?the?build.??The?source_dir?specifies?the
          directory?in?which?the?source?CMakeLists.txt?and?code?files?are
          located.??If?it?is?a?relative?path?it?will?be?evaluated?with?respect
          to?the?current?directory?(the?typical?usage),?but?it?may?also?be?an
          absolute?path.??The?binary_dir?specifies?the?directory?in?which?to
          place?the?output?files.??If?it?is?a?relative?path?it?will?be?evaluated
          with?respect?to?the?current?output?directory,?but?it?may?also?be?an
          absolute?path.??If?binary_dir?is?not?specified,?the?value?of
          source_dir,?before?expanding?any?relative?path,?will?be?used?(the
          typical?usage).??The?CMakeLists.txt?file?in?the?specified?source
          directory?will?be?processed?immediately?by?CMake?before?processing?in
          the?current?input?file?continues?beyond?this?command.

          If?the?EXCLUDE_FROM_ALL?argument?is?provided?then?targets?in?the
          subdirectory?will?not?be?included?in?the?ALL?target?of?the?parent
          directory?by?default,?and?will?be?excluded?from?IDE?project?files.
          Users?must?explicitly?build?targets?in?the?subdirectory.??This?is
          meant?for?use?when?the?subdirectory?contains?a?separate?part?of?the
          project?that?is?useful?but?not?necessary,?such?as?a?set?of?examples.
          Typically?the?subdirectory?should?contain?its?own?project()?command
          invocation?so?that?a?full?build?system?will?be?generated?in?the
          subdirectory?(such?as?a?VS?IDE?solution?file).??Note?that?inter-target
          dependencies?supercede?this?exclusion.??If?a?target?built?by?the
          parent?project?depends?on?a?target?in?the?subdirectory,?the?dependee
          target?will?be?included?in?the?parent?project?build?system?to?satisfy
          the?dependency.

          第二個CMakeLists.txt內(nèi)容分析:

          • aux_source_directory (. SRC_LIST):把當(dāng)前目錄的源文件:main.c test1.c ?test2.c都放到變量SRC_LIST里面去。

          • include_directories (../include):把include目錄的頭文件包含進來。

          • set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin):這里面的EXECUTABLE_OUT_PATH和PROJECT_SOURCE_DIR是CMake自帶的預(yù)定義變量,同時他們的作用分別如下:

          • ?EXECUTABLE_OUTPUT_PATH :目標(biāo)二進制可執(zhí)行文件的存放位置

          • PROJECT_SOURCE_DIR:工程的根目錄

          所以最終生成的elf文件(也就是我們的最終可執(zhí)行文件)就會放到bin目錄下,然后我們build目錄下會成一些配置中間文件。

          具體步驟過程我寫出來:

          root@txp-virtual-machine:/home/txp/testmy#?vim?CMakeLists.txt
          root@txp-virtual-machine:/home/txp/testmy#?cd?src
          root@txp-virtual-machine:/home/txp/testmy/src#?ls
          main.c??test1.c??test2.c
          root@txp-virtual-machine:/home/txp/testmy/src#?vim?CMakeLists.txt

          最后架構(gòu)如下:

          root@txp-virtual-machine:/home/txp/testmy#?tree
          .
          ├──?bin
          ├──?build
          ├──?CMakeLists.txt
          ├──?include
          │???├──?test1.h
          │???└──?test2.h
          └──?src
          ????├──?CMakeLists.txt
          ????├──?main.c
          ????├──?test1.c
          ????└──?test2.c

          2、編譯運行:

          root@txp-virtual-machine:/home/txp/testmy#?cd?build
          root@txp-virtual-machine:/home/txp/testmy/build#?ls
          root@txp-virtual-machine:/home/txp/testmy/build#?cmake?..
          --?The?C?compiler?identification?is?GNU?4.8.4
          --?The?CXX?compiler?identification?is?GNU?4.8.4
          --?Check?for?working?C?compiler:?/usr/bin/cc
          --?Check?for?working?C?compiler:?/usr/bin/cc?--?works
          --?Detecting?C?compiler?ABI?info
          --?Detecting?C?compiler?ABI?info?-?done
          --?Check?for?working?CXX?compiler:?/usr/bin/c++
          --?Check?for?working?CXX?compiler:?/usr/bin/c++?--?works
          --?Detecting?CXX?compiler?ABI?info
          --?Detecting?CXX?compiler?ABI?info?-?done
          --?Configuring?done
          --?Generating?done
          --?Build?files?have?been?written?to:?/home/txp/testmy/build
          root@txp-virtual-machine:/home/txp/testmy/build#?make
          Scanning?dependencies?of?target?main
          [?33%]?Building?C?object?src/CMakeFiles/main.dir/test2.c.o
          [?66%]?Building?C?object?src/CMakeFiles/main.dir/test1.c.o
          [100%]?Building?C?object?src/CMakeFiles/main.dir/main.c.o
          Linking?C?executable?../../bin/main
          [100%]?Built?target?main
          root@txp-virtual-machine:/home/txp/testmy/build#?cd?../bin
          root@txp-virtual-machine:/home/txp/testmy/bin#?ls
          main

          注意這里是切換到build目錄下去執(zhí)行cmake哈。?這里為啥這樣做呢,我們課可以看到在build目錄下執(zhí)行cmake .. 和make命令后,生成的一些配置文件都會在這個目錄下,不會在別的目錄下,就這樣看起來就舒服整潔多了:

          root@txp-virtual-machine:/home/txp/testmy/build#?ls
          CMakeCache.txt??CMakeFiles??cmake_install.cmake??Makefile??src

          現(xiàn)在整個架構(gòu)如下:

          root@txp-virtual-machine:/home/txp/testmy#?tree
          .
          ├──?bin
          │???└──?main
          ├──?build
          │???├──?CMakeCache.txt
          │???├──?CMakeFiles
          │???│???├──?2.8.12.2
          │???│???│???├──?CMakeCCompiler.cmake
          │???│???│???├──?CMakeCXXCompiler.cmake
          │???│???│???├──?CMakeDetermineCompilerABI_C.bin
          │???│???│???├──?CMakeDetermineCompilerABI_CXX.bin
          │???│???│???├──?CMakeSystem.cmake
          │???│???│???├──?CompilerIdC
          │???│???│???│???├──?a.out
          │???│???│???│???└──?CMakeCCompilerId.c
          │???│???│???└──?CompilerIdCXX
          │???│???│???????├──?a.out
          │???│???│???????└──?CMakeCXXCompilerId.cpp
          │???│???├──?cmake.check_cache
          │???│???├──?CMakeDirectoryInformation.cmake
          │???│???├──?CMakeOutput.log
          │???│???├──?CMakeTmp
          │???│???├──?Makefile2
          │???│???├──?Makefile.cmake
          │???│???├──?progress.marks
          │???│???└──?TargetDirectories.txt
          │???├──?cmake_install.cmake
          │???├──?Makefile
          │???└──?src
          │???????├──?CMakeFiles
          │???????│???├──?CMakeDirectoryInformation.cmake
          │???????│???├──?main.dir
          │???????│???│???├──?build.make
          │???????│???│???├──?C.includecache
          │???????│???│???├──?cmake_clean.cmake
          │???????│???│???├──?DependInfo.cmake
          │???????│???│???├──?depend.internal
          │???????│???│???├──?depend.make
          │???????│???│???├──?flags.make
          │???????│???│???├──?link.txt
          │???????│???│???├──?main.c.o
          │???????│???│???├──?progress.make
          │???????│???│???├──?test1.c.o
          │???????│???│???└──?test2.c.o
          │???????│???└──?progress.marks
          │???????├──?cmake_install.cmake
          │???????└──?Makefile
          ├──?CMakeLists.txt
          ├──?include
          │???├──?test1.h
          │???└──?test2.h
          └──?src
          ????├──?CMakeLists.txt
          ????├──?main.c
          ????├──?test1.c
          ????└──?test2.c

          看一下最終執(zhí)行結(jié)果:

          root@txp-virtual-machine:/home/txp/testmy/bin#?./main
          i?like?the?cmake
          a=8
          TXP嵌入式

          二、動態(tài)庫和靜態(tài)庫的學(xué)習(xí):

          這個話題就回到了我們最開始那位網(wǎng)友提出的需求了;不過我們還是從簡單的開始來學(xué)習(xí),然后慢慢深入。有的時候我們只需要編譯出動態(tài)庫、靜態(tài)庫,然后給其他程序來調(diào)用,那么在cmake里面如何實現(xiàn)呢?具體如下:

          注我這用到的源文件內(nèi)容(test1.c test2.c test1.h test2.h main.c都是一樣的來測試

          1、為了清晰明了,這里我重新創(chuàng)建了一個目錄工程來演示:

          root@txp-virtual-machine:/home/txp#?mkdir?testcmake
          root@txp-virtual-machine:/home/txp/testcmake#?mkdir?build?lib?lib_test
          root@txp-virtual-machine:/home/txp/testcmake#?ls
          build??lib??lib_test

          然后在lib_test目錄下放我們的源文件test1.c test1.h,并同時在lib_test目錄創(chuàng)建一個CMakeLists.txt;在testcmake目錄也創(chuàng)建一個CMakeLists.txt:

          root@txp-virtual-machine:/home/txp/testcmake/lib_test#?ls
          CMakeLists.txt??test1.c??test1.h



          /*lib_test目錄下的CMakeLists.txt的內(nèi)容:

          aux_source_directory(.?SRC_LIST)

          add_library(test1_shared?SHARED?${SRC_LIST})
          add_library(test1_static?STATIC?${SRC_LIST})

          set_target_properties(test1_shared?PROPERTIES?OUTPUT_NAME?"test1")
          set_target_properties(test1_static?PROPERTIES?OUTPUT_NAME?"test1")

          set?(LIBRARY_OUTPUT_PATH?${PROJECT_SOURCE_DIR}/lib)

          解釋說明:

          • add_library: 生成動態(tài)庫或靜態(tài)庫(第1個參數(shù)指定庫的名字;第2個參數(shù)決定是動態(tài)還是靜態(tài),如果沒有就默認(rèn)靜態(tài);第3個參數(shù)指定生成庫的源文件)。

          • set_target_properties: 設(shè)置輸出的名稱,還有其它功能,如設(shè)置庫的版本號等等。

          • LIBRARY_OUTPUT_PATH: 庫文件的默認(rèn)輸出路徑,這里設(shè)置為工程目錄下的lib目錄。

          testcmake目錄下的CMakeLists.txt內(nèi)容:

          cmake_minimum_required(VERSION?2.8)

          project(main)

          add_subdirectory(lib_test)

          最后架構(gòu)如下:

          root@txp-virtual-machine:/home/txp/testcmake#?ls
          build??CMakeLists.txt??lib??lib_test
          root@txp-virtual-machine:/home/txp/testcmake#?tree
          .
          ├──?build
          ├──?CMakeLists.txt
          ├──?lib
          └──?lib_test
          ????├──?CMakeLists.txt
          ????├──?test1.c
          ????└──?test1.h

          3?directories,?4?files

          2、編譯結(jié)果:

          root@txp-virtual-machine:/home/txp/testcmake/build#?cmake?..
          --?The?C?compiler?identification?is?GNU?4.8.4
          --?The?CXX?compiler?identification?is?GNU?4.8.4
          --?Check?for?working?C?compiler:?/usr/bin/cc
          --?Check?for?working?C?compiler:?/usr/bin/cc?--?works
          --?Detecting?C?compiler?ABI?info
          --?Detecting?C?compiler?ABI?info?-?done
          --?Check?for?working?CXX?compiler:?/usr/bin/c++
          --?Check?for?working?CXX?compiler:?/usr/bin/c++?--?works
          --?Detecting?CXX?compiler?ABI?info
          --?Detecting?CXX?compiler?ABI?info?-?done
          --?Configuring?done
          --?Generating?done
          --?Build?files?have?been?written?to:?/home/txp/testcmake/build
          root@txp-virtual-machine:/home/txp/testcmake/build#?make
          Scanning?dependencies?of?target?test1_shared
          [?50%]?Building?C?object?lib_test/CMakeFiles/test1_shared.dir/test1.c.o
          Linking?C?shared?library?../../lib/libtest1.so
          [?50%]?Built?target?test1_shared
          Scanning?dependencies?of?target?test1_static
          [100%]?Building?C?object?lib_test/CMakeFiles/test1_static.dir/test1.c.o
          Linking?C?static?library?../../lib/libtest1.a
          [100%]?Built?target?test1_static
          root@txp-virtual-machine:/home/txp/testcmake/build#?cd?../lib
          root@txp-virtual-machine:/home/txp/testcmake/lib#?ls
          libtest1.a??libtest1.so

          注意編譯規(guī)則上面講過,這里不再重復(fù)

          從lib目錄下我們可以看到生成了生成了靜態(tài)庫和動態(tài)庫:libtest1.a ?libtest1.so

          2、對庫進行鏈接:

          現(xiàn)在我們使用剛才生成的庫了。把build剛才的配置文件清空,并同時在testcmake目錄下創(chuàng)建bin和src目錄(跟剛才上面講的差不多):

          root@txp-virtual-machine:/home/txp/testcmake#?mkdir?src?bin
          root@txp-virtual-machine:/home/txp/testcmake#?ls
          bin??build??CMakeLists.txt??lib??lib_test??src
          root@txp-virtual-machine:/home/txp/testcmake#?cd?src
          root@txp-virtual-machine:/home/txp/testcmake/src#?vim?main.c

          并在testcmake目錄下的CMakeLists.txt內(nèi)容改成:

          cmake_minimum_required(VERSION?2.8)

          project(main)

          add_subdirectory(lib_test)

          add_subdirectory(src)

          src目錄下要創(chuàng)建一個CMakeLists.txt:

          aux_source_directory(.SRC_LIST)

          include_directories(../lib_test)

          link_directories(${PROJECT_SOURCE_DIR}/lib)

          add_executable(main?${SRC_LIST})

          target_link_libraries(main?test1)

          set(EXECUTABLE_OUTPUT_PATH?${PROJECT_SOURCE_DIR}/bin)

          解釋說明:

          --link_directories: 添加非標(biāo)準(zhǔn)的共享庫搜索路徑。

          --target_link_libraries: 把目標(biāo)文件與庫文件進行鏈接。

          3、編譯:

          root@txp-virtual-machine:/home/txp/testcmake/build#?cmake?..
          --?The?C?compiler?identification?is?GNU?4.8.4
          --?The?CXX?compiler?identification?is?GNU?4.8.4
          --?Check?for?working?C?compiler:?/usr/bin/cc
          --?Check?for?working?C?compiler:?/usr/bin/cc?--?works
          --?Detecting?C?compiler?ABI?info
          --?Detecting?C?compiler?ABI?info?-?done
          --?Check?for?working?CXX?compiler:?/usr/bin/c++
          --?Check?for?working?CXX?compiler:?/usr/bin/c++?--?works
          --?Detecting?CXX?compiler?ABI?info
          --?Detecting?CXX?compiler?ABI?info?-?done
          --?Configuring?done
          --?Generating?done
          --?Build?files?have?been?written?to:?/home/txp/testcmake/build
          root@txp-virtual-machine:/home/txp/testcmake/build#?make
          Scanning?dependencies?of?target?test1_shared
          [?33%]?Building?C?object?lib_test/CMakeFiles/test1_shared.dir/test1.c.o
          Linking?C?shared?library?../../lib/libtest1.so
          [?33%]?Built?target?test1_shared
          Scanning?dependencies?of?target?test1_static
          [?66%]?Building?C?object?lib_test/CMakeFiles/test1_static.dir/test1.c.o
          Linking?C?static?library?../../lib/libtest1.a
          [?66%]?Built?target?test1_static
          Scanning?dependencies?of?target?main
          [100%]?Building?C?object?src/CMakeFiles/main.dir/main.c.o
          Linking?C?executable?../../bin/main
          [100%]?Built?target?main
          root@txp-virtual-machine:/home/txp/testcmake/build#?cd?../bin
          root@txp-virtual-machine:/home/txp/testcmake/bin#?ls
          main
          root@txp-virtual-machine:/home/txp/testcmake/bin#?./main
          a=6
          TXP嵌入式

          從上面可以執(zhí)行成功。同時注意:

          我們lib下面又動態(tài)庫和靜態(tài)庫,而在我們src目錄下的CMakeLists.txt里面的target_link_libraries (main test1)默認(rèn)是使用動態(tài)庫,如果lib目錄下只有靜態(tài)庫,那么這種寫法就會去鏈接靜態(tài)庫。也可以直接指定使用動態(tài)庫還是靜態(tài)庫,寫法是:target_link_libraries (main libtest1.so)或target_link_libraries (main libtest1.a)

          同時我們可以查看elf文件到底使用了哪些庫文件:

          root@txp-virtual-machine:/home/txp/testcmake/bin#?readelf?-d?./main

          Dynamic?section?at?offset?0xe08?contains?26?entries:
          ??Tag????????Type?????????????????????????Name/Value
          ?0x0000000000000001?(NEEDED)?????????????Shared?library:?[libtest1.so]
          ?0x0000000000000001?(NEEDED)?????????????Shared?library:?[libc.so.6]
          ?0x000000000000000f?(RPATH)??????????????Library?rpath:?[/home/txp/testcmake/lib]
          ?0x000000000000000c?(INIT)???????????????0x4006a0
          ?0x000000000000000d?(FINI)???????????????0x400894
          ?0x0000000000000019?(INIT_ARRAY)?????????0x600df0
          ?0x000000000000001b?(INIT_ARRAYSZ)???????8?(bytes)
          ?0x000000000000001a?(FINI_ARRAY)?????????0x600df8
          ?0x000000000000001c?(FINI_ARRAYSZ)???????8?(bytes)
          ?0x000000006ffffef5?(GNU_HASH)???????????0x400298
          ?0x0000000000000005?(STRTAB)?????????????0x4004d8
          ?0x0000000000000006?(SYMTAB)?????????????0x4002f8
          ?0x000000000000000a?(STRSZ)??????????????260?(bytes)
          ?0x000000000000000b?(SYMENT)?????????????24?(bytes)
          ?0x0000000000000015?(DEBUG)??????????????0x0
          ?0x0000000000000003?(PLTGOT)?????????????0x601000
          ?0x0000000000000002?(PLTRELSZ)???????????96?(bytes)
          ?0x0000000000000014?(PLTREL)?????????????RELA
          ?0x0000000000000017?(JMPREL)?????????????0x400640
          ?0x0000000000000007?(RELA)???????????????0x400628
          ?0x0000000000000008?(RELASZ)?????????????24?(bytes)
          ?0x0000000000000009?(RELAENT)????????????24?(bytes)
          ?0x000000006ffffffe?(VERNEED)????????????0x400608
          ?0x000000006fffffff?(VERNEEDNUM)?????????1
          ?0x000000006ffffff0?(VERSYM)?????????????0x4005dc
          ?0x0000000000000000?(NULL)???????????????0x0

          三、小結(jié):

          這里還有一個網(wǎng)友的提的那個實現(xiàn),現(xiàn)在我們知道了怎么去使用動態(tài)庫和靜態(tài)庫就好辦了;限于篇幅原因,這個測試留在下篇cmake文章里面來做實驗看看到底能不能實現(xiàn)(這里我暫時還沒做實驗,等我做完實驗就會分享出來,這篇文章分享花的時間比較久,大家先暫時消化一下)

          推薦閱讀:


          嵌入式編程專輯
          Linux 學(xué)習(xí)專輯
          C/C++編程專輯

          長按前往圖中包含的公眾號關(guān)注

          瀏覽 87
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  a天堂资源在线 | 欧美 日韩 国产在线观看 | 黄色日逼视频免费看 | 艹逼视频| 亚洲综合免费观看高清完整版在线观 |