您的位置:首页

project管理之makefile与自己主动创建makefile文件过程

2017-07-22 17:13 405 查看
(风雪之隅 http://www.laruence.com/2009/11/18/1154.html)[/code] 


Linux Makefile自己主动编译和链接使用的环境

想知道到Linux Makefile系统的真相么,想知道Linux Makefile系统中藏有的内在奥义么,仅仅有我来给大家全面解说介绍Linux Makefile系统作为Linux下的程序开发者,大家一定都遇到过Linux Makefile,用make命令来编译自己写的程序确实是非常方便。普通情况下,大家都是手工写一个简单Linux Makefile,假设要想写出一个符合自由软件惯例的Linux Makefile就不那么easy了。

在本文中。将给大家介绍怎样使用autoconf和automake两个工具来帮助我们自己主动地生成符合自由软件惯例的Linux Makefile,这样就能够象常见的GNU程序一样。仅仅要使用“./configure”,“make”。“make instal”就能够把程序安装到Linux系统中去了。这将特别适合想做开放源码软件的程序开发者。又或假设你仅仅是自己写些小的Toy程序。那么这个文章对你也会有非常大的帮助。

一、Linux Makefile介绍

Linux Makefile是用于自己主动编译和链接的。一个project有非常多文件组成。每个文件的改变都会导致project的又一次链接,可是不是全部的文件都须要又一次编译,Linux Makefile中纪录有文件的信息,在Linux Makefile时会决定在链接的时候须要又一次编译哪些文件。

Linux Makefile的宗旨就是:让编译器知道要编译一个文件须要依赖其它的哪些文件。当那些依赖文件有了改变,编译器会自己主动的发现终于的生成文件已经过时。而又一次编译对应的模块。

Linux Makefile的基本结构不是非常复杂。但当一个程序开发者開始写Linux Makefile时,常常会怀疑自己写的是否符合惯例,并且自己写的 Linux Makefile常常和自己的开发环境相关联,当系统环境变量或路径发生了变化后,Linux Makefile可能还要跟着改动。这样就造成了手工书写 Linux Makefile的诸多问题,automake恰好能非常好地帮助我们解决这些问题。

使用automake,程序开发者仅仅须要写一些简单的含有提前定义宏的文件。由autoconf依据一个宏文件生成configure,由automake依据还有一个宏文件生成Linux Makefile.in,再使用configure依据Linux Makefile.in来生成一个符合惯例的Linux Makefile。以下我们将具体介绍Linux Makefile的automake生成方法。

二、使用的环境

本文所提到的程序是基于Linux发行版本号:Fedora Core release 1。它包括了我们要用到的autoconf。automake。

三、从helloworld入手

我们从大家最常使用的样例程序helloworld開始。以下的过程假设简单地说来就是:新建三个文件:

helloworld.c
configure.in
Linux Makefile.am


然后运行:

aclocal; autoconf; automake --add-missing; ./configure; make; ./helloworld

就能够看到Linux Makefile被产生出来,并且能够将helloworld.c编译通过。非常easy吧。几条命令就能够做出一个符合惯例的Linux Makefile。感觉怎样呀。如今開始介绍具体的过程:

1、建文件夹

在你的工作文件夹下建一个helloworld文件夹,我们用它来存放helloworld程序及相关文件,如在/home/my/build下:

$ mkdir helloword

$ cd helloworld

2、 helloworld.c

然后用你自己最喜欢的编辑器写一个hellowrold.c文件。如命令:vi helloworld.c。

使用以下的代码作为helloworld.c的内容。

int main(int argc, char** argv)
{
printf("Hello, Linux World!/n");
return 0;
}


完毕后保存退出。如今在helloworld文件夹下就应该有一个你自己写的helloworld.c了。

3、生成configure

我们使用autoscan命令来帮助我们依据文件夹下的源码生成一个configure.in的模板文件。

命令:

$ autoscan
$ ls
configure.scan helloworld.c


运行后在hellowrold文件夹下会生成一个文件:configure.scan,我们能够拿它作为configure.in的蓝本。如今将configure.scan改名为configure.in,而且编辑它,按以下的内容改动,去掉无关的语句:

configure.in内容開始

# -*- Autoconf -*-

# Process this file with autoconf to produce a configure script.

AC_INIT(helloworld.c)

AM_INIT_AUTOMAKE(helloworld, 1.0)

# 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_OUTPUT(Linux Makefile)

configure.in内容结束

然后运行命令aclocal和autoconf,分别会产生aclocal.m4及configure两个文件:

$ aclocal
$ls
aclocal.m4 configure.in helloworld.c
$ autoconf
$ ls
aclocal.m4 autom4te.cache configure configure.in helloworld.c


大家能够看到configure.in内容是一些宏定义。这些宏经autoconf处理后会变成检查系统特性、环境变量、软件必须的參数的shell脚本。autoconf 是用来生成自己主动配置软件源码脚本(configure)的工具。

configure脚本能独立于autoconf执行,且在执行的过程中。不须要用户的干预。要生成configure文件,你必须告诉autoconf怎样找到你所用的宏。方式是使用aclocal程序来生成你的aclocal.m4。

aclocal依据configure.in文件的内容。自己主动生成aclocal.m4文件。

aclocal是一个perl 脚本程序。它的定义是:“aclocal - create aclocal.m4 by scanning configure.ac”。autoconf从configure.in这个列举编译软件时所须要各种參数的模板文件里创建configure。autoconf须要GNU m4宏处理器来处理aclocal.m4,生成configure脚本。

m4是一个宏处理器。将输入复制到输出。同一时候将宏展开。宏能够是内嵌的,也能够是用户定义的。除了能够展开宏,m4另一些内建的函数,用来引用文件,运行命令。整数运算,文本操作,循环等。

m4既能够作为编译器的前端。也能够单独作为一个宏处理器。

4、新建Linux Makefile.am

新建Linux Makefile.am文件。命令:$ vi Linux Makefile.am 内容例如以下:

AUTOMAKE_OPTIONS=foreign
bin_PROGRAMS=helloworld
helloworldhelloworld_SOURCES=helloworld.c


automake会依据你写的Linux Makefile.am来自己主动生成Linux Makefile.in。Linux Makefile.am中定义的宏和目标,会指导automake生成指定的代码。比如,宏bin_PROGRAMS将导致编译和连接的目标被生成。

5、执行automake

命令:

$ automake --add-missing
configure.in: installing `./install-sh'
configure.in: installing `./mkinstalldirs'
configure.in: installing `./missing'
Linux Makefile.am: installing `./depcomp'


automake会依据Linux Makefile.am文件产生一些文件,包括最重要的Linux Makefile.in。

6、运行configure生成Linux Makefile

$ ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for gcc... gcc
checking for C compiler default output... 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 ANSI C... none needed
checking for style of include used by make... GNU
checking dependency style of gcc... gcc3
configure: creating ./config.status
config.status: creating Linux Makefile
config.status: executing depfiles commands
$ ls -l Linux Makefile
-rw-rw-r-- 1 yutao yutao 15035 Oct 15 10:40 Linux Makefile


你能够看到,此时Linux Makefile已经产生出来了。

7、使用Linux Makefile编译代码

$ make if gcc -DPACKAGE_NAME="" -DPACKAGE_TARNAME="" -DPACKAGE_VERSION="" -DPACKAGE_STRING="" -DPACKAGE_BUGREPORT="" -DPACKAGE="helloworld" -DVERSION="1.0"

-I. -I. -g -O2 -MT helloworld.o -MD -MP -MF ".deps/helloworld.Tpo" /-c -o helloworld.o `test -f 'helloworld.c' || echo './'`helloworld.c; /then mv -f ".deps/helloworld.Tpo" ".deps/helloworld.Po"; /else rm -f ".deps/helloworld.Tpo"; exit 1; /figcc -g -O2 -o
helloworld helloworld.o 执行helloworld$ ./helloworld Hello, Linux World!

这样helloworld就编译出来了,你假设按上面的步骤来做的话,应该也会非常easy地编译出正确的helloworld文件。你还能够试着使用一些其它的make命令,如make clean,make install,make dist,看看它们会给你什么样的效果。

感觉怎样?自己也能写出这么专业的Linux Makefile,老板一定会对你刮目相看。

四、深入浅出

针对上面提到的各个命令,我们再做些具体的介绍。

1、 autoscan

autoscan是用来扫描源码文件夹生成configure.scan文件的。

autoscan能够用文件夹名做为參数,但假设你不使用參数的话,那么 autoscan将觉得使用的是当前文件夹。autoscan将扫描你所指定文件夹中的源文件,并创建configure.scan文件。

2、 configure.scan

configure.scan包括了系统配置的基本选项,里面都是一些宏定义。我们须要将它改名为configure.in

3、 aclocal

aclocal是一个perl 脚本程序。aclocal依据configure.in文件的内容,自己主动生成aclocal.m4文件。

aclocal的定义是:“aclocal - create aclocal.m4 by scanning configure.ac”。

4、 autoconf

autoconf是用来产生configure文件的。

configure是一个脚本,它能设置源程序来适应各种不同的操作系统平台,而且依据不同的系统来产生合适的Linux Makefile,从而能够使你的源码能在不同的操作系统平台上被编译出来。

configure.in文件的内容是一些宏,这些宏经过autoconf 处理后会变成检查系统特性、环境变量、软件必须的參数的shell脚本。configure.in文件里的宏的顺序并没有规定。可是你必须在全部宏的最前面和最后面分别加上AC_INIT宏和AC_OUTPUT宏。

在configure.ini中:#号表示凝视,这个宏后面的内容将被忽略。AC_INIT(FILE) 这个宏用来检查源码所在的路径。

AM_INIT_AUTOMAKE(PACKAGE, VERSION) 这个宏是必须的。它描写叙述了我们将要生成的软件包的名字及其版本:PACKAGE是软件包的名字。VERSION是版本。

当你使用make dist命令时,它会给你生成一个类似helloworld-1.0.tar.gz的软件发行包,当中就有相应的软件包的名字和版本。AC_PROG_CC这个宏将检查系统所用的C编译器。 AC_OUTPUT(FILE)这个宏是我们要输出的Linux Makefile的名字。

我们在使用automake时,实际上还须要用到其它的一些宏。但我们能够用aclocal 来帮我们自己主动产生。运行aclocal后我们会得到aclocal.m4文件。产生了configure.in和aclocal.m4 两个宏文件后。我们就能够使用autoconf来产生configure文件了。

5、 Linux Makefile.am

Linux Makefile.am是用来生成Linux Makefile.in的,须要你手工书写。Linux Makefile.am中定义了一些内容:AUTOMAKE_OPTIONS 这个是automake的选项。在运行automake时,它会检查文件夹下是否存在标准GNU软件包中应具备的各种文件。比如AUTHORS、ChangeLog、NEWS等文件。

我们将其设置成foreign时。automake会改用一般软件包的标准来检查。

bin_PROGRAMS这个是指定我们所要产生的可运行文件的文件名称。假设你要产生多个可运行文件,那么在各个名字间用空格隔开。 helloworld_SOURCES 这个是指定产生“helloworld”时所须要的源码。

假设它用到了多个源文件。那么请使用空格符号将它们隔开。

比方须要 helloworld.h,helloworld.c那么请写成helloworld_SOURCES= helloworld.h helloworld.c。

假设你在bin_PROGRAMS定义了多个可运行文件。则相应每一个可运行文件都要定义相对的filename_SOURCES。

6、 automake

我们使用automake --add-missing来产生Linux Makefile.in。

选项--add-missing的定义是“add missing standard files to package”,它会让automake增加一个标准的软件包所必须的一些文件。

我们用automake产生出来的Linux Makefile.in文件是符合GNU Linux Makefile惯例的,接下来我们仅仅要运行configure这个shell
脚本就能够产生合适的 Linux Makefile 文件了。

7、 Linux Makefile

在符合GNU Makefiel惯例的Linux Makefile中,包括了一些主要的预先定义的操作:make依据Linux Makefile编译源码,连接,生成目标文件,可运行文件。make clean清除上次的make命令所产生的object文件(后缀为“.o”的文件)及可运行文件。

make install将编译成功的可运行文件安装到系统文件夹中,一般为/usr/local/bin文件夹。make dist产生公布软件包文件(即distribution package)。

这个命令将会将可运行文件及相关文件打包成一个tar.gz压缩的文件用来作为公布软件的软件包。它会在当前文件夹下生成一个名字类似“PACKAGE-VERSION.tar.gz”的文件。

PACKAGE和VERSION,是我们在configure.in中定义的AM_INIT_AUTOMAKE(PACKAGE, VERSION)。

make distcheck生成公布软件包并对其进行測试检查,以确定公布包的正确性。这个操作将自己主动把压缩包文件解开,然后运行configure命令。

而且运行make,来确认编译不出现错误,最后提示你软件包已经准备好,能够公布了。helloworld-1.0.tar.gz is ready for distributionmake distclean 类似make clean,但同一时候也将configure生成的文件所有删除掉。包含Linux Makefile。

五、结束语

通过上面的介绍,你应该能够非常easy地生成一个你自己的符合GNU惯例的Linux Makefile文件及相应的项目文件。假设你想写出更复杂的且符合惯例的Linux Makefile,你能够參考一些开放代码的项目中的configure.in和Linux Makefile.am文件,比方:嵌入式数据库sqlite,单元測试cppunit。

【推荐】

Linux Makefile介绍使用的环境深入浅出

阐述Linux Makefile文件概念

Linux Makefile由浅入深剖析

linux makefile文件心得笔记

Linux系统手工挂载和自己主动挂载

例解 Linux 下 make 命令(http://blog.csdn.net/hazir/article/details/18408007)

Linux 下 make 命令是系统管理员和程序猿用的最频繁的命令之中的一个。管理员用它通过命令行来编译和安装非常多开源的工具。程序猿用它来管理他们大型复杂的项目编译问题。本文我们将用一些实例来讨论 make 命令背后的工作机制。


Make
怎样工作的

对于不知道背后机理的人来说。make 命令像命令行參数一样接收目标。这些目标通常存放在以 “Makefile” 来命名的特殊文件里,同一时候文件也包括与目标相相应的操作。

很多其它信息,阅读关于 Makefiles 怎样工作的系列文章。

当 make 命令第一次运行时,它扫描 Makefile 找到目标以及其依赖。假设这些依赖自身也是目标,继续为这些依赖扫描 Makefile 建立其依赖关系,然后编译它们。

一旦主依赖编译之后。然后就编译主目标(这是通过 make 命令传入的)。

如今,如果你对某个源文件进行了改动,你再次运行 make 命令,它将仅仅编译与该源文件相关的目标文件。因此,编译完终于的可运行文件节省了大量的时间。


Make
命令实例

以下是本文所使用的測试环境:

OS —— Ubunut 13.04
Shell —— Bash 4.2.45
Application —— GNU Make 3.81


以下是project的内容:

$ ls
anotherTest.c Makefile test.c test.h


以下是 Makefile 的内容:

all: test

test: test.o anotherTest.o
gcc -Wall test.o anotherTest.o -o test

test.o: test.c
gcc -c -Wall test.c

anotherTest.o: anotherTest.c
gcc -c -Wall anotherTest.c

clean:
rm -rf *.o test


如今我们来看 Linux 下一些 make 命令应用的实例:


1.
一个简单的样例

为了编译整个project,你能够简单的使用
make
或者在 make 命令后带上目标
all


$ make
gcc -c -Wall test.c
gcc -c -Wall anotherTest.c
gcc -Wall test.o anotherTest.o -o test


你能看到 make 命令第一次创建的依赖以及实际的目标。

假设你再次查看文件夹内容。里面多了一些 .o 文件和运行文件:

$ ls
anotherTest.c anotherTest.o Makefile test test.c test.h test.o


如今。如果你对 test.c 文件做了一些改动,又一次使用 make 编译project:

$ make
gcc -c -Wall test.c
gcc -Wall test.o anotherTest.o -o test


你能够看到仅仅有 test.o 又一次编译了,然而还有一个 Test.o 没有又一次编译。

如今清理全部的目标文件和可运行文件 test,你能够使用目标
clean
:

$ make clean
rm -rf *.o test

$ ls anotherTest.c Makefile test.c test.h


你能够看到全部的 .o 文件和运行文件 test 都被删除了。


2.
通过 -B 选项让全部目标总是又一次建立

到眼下为止,你可能注意到 make 命令不会编译那些自从上次编译之后就没有更改的文件。可是,假设你想覆盖 make 这样的默认的行为,你能够使用 -B 选项。

以下是个样例:

$ make
make: Nothing to be done for `all’.

$ make -B
gcc -c -Wall test.c
gcc -c -Wall anotherTest.c
gcc -Wall test.o anotherTest.o -o test


你能够看到虽然 make 命令不会编译不论什么文件,然而
make -B
会强制编译全部的目标文件以及终于的运行文件。


3.
使用 -d 选项打印调试信息

假设你想知道 make 运行时实际做了什么,使用 -d 选项。

这是一个样例:

$ make -d | more
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.

This program built for x86_64-pc-linux-gnu
Reading makefiles…
Reading makefile `Makefile’…
Updating makefiles….
Considering target file `Makefile’.
Looking for an implicit rule for `Makefile’.
Trying pattern rule with stem `Makefile’.
Trying implicit prerequisite `Makefile.o’.
Trying pattern rule with stem `Makefile’.
Trying implicit prerequisite `Makefile.c’.
Trying pattern rule with stem `Makefile’.
Trying implicit prerequisite `Makefile.cc’.
Trying pattern rule with stem `Makefile’.
Trying implicit prerequisite `Makefile.C’.
Trying pattern rule with stem `Makefile’.
Trying implicit prerequisite `Makefile.cpp’.
Trying pattern rule with stem `Makefile’.
--More--


这是非常长的输出。你也看到我使用了
more
命令来一页一页显示输出。


4.
使用 -C 选项改变文件夹

你能够为 make 命令提供不同的文件夹路径。在寻找 Makefile 之前会切换文件夹的。

这是一个文件夹,如果你就在当前文件夹下:

$ ls
file file2 frnd frnd1.cpp log1.txt log3.txt log5.txt
file1 file name with spaces frnd1 frnd.cpp log2.txt log4.txt


可是你想执行的 make 命令的 Makefile 文件保存在 ../make-dir/ 文件夹下,你能够这样做:

$ make -C ../make-dir/
make: Entering directory `/home/himanshu/practice/make-dir’
make: Nothing to be done for `all’.
make: Leaving directory `/home/himanshu/practice/make-dir


你能看到 make 命令首先切到特定的文件夹下,在那运行,然后再切换回来。


5.
通过 -f 选项将其他文件看作 Makefile

假设你想将重命名 Makefile 文件。比方取名为 my_makefile 或者其他的名字。我们想让 make 将它也当成 Makefile。能够使用 -f 选项。

make -f my_makefile


通过这样的方法,make 命令会选择扫描 my_makefile 来取代 Makefile。

原文链接:http://linoxide.com/how-tos/linux-make-command-examples/

Makefile自己主动生成工具-----autotools的使用(具体)

相信每一个学习Linux的人都知道Makefile,这是一个非常实用的东西,可是编写它是比較复杂。今天介绍一个它的自己主动生成工具,autotools的使用。

非常多GNULinux的的软件都是用它生成Makefile的。包含我们非常熟悉的Linux内核源码。

1、准备:

须要工具

autoscan

aclocal

autoheader

automake

autoconf

auto make

在终端敲入命令。哪个没有安装哪个。通常是第一个autoscan没有。其他的我用的Ubuntu10.04下所有都有

2、測试程序编写:

建立文件夹:mkdir include src

编敲代码:include/str.h

[cpp] view
plain copy

#include <stdio.h>

int str(char *string);

编敲代码:src/str.c

[cpp] view
plain copy

#include "str.h"

//print string

int str(char *string){

printf("\n----PRINT STRING----\n\"%s\"\n",string);

return 0;

}

//interface of this program

int main(int argc , char **argv){

char str_read[1024];

printf("Please INPUT something end by [ENTER]\n");

scanf("%s",str_read);

return str(str_read );

}

3、生成configure.ac

configure.ac是automake的输入文件。所以必须先生成该文件。

运行命令:

[cpp] view
plain copy

[root@localhost str]# ls

include src

[root@localhost str]# autoscan

autom4te: configure.ac: no such file or directory

autoscan: /usr/bin/autom4te failed with exit status: 1

[root@localhost str]# ls

autoscan.log configure.scan include src

[root@localhost str]# cp configure.scan configure.ac

改 configure.ac

[cpp] view
plain copy

# -*- Autoconf -*-

# Process this file with autoconf to produce a configure script.

AC_PREREQ(2.59)

AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)

AC_CONFIG_SRCDIR([include/str.h])

AC_CONFIG_HEADER([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_OUTPUT

改动

[cpp] view
plain copy

AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)

改为:

[cpp] view
plain copy

AC_INIT(str,0.0.1, [bug@sounos.org])

当中:FULL-PACKAGE-NAME 为程序名称,VERSION为当前版本号。 BUG-REPORT-ADDRESS为bug汇报地址

然后加入两句话:

AM_INIT_AUTOMAKE

AC_CONFIG_FILES([Makefile])

结果例如以下:(两句话不是在一起的)

[cpp] view
plain copy

# -*- Autoconf -*-

# Process this file with autoconf to produce a configure script.

AC_PREREQ(2.59)

#AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)

AC_INIT(str, 0.0.1, [bug@sounos.org])

AM_INIT_AUTOMAKE

AC_CONFIG_SRCDIR([include/str.h])

AC_CONFIG_HEADER([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

4、运行aclocal

[cpp] view
plain copy

[root@localhost str]# aclocal

/usr/share/aclocal/libfame.m4:6: warning: underquoted definition of AM_PATH_LIBFAME

run info '(automake)Extending aclocal'

or see http://sources.redhat.com/automake/automake.html#Extending-aclocal
5、制作Makefile.am

[cpp] view
plain copy

[root@localhost str]# vi Makefile.am

#Makefile.am

bin_PROGRAMS = str

str_SOURCES = include/str.h src/str.c

str_CPPFLAGS = -I include/

automake 这个命令须要用到这个配置文件。

各个选项意思比較直观。不多说。

6、autoheader

[cpp] view
plain copy

[root@localhost str]# autoheader

7、automake必须文件:

[cpp] view
plain copy

* install-sh

* missing

* INSTALL

* NEWS

* README

* AUTHORS

* ChangeLog

* COPYING

* depcomp

当中,下面文件在运行automake -a的时候会自己主动生成

[cpp] view
plain copy

* install-sh

* missing

* INSTALL

* COPYING

* depcomp

所以,接下来手动生成剩下的文件

[cpp] view
plain copy

[root@localhost str]# touch NEWS README AUTHORS ChangeLog

8、运行automake -a

[cpp] view
plain copy

[root@localhost str]# automake -a

configure.ac: installing `./install-sh'

configure.ac: installing `./missing'

Makefile.am: installing `./INSTALL'

Makefile.am: installing `./COPYING'

Makefile.am: installing `./compile'

Makefile.am: installing `./depcomp'

9、autoconf

[cpp] view
plain copy

[root@localhost str]# autoconf

[root@localhost str]# ls

aclocal.m4 autoscan.log config.h.in configure.scan include Makefile.am NEWS

AUTHORS ChangeLog configure COPYING INSTALL Makefile.in README

autom4te.cache compile configure.ac depcomp install-sh missing src

10、运行測试:

运行./configure

[cpp] view
plain copy

[root@localhost str]# ./configure --prefix=/u

checking for a BSD-compatible install... /usr/bin/install -c

checking whether build environment is sane... yes

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 ANSI C... 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: config.h is unchanged

config.status: executing depfiles commands

运行 make

[cpp] view
plain copy

[root@localhost str]# make

make all-am

make[1]: Entering directory `/data/devel/c/str'

if gcc -DHAVE_CONFIG_H -I. -I. -I. -I include/ -g -O2 -MT str-str.o -MD -MP -MF ".deps/str-str.Tpo" -c -o str-str.o `test -f 'src/str.c' || echo './'`src/str.c; \

then mv -f ".deps/str-str.Tpo" ".deps/str-str.Po"; else rm -f ".deps/str-str.Tpo"; exit 1; fi

gcc -g -O2 -o str str-str.o

make[1]: Leaving directory `/data/devel/c/str'

此时已经生成了 str(可执行文件名称字在前面设置Makefile.am的參数时候去顶)这个,能够通过./str直接看到执行结果

[cpp] view
plain copy

[root@localhost str]# ./str

Please INPUT something end by [ENTER]

abcksdhfklsdklfdjlkfd

----PRINT STRING----

"abcksdhfklsdklfdjlkfd"

只是这里我们都做一步,把它安装到系统里面,这样我们仅仅要在终端输入str就能够执行程序了。

运行 make install:

[cpp] view
plain copy

[root@localhost str]# make install

make[1]: Entering directory `/data/devel/c/str'

test -z "/u/bin" || mkdir -p -- "/u/bin"

/usr/bin/install -c 'str' '/u/bin/str'

make[1]: Nothing to be done for `install-data-am'.

make[1]: Leaving directory `/data/devel/c/str'

接下来你能够make clean 清除安装的那些.o 文件了。这样生成了一个自己主动的Makefile。


Easymake 使用说明


介绍

Easymake 是一个在linux系统中 C/C++ 开发的通用 makefile。在一个简单的 C/C++ 程序中使用 easymake。你甚至能够不写一行 makefile 代码来生成目标文件。

Easymake 包括下面功能:

自己主动扫描 C/C++ 源文件。
自己主动生成和维护依赖关系,加快编译时间。
支持简单的单元測试,能够非常方便地管理多个程序入口(main 函数)。
完美地支持
VPATH
变量。

我将在后面的样例中一步步地向你展示怎样使用 easymake 来构建你的应用程序。别看文档这么长,以下一节的内容中大部分是在讲一个简单的 C/C++ 程序的开发。

就像 easymake 的名字一样,easymake 是很易学易用的。


開始学习 Easymake

在这一节中将展示怎样在一个简单的程序中使用 easymake。

接下来让我们一个加法程序,用户输入两个数字。然后程序输出这两个数字相加的结果。这个程序的源码能够在
samples/basics
文件夹中找到。


C/C++ 代码

这个程序非常easy,所以这里跳过程序设计环节。这里直接展示程序的 C/C++ 代码,然后再转入我们的正题。

File: main.cpp

#include <iostream>

#include "math/add.h"

using namespace std;

int main(){
cout<<"please enter two integer:"<<endl;

int a,b;
cin>>a>>b;

cout<<"add("<<a<<","<<b<<") returns "<<add(a,b)<<endl;
}


File: math/add.h

#ifndef ADD_H
#define ADD_H

int add(int,int);

#endif


File: math/add.cpp

#include "math/add.h"

int add(int a,int b){
return a+b;
}


使用 Easymake 来构建程序

代码非常easy,能够直接使用命令行来构建程序。假设你对 makefile 的语法熟悉。你也能够非常快地写出一个 makefile 来做完毕这个事情。那么怎样使用 easymake 来构建这个程序呢?先别急,接下来将使用刚才提到的三种方法来构建程序,希望你能清晰地了解和比較这三种方式。


使用命令行构建

g++ -c -o main.o main.cpp
g++ -c -o add.o math/add.cpp -I.
g++ -o target main.o add.o


或者也能够仅仅用一条命令
g++
-o target main.cpp math/add.cpp -I.
来构建程序。

然后输入
ls
./target
,就能够观察到程序的运行结果了:

[root@VM_6_207_centos basics]# ls
add.o  bin  main.cpp  main.o  makefile  math  target
[root@VM_6_207_centos basics]# ./target
please enter two integer:
5
3
add(5,3) returns 8


自己写一个 makefile 构建程序

创建一个新的 Makefile 文件,代码例如以下:

target: main.o add.o
g++ -o target main.o add.o

main.o: main.cpp
g++ -c -o main.o main.cpp -I.

add.o: math/add.cpp
g++ -c -o add.o math/add.cpp -I.


结果基本是一样的:

[root@VM_6_207_centos basics]# make
g++ -c -o main.o main.cpp -I.
g++ -c -o add.o math/add.cpp -I.
g++ -o target main.o add.o
[root@VM_6_207_centos basics]# ls
add.o  main.cpp  main.o  makefile  math  target
[root@VM_6_207_centos basics]# ./target
please enter two integer:
8
9
add(8,9) returns 17


使用 makefile 的优点就是,如果能非常好地确定依赖关系,那么就不须要在每次构建时把全部的源文件都又一次编译一次。可是随着项目的代码的增长。即使在一个良好的模块化设计中,手工维护依赖关系也是一件非常繁琐并且非常easy出错的工作。

比如,如果我们须要添加一个
multiply.cpp
multiply.h
文件,让程序支持乘法计算的功能。那么我必须改动我们的
makefile 才干构建新的程序。另外,假设头文件
add.h
被改动了,
multiply.cpp
就不须要又一次编译。所以我们应该在
makefile 中添加 .cpp 文件和 .h 文件之间的依赖关系的代码。

到这里,我想你也会认为我们应该有一个通用的 makefile 来帮助我们自己主动维护依赖关系了吧。


使用 easymake 构建程序

在这个样例中,包括
easymake.mk
文件就足够了。把我们的
Makefile 改动成以下的代码:

include ../../easymake.mk


在命令行中输入
make
构建我们的程序。接下来我们给你展示一些细节来帮助你理解
makefile 是怎样构建程序的。

[root@VM_6_207_centos basics]# ls
main.cpp  makefile  math
[root@VM_6_207_centos basics]# make
g++ -c -o bin/main.o main.cpp  -I.
entry detected
g++ -c -o bin/math/add.o math/add.cpp  -I.
g++ -o bin/target bin/main.o bin/math/add.o
BUILD_ROOT/TARGET: bin/target
ENTRY: main.cpp
[root@VM_6_207_centos basics]# ./bin/target
please enter two integer:
3
5
add(3,5) returns 8


你或许也已经注意到。和之前的方式相比。基本的不同就是输出中的
entry
detected
BUILD_ROOT/TARGET:
bin/target
ENTRY:
main.cpp
bin/target
就是我们的程序。至于这里的entry。会在后面讲到。

如今能够看一下当前的文件夹结构:

[root@VM_6_207_centos basics]# tree .
.
├── bin
│   ├── easymake_current_entry_file
│   ├── easymake_detected_entries
│   ├── easymake_entries_tmp.d
│   ├── main.d
│   ├── main.o
│   ├── math
│   │   ├── add.d
│   │   └── add.o
│   └── target
├── main.cpp
├── makefile
└── math
├── add.cpp
└── add.h

3 directories, 12 files


Easymake 使用
bin
文件夹作为
BUILD_ROOT
,用来存放生成的文件。这样一来我们的源文件文件夹也不会被污染。这里面的
*.d
easy_make_*
文件都是由
easymake 额外生成用来维护依赖关系的。
*.d
的文件事实上也算是
makefile 的一部分。比如 main.d 文件的内容例如以下:

[root@VM_6_207_centos basics]# cat bin/main.d
bin/main.o: main.cpp math/add.h

math/add.h:


这些依赖关系是 easymake 自己主动生成的,所以每当
math/add.h
被改动了,
main.o
就会又一次生成。其实,你不须要关注这些细节来使用
easymake,所以我们就忽略这些额外生成的文件吧。假设你有兴趣。能够查看
easymake.mk
的源码,我认为代码的凝视得已经足够帮助你理解了。


用户选项

假设你想使用 gcc 编译器的
-O2
优化选项和链接器的
-static
选项来构建这个程序。那么你须要添加几行代码来改动编译和链接选项。

以下是改动后的
makefile:

COMPILE_FLAGS   += -O2
LINK_FLAGS      += -static

include ../../easymake.mk


然后又一次构建程序:

[root@VM_6_207_centos basics]# make clean
rm -f \$(find bin -name \*.o)
rm -f \$(find bin -name \*.d)
rm -f \$(find bin -name \*.a)
rm -f \$(find bin -name \*.so)
rm -f \$(find bin -name \*.out)
rm -f bin/target
[root@VM_6_207_centos basics]# make
g++ -c -o bin/main.o main.cpp -O2  -I.
entry detected
g++ -c -o bin/math/add.o math/add.cpp -O2  -I.
g++ -o bin/target bin/main.o bin/math/add.o  -static
BUILD_ROOT/TARGET: bin/target
ENTRY: main.cpp


除些以外。还有很多其它可供设置的选项。使用
make
help
命令你就能够看到它们。

注意 basic settings 和user settings 两部分的内容就可以,其它部分能够忽略。

[root@VM_6_207_centos basics]# make help
---------------------
basic settings:
SETTINGS_ROOT       : build_settings
BUILD_ROOT          : bin
TARGET              : target
VPATH               :
CPPEXT              : cpp
CEXT                : c
GCC                 : gcc
GXX                 : g++
LINKER              : g++
---------------------
user settings files:
build_settings/entry_list
build_settings/compile_flags
build_settings/compile_search_path
build_settings/link_flags
build_settings/link_search_path
---------------------
user settings:
ENTRY_LIST          :
ENTRY               :
COMPILE_FLAGS       : -O2
COMPILE_SEARCH_PATH :  .
LINK_FLAGS          : -static
LINK_SEARCH_PATH    :
CPPSOURCES          : main.cpp math/add.cpp
CSOURCES            :
---------------------
internal informations:
...
...
...


用来測试的程序入口

如今我们须要给程序添加一个乘法运算功能,首先写一个 C++ 函数来做乘法运算,然后。在我们改动
main.cpp
的代码之前,我们应该測试一下这个这个
C++ 函数的功能,确保新添加的乘法模块的逻辑是正确的。以下的样例会告诉你假设使用 easymake 来完毕这项工作,你能够在
samples/entries
目录中找到这个样例的代码。


编写乘法模块的代码

File
math/multiply.h
:

#ifndef MULTIPLY_H
#define MULTIPLY_H

#include "stdint.h"

int64_t multiply(int32_t,int32_t);

#endif


File
math/multiply.cpp
:

#include "math/multiply.h"

int64_t multiply(int32_t a,int32_t b){
return (int64_t)a*(int64_t)b;
}


编写測试代码

在命令行中输入
mkdir
test
vim
test/multiply.cpp
然后编写我们的代码。为了简单起见。这里不过在
main
函数中打印了
8 乘 8 的结果。

#include "math/multiply.h"

#include <iostream>

using namespace std;

int main(){
cout<<"multiply(8,8)="<<multiply(8,8)<<endl;
}


构建測试程序

如今直接输入命令
make
./bin/target
就能够看到測试程序的输出了。

[root@VM_6_207_centos entries]# make
g++ -c -o bin/main.o main.cpp -O2  -I.
entry detected
g++ -c -o bin/math/add.o math/add.cpp -O2  -I.
g++ -c -o bin/math/multiply.o math/multiply.cpp -O2  -I.
g++ -c -o bin/test/multiply.o test/multiply.cpp -O2  -I.
entry detected
g++ -o bin/target bin/math/add.o bin/math/multiply.o bin/test/multiply.o  -static
BUILD_ROOT/TARGET: bin/target
ENTRY: test/multiply.cpp
[root@VM_6_207_centos entries]# ./bin/target
multiply(8,8)=64
[root@VM_6_207_centos entries]#


注意到
main.cpp
test/multiply.cpp
都有被成功编译,可是仅仅有
test/multiply.cpp
被链接到目标文件里。并且输出中
ENTRY
相应的值也变成了
test/multiply.cpp
。在
easymake,全体一个包括
main
函数定义的源文件都会被自己主动检測到。而且被当作程序入口文件(
ENTRY
)。在众多入口文件其中,仅仅有一个会被选中,其它文件不会被链接到目标文件里。

另外注意这里的
ENTRY
所表示的文件名称相应的文件也能够不存在。在某些场景中,比如生成动态库
so 文件。就须要选择这个
ENTRY
来阻止其它入口文件被链接到目标文件里。

如今你肯定是在纳闷。easymake 是怎样知道要选择
test/multiply.cpp
而不是
main.cpp
的?是不是非常奇妙?事实上这里使用的是入口文件的最后改动时间。假设有多个入口文件,并且用户没有显式地声明使用哪个入口,那么
easymake 就会自己主动选择最新的那个计算器文件。

假设你须要显式地声明
ENTRY
,以选择
main.cpp
为例,能够输入命令
make
ENTRY=main.cpp
或者
make
ENTRY=m


[root@VM_6_207_centos entries]# make ENTRY=main.cpp
g++ -o bin/target bin/main.o bin/math/add.o bin/math/multiply.o  -static
BUILD_ROOT/TARGET: bin/target
ENTRY: main.cpp


到这里已经完毕了乘法模块的測试,接下来能够改动
main.cpp
的代码来整合我们的新模块了。为了简洁,接下来的步骤就不在这里赘述了,假设有须要。能够查看
samples/entries
文件夹中的代码。


原文及代码下载

最新的代码和文档请前往此处下载 https://github.com/roxma/easymake
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: