打印
[ARM入门]

构建Make,Automake,CMAKE

[复制链接]
1067|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
明远智睿Lan|  楼主 | 2019-1-29 09:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

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.o1.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 $ makegcc -c main.c -o main.ogcc -c hello.c -o hello.ogcc -o main main.o hello.ocdai@vm /syspace/2-ccpp/24-pragmatic/build-tool/make $ ./mainHello, 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 $ makemake: 'main' is up to date.cdai@vm /syspace/2-ccpp/24-pragmatic/build-tool/make $ makegcc -c hello.c -o hello.ogcc -o main main.o hello.ocdai@vm /syspace/2-ccpp/24-pragmatic/build-tool/make $ ./mainHello111, Make!2.Make进阶2.1 变量在Makefile中,我们可以用变量来替换重复出现在先决条件或动作中的字符串。例如,对于前面我们的示例Makefile,最明显的问题就是gcc和main目标依赖的main.o和hello.o出现了多次,我们可以用变量将它们提取出来。同样地,我们也经常将链接和编译选项做成变量。LD = gccCC = gccCFLAGS = -WallOBJECTS = 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 $ makegcc -Wall -c main.c -o main.ogcc -Wall -c hello.c -o hello.ogcc -o main main.o hello.o2.2 隐式规则使用Make编译.c源文件时,规则的命令和先决条件都可以简化,对于命令,我们不用明确指出,Make能够自动将.c编译成.o;对于先决条件,Make还会自动寻找.o对应的.c源文件,我们只需给出头文件即可。LD = gccOBJECTS = main.o hello.oall: mainmain: $(OBJECTS)$(LD) -o main $(OBJECTS)main.o: hello.hhello.o: hello.h我们将main.o和hell.o的规则都做了简化,执行一下可以看到Make自动执行了cc -c,并根据目标找到了对应的源文件main.c和hello.c。cdaih@vm /syspace/2-ccpp/24-pragmatic/build-tool/make $ makecc -c -o main.o main.ccc -c -o hello.o hello.cgcc -o main main.o hello.o2.3 模式规则隐式规则虽然很方便,但有时我们还想自己控制规则,这时我们可以使用模式规则。老Make支持.c.o这种规则定义,而新Make一般推荐使用模式规则,因为它支持模式匹配,更灵活、更强大!例如,我们定义目标名匹配%.o和先决条件匹配%.c的话,就执行编译命令。这样main.o和hello.o被简化的同时,我们还对其进行了精确的控制。LD = gccCC = gccCFLAGS = -WallOBJECTS = main.o hello.o%.o: %.c$(CC) $(CFLAGS) -c $< -o $@all: mainmain: $(OBJECTS)$(LD) -o main $(OBJECTS)main.o: main.c hello.hhello.o: hello.c hello.h执行一下看看效果。cdaih@vm /syspace/2-ccpp/24-pragmatic/build-tool/make $ makegcc -Wall -c main.c -o main.ogcc -Wall -c hello.c -o hello.ogcc -o main main.o hello.o3.Makefile生成工具Make的流行也带动起一批自动生成Makefile的工具,目的就是进一步减轻项目构建中的工作量,让我们程序员全身心投入到开发之中。在这些工具中,不得不提Automake和CMake。3.1 AutomakeAutomake其实是一系列工具集Autotools中的一员,要想发挥Automake的威力,需要配合使用Autotools中的其他工具,例如autoscan、aclocal、autoconf和autoheader。在下面的Automake构建流程中,能看到这些工具的身影。autoscan:生成configure.scanconfigure.in:将configure.scan重命名为configure.in后,修改内容。重点是AM_INIT_AUTOMAKE和AC_CONFIG_FILES两项,如果没配置的话,下一步的aclocal是无法产生aclocal.m4的aclocal:生成aclocal.m4autoconf:生成configureautoheader:生成config.h.in,使程序可移植Makefile.am:手动编写Makefile.am。bin_PROGRAMS指定最终生成可执行文件的名称,helloworld_SOURCES指定所有源文件NEWS AUTHORS README ChangeLog:手动创建automake:执行automake -a生成Makefile.inconfigure:执行./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=mainmain_SOURCES=main.c hello.c# Step 7:[root@vm automaketest# touch NEWS README AUTHORS ChangeLog# Step 8:[root@vm automaketest# automake -aconfigure.in:6: installing './install-sh'configure.in:6: installing './missing'Makefile.am: installing './INSTALL'Makefile.am: installing './COPYING' using GNU General Public License v3 fileMakefile.am: Consider adding the COPYING file to the version control systemMakefile.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 -cchecking whether build environment is sane... yeschecking for a thread-safe mkdir -p... /bin/mkdir -pchecking for gawk... gawkchecking whether make sets $(MAKE)... yeschecking for gcc... gccchecking for C compiler default output file name... a.outchecking whether the C compiler works... yeschecking whether we are cross compiling... nochecking for suffix of executables... checking for suffix of object files... ochecking whether we are using the GNU C compiler... yeschecking whether gcc accepts -g... yeschecking for gcc option to accept ISO C89... none neededchecking for style of include used by make... GNUchecking dependency style of gcc... gcc3configure: creating ./config.statusconfig.status: creating Makefileconfig.status: creating config.hconfig.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 distcleantest -z "main" || rm -f mainrm -f *.orm -f *.tab.ctest -z "" || rm -f test . = "." || test -z "" || rm -f rm -f config.h stamp-h1rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tagsrm -f config.status config.cache config.log configure.lineno config.status.linenorm -rf ./.depsrm -f Makefile测试一下,看看Automake生成的Makefile是否能正常工作。[root@vm automaketest# makemake all-ammake[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.cmv -f .deps/main.Tpo .deps/main.Pogcc -DHAVE_CONFIG_H -I. -g -O2 -MT hello.o -MD -MP -MF .deps/hello.Tpo -c -o hello.o hello.cmv -f .deps/hello.Tpo .deps/hello.Pogcc -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# makeScanning dependencies of target main[ 50 Building C object CMakeFiles/main.dir/main.c.o[100 Building C object CMakeFiles/main.dir/hello.c.oLinking C executable main[100 Built target main
资料来源于网络

相关帖子

沙发
二九结狐六体| | 2019-1-29 10:33 | 只看该作者
有点乱啊

使用特权

评论回复
板凳
yjmwxwx| | 2019-1-29 17:37 | 只看该作者

明远智睿这些发帖的是从网啊赚平台雇来的吧

使用特权

评论回复
地板
明远智睿Lan|  楼主 | 2019-1-31 11:39 | 只看该作者
yjmwxwx 发表于 2019-1-29 17:37
明远智睿这些发帖的是从网啊赚平台雇来的吧

看到好的就分享,相互学习

使用特权

评论回复
5
明远智睿Lan|  楼主 | 2019-1-31 11:40 | 只看该作者

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

206

主题

261

帖子

4

粉丝