日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

C实战:项目构建Make,Automake,CMake

發布時間:2024/6/21 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C实战:项目构建Make,Automake,CMake 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

C實戰:項目構建Make,Automake,CMake

在本系列文章《C實戰:強大的程序調試工具GDB》中我們簡要學習了流行的調試工具GDB的使用方法。本文繼續“C實戰”的主題,對同樣非常流行的構建工具Make的用法和原理一探究竟,并順便看一下一些高級衍生產品。


1.Make基礎

首先我們編寫一個簡單的C項目,以此項目在實戰中學習Make的相關知識。更全面的介紹請參考官方手冊。

cdai@vm /syspace/2-ccpp/24-pragmatic/build-tool/make $ tree . ├── hello.c ├── hello.h ├── main.c └── Makefile0 directories, 4 files

整個程序的邏輯非常簡單:main.c中包含一個main方法,調用了hello.c中的sayHello()函數,打印了一句話到控制臺上。

// cat main.c hello.h hello.c // ----- main.c ----- #include "hello.h"int main(void) {sayHello("Make");return 1; }// ----- hello.h ----- #ifndef _HELLO_H_ #define _HELLO_H_void sayHello(char *name);#endif// ----- hello.c ----- #include "hello.h" #include <stdio.h>void sayHello(char *name) {printf("Hello, %s!\n", name); }

1.1 基本語法

一個簡單的Makefile包含很多規則(Rule),每一條規則的語法結構由目標(Target)、先決條件(Prerequisite)、動作(Recipe)三部分組成:

  • 目標:通常有兩種命名方法,一是與要生成的可執行文件或目標文件同名,二是說明動作的目的,例如最常見的clean清理規則。對于第二種規則命名,為了避免與同名文件沖突,可以將目標名加入到.PHONY偽目標列表中。默認情況下,make執行Makefile中的第一個規則,此規則被稱為最終目標
  • 先決條件:先決條件是用來創建目標的輸入文件,一個目標可以依賴多個先決條件
  • 動作:動作由Make命令負責執行,可以包含多個命令,每個命令可以另起一行。一定要注意的是:命令必須以TAB開頭
target: prerequisiterecipe

下面就看一下示例項目的Makefile是什么樣子的。在Makefile中有3個規則,其中目標main依賴于main.o和hello.o,利用gcc執行鏈接,這與我們的代碼結構是相對應的。而main.o和hello.o則分別依賴于各自的源代碼.c文件和hello.h頭文件,并利用gcc -c執行編譯。

main: main.o hello.ogcc -o main main.o hello.omain.o: main.c hello.hgcc -c main.c -o main.ohello.o: hello.c hello.hgcc -c hello.c -o hello.o

1.2 實現原理

