转自:https://blog.csdn.net/dc_726/article/details/48978849

版权声明:本文为博主原创文章,未经博主允许不得转载。欢迎访问 http://blog.csdn.net/dc_726 https://blog.csdn.net/dc_726/article/details/48978849

C实战:项目构建Make,Automake,CMake
在本系列文章《C实战:强大的程序调试工具GDB》
https://blog.csdn.net/dc_726/article/details/46475623
中我们简要学习了流行的调试工具GDB的使用方法。本文继续“C实战”的主题,对同样非常流行的构建工具Make的用法和原理一探究竟,并顺便看一下一些高级衍生产品。 .Make基础
首先我们编写一个简单的C项目,以此项目在实战中学习Make的相关知识。更全面的介绍请参考官方手册。 cdai@vm /syspace/-ccpp/-pragmatic/build-tool/make $ tree
.
├── hello.c
├── hello.h
├── main.c
└── Makefile directories, 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 ;
} // ----- 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: prerequisite
recipe 下面就看一下示例项目的Makefile是什么样子的。在Makefile中有3个规则,其中目标main依赖于main.o和hello.o,利用gcc执行链接,这与我们的代码结构是相对应的。而main.o和hello.o则分别依赖于各自的源代码.c文件和hello.h头文件,并利用gcc -c执行编译。 main: main.o hello.o
gcc -o main main.o hello.o main.o: main.c hello.h
gcc -c main.c -o main.o hello.o: hello.c hello.h
gcc -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/-ccpp/-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.o cdai@vm /syspace/-ccpp/-pragmatic/build-tool/make $ ./main
Hello, Make! 再次执行make会看到“‘main’ is up to date.”的提示,说明Make检测到了没有发生任何修改。如果我们做一点改动,例如修改以下sayHello()函数中的输出,再执行Make就能看到hello.o和main被重新构建,而main.o规则的命令没有被执行。 cdai@vm /syspace/-ccpp/-pragmatic/build-tool/make $ make
make: 'main' is up to date. cdai@vm /syspace/-ccpp/-pragmatic/build-tool/make $ make
gcc -c hello.c -o hello.o
gcc -o main main.o hello.o cdai@vm /syspace/-ccpp/-pragmatic/build-tool/make $ ./main
Hello111, Make! .Make进阶
2.1 变量
在Makefile中,我们可以用变量来替换重复出现在先决条件或动作中的字符串。例如,对于前面我们的示例Makefile,最明显的问题就是gcc和main目标依赖的main.o和hello.o出现了多次,我们可以用变量将它们提取出来。同样地,我们也经常将链接和编译选项做成变量。 LD = gcc
CC = gcc
CFLAGS = -Wall
OBJECTS = main.o hello.o all: main main: $(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/-ccpp/-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.o all: main main: $(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/-ccpp/-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: main main: $(OBJECTS)
$(LD) -o main $(OBJECTS) main.o: main.c hello.h
hello.o: hello.c hello.h 执行一下看看效果。 cdaih@vm /syspace/-ccpp/-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 .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 :
[root@vm automaketest]# autoscan # Step :
[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 :
[root@vm automaketest]# aclocal # Step :
[root@vm automaketest]# autoconf # Step :
[root@vm automaketest]# autoheader # Step :
[root@vm automaketest]# cat Makefile.am
bin_PROGRAMS=main
main_SOURCES=main.c hello.c # Step :
[root@vm automaketest]# touch NEWS README AUTHORS ChangeLog # Step :
[root@vm automaketest]# automake -a
configure.in:: installing './install-sh'
configure.in:: 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 :
[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 - -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 - \
-exec chmod u+rwx,go+rx {} \; -o \
! -type d ! -perm - -links -exec chmod a+r {} \; -o \
! -type d ! -perm - -exec chmod a+r {} \; -o \
! -type d ! -perm - -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 - -exec chmod u+w {} ';' && rm -fr "main-1.0"; }; } [root@vm automaketest]# tree -L
.
├── 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-h1 directory, 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[]: 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[]: 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. 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. cmake
现在执行cmake .就能得到一个CMake为我们自动生成的Makefile。这个Makefile比我们手写的要复杂得多,这里就不深入分析了。除了Makefile外,CMake还产生了一些缓存文件和临时文件,目前还不清楚具体是做什么的。 [root@vm cmaketest]# cmake .
-- The C compiler identification is GNU 4.4.
-- The CXX compiler identification is GNU 4.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: /root/Temp/cmaketest [root@vm cmaketest]# tree -L
.
├── CMakeCache.txt
├── CMakeFiles
├── cmake_install.cmake
├── CMakeLists.txt
├── hello.c
├── hello.h
├── main.c
└── Makefile directory, files [root@vm cmaketest]# make
Scanning dependencies of target main
[ %] Building C object CMakeFiles/main.dir/main.c.o
[%] Building C object CMakeFiles/main.dir/hello.c.o
Linking C executable main
[%] Built target main

附:参考资料
make官方手册

https://www.gnu.org/software/make/manual/html_node/index.html#SEC_Contents
make学习记录

http://www.cnblogs.com/machine/archive/2012/11/21/2781508.html
CMake入门实战

https://www.hahack.com/codes/cmake/
使用autotools生成makefile文件入门

http://www.cnblogs.com/flatfoosie/archive/2010/12/21/1912946.html
automake/autoconf入门

https://blog.csdn.net/guomei/article/details/7315510
---------------------
作者:cdai
来源:CSDN
原文:https://blog.csdn.net/dc_726/article/details/48978849
版权声明:本文为博主原创文章,转载请附上博文链接!

C实战:项目构建Make,Automake,CMake【转】的更多相关文章

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

    C实战:项目构建Make,Automake,CMake 在本系列文章<C实战:强大的程序调试工具GDB>中我们简要学习了流行的调试工具GDB的使用方法.本文继续"C实战" ...

  2. C语言----项目构建Make,Automake,CMake

    http://blog.csdn.net/dc_726/article/details/48978849

  3. ES6 实战项目构建 ES6+glup+express

    ES6推出已经有几个年头了,平时也有学过一些基本语法,无奈实践经验太少.而且前端早已脱离了刀耕火种的时代,一些自动化构建工具像gulp.webpack等也需要熟练掌握.最近刚签了三方,闲暇之余就找了个 ...

  4. 基于Cmake+QT+VS的C++项目构建开发编译简明教程

    目录 一.工具下载与安装 1.     Qt 2.     Visual Studio 2015 3.     Cmake 二.C++及Qt项目构建 1.     基于VS构建Qt项目 2.     ...

  5. vue项目构建与实战

    关于 微信公众号:前端呼啦圈(Love-FED) 我的博客:劳卜的博客 知乎专栏:前端呼啦圈 前言 由于vue相对来说比较平缓的学习过程和新颖的技术思路,使其受到了广大前后端开发者的青睐,同时其通俗易 ...

  6. List多个字段标识过滤 IIS发布.net core mvc web站点 ASP.NET Core 实战:构建带有版本控制的 API 接口 ASP.NET Core 实战:使用 ASP.NET Core Web API 和 Vue.js 搭建前后端分离项目 Using AutoFac

    List多个字段标识过滤 class Program{  public static void Main(string[] args) { List<T> list = new List& ...

  7. Vue实战Vue-cli项目构建(Vue+webpack系列之一)

    用Vue比较长一段时间了,大大小小做了一些项目,最近想总结一下知识点,出一个Vue+webpack系列,先从项目构建说起--vue-cli. 由于是Vue+webpack这里就不赘述git那些东西,默 ...

  8. gradle入门(1-4)多项目构建实战

    一.多项目构建 1.多项目构建概念 尽管我们可以仅使用单个组件来创建可工作的应用程序,但有时候更广泛的做法是将应用程序划分为多个更小的模块. 因为这是一个非常普遍的需求,因此每个成熟的构建工具都必须支 ...

  9. 《React+Redux前端开发实战》笔记1:不涉及React项目构建的Hello World案例

    本小节实现一个不涉及项目构建的Hello World. [React的第一个Hello World网页] 源码地址:https://jsfiddle.net/allan91/2h1sf0ky/8/ & ...

随机推荐

  1. 比Kafka Mangaer更优秀的开源监控工具-Kafka Eagle

    比Kafka Mangaer更优秀的开源监控工具-Kafka Eagle 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在Kafka的监控系统中有很多优秀的开源监控系统.比如Kaf ...

  2. git lg 使用 转

    命令: git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yello ...

  3. 【转】第8章 前摄器(Proactor):用于为异步事件多路分离和分派处理器的对象行为模式

    目录: Reactor(反应堆)和Proactor(前摄器) <I/O模型之三:两种高性能 I/O 设计模式 Reactor 和 Proactor> <[转]第8章 前摄器(Proa ...

  4. layui(六)——upload组件常见用法总结

    layui中提供了非常简单的文件上传组件,这里写了一个上传图片的栗子,上传成功后返回图片在服务器的路径,并设置为页面中img的src属性.因为上传十分简单,没什么可说的,就直接上代码了. html代码 ...

  5. Drupal8 入门教程(一)安装部署

    一.Drupal简介 Drupal 是使用PHP语言编写的开源内容管理框架(CMF),它由内容管理系统(CMS)和PHP开发框架(Framework)共同构成.连续多年荣获全球最佳CMS大奖,是基于P ...

  6. STL优先队列

    #include<cstdio> #include<iostream> #include<algorithm> #include<queue> usin ...

  7. vee-validate表单验证组件

    vee-validate是VUE的基于模板的验证框架,允许您验证输入并显示错误 安装 npm i vee-validate --save 引入 import Vue from 'vue'; impor ...

  8. Vertica系列: Vertica DB连接负载均衡

    背景 谈到负载均衡, 对于数据库集群需要区分几个概念: 运算的负载均衡, Vertica 本身是 MPP 数据库, SQL 操作自动会利用多台机器来加快处理速度. 数据库连接的负载均衡, Vertic ...

  9. 大规模数据导入和导出(mysql)

    测试数据2.5G,共有数据9427567条.用的mysql的large服务器的配置.load 一次需要大概10分钟左右.建的表用的是MYISAM,调整了几个session的参数值 SET SESSIO ...

  10. 【51nod 1288】汽油补给

    Description 有(N+1)个城市,0是起点N是终点,开车从0 -> 1 - > 2...... -> N,车每走1个单位距离消耗1个单位的汽油,油箱的容量是T.给出每个城市 ...