linux程序设计——多个源文件带来的问题(第九章)

第九章 开发工具

本章介绍一些linux系统中的程序开发工具,其中一些工具也可以在UNIX系统中使用.linux系统除提供开发人员必须的编译器和调试器外,还提供一组工具,其中每个都可以完成一件独立的任务,并且允许开发人员将它们创造性地组合在一起,而这种组合能力也是linux从UNIX的哲学体系中继承而来的.

9.1 多个源文件带来的问题

在编写小程序时,许多人都会在编辑完源文件后重新编译所有文件来重组应用程序.但是对大型程序来说,使用这种简单的处理方式会带来一些很明显的问题.编辑--编译--测试这一循环的周期将变长.如果仅改动了一个源文件,可能需要重新编译所有的源文件.

如果在程序中创建了多个头文件,并在不同的源文件中包含它们,这种处理方式会带来一个潜在的,更严重的问题.比如说,有3个头文件a.h,b.h,c.h,3个C源文件main.c,2.c和3.c,具体情况如下所示:

/* main.c */

#include "a.h"

...

/* 2.c */

#include "a.h"

#include "b.h"

...

/* 3.c */

#include "b.h"

#include "c.h"

...

如果程序员只修改了头文件c.h,则源文件main.c和2.c无需重新编译,因为它们并不依赖于这个头文件,而对于源文件3.c来说,因为它包含了头文件c.h,所以在头文件c.h改动后,就必须编译它.如果忘记重新编译,则最终的程序很可能无法正常工作的.

make工具可以解决这个问题,它会在必要时重新编译所有受影响的源文件.

make命令不仅用于编译程序,无论何时,当需要通过多个输入文件来生成输出文件时,可以利用它来完成任务,它的其他用法还包括文档处理(例如针对troff或者TeX文档)

9.2 make命令和makefile文件

虽然make命令内置了很多智能机制,但是光凭自身是无法了解如何建立应用程序的.必须为其提供一个文件,告诉它应用程序应该如何构造,这个文件称为makefile.

makefile文件一般都会和项目的其他源文件放在同一目录下.事实上,如果管理的是一个大项目,可以用多个不同的makefile文件来分别管理项目的不同部分.

make命令和makefile文件的结合提供了一个在项目管理领域非常强大的工具.它不仅常被用于控制源代码的编译,而且还用于手册页的编写以及将应用程序安装到目标目录.

9.2.1 makefile的语法

makefile文件由一组依赖关系和规则构成.每个依赖关系由一个目标(即要创建的文件)和一组该目标所依赖的源文件组成.而规则描述了如何通过这些依赖文件创建目标.一般来说,目标是一个单独的可执行文件.

make命令会读取makefile文件的内容,它先确定目标文件或要创建的文件,然后比较目标所依赖的源文件的日期和时间以决定该采用哪条规则来构造目标.通常在创建最终的目标文件之前,它需要先创建一些中间目标.make命令会根据makefile文件来确定目标文件的创建顺序以及正确规则调用顺序.

9.2.2 make命令的选项和参数

make程序本身有许多选项,其中最常用的3个选项入校所示:

-k:它的作用是让make命令在发现错误时仍然继续执行,而不是在检测到第一个错误时就停下来.可以利用这个选项在一次操作中发现所有未编译成功的源文件.

-n:它的作用是让make命令输出将要执行的操作步骤,而不是真正执行这些操作.

-f <filename>:它的作用是告诉make命令将哪个文件作为makefile文件.如果未使用这个选项,标准版本的make命令将首先在当前目录下查找名为makefile的文件.如果该文件不存在,它就会查找名为Makefile的文件.按照惯例许多linux程序员使用文件名Makefile,因为如果一个目录下都是以小写字母为名称的文件,则Makefile文件将在目录的文件列表中第一个出现.

为了指示make命令创建一个特定的目标(通常是可执行文件),可以把该目标的名字作为make命令的一个参数.

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-07 07:04:15

linux程序设计——多个源文件带来的问题(第九章)的相关文章

linux程序设计——make命令和makefile文件(第九章)

9.2 make命令和makefile文件 9.2.3 makefile文件中的注释 makefile文件中的注释以#号开头,一直延续到这一行的结束.和C语言的源文件注释一样,makefile文件中的注释可以帮助程序的编写者以及其他人理解最初编写这个文件的目的. 9.2.4 makefile文件中的宏 mkaefile文件允许使用宏以一种更通用的格式来书写它们. 通过语句MACRONAME=value在makefile文件中定义宏,引用宏的方法是使用$(MACRONAME)或${MACRONAM