Make看似非常智能,其實它的原理就像其語法規則一樣簡單。

  • 確定目標:如果沒有指明,則執行最終目標,即第一個規則的目標
  • 處理變量和規則:替換變量,推導隱式規則(下一節會學習)
  • 生成依賴關系鏈:為所有目標生成依賴關系鏈
  • 遞歸構建:從依賴鏈的底部向上,根據先決條件會有三種情況:
    4.1 先決條件不存在,則執行規則中的命令
    4.2 先決條件存在,且至少一個比目標“更新”,則執行規則中的命令重新生成
    4.3 先決條件存在,且都比目標“更舊”, 則什么都不做
  • 了解了Make的原理,就看一下我們的示例項目Make的執行過程。可以看到,Make以第一個目標main作為構建目標,從關系鏈底部的main.o和hello.o開始構建,最終生成了可執行文件main。接下來就執行main,可以看到控制臺輸出了”Hello, Make!”,證明我們構建成功了!

    cdai@vm /syspace/2-ccpp/24-pragmatic/build-tool/make $ make gcc -c main.c -o main.o gcc -c hello.c -o hello.o gcc -o main main.o hello.ocdai@vm /syspace/2-ccpp/24-pragmatic/build-tool/make $ ./main Hello, Make!

    再次執行make會看到“‘main’ is up to date.”的提示,說明Make檢測到了沒有發生任何修改。如果我們做一點改動,例如修改以下sayHello()函數中的輸出,再執行Make就能看到hello.o和main被重新構建,而main.o規則的命令沒有被執行。

    cdai@vm /syspace/2-ccpp/24-pragmatic/build-tool/make $ make make: 'main' is up to date.cdai@vm /syspace/2-ccpp/24-pragmatic/build-tool/make $ make gcc -c hello.c -o hello.o gcc -o main main.o hello.ocdai@vm /syspace/2-ccpp/24-pragmatic/build-tool/make $ ./main Hello111, Make!

    2.Make進階

    2.1 變量

    在Makefile中,我們可以用變量來替換重復出現在先決條件或動作中的字符串。例如,對于前面我們的示例Makefile,最明顯的問題就是gcc和main目標依賴的main.o和hello.o出現了多次,我們可以用變量將它們提取出來。同樣地,我們也經常將鏈接和編譯選項做成變量。

    LD = gcc CC = gcc CFLAGS = -Wall OBJECTS = main.o hello.oall: mainmain: $(OBJECTS)$(LD) -o main $(OBJECTS)main.o: main.c hello.h$(CC) $(CFLAGS) -c $< -o $@hello.o: hello.c hello.h$(CC) $(CFLAGS) -c hello.c -o hello.o

    執行一下make可以看到效果,我們提取出來的變量在執行之前都被替換到了正確的位置。

    cdaih@vm /syspace/2-ccpp/24-pragmatic/build-tool/make $ make gcc -Wall -c main.c -o main.o gcc -Wall -c hello.c -o hello.o gcc -o main main.o hello.o

    2.2 隱式規則

    使用Make編譯.c源文件時,規則的命令和先決條件都可以簡化,對于命令,我們不用明確指出,Make能夠自動將.c編譯成.o;對于先決條件,Make還會自動尋找.o對應的.c源文件,我們只需給出頭文件即可。

    LD = gcc OBJECTS = main.o hello.oall: mainmain: $(OBJECTS)$(LD) -o main $(OBJECTS)main.o: hello.h hello.o: hello.h

    我們將main.o和hell.o的規則都做了簡化,執行一下可以看到Make自動執行了cc -c,并根據目標找到了對應的源文件main.c和hello.c。

    cdaih@vm /syspace/2-ccpp/24-pragmatic/build-tool/make $ make cc -c -o main.o main.c cc -c -o hello.o hello.c gcc -o main main.o hello.o

    2.3 模式規則

    隱式規則雖然很方便,但有時我們還想自己控制規則,這時我們可以使用模式規則。老Make支持.c.o這種規則定義,而新Make一般推薦使用模式規則,因為它支持模式匹配,更靈活、更強大!例如,我們定義目標名匹配%.o和先決條件匹配%.c的話,就執行編譯命令。這樣main.o和hello.o被簡化的同時,我們還對其進行了精確的控制。

    LD = gcc CC = gcc CFLAGS = -Wall OBJECTS = main.o hello.o%.o: %.c$(CC) $(CFLAGS) -c $< -o $@all: mainmain: $(OBJECTS)$(LD) -o main $(OBJECTS)main.o: main.c hello.h hello.o: hello.c hello.h

    執行一下看看效果。

    cdaih@vm /syspace/2-ccpp/24-pragmatic/build-tool/make $ make gcc -Wall -c main.c -o main.o gcc -Wall -c hello.c -o hello.o gcc -o main main.o hello.o

    3.Makefile生成工具

    Make的流行也帶動起一批自動生成Makefile的工具,目的就是進一步減輕項目構建中的工作量,讓我們程序員全身心投入到開發之中。在這些工具中,不得不提Automake和CMake。

    3.1 Automake

    Automake其實是一系列工具集Autotools中的一員,要想發揮Automake的威力,需要配合使用Autotools中的其他工具,例如autoscan、aclocal、autoconf和autoheader。在下面的Automake構建流程中,能看到這些工具的身影。

  • autoscan:生成configure.scan
  • configure.in:將configure.scan重命名為configure.in后,修改內容。重點是AM_INIT_AUTOMAKE和AC_CONFIG_FILES兩項,如果沒配置的話,下一步的aclocal是無法產生aclocal.m4的
  • aclocal:生成aclocal.m4
  • autoconf:生成configure
  • autoheader:生成config.h.in,使程序可移植
  • Makefile.am:手動編寫Makefile.am。bin_PROGRAMS指定最終生成可執行文件的名稱,helloworld_SOURCES指定所有源文件
  • NEWS AUTHORS README ChangeLog:手動創建
  • automake:執行automake -a生成Makefile.in
  • configure:執行./configure生成Makefile
  • # Step 1: [root@vm automaketest]# autoscan# Step 2: [root@vm automaketest]# mv configure.scan configure.in [root@vm automaketest]# cat configure.in # -*- Autoconf -*- # Process this file with autoconf to produce a configure script.AC_PREREQ([2.63]) AC_INIT(main, 1.0) AM_INIT_AUTOMAKE(main, 1.0) AC_CONFIG_SRCDIR([main.c]) AC_CONFIG_HEADERS([config.h])# Checks for programs. AC_PROG_CC# Checks for libraries.# Checks for header files.# Checks for typedefs, structures, and compiler characteristics.# Checks for library functions.AC_CONFIG_FILES([Makefile]) AC_OUTPUT# Step 3: [root@vm automaketest]# aclocal# Step 4: [root@vm automaketest]# autoconf# Step 5: [root@vm automaketest]# autoheader# Step 6: [root@vm automaketest]# cat Makefile.am bin_PROGRAMS=main main_SOURCES=main.c hello.c# Step 7: [root@vm automaketest]# touch NEWS README AUTHORS ChangeLog# Step 8: [root@vm automaketest]# automake -a configure.in:6: installing './install-sh' configure.in:6: installing './missing' Makefile.am: installing './INSTALL' Makefile.am: installing './COPYING' using GNU General Public License v3 file Makefile.am: Consider adding the COPYING file to the version control system Makefile.am: for your code, to avoid questions about which license your project uses. Makefile.am: installing './depcomp'# Step 9: [root@BC-VM-edce4ac67d304079868c0bb265337bd4 automaketest]# ./configure checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... gawk checking whether make sets $(MAKE)... yes checking for gcc... gcc checking for C compiler default output file name... a.out checking whether the C compiler works... yes checking whether we are cross compiling... no checking for suffix of executables... checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking for style of include used by make... GNU checking dependency style of gcc... gcc3 configure: creating ./config.status config.status: creating Makefile config.status: creating config.h config.status: executing depfiles commands

    這樣Makefile就生成好了,看一下當前目錄發現已經這么多文件了!如果想清理一下怎么辦呢?其實Automake早為我們想好了,它生成的Makefile功能很多:
    + make:編譯源代碼,生成目標文件
    + make clean:清理之前make產生的臨時文件
    + make install:將編譯好的可執行文件安裝到系統目錄,一般為/usr/local/bin
    + make dist:生成軟件發布包,將可執行文件及相關文件打包成”PACKAGE-VERSION.tar.gz”的tarball。其中PACKAGE和VERSION可以在configure.in中通過AM_INIT_AUTOMAKE(PACKAGE, VERSION)定義。對于我們的例子,執行后會生成main-1.0.tar.gz
    + make distcheck:查看發布包是否正確,解壓開執行configure和make來確認
    + make distclean:不僅將make產生的文件,同時將configure生成的文件也都刪除,包括Makefile

    [root@vm automaketest]# make dist { test ! -d "main-1.0" || { find "main-1.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -fr "main-1.0"; }; } test -d "main-1.0" || mkdir "main-1.0" test -n "" \|| find "main-1.0" -type d ! -perm -755 \-exec chmod u+rwx,go+rx {} \; -o \! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \! -type d ! -perm -400 -exec chmod a+r {} \; -o \! -type d ! -perm -444 -exec /bin/sh /root/Temp/automaketest/install-sh -c -m a+r {} {} \; \|| chmod -R a+r "main-1.0" tardir=main-1.0 && /bin/sh /root/Temp/automaketest/missing --run tar chof - "$tardir" | GZIP=--best gzip -c >main-1.0.tar.gz { test ! -d "main-1.0" || { find "main-1.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -fr "main-1.0"; }; }[root@vm automaketest]# tree -L 1 . ├── aclocal.m4 ├── AUTHORS ├── autom4te.cache ├── autoscan.log ├── ChangeLog ├── config.h ├── config.h.in ├── config.log ├── config.status ├── configure ├── configure.in ├── COPYING -> /usr/share/automake-1.11/COPYING ├── depcomp -> /usr/share/automake-1.11/depcomp ├── hello.c ├── hello.h ├── INSTALL -> /usr/share/automake-1.11/INSTALL ├── install-sh -> /usr/share/automake-1.11/install-sh ├── main.c ├── main-1.0.tar.gz ├── Makefile ├── Makefile.am ├── Makefile.in ├── missing -> /usr/share/automake-1.11/missing ├── NEWS ├── README └── stamp-h11 directory, 24 files[root@vm automaketest]# make distclean test -z "main" || rm -f main rm -f *.o rm -f *.tab.c test -z "" || rm -f test . = "." || test -z "" || rm -f rm -f config.h stamp-h1 rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags rm -f config.status config.cache config.log configure.lineno config.status.lineno rm -rf ./.deps rm -f Makefile

    測試一下,看看Automake生成的Makefile是否能正常工作。

    [root@vm automaketest]# make make all-am make[1]: Entering directory '/root/Temp/automaketest' gcc -DHAVE_CONFIG_H -I. -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c mv -f .deps/main.Tpo .deps/main.Po gcc -DHAVE_CONFIG_H -I. -g -O2 -MT hello.o -MD -MP -MF .deps/hello.Tpo -c -o hello.o hello.c mv -f .deps/hello.Tpo .deps/hello.Po gcc -g -O2 -o main main.o hello.o make[1]: Leaving directory '/root/Temp/automaketest'[root@vm automaketest]# ./main Hello, Make!

    3.2 CMake

    前面我們已經見識了Automake的強大和復雜。現在我們重新用CMake生成Makefile,Automake中的9步被壓縮到了只需要2步

  • 編寫CMakeLists.txt
  • 執行cmake .
  • 3.2.1 CMakeLists.txt

    對于我們示例中這種簡單的項目,CMakeLists.txt簡單得不能再簡單了。指定好項目名稱和最終生成的可執行文件名稱后,就完成了!

    # CMake 最低版本號要求 cmake_minimum_required (VERSION 2.8)# 項目信息 project (main)# 查找當前目錄下的所有源文件 # 并將名稱保存到 DIR_SRCS 變量 aux_source_directory(. DIR_SRCS)# 指定生成目標 add_executable(main ${DIR_SRCS})

    3.2.2 cmake

    現在執行cmake .就能得到一個CMake為我們自動生成的Makefile。這個Makefile比我們手寫的要復雜得多,這里就不深入分析了。除了Makefile外,CMake還產生了一些緩存文件和臨時文件,目前還不清楚具體是做什么的。

    [root@vm cmaketest]# cmake . -- The C compiler identification is GNU 4.4.7 -- The CXX compiler identification is GNU 4.4.7 -- 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: /root/Temp/cmaketest[root@vm cmaketest]# tree -L 1 . ├── CMakeCache.txt ├── CMakeFiles ├── cmake_install.cmake ├── CMakeLists.txt ├── hello.c ├── hello.h ├── main.c └── Makefile1 directory, 7 files[root@vm cmaketest]# make Scanning dependencies of target main [ 50%] Building C object CMakeFiles/main.dir/main.c.o [100%] Building C object CMakeFiles/main.dir/hello.c.o Linking C executable main [100%] Built target main

    附:參考資料

  • make官方手冊
  • make學習記錄
  • CMake入門實戰
  • 使用autotools生成makefile文件入門
  • automake/autoconf入門
  • 轉載于:https://www.cnblogs.com/xiaomaohai/p/6157594.html

    總結

    以上是生活随笔為你收集整理的C实战:项目构建Make,Automake,CMake的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。