歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 動靜態GCC編譯case1

動靜態GCC編譯case1

日期:2017/3/1 9:17:28   编辑:Linux編程

源文件(這是Rechard Steven在unix 高級編程的代碼)
# cat liberr.h
#ifndef _LIBERR_H
#define _LIBERR_H

#include <stdarg.h>
#define MAXLINELEN 4096

void err_ret(const char *fmt, ...);

void err_quit(const char *fmt, ...);

void log_ret (char *logfile,const char *fmt, ...);

void log_quit(char *logfile,const char *fmt, ...);

void err_prn(const char *fmt,va_list ap, char *logfile);

#endif


# cat liberr.c
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "liberr.h"

void err_ret(const char *fmt, ...)
{
va_list ap;

va_start(ap,fmt);
err_prn(fmt,ap,NULL);
va_end(ap);
return;
}

void err_quit(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_prn(fmt, ap, NULL);
va_end(ap);
exit(EXIT_FAILURE);
}

void log_ret(char *logfile,const char *fmt, ...)
{
va_list ap;

va_start(ap,fmt);
err_prn(fmt,ap,logfile);
va_end(ap);
return;
}

void log_quit(char * logfile,const char *fmt, ...)
{
va_list ap;

va_start(ap,fmt);
err_prn(fmt,ap,logfile);
va_end(ap);
exit(EXIT_FAILURE);
}

extern void err_prn(const char *fmt, va_list ap, char *logfile)
{
int save_err;
char buf[MAXLINELEN];
FILE *plf;

save_err=errno;
vsprintf(buf,fmt,ap);
sprintf(buf + strlen(buf),":%s",strerror(save_err));
strcat(buf,"\n");
fflush(stdout);
if(logfile != NULL)
if((plf = fopen(logfile,"a")) != NULL ) {
fputs(buf,plf);
fclose(plf);
} else
fputs("failed to open log file\n,", stderr);
else
fputs(buf,stderr);
fflush(NULL);
return;
}
編譯及打包靜態包
#gcc -c liberr.c -o liberr.o
#ar rcs liberr.a liberr.o


# cat errtest.c
#include <stdio.h>
#include <stdlib.h>
#include "liberr.h"

#define ERR_QUIT_SKIP 1
#define LOG_QUIT_SKIP 1

int main(void)
{
FILE *pf;

puts("Tesing err_ret");
if((pf = fopen("foo","r")) == NULL) {
err_ret("%s %s","err_ret:","failed to open foo");
}

puts("Tesing log_ret");
if((pf = open("foo","r")) == NULL) {
log_ret("errtest.log","%s %s","log_ret:","failed to open foo");
}

#ifndef ERR_QUIT_SKIP
puts("Testing err_quit");
if((pf = open("foo","r")) == NULL) {
err_ret("%s %s","err_ret:","failed to open foo");
}
#endif


#ifndef LOG_QUIT_SKIP
puts("Testing log_quit");
if((pf = open("foo","r")) == NULL) {
log_ret("errtest.log","%s %s","log_quit:","failed to open foo");
}
#endif

exit(EXIT_SUCCESS);
}
靜態庫編譯:
[root@pc201 linux_guide]# gcc errtest.c -o errtest -L. -lerr --static
errtest.c: In function ‘main’:
errtest.c:18: warning: assignment makes pointer from integer without a cast
/usr/bin/ld: cannot find -lc
collect2: ld returned 1 exit status

解決辦法是安裝glibc-static
[root@pc201 linux_guide]# yum install glibc-static
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: mirrors.163.com
* extras: mirrors.163.com
* updates: ftp.stu.edu.tw
Setting up Install Process
Resolving Dependencies
--> Running transaction check
.... ..... ..........
Complete!

再次運行就沒有報錯了
[root@pc201 linux_guide]# gcc errtest.c -o errtest -L. -lerr --static
errtest.c: In function ‘main’:
errtest.c:18: warning: assignment makes pointer from integer without a cast


與動態庫分析:
建立動態庫:
#gcc -fPIC -g -c liberr.c -o liberr.o
#gcc -g -shared -Wl,soname,liberr.so -o liberr.so.1.0.0 liberr.o -lc
動態鏈接編譯的結果

靜態編譯的結果

看到比動態鏈接的大接近100倍。

下面示例調用動態庫內部的函數。這裡,我們要調用liberr.so裡的err_ret函數:

# cat dltest.c
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

int main(void)
{
void *handle;
void (*errfcn) (const char *fmt, ...); //errfcn是函數指針,它要指向要調用的err_ret
const char *errmsg;
FILE *pf;

handle = dlopen("./liberr.so",RTLD_NOW); // dlopen打開liberr.so,返回handle
if(handle==NULL) {
fprintf(stderr,"Failed to load liberr.so:%s\n",dlerror());
exit(EXIT_FAILURE);
}
dlerror(); // reset dl error
errfcn=dlsym(handle,"err_ret"); // dlsym 尋找handle裡的err_ret函數
if((errmsg = dlerror()) != NULL) {
fprintf(stderr,"Didn't find err_ret:%s\n",errmsg);
exit(EXIT_FAILURE);
}

if((pf = fopen("foobar","r")) == NULL) {
errfcn("Couldn't open foobar");
}

dlclose(handle); //關閉handle
exit(EXIT_FAILURE);
}

編譯
gcc -g dltest.c -Wall -ldl -o dltest

執行結果

無結果,調試:

發現代碼少了一段
if((pf = fopen("foobar","r")) == NULL) {
errfcn("Couldn't open foobar");
}
加進去,編譯,執行

Unix環境高級編程 源代碼地址 http://www.linuxidc.com/Linux/2011-04/34826.htm

Unix環境高級編程源碼編譯 http://www.linuxidc.com/Linux/2011-09/42503.htm

apue.h頭文件(Unix環境高級編程) http://www.linuxidc.com/Linux/2012-01/51729.htm

《Unix環境高級編程》(第二版)apue.h的錯誤 http://www.linuxidc.com/Linux/2011-04/34662.htm

Unix環境高級編程第二版讀書筆記 http://www.linuxidc.com/Linux/2011-04/34235.htm

《Unix環境高級編程》中apue.h的問題 http://www.linuxidc.com/Linux/2013-01/77686.htm

Linux升級GCC 4.8.1清晰簡明教程(Ubuntu 12.04 64位版為例) http://www.linuxidc.com/Linux/2014-04/99583.htm

Ubuntu下Vim+GCC+GDB安裝及使用 http://www.linuxidc.com/Linux/2013-01/78159.htm

Ubuntu下兩個GCC版本切換 http://www.linuxidc.com/Linux/2012-10/72284.htm

CentOS6.5升級手動安裝GCC4.8.2 http://www.linuxidc.com/Linux/2015-01/112595.htm

GCC 的詳細介紹:請點這裡

Copyright © Linux教程網 All Rights Reserved