linux程序设计——进程和信号总结(第十一章)

11.4.2    信号集 头文件signal.h定义了类型sigset_t和用来处理信号集的函数.sigaction和其他函数.sigaction和其他函数将用这些信号集来修改进程在接收到信号时的行为. #include <signal.h> int sigaddset(sigset_t *set, int signo); int sigemptyset(sigset_t *set); int sigfillset(sigset_t *set); int sigdelset(sigset_t

linux程序设计——IPC状态命令(第十四章)

14.5    IPC状态命令 虽然X/Open规范并没有定义它们,但大多数linux系统都提供了一组命令,用于从命令行上访问IPC信息以及清理游离的IPC机制.它们是ipcs和ipcrm命令,这两个命令对于开发程序非常有用. IPC机制一个让人烦恼的问题是:编写错误的程序或者因为某些原因而执行失败的程序把它的IPC资源(如消息队列中的数据)遗留在系统中,并且这些资源在程序结束后很长时间仍然在系统中游荡.这将导致对程序的新调用执行失败,因为程序期望以一个干净的系统来启动,但事实上却发现一些遗留的

linux程序设计——CD唱片应用程序(第七章)

7.4 CD唱片应用程序 这篇为第七章的CD唱片应用程序,代码在CD唱片应用程序代码下载.我们使用dbm数据库对数据存储,改进之前的CD唱片应用程序. 7.4.1 更新设计 虽然在文件中以逗号分隔变量来存储信息是一种在shell中很容易实现的方式,但是这样局限性很大,因为许多CD标题和曲目都包含逗号.可以通过使用dbm数据库来改进这种方法. 将CD资料分为标题和曲目两个部分,并用不同的文件来保存它们. 前面的实现存在一个问题,即将应用程序的数据访问部分和用户接口部分混在了一起,这与程序全实现在一

《Linux程序设计 第四版》之第三章的练习题

1.P103 一个目录扫描程序. #include<stdio.h> #include<dirent.h> #include<sys/stat.h> int isAdir(char* path); //判断路径是否是目录类型 void printdirs(char* path,int depth) //递归遍历打印文件与目录名 { DIR* dir=opendir(path); struct dirent* dirents; chdir(path); while(dir

linux程序设计——取消一个线程(第十二章)

12.7    取消一个线程 有时,想让一个线程能够要求还有一个线程终止,就像给它发送一个信号一样. 线程有方法能够做到这一点,与与信号处理一样.线程能够被要求终止时改变其行为. pthread_cancel是用于请求一个线程终止的函数: #inlude <pthread.h> int pthread_cancel(pthread_t thread); 这个函数提供一个线程标识符就能够发送请求来取消它. 线程能够用pthread_setcancelstate设置线程的取消状态 #include

linux程序设计——线程的属性(第十二章)

12.6    线程的属性 在前面的所有程序示例中,都在程序退出之前用pthread_join对线程再次进行同步,如果想让线程向创建它的线程返回数据就需要这样做.但有时,也有这种情况,既不需要第二个线程向主线程返回信息,也不想让主线程等待它的结束. 假设在主线程继续为用户提供服务的同时创建了第二个线程,新线程的作用是将用户正在编辑的数据文件进行备份存储.备份工作结束后,第二个线程就可以直接终止了,它没有必要再回到主线程中. 可以创建这一类型的线程,它们被称为脱离线程(detached threa

《Linux程序设计 第四版》之第四章的练习题

1.P128 一个获取日期 时间 格式化获取时间 日期 的程序. #include<stdio.h> #include<time.h> int main(int argc,char** argv) { struct tm* time1,*time_trans; //时间数据结构 time_t alt; char c_time[128]; char* result; char* result1=""; time(&alt); time1=localtime

linux程序设计——父进程和子进程(第十三章)

13.5    父进程和子进程 这节将介绍如何在子进程中运行一个与父进程完全不同的另外一个程序,而不是仅仅运行一个相同程序.使用exec调用来完成这一项工作.这里的一个难点是,通过exec调用的进程需要知道应该访问哪个文件描述符.在前面的例子中,因为子进程本身有file_pipes数据的一份副本(点击打开"fork复制进程映像"链接),所以这并不成为问题.但经过exec调用后,情况就不一样了,因为原来的进程已经被新的进程替换了.为解决这个问题,可以将文件描述符(实际上它只是一个数字)作