斯坦佛编程教程-Unix编程工具(二)
第二节-make 当项目变得越来越大的时候,还用gcc命令来编译项目就没有那么吸引人了。make工具能够使编译和链接全自动化。在使用make工具的时候,程序员只需设置好项目所包含的文件和怎样去搭配好他们,接下来的make工具会自动完成编译和链接的工作。Make能够加速你的编译过程,因为假如你有十个.c的源文件但你只变动了一个文件而其它的九个文件在之前编译过那么它会知道在链接之前只需重新编译那一个单独的文件。Make有一些复杂的特性,但用它来作一些简单的事情是非常简单的。
运行make 进入到你的项目目录并且直接在控制台中输入make命令就能运行make了,或者在emacs中输入[esc]-x compile效果也是一样的。通常情况下,make会在当前目录下寻找一个名为MakeFile或是makefile的文件作为运行说明。如果在编译其中的一个目标文件的时候发生了错误,那么错误提示写入到标准错误提示中或是emacs编译缓冲中。
Makefiles Makefile文件中包含着一系列的变量定义和依赖规则。makefile中的一个变量是指 用于代表一些字符串的名字。这和c的预编译器中大量的替代很类似。这些变量通常用于表示一系列要搜寻的目录,编译器的选项,要运行的程序的名字。变量使用之前不许要提前声明,你只需要使用“=”来设置,例如: CC = gcc 就会生成一个叫做CC的变量,并且将它的值设置成gcc,变量名是大小写敏感的,通常我们会用大写来命名变量。
虽然我们能够为变量自定义变量名,但是有一些约定俗成的变量最好用于默认的设置,这样可以在使用makefile的时候更顺手。最重要的几个变量是:CC,CFLAGS和LDFLAGS。 CCC编译器的名称,这个在make的大部分版本中默认cc或gcc。 CFLAGS用于在编译的时候传给C的编译器的命令。这通常用来设置包含的路径和非标准目录或是编译版本。 LDFLAGS传给链接器的命令。这个通常用来包含库文件(-l)和设置库的搜索路径(-L)。
在需要引用一个变量的时候,只需将变量名扩起来,并且在前面加上一个美元符($)... CFLAGS = -g -I/usr/class/cs107/include $(CC) $(CFLAGS) -c binky.c
第一行是用来设置CFLAGS变量,加入一些调试信息,将-I/usr/class/cs107/include加入到搜索目录中去。第二行是引用CC变量来获得编译器的名字,引用CFLAGS来获得编译器的编译命令。没有被赋值的变量将是一个空的字符串。
第二个makefile的重要组成部分是依赖/建立规则,用于将源文件生成目标文件的规则。规则的书写顺序并没有多大影响,除了第一条规则被当成默认的规则——在make被调用的时候,如果没有任何参数,这条规则就会被调用(通常会是这种情况)。
一条命令通常包含两行:一条命令行,一条依赖行。 下面是一个例子: binky.o : binky.c binky.h akbar.h tab$(CC) $(CFLAGS) -c binky.c
这个依赖行指明了目标文件binky.o在binky.c binky.h akbar.h这三个文件中任何一个变化了之后都要再编译一遍,binky.o依赖于这三个文件。通常情况下,目标文件依赖于它的源文件和它里面包含的任何的非系统文件。程序员负责在makefile文件中表述清楚源文件中的依赖。在上面的例子中,很明显源文件是bink.c,头文件包括binky.h和akbar.h——它们中任何一个文件发生了改变,binky.c都要被重新编译一遍。(make工具依赖于尝试自动化makefile的设备,但这已经超出了我们的讨论范围了。)
命令行列出了建立binky.o的命令——在调用C编译器的时候使用,不管之前是否设置过(实际上可以有多行命令)。实质上,依赖行是一个触发器,用于设置什么时候去做什么是。命令则指明了做什么。
命令行之前必须有tab制表符用于缩进——如果只是用空格的话是没用的,虽然在你的编辑器中多个的空格看起来和一个制表符是一样的。(这样设定的原因是在make设计之初,当make的设计者意识到tab格式是一个很糟糕的设计的时候,他们依然维持了原先的设计只是为了兼容之前的版本——虽然那时之后10个用户。这就是“向后”在“向后兼容”这个词中的原因。最好不要再考虑这个问题了。)
因为空格和tab的问题,请确保你的编辑器可以分清多个空格和tab。当你在一些终端程序中使用复制/粘贴的时候,这可能会引发一些问题。为了确定在行首是否有一个tab字符,请将光标移至行首然后向右移动一个字符。如果光标移动了8个位置,那么那个位置是一个tab字符,如果是一个空格一个空格的移动的,那么你得删除所有的空格然后输入一个制表符。
在标准的编译中,命令行可以省略,make会更具源文件的格式使用默认的建立规则,.c是C文件,.f是Fortran文件等等。默认的C文件建立规则如下.. $(CC) $(CFLAGS) -c source-file.c
我们普遍会依赖与上面的默认建立规则——大部分的调整可以用修改CFLAGS变量来实现。下面十一个简单的但非常具有代表性的makefile。它编译了下面的文件:main.c, binky.c, binky.h, akbar.c,akbar.h, 和defs.h。这些文件会产生一些中间文件——main.0,binky.o和akbar.o。这些文件最后会链接在一起,生成一个可执行文件program。在makefile中空白行会被忽略,而注释的标志是'#'。
## A simple makefile
CC = gcc CFLAGS = -g -I/usr/class/cs107/include LDFLAGS = -L/usr/class/cs107/lib -lgraph
PROG = program HDRS = binky.h akbar.h defs.h SRCS = main.c binky.c akbar.c
## This incantation says that the object files ## have the same name as the .c files, but with .o OBJS = $(SRCS:.c=.o)
## This is the first rule (the default) ## Build the program from the three .o's $(PROG) : $(OBJS) tab$(CC) $(LDFLAGS) $(OBJS) -o $(PROG)
## Rules for the source files -- these do not have ## second build rule lines, so they will use the ## default build rule to compile X.c to make X.o main.o : main.c binky.h akbar.h defs.h
binky.o : binky.c binky.h akbar.o : akbar.c akbar.h defs.h
## Remove all the compilation and debugging files clean : tabrm -f core $(PROG) $(OBJS)
## Build tags for these sources TAGS : $(SRCS) $(HDRS) tabetags -t $(SRCS) $(HDRS)
第一条命令是用三个.o文件来编译程序,接下来是定义了三个命令比如 “main.o : main.c binky.h akbar.h defs.h” 用来定义.o目标文件的源文件依赖, 这些规则定义了要建立些什么文件,但是命令行被省略掉了,因此会采用默认的规则来创建.o文件,使用和.c文件相同的文件名。最后,make会自动识别X.o的源文件X.c,所以X.c在规则也可以被省略。所以第一条规则可以去掉main.c,改写成这样: "main.o : binky.h akbar.h defs.h".
接下来的命令,clean和TAGS,也执行了一些使过程简化的操作。clean命令是用来移除所有的目标文件、可执行文件,如果你没有调试过,有意个核心文件也会被移除,所以你可以从原始文件来执行建立。如果你想上初所有的编译和调试所产生的文件的话,你可以用make clean命令。如果你换了一个系统,这个系统和你目标库原始编译的系统的机构不一样,那么你也需要使用make clean 命令,而且你需要从草稿重新编译。TAGS规则用来创建一些标签,Unix的编写者可以用它来作为搜索的标志。
在Emacs中进行编译 Emacs对编译过程有着内置的支持。键入M-x compile即可在emacs中编译你的代码。你会得到一个编译命令提示。如果你写了makefile,只要输入make并回车,makefile就会被读取,一些命令就会执行。在这个时候Emacs的缓冲区就会分离开来,编译错误信息会放在最新产生的缓冲区。为了到错误产生的代码所在的行,只需把光标定位在错误信息上,并按^c-^c,这样就会跳转到对应的代码上(“cc”是很早的一个C编译器的简称)。
运行make 进入到你的项目目录并且直接在控制台中输入make命令就能运行make了,或者在emacs中输入[esc]-x compile效果也是一样的。通常情况下,make会在当前目录下寻找一个名为MakeFile或是makefile的文件作为运行说明。如果在编译其中的一个目标文件的时候发生了错误,那么错误提示写入到标准错误提示中或是emacs编译缓冲中。
Makefiles Makefile文件中包含着一系列的变量定义和依赖规则。makefile中的一个变量是指 用于代表一些字符串的名字。这和c的预编译器中大量的替代很类似。这些变量通常用于表示一系列要搜寻的目录,编译器的选项,要运行的程序的名字。变量使用之前不许要提前声明,你只需要使用“=”来设置,例如: CC = gcc 就会生成一个叫做CC的变量,并且将它的值设置成gcc,变量名是大小写敏感的,通常我们会用大写来命名变量。
虽然我们能够为变量自定义变量名,但是有一些约定俗成的变量最好用于默认的设置,这样可以在使用makefile的时候更顺手。最重要的几个变量是:CC,CFLAGS和LDFLAGS。 CCC编译器的名称,这个在make的大部分版本中默认cc或gcc。 CFLAGS用于在编译的时候传给C的编译器的命令。这通常用来设置包含的路径和非标准目录或是编译版本。 LDFLAGS传给链接器的命令。这个通常用来包含库文件(-l)和设置库的搜索路径(-L)。
在需要引用一个变量的时候,只需将变量名扩起来,并且在前面加上一个美元符($)... CFLAGS = -g -I/usr/class/cs107/include $(CC) $(CFLAGS) -c binky.c
第一行是用来设置CFLAGS变量,加入一些调试信息,将-I/usr/class/cs107/include加入到搜索目录中去。第二行是引用CC变量来获得编译器的名字,引用CFLAGS来获得编译器的编译命令。没有被赋值的变量将是一个空的字符串。
第二个makefile的重要组成部分是依赖/建立规则,用于将源文件生成目标文件的规则。规则的书写顺序并没有多大影响,除了第一条规则被当成默认的规则——在make被调用的时候,如果没有任何参数,这条规则就会被调用(通常会是这种情况)。
一条命令通常包含两行:一条命令行,一条依赖行。 下面是一个例子: binky.o : binky.c binky.h akbar.h tab$(CC) $(CFLAGS) -c binky.c
这个依赖行指明了目标文件binky.o在binky.c binky.h akbar.h这三个文件中任何一个变化了之后都要再编译一遍,binky.o依赖于这三个文件。通常情况下,目标文件依赖于它的源文件和它里面包含的任何的非系统文件。程序员负责在makefile文件中表述清楚源文件中的依赖。在上面的例子中,很明显源文件是bink.c,头文件包括binky.h和akbar.h——它们中任何一个文件发生了改变,binky.c都要被重新编译一遍。(make工具依赖于尝试自动化makefile的设备,但这已经超出了我们的讨论范围了。)
命令行列出了建立binky.o的命令——在调用C编译器的时候使用,不管之前是否设置过(实际上可以有多行命令)。实质上,依赖行是一个触发器,用于设置什么时候去做什么是。命令则指明了做什么。
命令行之前必须有tab制表符用于缩进——如果只是用空格的话是没用的,虽然在你的编辑器中多个的空格看起来和一个制表符是一样的。(这样设定的原因是在make设计之初,当make的设计者意识到tab格式是一个很糟糕的设计的时候,他们依然维持了原先的设计只是为了兼容之前的版本——虽然那时之后10个用户。这就是“向后”在“向后兼容”这个词中的原因。最好不要再考虑这个问题了。)
因为空格和tab的问题,请确保你的编辑器可以分清多个空格和tab。当你在一些终端程序中使用复制/粘贴的时候,这可能会引发一些问题。为了确定在行首是否有一个tab字符,请将光标移至行首然后向右移动一个字符。如果光标移动了8个位置,那么那个位置是一个tab字符,如果是一个空格一个空格的移动的,那么你得删除所有的空格然后输入一个制表符。
在标准的编译中,命令行可以省略,make会更具源文件的格式使用默认的建立规则,.c是C文件,.f是Fortran文件等等。默认的C文件建立规则如下.. $(CC) $(CFLAGS) -c source-file.c
我们普遍会依赖与上面的默认建立规则——大部分的调整可以用修改CFLAGS变量来实现。下面十一个简单的但非常具有代表性的makefile。它编译了下面的文件:main.c, binky.c, binky.h, akbar.c,akbar.h, 和defs.h。这些文件会产生一些中间文件——main.0,binky.o和akbar.o。这些文件最后会链接在一起,生成一个可执行文件program。在makefile中空白行会被忽略,而注释的标志是'#'。
## A simple makefile
CC = gcc CFLAGS = -g -I/usr/class/cs107/include LDFLAGS = -L/usr/class/cs107/lib -lgraph
PROG = program HDRS = binky.h akbar.h defs.h SRCS = main.c binky.c akbar.c
## This incantation says that the object files ## have the same name as the .c files, but with .o OBJS = $(SRCS:.c=.o)
## This is the first rule (the default) ## Build the program from the three .o's $(PROG) : $(OBJS) tab$(CC) $(LDFLAGS) $(OBJS) -o $(PROG)
## Rules for the source files -- these do not have ## second build rule lines, so they will use the ## default build rule to compile X.c to make X.o main.o : main.c binky.h akbar.h defs.h
binky.o : binky.c binky.h akbar.o : akbar.c akbar.h defs.h
## Remove all the compilation and debugging files clean : tabrm -f core $(PROG) $(OBJS)
## Build tags for these sources TAGS : $(SRCS) $(HDRS) tabetags -t $(SRCS) $(HDRS)
第一条命令是用三个.o文件来编译程序,接下来是定义了三个命令比如 “main.o : main.c binky.h akbar.h defs.h” 用来定义.o目标文件的源文件依赖, 这些规则定义了要建立些什么文件,但是命令行被省略掉了,因此会采用默认的规则来创建.o文件,使用和.c文件相同的文件名。最后,make会自动识别X.o的源文件X.c,所以X.c在规则也可以被省略。所以第一条规则可以去掉main.c,改写成这样: "main.o : binky.h akbar.h defs.h".
接下来的命令,clean和TAGS,也执行了一些使过程简化的操作。clean命令是用来移除所有的目标文件、可执行文件,如果你没有调试过,有意个核心文件也会被移除,所以你可以从原始文件来执行建立。如果你想上初所有的编译和调试所产生的文件的话,你可以用make clean命令。如果你换了一个系统,这个系统和你目标库原始编译的系统的机构不一样,那么你也需要使用make clean 命令,而且你需要从草稿重新编译。TAGS规则用来创建一些标签,Unix的编写者可以用它来作为搜索的标志。
在Emacs中进行编译 Emacs对编译过程有着内置的支持。键入M-x compile即可在emacs中编译你的代码。你会得到一个编译命令提示。如果你写了makefile,只要输入make并回车,makefile就会被读取,一些命令就会执行。在这个时候Emacs的缓冲区就会分离开来,编译错误信息会放在最新产生的缓冲区。为了到错误产生的代码所在的行,只需把光标定位在错误信息上,并按^c-^c,这样就会跳转到对应的代码上(“cc”是很早的一个C编译器的简称)。