在开始学习Stevens的《UNIX环境高级编程》的时候遇到一个问题,即是书中大量的例程用到了作者自己的头文件ourhdr.h,导致例程无法编译通过。这其实Stevens为了让例程更简洁而写的头文件和错误处理例程myerror.c,即书附录中的ourhdr.h,
err_xxx,log_xxx。
如下是书中Program
1.1例程ls.c。其中的err_quit()函数就是myerror.c中的函数,其头文件就定义ourhdr.h当中。我们在编译ls.c的时候必须将myerror.c列入gcc编译源文件,或者将myerror.c预先编译成库文件即
.a 文件,然后通过第三方函数库引入编译过程,即gcc提供的 -I -L选项。
#include
#include
#include "ourhdr.h"
int
main(int argc, char *argv[])
{
DIR *dp;
struct dirent *dirp;
if (argc != 2)
err_quit("a single argument (the directory name) is
required");
if ( (dp = opendir(argv[1])) == NULL)
err_sys("cat't open %s, argv[1]");
while ( (dirp = readdir(dp)) != NULL)
printf("%s\n", dirp->d_name);
closedir(dp);
exit(0);
}
这里介绍两种解决方法:
第1种,用gcc编译时加上myserror.c,也可用makefile编译程序
第2种,将myerror.c生成库文件libmy.a,每次编译时只需加个这个函数库。
第1种方案如图:
第2种方案其实就是预编译函数库的问题。在BBK小布老师GCC视频课程有详细介绍。这里就这个问题作个简单说明。
最初在编译myerror.c的时候遇到如下问题:
/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../../crt1.o(.text+0x18):
In function `_start':
../sysdeps/i386/elf/start.S:77: undefined reference to `main'
collect2: ld returned 1 exit status
这是因为myerror.c文件中没有main函数,只有一系列的错误处理函数,所以编译时不能通过。
解决步骤:
1.生成目标文件:$gcc -Wall -c
myerror.c 生成myerror.o
2.生成库文件: $ar cr libmy.a
myerror.o 生成libmy.a,这里可以将多个.o文件放在后面做成一个库
3.编译ls.c: $gcc -Wall ls.c
libmy.a 生成a.out可以执行文件
以下方法和贴出源文件均在虚拟机Reahat
9.0上实验通过,过程如下:
ourhdr.h, myerror.c(加粗,红色)如下:
#ifndef __ourhdr_h
#define __ourhdr_h
#include
#include
#include
#include
#include
#define MAXLINE 4096 #define
FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
#define
DIR_MODE (FILE_MODE | S_IXUSR | S_IXGRP | S_IXOTH)
typedef void Sigfunc (int);
#if defined(SIG_IGN) &&
!defined(SIG_ERR)
#define SIG_ERR ((Sigfunc *)-1)
#endif
#define
min(a,b) ((a) < (b) ? (a) : (b))
#define
max(a,b) ((a) > (b) ? (a) : (b))
char *path_alloc (int *);
int open_max (void); void clr_fl (int, int); void set_fl (int, int); void pr_exit (int); void pr_mask (const char *);
Sigfunc *signal_intr (int, Sigfunc *);
int tty_cbreak (int); int tty_raw (int); int tty_reset (int); void tty_atexit
(void);
#ifdef ECHO struct termios *tty_termios (void);
#endif
void sleep_us (unsigned int);
ssize_t readn (int, void *, size_t);
ssize_t writen (int, const void *, size_t);
int daemon_init (void); int s_pipe (int *); int recv_fd (int, ssize_t (*func) (int, const void *,
size_t));
int send_fd (int, int); int send_err (int, int, const char *);
int serv_listen (const char *);
int serv_accept (int, uid_t *);
int cli_conn (const char *);
int buf_args (char *, int (*func) (int, char **));
int ptym_open (char *); int ptys_open (int, char *);
#ifdef TIOCGWINSZ
pid_t pty_fork (int *, char *, const struct termios *, const struct
winsize *);
#endif
int lock_reg (int, int, int, off_t, int, off_t);
#define read_lock(fd, offset, whence, len) \
lock_reg (fd, F_SETLK,
F_RDLCK, offset, whence, len)
#define readw_lock(fd, offset, whence, len) \
lock_reg (fd, F_SETLKW,
F_RDLCK, offset, whence, len)
#define write_lock(fd, offset, whence, len) \
lock_reg (fd, F_SETLK,
F_WRLCK, offset, whence, len)
#define writew_lock(fd, offset, whence, len) \
lock_reg (fd, F_SETLKW,
F_WRLCK, offset, whence, len)
#define un_lock(fd, offset, whence, len) \
lock_reg (fd, F_SETLK,
F_UNLCK, offset, whence, len)
pid_t lock_test (int, int, off_t, int, off_t);
#define is_readlock(fd, offset, whence, len) \
lock_test (fd, F_RDLCK,
offset, whence, len)
#define is_writelock(fd, offset, whence, len) \
lock_test (fd, F_WRLCK, offset, whence, len)
void err_dump (const char *, ...);
void err_msg (const char *, ...);
void err_quit (const char *, ...);
void err_ret (const char *, ...);
void err_sys (const char *, ...);
void log_msg (const char *, ...);
void log_open (const char *, int, int);
void log_quit (const char *, ...);
void log_ret (const char *, ...);
void log_sys (const char *, ...);
void TELL_WAIT (void); void TELL_PARENT (pid_t);
void TELL_CHILD (pid_t);
void WAIT_PARENT (void);
void WAIT_CHILD (void);
#endif
#include
#include
#include "ourhdr.h" static void err_doit(int, const char *,
va_list); char *pname =
NULL; void err_ret(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(1, fmt, ap); va_end(ap); return; } void err_sys(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(1, fmt, ap); va_end(ap); exit(1); } void err_dump(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(1, fmt, ap); va_end(ap); abort(); exit(1); } void err_msg(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(0, fmt, ap); va_end(ap); return; } void err_quit(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(0, fmt, ap); va_end(ap); exit(1); } static void err_doit(int errnoflag, const char *fmt, va_list
ap) { int errno_save; char buf[MAXLINE]; errno_save =
errno; vsprintf(buf, fmt, ap); if (errnoflag) sprintf
(buf+strlen(buf), ": %s", strerror
(errno_save)); strcat (buf, "\n"); fflush(stdout); fputs(buf, stderr); fflush(NULL);